
Nedávno oznámila jedna známá společnost, že přechází na ARM architekturu pro svou řadu notebooků. Když jsem slyšel tuto zprávu, vzpomněl jsem si, že když jsem znovu procházel ceny EC2 v AWS, všiml jsem si Gravitonů s velmi lákavou cenou. Podvod byl samozřejmě v tom, že jde o ARM. Tehdy mě ani nenapadlo, že ARM je velmi vážná technologie...
Pro mě byla tato architektura vždy spojena s mobilními zařízeními a dalšími IoT gadgety. "Opravdové" servery na ARM - to je nějaké zvláštní, v něčem dokonce šílené... Nicméně se mi v hlavě usadila nová myšlenka, a tak jsem se rozhodl o víkendu zjistit, co lze dnes na ARM spustit. A začal jsem s něčím blízkým a známým - clusterem Kubernetes. A nejen tak nějakým "clusterem", ale pořádně, aby byl maximálně podobný tomu, co jsem zvyklý vidět v produkci.
Podle mých plánů by měl být cluster přístupný z internetu, měl by hostit nějakou webovou aplikaci a také by měl mít alespoň monitoring. Pro realizaci této myšlenky budu potřebovat pár (nebo více) Raspberry Pi minimálně model 3B+. Experimentální platformou by mohl být AWS, ale zajímaly mě právě "maliny" (které stejně ležely bez používání). Takže na nich rozběhneme cluster Kubernetes s Ingress, Prometheem a Grafanou.
Příprava "malin"
Instalace OS a SSH
S výběrem OS pro instalaci jsem se nijak nemazal: vzal jsem jednoduše nejnovější Raspberry Pi OS Lite z . Tam je k dispozici , všechny kroky je třeba provést na všech uzlech budoucího clusteru. Dále je třeba provést následující úpravy (také na všech uzlech).
Po připojení monitoru a klávesnice je nutné předem nastavit síť a SSH:
- Pro správnou funkci clusteru musí mít master statickou IP adresu, pracovní uzly mohou mít adresy podle uvážení. Preferoval jsem statické adresy všude z důvodu usnadnění nastavení.
- Statickou adresu lze nakonfigurovat v OS (ve souboru
/etc/dhcpcd.confje vhodný příklad) nebo fixací lease v DHCP serveru použitého (v mém případě domácího) routeru. - ssh-server se jednoduše aktivuje v raspi-config (interfacing options → ssh).
Po tomto kroku se můžete přihlásit přes SSH (uživatelské jméno je defaultně pi, a heslo je raspberry nebo to, které jste změnili) a pokračovat v nastavení.
Další nastavení
- Nastavíme název hostitele. V mém příkladu budeme používat
pi-controlapi-worker. - Zkontrolujeme, zda je souborový systém rozšířen na celý disk (
df -h /). V případě potřeby jej lze rozšířit pomocí raspi-config. - Změníme výchozí heslo uživatele v raspi-config.
- Vypneme swap soubor (to je požadavek Kubernetes; pokud vás zajímají podrobnosti k tomuto tématu, ):
dphys-swapfile swapoff systemctl disable dphys-swapfile - Aktualizujeme balíčky na poslední verze:
apt-get update && apt-get dist-upgrade -y - Nainstalujeme Docker a další balíčky:
apt-get install -y docker docker.io apt-transport-https curl bridge-utils iptables-persistentPři instalaci
iptables-persistentbude třeba uložit nastavení iptables pro ipv4, a v souboru/etc/iptables/rules.v4— přidat pravidla do řetězceFORWARD, takto:# 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 - Teď už zbývá jen restartovat.
Nyní je vše připraveno k instalaci clustera Kubernetes.
Instalace Kubernetes
V této fázi jsem úmyslně odložil všechny svoje i naše firemní práce na automatizaci instalace a konfigurace clustera K8s. Místo toho využijeme oficiální dokumentaci z (lehce doplněné komentáři a zjednodušeními).
Přidáme repozitář Kubernetes:
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 updateDále dokumentace doporučuje nainstalovat CRI (container runtime interface). Protože je Docker již nainstalován, pokračujeme dál a nainstalujeme základní komponenty:
sudo apt-get install -y kubelet kubeadm kubectl kubernetes-cni Při instalaci základních komponent jsem hned přidal kubernetes-cni, který je potřebný k fungování clustera. A tady je důležitý moment: balíček kubernetes-cni z nějakého důvodu nevytváří výchozí adresář pro nastavení CNI rozhraní, takže jsem ho musel vytvořit ručně:
mkdir -p /etc/cni/net.dPro fungování network backendu, o kterém se zmíním níže, je nutné doinstalovat plugin pro CNI. Vybral jsem známý a srozumitelný plugin portmap (úplný seznam najdete v ):
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/ ./portmapNastavení Kubernetes
Uzlový stroj s control plane
Instalace samotného clustera se provádí poměrně jednoduše. Pro urychlení tohoto procesu a ověření, že jsou obrázky Kubernetes dostupné, lze předem provést:
kubeadm config images pullNyní provedeme samotnou instalaci — inicializujeme control plane clustera:
kubeadm init --pod-network-cidr=10.1.0.0/16 --service-cidr=10.2.0.0/16 --upload-certsVšimněte si, že podsítě pro služby a pody by se neměly překrývat mezi sebou a s existujícími sítěmi.
Na konci nám zobrazí zprávu, že vše je v pořádku, a zároveň nám poradí, jak připojit pracovní uzly k řídicímu plánu:
Vaše ovládací plán Kubernetes byl úspěšně inicializován! Chcete-li začít používat svůj cluster, musíte provést následující jako běžný uživatel: mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config Nyní byste měli nasadit síť podů do clusteru. Spusťte "kubectl apply -f [podnetwork].yaml" s jednou z možností uvedených na: https://kubernetes.io/docs/concepts/cluster-administration/addons/ Nyní se můžete připojit k jakémukoli počtu uzlů řídicího plánu spuštěním následujícího příkazu jako root: kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4 --discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050 --contrl-plane --certificate-key 72a3c0a14c627d6d7fdade1f4c8d7a41b0fac31b1faf0d8fdf9678d74d7d2403 Vezměte prosím na vědomí, že certificate-key poskytuje přístup k citlivým údajům clusteru, uchovávejte jej v tajnosti! Jako ochranu budou uploaded-certs smazány za dvě hodiny; Pokud je potřeba, můžete použít "kubeadm init phase upload-certs --upload-certs" pro načtení certifikátů poté. Pak se můžete připojit k jakémukoli počtu pracovních uzlů spuštěním následujícího příkazu na každém jako root: kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4 --discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050Vykonáme doporučení pro přidání konfigurace pro uživatele. A doporučuji hned přidat také automatické dokončování pro kubectl:
kubectl completion bash > $HOME/.kube/completion.bash.inc printf "
# Kubectl shell completion
source '$HOME/.kube/completion.bash.inc'
" >> $HOME/.bash_profile source $HOME/.bash_profileV této fázi již můžeme vidět první uzel v clusteru (i když ještě není připraven):
root@pi-control:~# kubectl get no NAME STATUS ROLES AGE VERSION pi-control NotReady master 29s v1.18.6Konfigurace sítě
Dále, jak bylo řečeno ve zprávě po instalaci, bude potřeba nastavit síť v clusteru. V dokumentaci se nabízí výběr z Calico, Cilium, contiv-vpp, Kube-router a Weave Net… Zde jsem odstoupil od oficiální instrukce a zvolil známější a srozumitelnější variantu: v režimu host-gw (více o dostupných backendů viz ).
Nainstalovat ho do clusteru je docela jednoduché. Nejprve stáhneme manifesty:
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml Pak změníme v nastavení typ na vxlan na host-gw:
sed -i 's/vxlan/host-gw/' kube-flannel.yml… a podsíť podů — ze základní hodnoty na tu, která byla uvedena při inicializaci clusteru:
sed -i 's#10.244.0.0/16#10.1.0.0/16#' kube-flannel.ymlPo tomto vytvoříme zdroje:
kubectl create -f kube-flannel.yml Hotovo! Po nějaké době první uzel K8s přejde do stavu Ready:
NAME STATUS ROLES AGE VERSION
pi-control Ready master 2m v1.18.6Přidání pracovního uzlu
Nyní můžete přidat worker. K tomu je třeba na něm — po instalaci samotného Kubernetes podle scénáře popsaného výše — jednoduše provést předtím získaný příkaz:
kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4
--discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050Na tomto místě lze považovat klastr za připravený:
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.6Měl jsem po ruce pouze dvě Raspberry Pi, takže se mi nechtělo jednu z nich pouze pouštět pod control plane. Proto jsem odstranil automaticky nastavený taint z uzlu pi-control pomocí:
root@pi-control:~# kubectl edit node pi-control… a odstranil řádky:
- effect: NoSchedule
key: node-role.kubernetes.io/masterNaplnění klastru nezbytným minimem
V první řadě budeme potřebovat Helm. Samozřejmě, můžete to dělat i bez něj, ale Helm umožňuje doslova bez úprav souborů nastavit některé komponenty podle vlastního uvážení. A ve skutečnosti je to prostě spustitelný soubor, který "nevyžaduje nic".
Takže přejdeme na do sekce docs/installation a provedeme tam příkaz:
curl -s https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bashPoté přidáme repozitář chartů:
helm repo add stable https://kubernetes-charts.storage.googleapis.com/Nyní nainstalujeme infrastrukturní komponenty podle plánu:
- Ingress controller;
- Prometheus;
- Grafana;
- cert-manager.
Ingress controller
První komponenta — Ingress controller — se instalujeme docela snadno a je připravena k použití "z krabice". K tomu stačí přejít na a provést instalační příkaz odtud:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.34.1/deploy/static/provider/baremetal/deploy.yamlBěhem této chvíle začala "malina" zatěžovat diskový IOPS. Je to tím, že společně s Ingress kontrolérem se instaluje velké množství zdrojů, provádí se hodně požadavků na API a tím pádem se zapisuje mnoho dat do etcd. V zásadě, buď paměťová karta třídy 10 nemá dostatečný výkon, nebo SD karty pro tuto zátěž jednoduše nestačí. Nicméně, po 5 minutách se všechno spustilo.
Byl vytvořen namespace a v něm se objevil kontrolér a vše potřebné:
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
Následující dva komponenty se snadno instalují přes Helm z chart repo.
Najdeme Prometheus, vytvoříme namespace a nainstalujeme do něj:
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"}Ve výchozím nastavení Prometheus objednává 2 disky: pro data samotného Promethea a pro data AlertManageru. Vzhledem k tomu, že v clusteru nebyl vytvořen storage class, disky se neobjednají a pod'y se nespustí. Pro bare metal instalace Kubernetes obvykle používáme Ceph rbd, ale v případě Raspberry Pi to je zbytečné.
Proto vytvoříme jednoduché local storage na hostpath. Manifesty PV (persistent volume) pro prometheus-server a prometheus-alertmanager jsou spojeny v souboru prometheus-pv.yaml v . Direktorium pro PV je třeba předem vytvořit na disku toho uzlu, ke kterému chceme připojit Prometheus: v příkladu je uvedeno nodeAffinity podle hostname pi-worker a na něm jsou vytvořeny adresáře /data/localstorage/prometheus-server a /data/localstorage/prometheus-alertmanager.
Stáhneme (klonujeme) manifest a přidáváme do Kubernetes:
kubectl create -f prometheus-pv.yamlV této fázi jsem se poprvé setkal s problémem architektury ARM. Kube-state-metrics, který je ve výchozím nastavení instalován v chartu Prometheus, se odmítl spustit. Vydával chybu:
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"Jde o to, že pro kube-state-metrics se používá obraz projektu CoreOS, který není sestaven pro 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.7Musel jsem si trochu vygooglit a najít například . Abychom jej mohli použít, aktualizujeme release a určíme, jaký obraz použít pro 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.6Kontrolujeme, že všechno běží:
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 a cert-manager
Pro grafy a dashboardy instalujeme Grafana:
helm install grafana --namespace monitoring stable/grafana --set ingress.enabled=true --set ingress.hosts={"grafana.home.pi"}Na konci výstupu nám ukážou, jak získat heslo pro přístup:
kubectl get secret --namespace monitoring grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echoPro objednání certifikátů nainstalujeme cert-manager. Pro jeho instalaci se obrátíme na , která nabízí odpovídající příkazy pro 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=truePro self-signed certifikáty pro domácí použití je to zcela dostačující. Pokud však chcete získat stejný Let’s Encrypt, pak je potřeba nastavit také cluster issuer. Podrobnosti o tom naleznete v našem článku „».
Já jsem se zastavil u varianty z , rozhodl jsem se, že staging varianta LE bude dostatečná. Změňte v příkladu e-mail, uložit do souboru a přidat do clusteru ():
kubectl create -f cert-manager-cluster-issuer.yamlNyní můžeme objednat certifikát, například pro Grafanu. K tomu budeme potřebovat doménu a přístup do clusteru zvenčí. Doménu mám, a provoz jsem nastavil přesměrováním portů 80 a 443 na domácím routeru podle vytvořeného service ingress-controller’a:
kubectl -n ingress-nginx get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.2.206.61 80:31303/TCP,443:30498/TCP 23d80. port je v tomto případě přenášen na 31303, a 443 na 30498. (Porty se generují náhodně, takže u vás budou jiné.)
Zde je příklad certifikátu ():
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-stagingPřidáme ho do clusteru:
kubectl create -f cert-manager-grafana-certificate.yamlPo této akci se objeví zdroj Ingress, přes který proběhne validace Let’s Encrypt:
root@pi-control:~# kubectl -n monitoring get ing
NAME CLASS HOSTS ADDRESS PORTS AGE
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 Jakmile proběhne validace, uvidíme, že zdroj certificate je připraven, a v výše uvedeném secretu grafana-tls je certifikát a klíč. Můžete okamžitě zkontrolovat, kdo certifikát vydal:
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 X1Vraťme se k Grafaně. Budeme potřebovat trochu upravit její Helm release, změnit nastavení pro TLS podle vytvořeného certifikátu.
K tomu si stáhneme chart, upravíme ho a aktualizujeme z místní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 můžeme hned 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 místního adresáře aktualizujeme chart Grafany:
helm upgrade grafana --namespace monitoring ./grafana --set ingress.enabled=true --set ingress.hosts={"grafana.home.pi"} Kontrolujeme, že Ingress grafana přidává port 443 a je dostupný 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 si můžete stáhnout a přidat . Takhle to vypadá:

Doporučuji také přidat dashboard pro node exporter: detailně ukáže, co se děje s "malinami" (zátěž CPU, využití paměti, sítě, disku atd.).
Po tomto považuji, že klastr je připraven přijímat a spouštět aplikace!
Poznámka o sestavení
Pro sestavení aplikací pro architekturu ARM existují minimálně dvě možnosti. Za prvé, můžete stavět na ARM zařízení. Nicméně, podíval jsem se na aktuální využití dvou Raspberry Pi a uvědomil jsem si, že ani to by nevydržely. Proto jsem si objednal novou Raspberry Pi 4 (je výkonnější a má dokonce 4 GB paměti) — plánuju na ní sestavovat.
Druhá varianta — sestavení multiarchitektonického obrazu Docker na výkonnějším stroji. K tomu je . Pokud je aplikace napsána v kompilovaném jazyce, bude potřeba kros-kompilace pro ARM. Nepopisuji všechny nastavení pro tuto cestu, protože by to vyžadovalo samostatný článek. Při realizaci takového přístupu lze dosáhnout "univerzálních" obrazů: Docker spuštěný na ARM stroji si automaticky stáhne odpovídající obraz pro architekturu.
Závěr
Prováděný experiment předčil všechna má očekávání: [alespoň] „vanilkový“ Kubernetes s potřebným základem si na ARM vedl docela dobře, a při jeho konfiguraci vzniklo pouze pár nuancí.
Sami Raspberry Pi 3B+ zvládají zátěž na CPU, avšak jejich SD karty jsou jasným úzkým hrdlem. Kolegové mi naznačili, že v některých verzích je možnost bootovat z USB, kam lze připojit SSD: pak se situace pravděpodobně zlepší.
Tady je příklad zatížení CPU při instalaci Grafana:

Pro experimenty a "zkušební" provoz, podle mě, Kubernetes cluster na „malinách“ daleko lépe přenáší pocity z používání, než ten samý Minikube, protože všechny komponenty clusteru se instalují a fungují "jako v reálu".
Do budoucna mám v úmyslu přidat do clusteru celý cyklus CI/CD, realizovaný zcela na Raspberry Pi. A budu rád, pokud se někdo podělí o své zkušenosti s nastavením K8s na AWS Graviton.
P.S. Ano, "produkce" může být blíže, než jsem si myslel:

P.P.S.
Přečtěte si také náš blog:
- «».
Zdroj: habr.com
