
最近,一家知名公司宣布將其筆記本電腦系列轉移到 ARM 架構。 當我聽到這個消息時,我想起:再次查看AWS中EC2的價格,我發現Gravitons的價格非常可觀。 當然,問題在於它是 ARM。 然後沒想到ARM還挺認真的……
對我來說,這種架構一直是移動和其他物聯網事物的重要組成部分。 ARM 上的“真正”服務器在某種程度上是不尋常的,在某些方面甚至是瘋狂的……然而,一個新的想法浮現在我的腦海中,所以在一個週末我決定檢查一下今天通常可以在ARM 上啟動的內容。 為此,我決定從一個親密的、親愛的開始——Kubernetes 集群。 不僅僅是某種有條件的“集群”,而是一切“以成人的方式”,因此它盡可能地與我在生產中看到的相同。
根據我的想法,集群應該可以從互聯網訪問,一些Web應用程序應該在其中運行,並且至少應該有監控。 要實現這個想法,您需要一對(或更多)至少型號為 3B+ 的 Raspberry Pi。 AWS也可以成為一個實驗平台,但我感興趣的是“樹莓派”(仍然閒置)。 因此,我們將使用 Ingress、Prometheus 和 Grafana 在其上部署 Kubernetes 集群。
準備“覆盆子”
操作系統安裝和 SSH
我並沒有太在意安裝操作系統的選擇:我只是選擇了最新的 Raspberry Pi OS Lite 。 在那裡可用 ,其中的所有操作都必須在未來集群的所有節點上執行。 接下來,您將需要執行以下操作(也在所有節點上)。
連接顯示器和鍵盤後,必須首先配置網絡和 SSH:
- 為了使集群工作,主節點必須有一個靜態IP地址,並且工作節點必須自行擁有它。 出於易於設置的原因,我更喜歡到處都是靜態地址。
- 靜態地址可以在操作系統中配置(在文件中
/etc/dhcpcd.conf有一個合適的例子)或通過修復所用(在我的例子中是家庭)路由器的 DHCP 服務器中的租約。 - ssh-server 只是包含在 raspi-config 中(接口選項 → ssh).
之後你就可以通過SSH登錄了(默認登錄是 pi,密碼是 raspberry 或您更改為的那個)並繼續設置。
其他設置
- 設置主機名。 在我的示例中,我們將使用
pi-controlиpi-worker. - 檢查文件系統是否擴展到整個磁盤(
df -h /)。 如果需要,可以使用 raspi-config 進行擴展。 - 更改 raspi-config 中的默認用戶密碼。
- 關閉交換文件(這是 Kubernetes 的要求;如果您對此主題的詳細信息感興趣,請參閱。 ):
dphys-swapfile swapoff systemctl disable dphys-swapfile - 將軟件包更新到最新版本:
apt-get update && apt-get dist-upgrade -y - 安裝 Docker 和其他軟件包:
apt-get install -y docker docker.io apt-transport-https curl bridge-utils iptables-persistent安裝時
iptables-persistent您需要保存 ipv4 的 iptables 設置,並在文件中/etc/iptables/rules.v4- 添加規則到鏈中FORWARD, 像這樣:# 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 - 剩下的只是重新啟動。
您現在已準備好安裝 Kubernetes 集群。
安裝 Kubernetes
在這個階段,我特意將我和我們公司的所有開發放在自動化 K8s 集群的安裝和配置上。 相反,讓我們使用官方文檔 (稍微補充了評論和縮寫)。
讓我們添加 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 update此外,文檔建議安裝 CRI(容器運行時接口)。 由於 Docker 已經安裝,讓我們繼續安裝主要組件:
sudo apt-get install -y kubelet kubeadm kubectl kubernetes-cni 在安裝主要組件的步驟中,我立即添加了 kubernetes-cni,這是集群工作所必需的。 還有很重要的一點:包裝 kubernetes-cni 由於某種原因,沒有為 CNI 設置創建默認目錄,因此我必須手動創建它:
mkdir -p /etc/cni/net.d為了使網絡後端正常工作(將在下面討論),您需要安裝 CNI 插件。 我選擇了熟悉易懂的portmap插件 (有關完整列表,請參閱 ):
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/ ./portmap配置 Kubernetes
具有控制平面的節點
安裝集群本身非常簡單。 為了加快此過程並檢查 Kubernetes 映像是否可用,您可以預運行:
kubeadm config images pull現在我們執行安裝本身 - 我們初始化集群的控制平面:
kubeadm init --pod-network-cidr=10.1.0.0/16 --service-cidr=10.2.0.0/16 --upload-certs請注意,服務和 Pod 的子網不應相互重疊,也不應與現有網絡重疊。
最後,我們將看到一條消息,表示一切正常,同時告訴我們如何將工作節點附加到控制平面:
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
You can now join any number of the control-plane node running the following command on each as root:
kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4
--discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050
--contrl-plane --certificate-key 72a3c0a14c627d6d7fdade1f4c8d7a41b0fac31b1faf0d8fdf9678d74d7d2403
Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4
--discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050讓我們按照建議為用戶添加配置。 同時我建議立即為 kubectl 添加自動完成功能:
kubectl completion bash > ~/.kube/completion.bash.inc
printf "
# Kubectl shell completion
source '$HOME/.kube/completion.bash.inc'
" >> $HOME/.bash_profile
source $HOME/.bash_profile此時,您已經可以看到集群中的第一個節點(但是,它還沒有準備好):
root@pi-control:~# kubectl get no
NAME STATUS ROLES AGE VERSION
pi-control NotReady master 29s v1.18.6網絡配置
此外,正如安裝後的消息中所說,您需要在集群中安裝網絡。 文檔提供了 Calico、Cilium、contiv-vpp、Kube-router 和 Weave Net 的選擇...這裡我偏離了官方說明,選擇了一個對我來說更熟悉和易於理解的選項: 在 host-gw 模式下(有關可用後端的詳細信息,請參閱 ).
在集群中安裝它非常簡單。 首先,讓我們下載清單:
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml 然後我們將設置中的類型更改為 vxlan 上 host-gw:
sed -i 's/vxlan/host-gw/' kube-flannel.yml...以及 Pod 的子網 - 從默認值到集群初始化期間指定的值:
sed -i 's#10.244.0.0/16#10.1.0.0/16#' kube-flannel.yml之後,我們創建資源:
kubectl create -f kube-flannel.yml 準備好! 過一會兒,第一個K8s節點就會進入狀態 Ready:
NAME STATUS ROLES AGE VERSION
pi-control Ready master 2m v1.18.6添加工作節點
現在您可以添加一名工人。 為此,在根據上述場景安裝 Kubernetes 本身之後,您只需執行之前收到的命令:
kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4
--discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050至此,我們可以假設集群已準備就緒:
root@pi-control:~# kubectl get no
NAME STATUS ROLES AGE VERSION
pi-control Ready master 28m v1.18.6
pi-worker Ready <none> 2m8s v1.18.6我手頭只有兩個 Raspberry Pi,所以捐贈其中一個。 僅 在我不想的控制平面下。 因此,我通過運行以下命令從 pi-control 節點中刪除了自動安裝的污點:
root@pi-control:~# kubectl edit node pi-control...並刪除行:
- effect: NoSchedule
key: node-role.kubernetes.io/master用必要的最小值填充集群
首先,我們需要 舵。 當然,您可以在沒有它的情況下完成所有操作,但 Helm 允許您自行決定配置某些組件,而無需編輯文件。 而事實上它只是一個“不求麵包”的二進製文件。
那麼讓我們去 到 docs/installation 部分並從那裡執行命令:
curl -s https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash之後,添加圖表存儲庫:
helm repo add stable https://kubernetes-charts.storage.googleapis.com/現在我們按照思路來安裝基礎設施組件:
- 入口控制器;
- 普羅米修斯;
- 格拉法納;
- 證書經理。
入口控制器
第一個組件是 入口控制器 - 易於安裝,開箱即可使用。 要執行此操作,只需轉到 並從那裡運行安裝命令:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.34.1/deploy/static/provider/baremetal/deploy.yaml然而,就在這時,“樹莓派”開始緊張,對磁盤IOPS產生了壓力。 事實是,隨著 Ingress 控制器的安裝,大量資源被安裝,許多 API 請求被發出,相應地,大量數據被寫入 etcd。 一般來說,要么 10 級存儲卡生產力不高,要么 SD 卡原則上不足以滿足這樣的負載。 然而,5分鐘後一切就開始了。
創建了一個命名空間,一個控制器和他需要的一切都出現在其中:
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 48s普羅米修斯
通過 Helm 從圖表存儲庫可以輕鬆安裝以下兩個組件。
我們發現 普羅米修斯,創建一個命名空間並將其設置為:
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"}默認情況下,Prometheus 訂購 2 個磁盤:用於 Prometheus 本身的數據和 AlertManager 的數據。 由於集群中尚未創建存儲類,因此不會對磁盤進行排序,並且 Pod 也不會啟動。 對於裸機 Kubernetes 安裝,我們通常使用 Ceph rbd,但對於 Raspberry Pi 來說,這有點矯枉過正了。
因此,我們將在hostpath上創建一個簡單的本地存儲。 prometheus-server 和 prometheus-alertmanager 的 PV(持久卷)清單合併在文件中 prometheus-pv.yaml в 。 需要PV目錄 提前 在我們要綁定Prometheus的節點的磁盤上創建:示例中是這樣寫的 nodeAffinity 按主機名 pi-worker 並在其上創建目錄 /data/localstorage/prometheus-server и /data/localstorage/prometheus-alertmanager.
下載(克隆)清單並將其添加到 Kubernetes:
kubectl create -f prometheus-pv.yaml在這個階段,我首先遇到了ARM架構的問題。 Prometheus 圖表上默認安裝的 Kube-state-metrics 拒絕運行。 它給出了一個錯誤:
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"事實上,對於 kube-state-metrics,使用的是 CoreOS 項目的映像,該映像不是為 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.7我不得不用谷歌搜索一下,發現,例如, 。 為了利用這一點,讓我們更新用於 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.6檢查一切是否正在運行:
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 和證書管理器
對於圖表和儀表板,設置 格拉法納:
helm install grafana --namespace monitoring stable/grafana --set ingress.enabled=true --set ingress.hosts={"grafana.home.pi"}在輸出的最後,我們將看到如何獲取訪問密碼:
kubectl get secret --namespace monitoring grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo要訂購證書,請安裝 證書經理。 安裝方法請參考 ,它為 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=true對於家庭使用的自簽名證書,這已經足夠了。 如果你想得到同樣的 讓我們加密,那麼您需要配置另一個集群發行者。 有關詳細信息,請參閱我們的文章““。
我自己選擇了 ,決定分期 LE 就足夠了。 我們在示例中更改電子郵件,將其保存到文件中並將其添加到集群中():
kubectl create -f cert-manager-cluster-issuer.yaml現在您可以訂購證書,例如 Grafana 的證書。 這將需要一個域並從外部訪問集群。 我有一個域,我根據創建的 ingress-controller 服務通過在家庭路由器上轉發端口 80 和 443 來配置流量:
kubectl -n ingress-nginx get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.2.206.61 <none> 80:31303/TCP,443:30498/TCP 23d在本例中,端口 80 被轉換為 31303,端口 443 被轉換為 30498。 (端口是隨機生成的,因此您的端口會有所不同。)
這是證書的示例():
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-staging將其添加到集群中:
kubectl create -f cert-manager-grafana-certificate.yaml之後,會出現 Ingress 資源,Let's Encrypt 將通過該資源進行驗證:
root@pi-control:~# kubectl -n monitoring get ing
NAME CLASS HOSTS ADDRESS PORTS AGE
cm-acme-http-solver-rkf8l <none> grafana.home.pi 192.168.88.31 80 72s
grafana <none> grafana.home.pi 192.168.88.31 80 6d17h
prometheus-server <none> prometheus.home.pi 192.168.88.31 80 8d 驗證通過後,我們會看到該資源 certificate 準備好,並在上面的秘密 grafana-tls - 證書和密鑰。 您可以立即檢查誰頒發了證書:
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 X1讓我們回到 Grafana。 我們需要根據生成的證書更改 TLS 設置,稍微修復她的 Helm 版本。
為此,請下載圖表,從本地目錄進行編輯和更新:
helm pull --untar stable/grafana 在文件中編輯 grafana/values.yaml TLS 參數:
tls:
- secretName: grafana-tls
hosts:
- grafana.home.pi 在這裡您可以立即將安裝的 Prometheus 配置為 datasource:
datasources:
datasources.yaml:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
url: http://prometheus-server:80
access: proxy
isDefault: true現在我們從本地目錄更新 Grafana 圖表:
helm upgrade grafana --namespace monitoring ./grafana --set ingress.enabled=true --set ingress.hosts={"grafana.home.pi"} 我們在 Ingress 中檢查 grafana 已添加443端口,可通過HTTPS訪問:
root@pi-control:~# kubectl -n monitoring get ing grafana
NAME CLASS HOSTS ADDRESS PORTS AGE
grafana <none> 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=%2F; Path=/; HttpOnly; SameSite=Lax
x-frame-options: deny
strict-transport-security: max-age=15724800; includeSubDomains要演示 Grafana 的實際應用,您可以下載並添加 。 它看起來是這樣的:

