Linux中國

用樹莓派構建 Kubernetes 集群

Kubernetes 從一開始就被設計為雲原生的企業級容器編排系統。它已經成長為事實上的雲容器平台,並由於接受了容器原生虛擬化和無伺服器計算等新技術而繼續發展。

從微型的邊緣計算到大規模的容器環境,無論是公有雲還是私有雲環境,Kubernetes 都可以管理其中的容器。它是「家庭私有雲」項目的理想選擇,既提供了強大的容器編排,又讓你有機會了解一項這樣的技術 —— 它的需求如此之大,與雲計算結合得如此徹底,以至於它的名字幾乎就是「雲計算」的代名詞。

沒有什麼比 Kubernetes 更懂「雲」,也沒有什麼能比樹莓派更合適「集群起來」!在廉價的樹莓派硬體上運行本地的 Kubernetes 集群是獲得在真正的雲技術巨頭上進行管理和開發的經驗的好方法。

在樹莓派上安裝 Kubernetes 集群

本練習將在三個或更多運行 Ubuntu 20.04 的樹莓派 4 上安裝 Kubernetes 1.18.2 集群。Ubuntu 20.04(Focal Fossa)提供了針對 64 位 ARM(ARM64)的樹莓派鏡像(64 位內核和用戶空間)。由於目標是使用這些樹莓派來運行 Kubernetes 集群,因此運行 AArch64 容器鏡像的能力非常重要:很難找到 32 位的通用軟體鏡像乃至於標準基礎鏡像。藉助 Ubuntu 20.04 的 ARM64 鏡像,可以讓你在 Kubernetes 上使用 64 位容器鏡像。

AArch64 vs. ARM64;32 位 vs. 64 位;ARM vs. x86

請注意,AArch64 和 ARM64 實際上是同一種東西。不同的名稱源於它們在不同社區中的使用。許多容器鏡像都標為 AArch64,並能在標為 ARM64 的系統上正常運行。採用 AArch64/ARM64 架構的系統也能夠運行 32 位的 ARM 鏡像,但反之則不然:32 位的 ARM 系統無法運行 64 位的容器鏡像。這就是 Ubuntu 20.04 ARM64 鏡像如此有用的原因。

這裡不會太深入地解釋不同的架構類型,值得注意的是,ARM64/AArch64 和 x86_64 架構是不同的,運行在 64 位 ARM 架構上的 Kubernetes 節點無法運行為 x86_64 構建的容器鏡像。在實踐中,你會發現有些鏡像沒有為兩種架構構建,這些鏡像可能無法在你的集群中使用。你還需要在基於 Arch64 的系統上構建自己的鏡像,或者跳過一些限制以讓你的常規的 x86_64 系統構建 Arch64 鏡像。在「家庭私有雲」項目的後續文章中,我將介紹如何在常規系統上構建 AArch64 鏡像。

為了達到兩全其美的效果,在本教程中設置好 Kubernetes 集群後,你可以在以後向其中添加 x86_64 節點。你可以通過使用 Kubernetes 的 污點 taint 容忍 toleration 能力,由 Kubernetes 的調度器將給定架構的鏡像調度到相應的節點上運行。

關於架構和鏡像的內容就不多說了。是時候安裝 Kubernetes 了,開始吧!

前置需求

這個練習的要求很低。你將需要:

  • 三台(或更多)樹莓派 4(最好是 4GB 內存的型號)。
  • 在全部樹莓派上安裝 Ubuntu 20.04 ARM64。

為了簡化初始設置,請閱讀《修改磁碟鏡像來創建基於樹莓派的家庭實驗室》,在將 Ubuntu 鏡像寫入 SD 卡並安裝在樹莓派上之前,添加一個用戶和 SSH 授權密鑰(authorized_keys)。

配置主機

在 Ubuntu 被安裝在樹莓派上,並且可以通過 SSH 訪問後,你需要在安裝 Kubernetes 之前做一些修改。

安裝和配置 Docker

