自己搭建一個 k8s 環境

背景

Kubernetes 是時下流行的容器編排引擎,因爲字母太多,且掐頭去尾後剩下 8 個字母,於是被大家親切的縮寫爲 k8s。

Kubernetes https://kubernetes.io/

另外所謂 “雲原生” 概念火爆,各大雲廠商也紛紛推出了自己的容器服務,例如阿里雲的 ACK、騰訊雲的 TKE、微軟雲的 AKS 等,無不是基於 Kubernetes 。

阿里雲 ACK https://www.aliyun.com/product/kubernetes
騰訊雲 TKE https://cloud.tencent.com/product/tke
微軟雲 AKS https://azure.microsoft.com/services/kubernetes-service/

由於我個人博客搭建在騰訊雲上,大概是去年(2021 年)11、12 月的時候萌生的 “要不把博客搬到 k8s 上?” 的想法。雲廠商提供的容器服務一般都支持從原有_雲服務器_轉換爲 Kubernetes 的 worker 節點;不過當然也有一些限制,例如騰訊雲價格相對低廉的_輕量應用服務器_則不支持轉換。不過正巧我的博客使用的是雲服務器,那就試試騰訊雲的 TKE 吧。

結果懶惰使人省錢,從學習到實戰的腳步總是異常的緩慢,在此期間騰訊雲發生了 2 件大事:

  1. 負載均衡實例升級調價公告
    https://cloud.tencent.com/document/product/214/59398

  2. 騰訊雲容器服務於 2022 年 3 月 21 日 10:00(北京時間)對託管集羣計費通知
    https://cloud.tencent.com/document/product/457/68706

運行在 k8s 裏的程序想要暴露到公網上,在雲廠商的環境中最常用的就是通過負載均衡實現,騰訊雲這一調價直接從原來的每小時 0.02 元漲到了 0.2 元,個人用戶應該很少用這麼貴的服務。(相較而言,阿里雲則提供廉價版的負載均衡,個人用戶的福音。)

另外徹底阻止我使用 TKE 的是,我們知道 k8s 集羣需要有 master 和 worker 節點分工合作,雲廠商會提供託管 master 節點的服務,用戶只需要自己照料好 worker 節點即可。騰訊雲也不例外,不過原來託管是免費的,即將要開始收費了!而不使用託管,意味着我必須再準備一臺雲服務器,又是一筆開銷……

雖然上雲等於花錢,但是貧窮就能阻止我們上雲嗎?答案是否定的,我們可以自己搭建 k8s 集羣!甚至還能從中收穫許多,如:

話雖如此,但強烈建議沒有接觸過 Kubernetes 的朋友們,先通過官方文檔 和 minikube 在本地學習後,再繼續深入。

ingress https://kubernetes.io/docs/concepts/services-networking/ingress/
官方文檔 https://kubernetes.io/zh/docs/setup/
minikube https://minikube.sigs.k8s.io/docs/

我計劃通過幾篇文章來介紹:

cert-manager https://cert-manager.io/
本地卷 https://kubernetes.io/docs/concepts/storage/volumes/#local

好了,廢話說的太多,現在就開始進行 k8s 集羣的搭建吧~

環境介紹

本文下面的操作都是在騰訊雲裏進行的,使用的是 1 臺雲服務器 CVM 和 1 臺輕量應用服務器 TencentCloud Lighthouse 進行。(一般雲廠商都會給新用戶很大的優惠力度,特別是第一臺雲服務器和輕量應用服務器,意味着前 3 年可以以很低的成本體驗。)

雲服務器 CVM https://cloud.tencent.com/product/cvm
輕量應用服務器 TencentCloud Lighthouse https://cloud.tencent.com/product/lighthouse

我使用的具體配置和規劃如下:

操作系統都使用的是 Debian 11.1,上述機器都在同一地域。

Debian http://debian.org/

