
Nedavno je jedna poznata kompanija objavila da prebacuje svoju liniju laptopa na ARM arhitekturu. Kada sam čuo tu vest, setio sam se: dok sam još jednom pregledavao cene EC2 na AWS-u, primetio sam Graviton procesore sa vrlo atraktivnom cenom. U toj situaciji, naravno, postojala je caka, jer je to ARM. Tada mi nije padalo na pamet da je ARM zapravo vrlo ozbiljna stvar...
Ova arhitektura mi je uvek bila rezervisana za mobilne i razne IoT uređaje. "Pravi" serveri na ARM-u deluju nekako neobično, čak i ekstremno... Međutim, nova ideja mi se uvučila u glavu, pa sam jednog vikenda odlučio da proverim što se danas može pokrenuti na ARM-u. I za to sam odlučio da počnem sa nečim bliskim i poznatim — Kubernetes klasterom. Pri tome ne govorim o nekakvom uslovnom "klasteru", već o pravom, da bude što sličniji onome što sam navikao da viđam u produkciji.
Moj plan je bio da klaster bude dostupan sa interneta, da pokreće neku web aplikaciju i takođe da ima bar osnovni nadzor. Za realizaciju ove ideje biće mi potrebno nekoliko (ili više) Raspberry Pi uređaja, modela 3B+. Mesto za eksperimentisanje moglo bi biti i AWS, ali su me zapravo zanimali upravo "malini" (koji su, ionako, stajali neiskorišćeni). Tako ćemo na njima postaviti Kubernetes klaster sa Ingress-om, Prometheus-om i Grafana-om.
Priprema "malina"
Instalacija OS-a i SSH
Sa izborom OS-a za instalaciju nisam se previše opterećivao: jednostavno sam uzeo najnoviji Raspberry Pi OS Lite sa . Tamo je dostupna , sve radnje koje treba izvršiti na svim čvorovima budućeg klastera. Zatim je potrebno izvršiti sledeće radnje (takođe na svim čvorovima).
Povezivanje monitora i tastature, potrebno je prethodno podesiti mrežu i SSH:
- Za rad klastera, master mora imati statičku IP adresu, dok radni čvorovi mogu imati po izboru. Ja sam odabrao statične adrese svuda zbog lakšeg podešavanja.
- Statičku adresu možete konfigurisati u OS-u (u datoteci
/etc/dhcpcd.confima adekvatan primer) ili fiksiranjem lease-a na DHCP serveru korišćenog (u mom slučaju — domaćem) ruteru. - ssh-server se jednostavno uključuje u raspi-config (interfacing options → ssh).
Nakon toga se možete ulogovati putem SSH-a (podrazumevani korisnički naziv je pi, a lozinka je raspberry ili ona koju ste promenili) i nastaviti sa podešavanjima.
Druge postavke
- Nastavimo ime hosta. U mom primeru koristićemo
pi-controlinpi-worker. - Proverimo da li je datotečni sistem proširen na celu disk (
df -h /). U slučaju potrebe, može se proširiti pomoću raspi-config. - Promenićemo zadatu lozinku korisnika u raspi-config.
- Isključićemo swap-fajl (to je zahtev Kubernetes-a; ako vas zanimaju detalji o ovoj temi, pogledajte ):
dphys-swapfile swapoff systemctl disable dphys-swapfile - Ažuriraćemo pakete na najnovije verzije:
apt-get update && apt-get dist-upgrade -y - Instaliraćemo Docker i dodatne pakete:
apt-get install -y docker docker.io apt-transport-https curl bridge-utils iptables-persistentTokom instalacije
iptables-persistentbiće potrebno sačuvati postavke iptables za ipv4, a u datoteci/etc/iptables/rules.v4— dodati pravila u lanacFORWARD, tako:# Generated by xtables-save v1.8.2 on Sun Jul 19 00:27:43 2020 *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] -A FORWARD -s 10.1.0.0/16 -j ACCEPT -A FORWARD -d 10.1.0.0/16 -j ACCEPT COMMIT - Preostaje samo da se ponovo pokrene.
Sada je sve spremno za instalaciju Kubernetes klastera.
Instalacija Kubernetes-a
U ovoj fazi namerno sam odložio svu moju i našu korporativnu obradu automatizacije instalacije i konfiguracije K8s klastera. Umesto toga, koristićemo zvaničnu dokumentaciju sa (malo dopunjenom komentarima i skraćenicama).
Dodajemo repozitorij Kubernetes-a:
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt-get updateDalje u dokumentaciji predlaže se instalacija CRI (interfejs za izvršavanje kontejnera). Pošto je Docker već instaliran, idemo dalje i instaliramo glavne komponente:
sudo apt-get install -y kubelet kubeadm kubectl kubernetes-cni Na koraku instalacije glavnih komponenti odmah sam dodao kubernetes-cni, koji je neophodan za rad klastera. I ovde postoji važna stvar: paket kubernetes-cni iz nekog razloga ne stvara podrazumevanu direktoriju za postavke CNI interfejsa, pa sam je morao kreirati ručno:
mkdir -p /etc/cni/net.dZa rad network-bekenda, o kojem će biti reči u nastavku, potrebno je dodatno instalirati CNI plugin. Izabrao sam poznati i razumljiv meni plugin portmap (ceo njihov spisak pogledajte u ):
curl -sL https://github.com/containernetworking/plugins/releases/download/v0.7.5/cni-plugins-arm-v0.7.5.tgz | tar zxvf - -C /opt/cni/bin/ ./portmapNastavitev Kubernetes
Čvor sa kontrolnim planom
Instalacija samog klastera odvija se prilično jednostavno. A da bismo ubrzali ovaj proces i proverili da li su Kubernetes imidži dostupni, možemo prethodno izvršiti:
kubeadm config images pullSada sprovodimo samu instalaciju — inicijalizujemo control plane klastera:
kubeadm init --pod-network-cidr=10.1.0.0/16 --service-cidr=10.2.0.0/16 --upload-certsUpoštevajte, da se omrežja za storitve in pod-e ne smejo prekrivati med seboj in z obstoječimi omrežji.
Na koncu bomo prejeli sporočilo, da je vse v redu, in nam povedali, kako povezati delovne vozlišča s kontrolno enoto:
Vaša kontrolna enota Kubernetes je uspešno inicializirana!
Za začetek dela s svojim grozdom morate kot navaden uporabnik izvesti naslednje:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Zdaj morate razporediti omrežje podov v grozd.
Zaženite "kubectl apply -f [podnetwork].yaml" z eno od možnosti, navedenih na:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Zdaj lahko na kontrolno enoto povežete poljubno število vozlišč z izvajanjem naslednjega ukaza na vsakem kot root:
kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4
--discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050
--contrl-plane --certificate-key 72a3c0a14c627d6d7fdade1f4c8d7a41b0fac31b1faf0d8fdf9678d74d7d2403
Upoštevajte, da ključ certifikata daje dostop do občutljivih podatkov grozda, zato ga hranite v tajnosti!
Kot zaščita se naloženi certifikati izbrišejo v dveh urah; po potrebi lahko uporabite
"kubeadm init phase upload-certs --upload-certs" za ponovno nalaganje certifikatov.
Nato lahko na delovna vozlišča povežete poljubno število vozlišč tako, da na vsakem izvedete naslednje kot root:
kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4
--discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050Izvedimo priporočila za dodajanje konfiguracije za uporabnika. Priporočam tudi, da takoj dodate samodejno dopolnjevanje za kubectl:
kubectl completion bash > ~$HOME/.kube/completion.bash.inc
printf "
# Dopolnjevanje lupine Kubectl
source '$HOME/.kube/completion.bash.inc'
" >> $HOME/.bash_profile
source $HOME/.bash_profileNa tej točki lahko že vidite prvo vozlišče v grozdu (res je, da še ni pripravljeno):
root@pi-control:~# kubectl get no
IME STATUS ROLI STAROST VERZIJA
pi-control NotReady master 29s v1.18.6Konfiguracija omrežja
Nato, kot je bilo omenjeno v sporočilu po namestitvi, bo potrebno v grozd namestiti omrežje. V dokumentaciji ponujajo izbiro med Calico, Cilium, contiv-vpp, Kube-router in Weave Net… Tukaj sem odstopil od uradne navodila in izbral bolj znano in razumljivo možnost: v načinu host-gw (več o razpoložljivih backendih glejte v ).
Namestitev v grozd je precej enostavna. Na začetku — prenesemo manifeste:
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml Nato v nastavitvah spremenimo tip z vxlan na host-gw:
sed -i 's/vxlan/host-gw/' kube-flannel.yml… in podomrežje podov — iz privzete vrednosti na tisto, ki je navedena pri inicializaciji grozda:
sed -i 's#10.244.0.0/16#10.1.0.0/16#' kube-flannel.ymlPo tem ustvarimo vire:
kubectl create -f kube-flannel.yml Končano! Čez nekaj časa bo prvo vozlišče K8s prešlo v stanje Ready:
IME STATUS ROLI STAROST VERZIJA
pi-control Ready master 2m v1.18.6Dodajanje delovnega vozlišča
Sedaj lahko dodate delavca. To storite tako, da na njem — po namestitvi samega Kubernetes po scenariju, opisanem zgoraj — preprosto izvedete prej pridobljeno ukaz:
kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4
--discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050S tem lahko štejemo, da je grozd pripravljen:
root@pi-control:~# kubectl get no
NAME STATUS ROLES AGE VERSION
pi-control Ready master 28m v1.18.6
pi-worker Ready 2m8s v1.18.6Imel sem na voljo samo dve Raspberry Pi, zato mi ni bilo ljubše, da bi eno od njih le da bi postala del kontrolnega vozlišča. Zato sem s pomočjo ukaza odstranil samodejno nameščen taint na vozlišču pi-control:
root@pi-control:~# kubectl edit node pi-control… in izbrisal vrstice:
- effect: NoSchedule
key: node-role.kubernetes.io/masterNapolnitev grozda z minimalnimi zahtevami
Najprej potrebujemo Helm. Seveda, vse to lahko naredite tudi brez njega, a Helm omogoča, da nekaterih komponent praktično ne spreminjate, ampak jih nastavljate po svoji izbiri. Po dejanskem stanju gre preprosto za izvršljivo datoteko, ki „ne prosi za hrano“.
Torej, odprete spletno stran v razdelku docs/installation in izvedete ukaz od tam:
curl -s https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bashPo tem dodamo repo za grafe:
helm repo add stable https://kubernetes-charts.storage.googleapis.com/Zdaj namestimo infrastrukturne komponente v skladu z načrtom:
- Ingress kontroler;
- Prometheus;
- Grafana;
- cert-manager.
Ingress kontroler
Prva komponenta — Ingress kontroler — se namestiti precej enostavno in je pripravljena za uporabo „iz škatle“. Za to zadostuje, da se prijavite v in izvedete ukaz za namestitev od tam:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.34.1/deploy/static/provider/baremetal/deploy.yamlVendar pa je v tem trenutku „malina“ začela obremenjevati in trčiti ob diskovni IOPS. Gre za to, da z Ingress kontrolerjem namestimo veliko število virov, se opravijo številna API povpraševanja in posledično se zapiše veliko podatkov v etcd. Na splošno, bodisi je SD kartica razreda 10 ne zelo zmogljiva, bodisi preprosto pomnilniške kartice ne zadoščajo za takšno obremenitev. Kljub temu se je po približno 5 minutah vse zagnalo.
Ustvarjen je bil namespace in v njem se je pojavil kontroler ter vse, kar je potreboval:
root@pi-control:~# kubectl -n ingress-nginx get pod
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-2hwdx 0/1 Completed 0 31s
ingress-nginx-admission-patch-cp55c 0/1 Completed 0 31s
ingress-nginx-controller-7fd7d8df56-68qp5 1/1 Running 0 48sPrometheus
Naslednji dva komponenta sta precej enostavna za namestitev preko Helma iz chart repozitorija.
Najdemo Prometheus, ustvarimo namespace in ga namestimo:
helm search repo stable | grep prometheus
kubectl create ns monitoring
helm install prometheus --namespace monitoring stable/prometheus --set server.ingress.enabled=True --set server.ingress.hosts={"prometheus.home.pi"}Privzeto Prometheus zahteva 2 diska: enega za podatke samega Prometheusa in drugega za podatke AlertManagerja. Ker v grozdu ni ustvarjen storage class, diski ne bodo zahtevani in podi se ne bodo zagnali. Za bare metal namestitve Kubernetes običajno uporabljamo Ceph rbd, vendar je v primeru Raspberry Pi to očitno preveliko breme.
Zato bomo ustvarili enostavno lokalno shrambo na hostpath. Manifesti PV (persistent volume) za prometheus-server in prometheus-alertmanager so združeni v datoteki prometheus-pv.yaml u . Direktorij za PV je treba vnaprej ustvariti na disku tistega vozlišča, na katerega želimo povezati Prometheus: v primeru je navedeno nodeAffinity po hostname pi-worker inna in na njem so ustvarjeni direktoriji /data/localstorage/prometheus-server in /data/localstorage/prometheus-alertmanager.
Prenesemo (kloniramo) manifest in ga dodamo v Kubernetes:
kubectl create -f prometheus-pv.yamlV tem koraku sem se prvič srečal s težavo ARM arhitekture. Kube-state-metrics, ki je privzeto nameščen v chartu Prometheus, se ni zagnal. Vračal je napako:
root@pi-control:~# kubectl -n monitoring logs prometheus-kube-state-metrics-c65b87574-l66d8
standard_init_linux.go:207: exec user process caused "exec format error"Gre za to, da za kube-state-metrics uporabljamo sliko projekta CoreOS, ki je ne izdelujejo za ARM:
kubectl -n monitoring get deployments.apps prometheus-kube-state-metrics -o=jsonpath={.spec.template.spec.containers[].image}
quay.io/coreos/kube-state-metrics:v1.9.7Moral sem malo poiskati in najti, na primer, . Da jo uporabimo, bomo posodobili izdajo in navedli, katero sliko uporabiti za kube-state-metrics:
helm upgrade prometheus --namespace monitoring stable/prometheus --set server.ingress.enabled=True --set server.ingress.hosts={"prometheus.home.pi"} --set kube-state-metrics.image.repository=carlosedp/kube-state-metrics --set kube-state-metrics.image.tag=v1.9.6Preverimo, da se je vse zagnalo:
root@pi-control:~# kubectl -n monitoring get po
NAME READY STATUS RESTARTS AGE
prometheus-alertmanager-df65d99d4-6d27g 2/2 Running 0 5m56s
prometheus-kube-state-metrics-5dc5fd89c6-ztmqr 1/1 Running 0 5m56s
prometheus-node-exporter-49zll 1/1 Running 0 5m51s
prometheus-node-exporter-vwl44 1/1 Running 0 4m20s
prometheus-pushgateway-c547cfc87-k28qx 1/1 Running 0 5m56s
prometheus-server-85666fd794-z9qnc 2/2 Running 0 4m52sGrafana in cert-manager
Za grafikone in nadzorne plošče namestimo Grafana:
helm install grafana --namespace monitoring stable/grafana --set ingress.enabled=true --set ingress.hosts={"grafana.home.pi"}Na koncu izhoda nam bodo pokazali, kako pridobiti geslo za dostop:
kubectl get secret --namespace monitoring grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echoZa naročilo certifikatov bomo namestili cert-manager. Za njegovo namestitev se obrnemo na , ki ponuja ustrezna ukaza za Helm:
helm repo add jetstack https://charts.jetstack.io
helm install
cert-manager jetstack/cert-manager
--namespace cert-manager
--version v0.16.0
--set installCRDs=trueZa samo-podpisane certifikate za domačo uporabo je to povsem dovolj. Če pa želite pridobiti enakega Let’s Encrypt, potem je potrebno nastaviti še cluster issuer. Podrobnosti o tem lahko najdete v našem članku „».
Sam sem se odločil za različico iz , saj sem se odločil, da bo staging različica LE zadostovala. Spremenimo e-poštni naslov v primeru, shranimo v datoteko in dodamo v kluster ():
kubectl create -f cert-manager-cluster-issuer.yamlZdaj lahko naročimo certifikat, na primer, za Grafano. Za to bo potreben domena in dostop do klustra z zunanje strani. Domena imam, promet pa sem konfiguriral z usmerjanjem vrat 80 in 443 na domačem usmerjevalniku v skladu z ustvarjeno storitvijo ingress-controller:
kubectl -n ingress-nginx get svc
IME VRSTA CLUSTER-IP ZUNANJI-IP VRATA STAROST
ingress-nginx-controller NodePort 10.2.206.61 80:31303/TCP,443:30498/TCP 23d80. vrata se v tem primeru prenašajo na 31303, 443 pa na 30498. (Vrata so generirana naključno, zato boste imeli drugačna.)
Tukaj je primer certifikata ():
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: grafana
namespace: monitoring
spec:
dnsNames:
- grafana.home.pi
secretName: grafana-tls
issuerRef:
kind: ClusterIssuer
name: letsencrypt-stagingDodamo ga v kluster:
kubectl create -f cert-manager-grafana-certificate.yamlPo tem se bo pojavil vir Ingress, preko katerega bo potekala validacija Let’s Encrypt:
root@pi-control:~# kubectl -n monitoring get ing
IME RAZRED GOSTITELJI NASLOV VRATA STAROST
cm-acme-http-solver-rkf8l grafana.home.pi 192.168.88.31 80 72s
grafana grafana.home.pi 192.168.88.31 80 6d17h
prometheus-server prometheus.home.pi 192.168.88.31 80 8d Ko bo validacija končana, bomo videli, da je vir certificate pripravljen, v navedeni skrivnosti pa grafana-tls je certifikat in ključ. Takoj lahko preverite, kdo je izdal certifikat:
root@pi-control:~# kubectl -n monitoring get certificate
NAME READY SECRET AGE
grafana True grafana-tls 13m
root@pi-control:~# kubectl -n monitoring get secrets grafana-tls -ojsonpath="{.data['tls.crt']}" | base64 -d | openssl x509 -issuer -noout
issuer=CN = Fake LE Intermediate X1Vrátíme se k Grafaně. Budeme muset mírně upravit její Helm release, aby se nastavení pro TLS shodovalo se vytvořeným certifikátem.
K tomu stáhneme chart, upravíme a aktualizujeme z lokálního adresáře:
helm pull --untar stable/grafana Upravujeme v souboru grafana/values.yaml parametry TLS:
tls:
- secretName: grafana-tls
hosts:
- grafana.home.pi Zde si také můžeme okamžitě nastavit nainstalovaný Prometheus jako datasource:
datasources:
datasources.yaml:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
url: http://prometheus-server:80
access: proxy
isDefault: trueNyní z lokálního adresáře aktualizujeme chart Grafana:
helm upgrade grafana --namespace monitoring ./grafana --set ingress.enabled=true --set ingress.hosts={"grafana.home.pi"} Ověřujeme, že v Ingress grafana byl přidán port 443 a je zde přístup přes HTTPS:
root@pi-control:~# kubectl -n monitoring get ing grafana
NAME CLASS HOSTS ADDRESS PORTS AGE
grafana grafana.home.pi 192.168.88.31 80, 443 63m
root@pi-control:~# curl -kI https://grafana.home.pi
HTTP/2 302
server: nginx/1.19.1
date: Tue, 28 Jul 2020 19:01:31 GMT
content-type: text/html; charset=utf-8
cache-control: no-cache
expires: -1
location: /login
pragma: no-cache
set-cookie: redirect_to=; Path=/; HttpOnly; SameSite=Lax
x-frame-options: deny
strict-transport-security: max-age=15724800; includeSubDomainsPro demonstraci Grafany v akci můžete stáhnout a přidat . Takto to vypadá:

Doporučuji také přidat dashboard pro node exporter: detailně ukáže, co se děje s "malinami" (zatížení CPU, využití paměti, sítě, disku atd.).
Po tom považuji, že klastr je připraven přijímat a spouštět aplikace!
Poznámka o sestavení
Pro sestavení aplikací pro ARM architekturu existují minimálně dvě možnosti. Zaprvé, lze sestavovat na ARM zařízení. Nicméně, po zhlédnutí aktuálního využití dvou Raspberry Pi jsem zjistil, že ani sestavování by nepřežily. Proto jsem si objednal novou Raspberry Pi 4 (je silnější a má rovnou 4 GB paměti) - plánuji na ní sestavovat.
Druhá možnost - sestavení multi-architekturového Docker obrazu na výkonnějším stroji. K tomu existuje . Če je aplikacija v kompiliranem jeziku, bo potrebna prevodna kompilacija za ARM. O opisovanju vseh nastavitev za to pot ne bom, ker bi to zahtevalo poseben članek. Z uresničitvijo takega pristopa lahko dosežete "univerzalne" slike: Docker, ki teče na ARM strojni opremi, bo samodejno nalagal ustrezno arhitekturo slike.
Zaključek
Izvedeni eksperiment je presegel vsa moja pričakovanja: [vsaj] "vanilni" Kubernetes s potrebno bazo se dobro obnaša na ARM, med njegovo konfiguracijo pa so se pojavili le nekateri manjši problemi.
Sami Raspberry Pi 3B+ obdržijo obremenitev na CPU, vendar so njihove SD-kartice očitno ožji del. Kolegi so mi povedali, da v nekaterih različicah obstaja možnost zagona z USB, kamor lahko priključite SSD: takrat se bo verjetno situacija izboljšala.
Tukaj je primer obremenitve CPU pri namestitvi Grafane:

Za eksperimente in "za preizkusiti" se mi zdi, da Kubernetes-kluster na "malinah" veliko bolje posreduje občutke uporabe kot isti Minikube, ker so vsi sestavni deli klustra tako nameščeni kot tudi delujejo "kot je treba".
V prihodnosti imam idejo dodati k klstru celoten cikel CI/CD, izveden popolnoma na Raspberry Pi. Prav tako bom vesel, če mi kdo deli svoje izkušnje s konfiguracijo K8s na AWS Gravitonih.
P.S. Da, "production" je morda bližje, kot sem mislil:

P.P.S.
Preberite tudi na našem blogu:
- «».
Izvor: habr.com