我還建議為節點導出器添加一個儀表板:它將詳細顯示“樹莓派”發生的情況(CPU 負載、內存、網絡、磁盤使用情況等)。
之後,我想 集群已準備好接收和運行應用程序!
構建註釋
至少有兩種用於構建 ARM 架構應用程序的選項。 首先,您可以在 ARM 設備上進行構建。 然而,在查看了當前兩個 Raspberry Pi 的回收情況後,我意識到它們也無法在組裝後倖存下來。 因此,我為自己訂購了一個新的 Raspberry Pi 4(它更強大,內存高達 4 GB) - 我打算在上面組裝它。
第二種選擇是在更強大的機器上構建多架構 Docker 映像。 為此有 。 如果應用程序是編譯語言,則需要針對 ARM 進行交叉編譯。 我不會描述該路徑的所有設置,因為這將導致一篇單獨的文章。 通過實現這種方法,您可以實現“通用”鏡像:運行在ARM機器上的Docker會自動加載與架構相對應的鏡像。
結論
進行的實驗超出了我的所有預期:[至少]具有必要基礎的“普通”Kubernetes 在 ARM 上感覺良好,並且在配置過程中只出現了一些細微差別。
Raspberry Pi 3B+ 本身將負載保持在 CPU 上,但它們的 SD 卡是一個明顯的瓶頸。 同事建議,在某些版本中可以從USB啟動,可以連接SSD:那麼情況很可能會變得更好。
以下是安裝 Grafana 時 CPU 使用情況的示例:

對於實驗和“嘗試”,在我看來,“樹莓派”上的 Kubernetes 集群比同一個 Minikube 傳達的操作感覺要好得多,因為所有集群組件都已“像成人一樣”安裝和工作。
未來,有一個想法將整個 CI/CD 週期添加到集群中,完全在 Raspberry Pi 上實現。 如果有人分享他們在 AWS Graviton 上設置 K8s 的經驗,我也會很高興。
PS 是的,“生產”可能比我想像的更接近:

聚苯硫醚
另請閱讀我們的博客:
- «“。
來源: www.habr.com