請注意,不應將這樣的配置使用在生產環境,因爲這不能保證可用性。不過自己玩兒的話,一臺機器也可以(建議至少 2C2G),將 master 和 worker 部署在同一機器內,但這麼做會增加不穩定的因素,另外都上 (hua) 雲(qian)了,新用戶購買輕量應用服務器約等於不要錢,當然配置拉滿整上。

當然,雖然你使用的可能不是騰訊雲或者 Debian,但這並不是你繼續閱讀的障礙,因爲雲基礎設施、Linux 命令都是類似的,下文在具體的地方會進行標註。

沒有具體標明在哪臺機器上進行的,則所有機器都需要進行這些步驟,例如內網配置、Debian 配置、安裝 docker、kubeadm 等。

集羣網絡配置

請查看你使用的雲廠商沒有類似的限制或配置,以免內網不通導致 master 和 worker 節點無法通信。

內網網段配置

要組建集羣,首先機器之間得能互相訪問。最理想的情況是機器都處在同一個網段,但省錢的方案並不能做到這一點,我的兩臺主機位於完全不同的兩個網段,Lighthouse 甚至不支持修改內網 IP 地址。

好在騰訊雲的 CVM 和 Lighthouse 之間雖然默認不能連通,但位於同一地域的機器可以通過內網互聯功能,享受 5Gbps 帶寬免費互通(不同地域需要收費),可以參考騰訊雲文檔進行操作,本文不多贅述。

內網互聯 https://cloud.tencent.com/document/product/1207/56847

雲服務器防火牆配置

另外需要注意的是雲廠商提供的防火牆的配置(不是系統裏的防火牆),需要在每臺主機的入站規則中添加上其它主機的 IP 地址,騰訊雲的配置入口位於 實例詳情 - 安全組(Lighthouse 爲防火牆)。

例如,我直接選擇放行整個網段,這樣未來如果增加機器就不用再來回改配置了:

因爲我是全部放行,可以使用 ping 命令查看機器是否連通了,例如在我的 worker 上 ping master:

> ping 10.0.16.13

PING 10.0.16.13 (10.0.16.13) 56(84) bytes of data.
64 bytes from 10.0.16.13: icmp_seq=1 ttl=64 time=0.288 ms
64 bytes from 10.0.16.13: icmp_seq=2 ttl=64 time=0.240 ms
64 bytes from 10.0.16.13: icmp_seq=3 ttl=64 time=0.264 ms

允許訪問公網

由於安裝 k8s 過程中需要拉取一些鏡像或下載一些文件,而這些鏡像或文件在騰訊雲內網鏡像服務中並沒有提供,所以至少安裝階段需要訪問公網。

Debian 基礎配置

如果你使用的是其它 Linux 發行版本,那麼通過互聯網搜索相關操作,能很快找到對應的命令。

配置機器名稱和 hosts

使用統一一致的機器名稱利於管理:

hostnamectl set-hostname bun-master-01

配置 hosts 文件讓機器名稱可以被訪問:

cat >> /etc/hosts << EOF
10.0.16.13 bun-master-01
172.17.0.2 bun-worker-01
EOF

關閉防火牆等配置

安裝 k8s 前需要將 Linux 的防火牆、安全配置(SELinux)、交換分區(Swap,類似於 Windows 的虛擬內存)關閉。不過這些內容默認情況下都是禁用的,如果你曾經開啓過記得關閉。

允許 iptables 檢查橋接流量

cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

配置時間同步

確保每臺機器時間都是正確的,我使用騰訊雲內網提供的 NTP 服務。

NTP 服務 https://cloud.tencent.com/document/product/213/30392

如果你的雲廠商沒有提供類似服務,可以採用公網上的 NTP 服務。

安裝 ntp:

apt-get install -y ntp

修改 ntp 配置:

vi /etc/ntp.conf

將騰訊雲的 NTP 服務器地址替換掉配置文件中默認的:

重啓 ntp 並查看效果:

service ntp restart
service ntp status
ntpq -p

最後設置 ntp 開機啓動:

systemctl enable ntp

安裝 docker

注意:所有節點都需要安裝 docker。

我們使用官方腳本安裝 docker,在此之前先把一些必要的程序安裝一下:

apt-get update
apt-get install -y \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

接着使用騰訊雲內網鏡像來進行下載:

http://mirrors.tencentyun.com 只能在騰訊雲內網訪問,你需要將它們換成你可用的,例如 http://mirrors.tencent.com。本文優先使用騰訊雲內網鏡像,因爲這樣高速,且不會產生任何公網流量和費用。

curl -fsSL http://mirrors.tencentyun.com/docker-ce/linux/debian/gpg \
    | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] http://mirrors.tencentyun.com/docker-ce/linux/debian \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

接下來開始安裝 docker:

apt-get update
apt-get install -y \
    docker-ce \
    docker-ce-cli \
    containerd.io

檢查 docker 網絡

安裝好之後,使用 ip a 命令檢查一下 docker 新建的網卡,避免 docker 新建的網卡導致網段衝突,內網機器無法訪問。

例如在 bun-master-01 機器上執行 ip a 得到如下返回:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 52:54:00:19:8b:e4 brd ff:ff:ff:ff:ff:ff
    altname enp0s5
    altname ens5
    inet 10.0.16.13/22 brd 10.0.19.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe19:8be4/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:c3:bf:8b:a6 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever

docker 創建的虛擬網卡 docker0 使用了 172.17.0.1 地址,而我的另一臺機器 bun-worker-01 則是 172.17.0.2。這樣導致無法從 bun-master-01 訪問 bun-worker-01

我們可以修改 docker 的配置文件指定它的虛擬網卡地址,例如我希望 docker 使用 192.168.0.1/16 網段,這樣和誰都不衝突:

cat >> /etc/docker/daemon.json << EOF
{
  "bip": "192.168.0.1/16"
}
EOF

然後重啓 docker,並重新運行 ip a 檢查配置是否生效,以及重新 ping 一下測試連通性:

service docker restart

配置 docker 鏡像加速源

https://mirror.ccs.tencentyun.com 只能在騰訊雲內網訪問,你需要將它們換成你可用的,例如使用阿里雲鏡像加速。

阿里雲鏡像加速 https://help.aliyun.com/document_detail/60750.html

修改 /etc/docker/daemon.json 文件,新增 registry-mirrors 的配置:

{
  "bip": "192.168.0.1/16",
  "registry-mirrors": ["https://mirror.ccs.tencentyun.com"]
}

接下來重啓 docker 應用配置:

service docker restart

如果一切正常,讓我們跑一下 docker 的 hello-world 試試:

docker run hello-world

如果看到 Hello from Docker! 則說明一切順利,繼續進行下一步吧。

docker 啓動失敗常見問題

如果在重啓 docker 時不幸遇到了這樣的提示:

Job for docker.service failed because the control process exited with error code.
See "systemctl status docker.service" and "journalctl -xe" for details.

不要慌,請運行 journalctl -xe 查看具體錯誤。例如我嘗試將 docker 的虛擬網卡 IP 修改爲了一個非法的值:

Mar 23 21:44:28 master-01.bun.local dockerd[186689]: time="2022-03-23T21:44:28.584331774+08:00" level=info msg="[graphdriver] using prior storage driver: overlay2"
Mar 23 21:44:28 master-01.bun.local dockerd[186689]: time="2022-03-23T21:44:28.589151624+08:00" level=info msg="Loading containers: start."
Mar 23 21:44:28 master-01.bun.local dockerd[186689]: time="2022-03-23T21:44:28.643081791+08:00" level=info msg="stopping event stream following graceful shutdown" error="<nil>" module=libcontainerd namespace=moby
Mar 23 21:44:28 master-01.bun.local dockerd[186689]: failed to start daemon: Error initializing network controller: Error creating default "bridge" network: failed to allocate gateway (192.168.0.0): Address already in use