截至目前,Ubuntu 20.04 在 base 軟體庫中提供了最新版本的 Docker,即 v19.03,可以直接使用 apt 命令安裝它。請注意,包名是 docker.io。請在所有的樹莓派上安裝 Docker:

# 安裝 docker.io 軟體包
$ sudo apt install -y docker.io

安裝好軟體包後,你需要做一些修改來啟用 cgroup(控制組)。cgroup 允許 Linux 內核限制和隔離資源。實際上,這可以讓 Kubernetes 更好地管理其運行的容器所使用的資源,並通過讓容器彼此隔離來增加安全性。

在對所有樹莓派進行以下修改之前,請檢查 docker info 的輸出:

# 檢查 `docker info`
# 省略了某些輸出
$ sudo docker info
(...)
 Cgroup Driver: cgroups
(...)
WARNING: No memory limit support
WARNING: No swap limit support
WARNING: No kernel memory limit support
WARNING: No kernel memory TCP limit support
WARNING: No oom kill disable support

上面的輸出突出顯示了需要修改的部分:cgroup 驅動和限制支持。

首先,將 Docker 使用的默認 cgroup 驅動從 cgroups 改為 systemd,讓 systemd 充當 cgroup 管理器,確保只有一個 cgroup 管理器在使用。這有助於系統的穩定性,這也是 Kubernetes 所推薦的。要做到這一點,請創建 /etc/docker/daemon.json 文件或將內容替換為:

# 創建或替換 /etc/docker/daemon.json 以啟用 cgroup 的 systemd 驅動

$ sudo cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

啟用 cgroup 限制支持

接下來,啟用限制支持,如上面的 docker info 輸出中的警告所示。你需要修改內核命令行以在引導時啟用這些選項。對於樹莓派 4,將以下內容添加到 /boot/firmware/cmdline.txt 文件中:

cgroup_enable=cpuset
cgroup_enable=memory
cgroup_memory=1
swapaccount=1

確保它們被添加到 cmdline.txt 文件的行末。這可以通過使用 sed 在一行中完成。

# 將 cgroup 和交換選項添加到內核命令行中
# 請注意 "cgroup_enable=cpuset" 前的空格,以便在該行的最後一個項目後添加一個空格
$ sudo sed -i &apos;$ s/$/ cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1 swapaccount=1/&apos; /boot/firmware/cmdline.txt

sed 命令匹配該行的終止符(由第一個 $ 代表),用列出的選項代替它(它實際上是將選項附加到該行)。

有了這些改變,Docker 和內核應該按照 Kubernetes 的需要配置好了。重新啟動樹莓派,當它們重新啟動後,再次檢查 docker info 的輸出。現在,Cgroups driver 變成了 systemd,警告也消失了。

允許 iptables 查看橋接流量

根據文檔,Kubernetes 需要配置 iptables 來查看橋接網路流量。你可以通過修改 sysctl 配置來實現。

# 啟用 net.bridge.bridge-nf-call-iptables 和 -iptables6
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
$ sudo sysctl --system

安裝 Ubuntu 的 Kubernetes 包

由於你使用的是 Ubuntu,你可以從 Kubernetes.io 的 apt 倉庫中安裝 Kubernetes 軟體包。目前沒有 Ubuntu 20.04(Focal)的倉庫,但最近的 Ubuntu LTS 倉庫 Ubuntu 18.04(Xenial) 中有 Kubernetes 1.18.2。最新的 Kubernetes 軟體包可以從那裡安裝。

將 Kubernetes 軟體庫添加到 Ubuntu 的源列表之中:

# 添加 packages.cloud.google.com 的 atp 密鑰
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -

# 添加 Kubernetes 軟體庫
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF

當 Kubernetes 添加了 Ubuntu 20.04(Focal)倉庫時 —— 也許是在下一個 Kubernetes 版本發布時 —— 請確保切換到它。

將倉庫添加到源列表後,安裝三個必要的 Kubernetes 包:kubelet、kubeadm 和 kubectl:

# 更新 apt 緩存並安裝 kubelet、kubeadm kubectl
# (輸出略)
$ sudo apt update && sudo apt install -y kubelet kubeadm kubectl

最後,使用 apt-mark hold 命令禁用這三個包的定期更新。升級到 Kubernetes 需要比一般的更新過程更多的手工操作,需要人工關注。

# 禁止(標記為保持)Kubernetes 軟體包的更新
$ sudo apt-mark hold kubelet kubeadm kubectl
kubelet set on hold.
kubeadm set on hold.
kubectl set on hold.

主機配置就到這裡了! 現在你可以繼續設置 Kubernetes 本身了。

創建 Kubernetes 集群

在安裝了 Kubernetes 軟體包之後,你現在可以繼續創建集群了。在開始之前,你需要做一些決定。首先,其中一個樹莓派需要被指定為控制平面節點(即主節點)。其餘的節點將被指定為計算節點。

你還需要選擇一個 CIDR(無類別域間路由)地址用於 Kubernetes 集群中的 Pod。在集群創建過程中設置 pod-network-cidr 可以確保設置了 podCIDR 值,它以後可以被 容器網路介面 Container Network Interface (CNI)載入項使用。本練習使用的是 FlannelCNI。你選擇的 CIDR 不應該與你的家庭網路中當前使用的任何 CIDR 重疊,也不應該與你的路由器或 DHCP 伺服器管理的 CIDR 重疊。確保使用一個比你預期需要的更大的子網:總是有比你最初計劃的更多的 Pod!在這個例子中,我將使用 CIDR 地址 10.244.0.0/16,但你可以選擇一個適合你的。

有了這些決定,你就可以初始化控制平面節點了。用 SSH 或其他方式登錄到你為控制平面指定的節點。

初始化控制平面

Kubernetes 使用一個引導令牌來驗證被加入集群的節點。當初始化控制平面節點時,需要將此令牌傳遞給 kubeadm init 命令。用 kubeadm token generate 命令生成一個令牌:

# 生成一個引導令牌來驗證加入集群的節點
$ TOKEN=$(sudo kubeadm token generate)
$ echo $TOKEN
d584xg.xupvwv7wllcpmwjy

現在你可以使用 kubeadm init 命令來初始化控制平面了:

# 初始化控制平面
#(輸出略)
$ sudo kubeadm init --token=${TOKEN} --kubernetes-version=v1.18.2 --pod-network-cidr=10.244.0.0/16

如果一切順利,你應該在輸出的最後看到類似這樣的東西:

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/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.2.114:6443 --token zqqoy7.9oi8dpkfmqkop2p5 
    --discovery-token-ca-cert-hash sha256:71270ea137214422221319c1bdb9ba6d4b76abfa2506753703ed654a90c4982b

注意兩點:第一,Kubernetes 的 kubectl 連接信息已經寫入到 /etc/kubernetes/admin.conf。這個 kubeconfig 文件可以複製到用戶的 ~/.kube/config 中,可以是主節點上的 root 用戶或普通用戶,也可以是遠程機器。這樣你就可以用 kubectl 命令來控制你的集群。

其次,輸出中以 kubernetes join 開頭的最後一行是你可以運行的命令,你可以運行這些命令加入更多的節點到集群中。

將新的 kubeconfig 複製到你的用戶可以使用的地方後,你可以用 kubectl get nodes 命令來驗證控制平面是否已經安裝:

# 顯示 Kubernetes 集群中的節點
# 你的節點名稱會有所不同
$ kubectl get nodes
NAME         STATUS   ROLES    AGE     VERSION
elderberry   Ready    master   7m32s   v1.18.2

安裝 CNI 載入項

CNI 載入項負責 Pod 網路的配置和清理。如前所述,這個練習使用的是 Flannel CNI 載入項,在已經設置好 podCIDR 值的情況下,你只需下載 Flannel YAML 並使用 kubectl apply 將其安裝到集群中。這可以用 kubectl apply -f - 從標準輸入中獲取數據,用一行命令完成。這將創建管理 Pod 網路所需的 ClusterRoles、ServiceAccounts 和 DaemonSets 等。

