# 使用 kubeadm 安裝 K8s - 本文將使用 Kubeadm 建立有兩個節點的 k8s 叢集 - 一個 master 節點和一個 worker 節點 - 使用 **Containerd** 作為 k8s 的 CRI ## 硬體環境 - 需要多台實體機器,或是使用 VM 模擬多台機器 - 至少需要兩個節點,才能形成完整的叢集 - 最小硬體需求: - CPU: 2 cores - RAM: 2 GB - 網路環境 - 必須可以連上網際網路 - 所有節點之間可以互相連線 (在相同的 LAN 中、或有公網 IP、或是可以透過 router 互連) - 可以用 `ping` 指令檢驗所有節點是否可以互連 - 作業系統 - 以 Linux 為佳,以下將以 Ubuntu 環境示範 ### 網路資訊 :::warning - 下列為本文操作中的兩個節點的網路資訊 - 於自己的環境操作時,請記得代換成你自己環境上的資訊 ::: - Hostname - Master Node: `k8s-master` - Worker Node: `k8s-1` - IP address: - Master Node: `192.168.56.80` - Worker Node: `192.168.56.81` - 網卡名稱: `enp0s8` ## 設定 DNS (所有 Node) - 使用文字編輯器修改 */etc/hosts* 設定檔 ```bash sudo nano /etc/hosts # 或 sudo vim /etc/hosts ``` - 加入其他節點的名稱和對應的 IP - 以我的環境為例 - Master Node: 名稱為 k8s-master,IP 為 192.168.56.80 - Worker Node: 名稱為 k8s-1,IP 為 192.168.56.81 - 在設定檔中應加入 ``` 192.168.56.80 k8s-master 192.168.56.81 k8s-1 ``` ## 關閉 Swap (所有 Node) ### 關閉 Swap 功能 ```bash sudo swapoff -a ``` 檢查是否成功關閉,若執行下面指令後沒有任何輸出,則代表關閉成功 ```bash sudo swapon --show ``` :::warning - `swapoff` 的效果並非永久 - 系統重新啟動後,swap 仍會重新開啟 - 需要執行下方的操作,避免開機時啟用 Swap ::: ### 永久關閉 Swap #### 修改 fstab,避免開機時掛載 swap 磁區 - 使用文字編輯器 (`nano`, `vim`, ...)開啟 */etc/fstab* ```bash sudo vim /etc/fstab # 或 sudo nano /etc/fstab ``` - 將所有包含 `swap` 的行都加上註解 (在該行前加上 `#`) - 以下面的內容為例,若 */etc/fstab* 的內容如下 (內容僅供參考,實際內容以你自己的機器為主) ```bash= # /etc/fstab: static file system information. # # Use 'blkid' to print the universally unique identifier for a # device; this may be used with UUID= as a more robust way to name devices # that works even if disks are added and removed. See fstab(5). # # <file system> <mount point> <type> <options> <dump> <pass> # / was on /dev/sda3 during curtin installation /dev/disk/by-uuid/85e6b527-dc3f-4921-8004-fbea382a88e0 / ext4 defaults 0 1 /dev/disk/by-uuid/f52bade4-4ae1-44ec-8342-38cea61fd2b0 none swap sw 0 0 # /boot was on /dev/sda2 during curtin installation /dev/disk/by-uuid/4280fffd-6ec8-4d4e-99fb-90238597a1f1 /boot ext4 defaults 0 1 ``` - 第 10 行是一個 swap 磁區的設定 (該行的最右邊有寫著 swap 的欄位),所以要在該行的開頭加上 `#` 將此行註解,結果如下 ```bash= # /etc/fstab: static file system information. # # Use 'blkid' to print the universally unique identifier for a # device; this may be used with UUID= as a more robust way to name devices # that works even if disks are added and removed. See fstab(5). # # <file system> <mount point> <type> <options> <dump> <pass> # / was on /dev/sda3 during curtin installation /dev/disk/by-uuid/85e6b527-dc3f-4921-8004-fbea382a88e0 / ext4 defaults 0 1 #/dev/disk/by-uuid/f52bade4-4ae1-44ec-8342-38cea61fd2b0 none swap sw 0 0 # /boot was on /dev/sda2 during curtin installation /dev/disk/by-uuid/4280fffd-6ec8-4d4e-99fb-90238597a1f1 /boot ext4 defaults 0 1 ``` - 記得修改完檔案後要存檔 - 使用 `vim`,先按 Esc 後輸入 `:wq` - 使用 `nano`,先按 Ctrl+O 再按 Ctrl+X #### 透過 Systemd 關閉所有 Swap Unit - 使用 `systemctl` 查詢所有 swap unit ``` sudo systemctl --type=swap -a ``` - 假設輸出如下,代表系統中有一個被啟用的 swap unit,名稱為 ***dev-sda4.swap*** ``` UNIT LOAD ACTIVE SUB DESCRIPTION dev-sda4.swap loaded inactive dead Swap Partition LOAD = Reflects whether the unit definition was properly loaded. ACTIVE = The high-level unit activation state, i.e. generalization of SUB. SUB = The low-level unit activation state, values depend on unit type. 1 loaded units listed. To show all installed unit files use 'systemctl list-unit-files'. ``` - 實際名稱可能不同,請以操作時拿到的實際輸出為準 - 使用 `systemctl` 關閉該 swap ``` sudo systemctl mask <swap unit> ``` - `<swap unit>` 要改成實際的 unit 名稱 - 以上面例子為例,指令應為: ``` sudo systemctl mask dev-sda4.swap ``` - 再次使用 `systemctl` 查詢,檢查 swap 是否被關閉 ``` sudo systemctl --type=swap -a ``` ## 安裝 Docker (所有 Node) ```bash sudo apt-get update sudo apt-get install ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin ``` ## 啟用 Kernel Module 並設定 Kernel 參數 (所有 Node) - 在 K8s 的所有節點中,需要執行下列指令載入指定的 Kernel Module,以保證網路傳輸正常 ```bash # 建立 Kernel Module 設定檔 cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF # 載入 Kernel Module sudo modprobe overlay sudo modprobe br_netfilter ``` - 在 K8s 的所有節點中,需要執行下列指令設定 Kernel 參數,以保證網路傳輸正常 ```bash # 建立 Kernel 參數設定檔 cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF # 載入 Kernel 參數 sudo sysctl --system ``` ## 安裝 K8s 套件 (所有 Node) ### 安裝網路工具 ```= sudo apt update sudo apt install -y apt-transport-https ca-certificates curl ``` ### 取得 K8s 安裝設定 **下面以 1.32 版為例**,其他版本可參考官方說明文件: https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/ ```bash sudo mkdir /etc/apt/keyrings curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.32/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list ``` ### 安裝 kubelet, kubeadm, kubectl - 安裝預設版本 ``` sudo apt update sudo apt install -y kubelet kubeadm kubectl ``` - 可以在套件名稱之後加上 `=<version>` 指定安裝的版本 ``` sudo apt install -y kubelet=1.32.2-1.1 kubeadm=1.32.2-1.1 kubectl=1.32.2-1.1 ``` - 查詢可用的版本號 ``` sudo apt list -a kubelet ``` - (可選) 鎖定版本,避免自動更新或升級 ``` sudo apt-mark hold kubelet kubeadm kubectl ``` ## 設定 Containerd (所有 Node) - 建立 Containerd 的設定檔資料夾 ``` sudo mkdir /etc/containerd ``` - 將預設的設定內容寫入設定檔案中 ```bash sudo sh -c "containerd config default > /etc/containerd/config.toml" ``` - 修改設定檔的內容,啟用 SystemdCgroup ```bash sudo sed -i 's/ SystemdCgroup = false/ SystemdCgroup = true/' /etc/containerd/config.toml ``` - 重啟 containerd 和 kubelet ``` sudo systemctl restart containerd sudo systemctl restart kubelet ``` ## 建立 K8s Cluster (Master Node) ### Pull 必要的 Image - 以下操作僅在 Master Node 執行 - Pull 所有 kubeadm 需要的 Image ``` sudo kubeadm config images pull ``` :::warning - 這個步驟需要下載一些檔案,可能需要較長時間 - 實際需要的時間取決於網路速度,請耐心等待 ::: ### 初始化 Cluster ```bash sudo kubeadm init \ --apiserver-advertise-address=<node ip address> \ --pod-network-cidr=<pod network cidr> ``` - `<node ip address>` 為 master 節點的 IP address (且此 IP address 必須能和其他節點溝通) - `<pod network cidr>` 為日後 pod 所使用的 IP 區段,可以自己定義 - 格式為 `XXX.XXX.XXX.XXX/OO`,需符合 [CIDR](https://zh.wikipedia.org/zh-tw/%E6%97%A0%E7%B1%BB%E5%88%AB%E5%9F%9F%E9%97%B4%E8%B7%AF%E7%94%B1) - 須注意使用的 IP 區段不能和機器實際使用的 IP 區段重疊 - 建議使用私有區段,例如 `10.XX.0.0/16` - 舉例來說 - 假設 master node 的 IP 為 192.168.56.81 - 希望 pod 使用的 IP 區段為 10.244.0.0/16 (即 10.20.0.0~10.244.255.255) - 初始化的指令應為 ``` sudo kubeadm init \ --apiserver-advertise-address=192.168.56.81 \ --pod-network-cidr=10.244.0.0/16 ``` - 初始化完成後,輸出的最後兩行是加入 worker 節點的指令,請先複製此指令並存在任意檔案中,在之後可以用到 - 該指令應類似: ``` kubeadm join 10.0.2.81:6443 --token XXXXXXX \ --discovery-token-ca-cert-hash sha256:XXXXXXXXX ``` ### 建立管理員設定檔 - 初始化完成後,會跳出如何設定的提示 ``` mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config ``` - 完成設定後,即可使用 `kubectl` 指令控制 cluster - 查看節點狀態 ```bash kubectl get node ``` - 輸出應類似: ``` NAME STATUS ROLES AGE VERSION k8s-master NotReady control-plane 1m v1.27.6 ``` - NotReady 是因為還未安裝 CNI,在下一篇筆記中會提到 ## Worker Node 加入 Cluster (Worker Node) - 在 Worker Node 中,執行剛剛複製的指令,即可將 worker node 加入 cluster 中 - 由於加入 node 的 token 是有時效性的,若已過期或是沒有存到指令,可以在<font color='red'> master node </font> 執行下面指令,產生新的 join 指令 ``` kubeadm token create --print-join-command ``` - 執行下面指令,查看 cluster 的所有節點,現在應有兩個節點 ``` kubectl get node ``` ## 安裝 Calico 作為 CNI - 在建立 cluster 之後,需要在 cluster 中部屬 CNI (container networking interface) 才能讓 cluster 開始運作 - 本文將使用 Calico 作為 CNI ### 下載 yaml (Mater Node) - 到 Calico 的 Github 找到 calico 的 yaml 檔,Calico 的所有 yaml 會放在 manifests 底下 - https://github.com/projectcalico/calico/tree/master/manifests - 找到 [calico.yaml](https://github.com/projectcalico/calico/blob/master/manifests/calico.yaml),打開該檔案的原始檔,複製它的 URL  - 在 master node 使用 `wget` 下載 yaml 檔 ``` wget https://raw.githubusercontent.com/projectcalico/calico/master/manifests/calico.yaml ``` ### 修改 yaml - 使用文字編輯器修改 calico.yaml ```bash nano ./calico.yaml # 或 vim ./calico.yaml ``` - 找到以下區段 - 可以搜尋 `# Auto-detect the BGP IP address.`  - 在相同的層級插入以下兩行 ```yaml - name: IP_AUTODETECTION_METHOD value: "interface=<network interface>" ``` - `<network interface>` 請替換成你正在使用的網卡名稱,請選擇可以和其他節點互連的那張網卡 - 縮排要對齊 `# Auto-detect the BGP IP address.`  - 以我的為例,所有節點上的網卡 `enp0s8`,都有 IP 位址 192.168.56.XX,所以我要填入 `enp0s8` - 修改完成後存檔 ### 部屬 Calico (Master Node) - 使用 `kubectl` 部屬修改好的 yaml 檔 ``` kubectl apply -f ./calico.yaml ``` - 完成部屬後(可能需要等幾分鐘),所有節點的狀態應為 `Ready` ``` kubectl get node ```
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up