docker 要求配置的值是一個真實的 IP 地址,所以不能配置爲 192.168.0.0/16,需要配置爲 192.168.0.1/16

如果是其它問題,可以在網上進行搜索。

安裝 kubeadm, kubelet 以及 kubectl

注意:所有節點都需要安裝 kubeadm, kubelet 以及 kubectl。

由於 Google 無法訪問,騰訊雲的鏡像又沒有 gpg 文件,只好從阿里雲的鏡像下載 pgp 文件😓感謝友商

curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg

不過騰訊雲的鏡像有相關的軟件包:

有熟悉 Debian 的小夥伴會注意到,這裏指定了 Debian 的 xenial 版本,它其實表示 Debian 的 k8s 最新版。這個 issue 解釋了背後的故事。

這個 issue https://github.com/kubernetes/kubernetes/issues/66300

echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] http://mirrors.tencentyun.com/kubernetes/apt/ kubernetes-xenial main" \
    | sudo tee /etc/apt/sources.list.d/kubernetes.list

接下來把它們統統安裝上,並固定住版本,避免不小心升級造成問題:

apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

部署 master 節點

網段的設置注意不要和現有網段衝突。

使用 kubeadm init 來部署 master 節點,下面的參數中:

kubeadm init \
  --apiserver-advertise-address=10.0.16.13 \
  --service-cidr=10.1.0.0/16 \
  --pod-network-cidr=10.10.0.0/16 \
  --image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers

稍等片刻,便可以部署成功:

[init] Using Kubernetes version: v1.23.5
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
...
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

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

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 10.0.16.13:6443 --token 5x8l46.p5716s1ezcgqt3n2 \
    --discovery-token-ca-cert-hash sha256:f775a880cff6c4bd250420931726a8bcb9344b0dd335aa9be52a315f65616e16

根據上面 To start using your cluster ... 部分的指引,繼續執行它下面的 3 條命令,好讓 kubectl 工作:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

接着把最後兩行 kubeadm 命令複製下來備用。到此,master 節點就配置完成了。

部署 worker 節點

執行從 master 節點執行成功後返回的 kubeadm 命令(就是剛剛複製的那個),當前機器就會加入到 master 的集羣:

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

回到 master 節點,通過 kubectl get nodes 命令查看集羣內節點的情況:

NAME            STATUS     ROLES                  AGE     VERSION
bun-master-01   NotReady   control-plane,master   4m13s   v1.23.5
bun-worker-01   NotReady   <none>                 51s     v1.23.5

可以看到 bun-worker-01 節點已經加入集羣,amazing!不過爲啥是 NotReady 狀態?

別急,還有最後一步,配置 CNI (Container Network Interface) 插件 —— 它爲容器管理系統(如 docker、k8s)提供網絡功能。

CNI https://github.com/containernetworking/cni

安裝 CNI 插件:Calico

Calico 是一款被廣泛使用的 k8s CNI 插件,先下載它的配置文件,因爲一會兒需要修改裏面的內容:

wget https://docs.projectcalico.org/manifests/calico.yaml

在 calico.yaml 文件中找到 CALICO_IPV4POOL_CIDR 的配置,將其設置爲執行 kubeadm init 時指定的 pod-network 一樣的值:

然後安裝 Calico:

kubectl apply -f calico.yaml

安裝好後,可以通過 ip a 命令在 master 和 worker 節點上查看到 Calico 創建的 tunl0 網卡。並且再檢查一下 master 和 worker 之間是否還能連通,避免因爲配置錯誤之類的問題導致內網不通。

現在再運行 kubectl get nodes 命令,就能看到 master 和 worker 節點已經處於 Ready 狀態。

參考

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/trcfXfO4x745FKTRzKbCuQ