下載並應用 Flannel YAML 數據到集群中:

# 下載 Flannel YAML 數據並應用它
# (輸出略)
$ curl -sSL https://raw.githubusercontent.com/coreos/flannel/v0.12.0/Documentation/kube-flannel.yml | kubectl apply -f -

將計算節點加入到集群中

有了 CNI 載入項,現在是時候將計算節點添加到集群中了。加入計算節點只需運行 kube init 命令末尾提供的 kubeadm join 命令來初始化控制平面節點。對於你想加入集群的其他樹莓派,登錄主機,運行命令即可:

# 加入節點到集群,你的令牌和 ca-cert-hash 應各有不同
$ sudo kubeadm join 192.168.2.114:6443 --token zqqoy7.9oi8dpkfmqkop2p5 
    --discovery-token-ca-cert-hash sha256:71270ea137214422221319c1bdb9ba6d4b76abfa2506753703ed654a90c4982b

一旦你完成了每個節點的加入,你應該能夠在 kubectl get nodes 的輸出中看到新節點:

# 顯示 Kubernetes 集群中的節點
# 你的節點名稱會有所不同
$ kubectl get nodes
NAME         STATUS   ROLES    AGE     VERSION
elderberry   Ready    master   7m32s   v1.18.2
gooseberry    Ready    <none>   2m39s   v1.18.2
huckleberry   Ready    <none>   17s     v1.18.2

驗證集群

此時,你已經擁有了一個完全正常工作的 Kubernetes 集群。你可以運行 Pod、創建部署和作業等。你可以使用服務從集群中的任何一個節點訪問集群中運行的應用程序。你可以通過 NodePort 服務或入口控制器實現外部訪問。

要驗證集群正在運行,請創建一個新的命名空間、部署和服務,並檢查在部署中運行的 Pod 是否按預期響應。此部署使用 quay.io/clcollins/kube-verify:01 鏡像,這是一個監聽請求的 Nginx 容器(實際上,與文章《使用 Cloud-init 將節點添加到你的私有雲》中使用的鏡像相同)。你可以在這裡查看鏡像的容器文件。

為部署創建一個名為 kube-verify 的命名空間:

# 創建一個新的命名空間
$ kubectl create namespace kube-verify
# 列出命名空間
$ kubectl get namespaces
NAME              STATUS   AGE
default           Active   63m
kube-node-lease   Active   63m
kube-public       Active   63m
kube-system       Active   63m
kube-verify       Active   19s

現在,在新的命名空間創建一個部署:

# 創建一個新的部署
$ cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kube-verify
  namespace: kube-verify
  labels:
    app: kube-verify
spec:
  replicas: 3
  selector:
    matchLabels:
      app: kube-verify
  template:
    metadata:
      labels:
        app: kube-verify
    spec:
      containers:
      - name: nginx
        image: quay.io/clcollins/kube-verify:01
        ports:
        - containerPort: 8080
EOF
deployment.apps/kube-verify created

Kubernetes 現在將開始創建部署,它由三個 Pod 組成,每個 Pod 都運行 quay.io/clcollins/kube-verify:01 鏡像。一分鐘左右後,新的 Pod 應該運行了,你可以用 kubectl get all -n kube-verify 來查看它們,以列出新命名空間中創建的所有資源:

# 檢查由該部署創建的資源
$ kubectl get all -n kube-verify
NAME                               READY   STATUS              RESTARTS   AGE
pod/kube-verify-5f976b5474-25p5r   0/1     Running             0          46s
pod/kube-verify-5f976b5474-sc7zd   1/1     Running             0          46s
pod/kube-verify-5f976b5474-tvl7w   1/1     Running             0          46s

NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/kube-verify   3/3     3            3           47s

NAME                                     DESIRED   CURRENT   READY   AGE
replicaset.apps/kube-verify-5f976b5474   3         3         3       47s

你可以看到新的部署、由部署創建的複製子集,以及由複製子集創建的三個 Pod,以滿足部署中的 replicas: 3 的要求。你可以看到 Kubernetes 內部工作正常。

現在,創建一個服務來暴露在三個 Pod 中運行的 Nginx 「應用程序」(在本例中是「歡迎」頁面)。這將作為一個單一端點,你可以通過它連接到 Pod:

# 為該部署創建服務
$ cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Service
metadata:
  name: kube-verify
  namespace: kube-verify
spec:
  selector:
    app: kube-verify
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
EOF
service/kube-verify created

創建服務後,你可以對其進行檢查並獲取新服務的 IP 地址:

# 檢查新服務
$ kubectl get -n kube-verify service/kube-verify
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kube-verify   ClusterIP   10.98.188.200   <none>        80/TCP    30s

你可以看到 kube-verify 服務已經被分配了一個 ClusterIP(僅對集群內部)10.98.188.200。這個 IP 可以從你的任何節點到達,但不能從集群外部到達。你可以通過在這個 IP 上連接到部署內部的容器來驗證它們是否在工作:

# 使用 curl 連接到 ClusterIP:
# (簡潔期間,輸出有刪節)
$ curl 10.98.188.200
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml_lang="en" lang="en">
<head>

成功了!你的服務正在運行,容器內的 Nginx 正在響應你的請求。你的服務正在運行,容器內的 Nginx 正在響應你的請求。

此時,你的樹莓派上有一個正在運行的 Kubernetes 集群,安裝了一個 CNI 載入項(Flannel),並有一個運行 Nginx Web 伺服器的測試部署和服務。在大型公有雲中,Kubernetes 有不同的入口控制器來與不同的解決方案交互,比如最近報道的 Skipper 項目。同樣,私有雲也有與硬體負載均衡器設備(如 F5 Networks 的負載均衡器)交互的入口控制器,或用於處理進入節點的流量的 Nginx 和 HAProxy 控制器。

在以後的文章中,我將通過安裝自己的入口控制器來解決將集群中的服務暴露給外界的問題。我還將研究動態存儲供應器和 StorageClasses,以便為應用程序分配持久性存儲,包括利用你在上一篇文章《將樹莓派家庭實驗室變成網路文件系統》中設置的 NFS 伺服器來為你的 Pod 創建按需存儲。

去吧,Kubernetes

「Kubernetes」(κυβερνήτης)在希臘語中是飛行員的意思 —— 但這是否意味著駕駛船隻以及引導船隻的人?誒,不是。「Kubernan」(κυβερνάω)是希臘語「駕駛」或「引導」的意思,因此,去吧,Kubernan,如果你在會議上或其它什麼活動上看到我,請試著給我一個動詞或名詞的通行證,以另一種語言 —— 我不會說的語言。

免責聲明:如前所述,我不會讀也不會講希臘語,尤其是古希臘語,所以我選擇相信我在網上讀到的東西。你知道那是怎麼一回事。我對此有所保留,放過我吧,因為我沒有開「對我來說都是希臘語」這種玩笑。然而,只是提一下,雖然我可以開玩笑,但是實際上沒有,所以我要麼偷偷摸摸,要麼聰明,要麼兩者兼而有之。或者,兩者都不是。我並沒有說這是個好笑話。

所以,去吧,像專業人員一樣在你的家庭私有雲中用自己的 Kubernetes 容器服務來試運行你的容器吧!當你越來越得心應手時,你可以修改你的 Kubernetes 集群,嘗試不同的選項,比如前面提到的入口控制器和用於持久卷的動態 StorageClasses。

這種持續學習是 DevOps 的核心,持續集成和新服務交付反映了敏捷方法論,當我們學會了處理雲實現的大規模擴容,並發現我們的傳統做法無法跟上步伐時,我們就接受了這兩種方法論。

你看,技術、策略、哲學、一小段希臘語和一個可怕的原始笑話,都匯聚在一篇文章當中。

via: https://opensource.com/article/20/6/kubernetes-raspberry-pi

作者:Chris Collins 選題:lujun9972 譯者:wxy 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的電子郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國