iT邦幫忙

2024 iThome 鐵人賽

DAY 7
0
Kubernetes

一起來看 Kubernetes 官方文件吧!系列 第 7

Day07 - 一起來看 Kubernetes 官方文件吧!- 使用 kubeadm 安裝 single-node cluster

  • 分享至 

  • xImage
  •  

前言

今天就讓我們透過 kubeadm 指令來建立一個自己的 k8s clsuter 吧!

本來是打算說直接對照安裝文件的建議裝 HA control-plane,但發現有些內容實在太豐富了,如果要每篇都看的話可能要到 Day20 才會裝,因此先略過一些內容來開始實作!

今日目標

  • 透過 kubeadm 在 ubuntu 24.04 上面建立一個 single node cluster
  • 確認所有文件內要求的內容

installing kubeadm

https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

kubeadm 是官方唯一直接維護的 k8s cluster 安裝方式
對於環境的前置要求如下:

  • 2 CPUs, 2GB RAM 或更多
  • 在 Linux 的 Debian 系 (e.g. ubuntu) 或是 Red Hat 系 (e.g CentOS) 的話,有提供套件管理網址下載
    其餘的 OS (e.g. Windows) 就必須直接下載二進位檔
  • 確保整座 cluster 都可以透過網路連線 (private or pubilc)
  • 唯一的 hostname, Mac address 和 product_uuid
  • Swap 必須關閉,否則 kubelet 預設會啟動失敗

💡 最新版本的 kubelet 已經沒有強制限制要關閉 swap 了,此功能在 k8s 1.22 進入 Alpha,並在 1.28 進入 Beta 版,同樣也是透過 KEP 的方式進入提案測試的,編號為 KEP-2400
進入 Beta 版後,僅支援在 Cgroupv2 的系統上使用,也完善了監控等等的議題,在 kubelet 也有許多相關的參數對應調整
延伸閱讀: https://kubernetes.io/blog/2023/08/24/swap-linux-beta/

接下來文件內也有提供每一項步驟需要檢查的方式:

Verify the MAC address and product_uuid are unique for every node

在實體機上面,通常都會有獨立的 prdouct_uuid, 但若是使用虛擬機就需要稍微注意一下

  • MAC address → 使用 ip linkifconfig 檢查
  • product_uuid → 使用 sudo cat /sys/class/dmi/id/product_uuid 檢查

💡 筆者是使用 vmware workstation player 來建立 ubuntu VM 做使用的,我是透過先安裝一台 ubuntu 之後當作 template,之後就用 clone 的方式來建立機器
本來覺得這樣做 prdouct_uuid 很可能會重複,不過看起來 workstation player 會特別產生不同的 product_uuid 給每台 VM

Check network adapters

要特別注意當有 2 張以上網卡時,要設定 IP route 告知 k8s cluster 應該要透過哪張卡來傳輸資訊

Check required ports

基本上就是確保 control plane 上面會跑的 process port 沒被占用,以 kube-apiserver 為例是使用 6443,檢查方式:

nc 127.0.0.1 6443 -v

另外還要確保: 2379-2381 (etcd), 10250 (kubelet), 10259 (kube-scheduler), 10257 (kube-controller-manager),以及不同 CNI 也可能會有不同的需求 (e.g. bgp 模式會占用 179 port)

Installing a container runtime

安裝 CRI,之前會看到不少 CRI 的實作,不過似乎越來越少了,最主要的就是以下三個:

  • containerd:擁有廣大的社群,也是 CNCF 的畢業專案之一。
  • CRI-O:由 RedHat 維護,簡化了許多功能,僅保留 CRI 的需求。主要是用於 RedHat 自家的 Openshift 平台。
  • cri-dockerd:在 k8s 1.24 之後,kubelet 移除了對 dockershim 的支援,取而代之的就是 cri-dockerd, 讓某些 docker 環境在新版的 k8s 依然可以透過 docker 來當作 CRI。

Installing kubeadm, kubelet and kubectl

kubeadm, kubelet, kubectl 是 k8s cluster 的三本柱,kubeadm 並不直接管理另外兩個的版本,因此需要手動配置,他們的分工為:

  • kubeadm:啟動 cluster 的工具
  • kubelet:透過跟 CRI 溝通建立 pods/containers
  • kubectl:k8s 的前端工具

在筆者的 ubuntu 24.04 環境上,使用 apt-get install kubeadm kubelet kubectl 指令時,還會安裝 conntrack cri-tools ebtables kubernetes-cni socat 等相依性套件

三本柱版本的相容性

在討論版本相容性時,都會以 kube-apiserver 當作基準點,而 kubeadm 的版本會直接對應到 kube-apiserevr

https://kubernetes.io/releases/version-skew-policy/

之前的文件是用 +- 去表達版本可相容多少,目前版本都直接是直接以當前版本 1.31 來舉例
以 kube-apiserver 為 1.31 為基準:

  • kubelet:可使用 1.31, 1.30, 1.29, 1.28 (-3,但在 1.25 之前只能差到 2 個版本)
  • kubectl:可使用 1.32, 1.31, 1.30 (+-1)

至於其他元件也與 kube-apiserver 的版本息息相關,只是若使用 kubeadm 升級的話基本上都會一起保持同個版本

Configuring a cgroup driver

linux 是透過 cgroup 來管理 pods 能使用的 cpu/memory 等硬體資源的,因此必須確保 kubelet 與 CRI 有設定正確,目前也只有兩個選項:

  • cgroupfs driver:為 kubelet 的預設,會讓 kubelet 直接與 cgroup filesystem 互動。
    但是若在 systemd 的系統下不建議採用此配置 (目前大部分的 OS 應該都是採用 systemd)
    • 補充:在 1.22 版後,使用 kubeadm 安裝的情況下,會預設使用 systemd cgroup
  • systemd cgroup:為了避免有兩種管理機制,統一由 systemd 來管理 cgroup 是比較好的方式,且在 cgroupv2 的環境底下也建議使用此配置

💡 目前新的 OS 版本大多都是開啟 cgroupv2,要檢查可以使用 mount 指令查看輸出,如以下:mount | grep cgroup2
有顯示:”cgroup2 on /sys/fs/cgroup type cgroup2” 的字樣,代表目前系統是使用 cgroupv2

透過腳本檢查

根據以上內容,請 AI 幫忙寫了一個簡易的腳本來檢查環境:

#!/bin/bash

# Output file
LOGFILE="check-k8s-env.log"

# Function to check if a command exists
command_exists() {
    command -v "$1" >/dev/null 2>&1
}

# Function to check if a port is in use
port_in_use() {
    nc -z localhost "$1" >/dev/null 2>&1
}

# Function to check swap status
check_swap() {
    if [ "$(swapon --show=NAME | wc -l)" -gt 0 ]; then
        echo "[x] Swap is enabled. Please disable swap before proceeding." | tee -a "$LOGFILE"
        return 1
    else
        echo "[o] Swap is disabled." | tee -a "$LOGFILE"
        return 0
    fi
}

# Initialize log file
echo "Starting environment checks..." | tee "$LOGFILE"

# Initialize status variables
status=0

# Check if containerd is installed
echo "Checking containerd installation..." | tee -a "$LOGFILE"
if command_exists containerd; then
    echo "[o] containerd is installed." | tee -a "$LOGFILE"
else
    echo "[x] containerd is not installed. Please install containerd before proceeding." | tee -a "$LOGFILE"
    status=1
fi

# Check if kubeadm is installed
echo "Checking kubeadm installation..." | tee -a "$LOGFILE"
if command_exists kubeadm; then
    echo "[o] kubeadm is installed." | tee -a "$LOGFILE"
else
    echo "[x] kubeadm is not installed. Please install kubeadm before proceeding." | tee -a "$LOGFILE"
    status=1
fi

# Check if kubectl is installed
echo "Checking kubectl installation..." | tee -a "$LOGFILE"
if command_exists kubectl; then
    echo "[o] kubectl is installed." | tee -a "$LOGFILE"
else
    echo "[x] kubectl is not installed. Please install kubectl before proceeding." | tee -a "$LOGFILE"
    status=1
fi

# Check system requirements
echo "Checking system requirements..." | tee -a "$LOGFILE"
cpu_cores=$(grep -c ^processor /proc/cpuinfo)
memory_size=$(grep MemTotal /proc/meminfo | awk '{print $2 / 1024}')

if [ "$cpu_cores" -lt 2 ]; then
    echo "[x] At least 2 CPU cores are required. Found $cpu_cores." | tee -a "$LOGFILE"
    status=1
else
    echo "[o] CPU core count is sufficient. Found $cpu_cores." | tee -a "$LOGFILE"
fi

if [ "$(echo "$memory_size < 2048" | bc)" -eq 1 ]; then
    echo "[x] At least 2GB of RAM is required. Found $memory_size MB." | tee -a "$LOGFILE"
    status=1
else
    echo "[o] RAM size is sufficient. Found $memory_size MB." | tee -a "$LOGFILE"
fi

# Check swap is disabled
echo "Checking swap status..." | tee -a "$LOGFILE"
if ! check_swap; then
    status=1
fi

# Check kernel version
echo "Checking kernel version..." | tee -a "$LOGFILE"
kernel_version=$(uname -r)
if ! [[ "$kernel_version" =~ ^[5-9]\. ]]; then
    echo "[x] A kernel version of 5.x or higher is required. Found $kernel_version." | tee -a "$LOGFILE"
    status=1
else
    echo "[o] Kernel version is sufficient. Found $kernel_version." | tee -a "$LOGFILE"
fi

# Check cgroup version
echo "Checking cgroup version..." | tee -a "$LOGFILE"
cgroup_info=$(mount | grep cgroup)
if echo "$cgroup_info" | grep -q 'cgroup2'; then
    echo "[o] Cgroup version 2 is enabled." | tee -a "$LOGFILE"
elif echo "$cgroup_info" | grep -q 'cgroup'; then
    echo "[o] Cgroup version 1 is enabled or cgroup version is not specified." | tee -a "$LOGFILE"
else
    echo "[x] Cgroup information not found. Please check cgroup setup." | tee -a "$LOGFILE"
    status=1
fi

# Check if required ports are in use
ports=("2379" "2381" "6443" "10250" "10257" "10259")
for port in "${ports[@]}"; do
    echo "Checking port $port..." | tee -a "$LOGFILE"
    if port_in_use "$port"; then
        echo "[x] Port $port is in use." | tee -a "$LOGFILE"
        status=1
    else
        echo "[o] Port $port is available." | tee -a "$LOGFILE"
    fi
done

if [ "$status" -eq 0 ]; then
    echo "[o] All checks passed. Your environment is ready for 'kubeadm init'." | tee -a "$LOGFILE"
else
    echo "[x] Some checks failed. Please review the log file '$LOGFILE' for details." | tee -a "$LOGFILE"
fi

目前在我的 ubuntu 24.04 主機上執行結果如下:

Starting environment checks...
Checking containerd installation...
[x] containerd is not installed. Please install containerd before proceeding.
Checking kubeadm installation...
[x] kubeadm is not installed. Please install kubeadm before proceeding.
Checking kubectl installation...
[x] kubectl is not installed. Please install kubectl before proceeding.
Checking system requirements...
[o] CPU core count is sufficient. Found 2.
[o] RAM size is sufficient. Found 3868.19 MB.
Checking swap status...
[x] Swap is enabled. Please disable swap before proceeding.
Checking kernel version...
[o] Kernel version is sufficient. Found 6.8.0-41-generic.
Checking cgroup version...
[o] Cgroup version 2 is enabled.
Checking port 2379...
[o] Port 2379 is available.
Checking port 2381...
[o] Port 2381 is available.
Checking port 6443...
[o] Port 6443 is available.
Checking port 10250...
[o] Port 10250 is available.
Checking port 10257...
[o] Port 10257 is available.
Checking port 10259...
[o] Port 10259 is available.
[x] Some checks failed. Please review the log file 'check-k8s-env.log' for details.

主要就是安裝 containerd, kubeadm 等等指令,以及關閉 swap

調整完畢之後,按著文件上面的指令操作,即可開始安裝 k8s cluster

kubeadm init

kubeadm init 為啟動 k8s cluster 的指令,之後預計會看看 kubeadm 的所有指令,這邊就先略過了

前置動作大致步驟為:

  1. 上方討論的環境檢查
  2. 設定 ip_forward,參考:https://discuss.kubernetes.io/t/kubeadmin-join-throws-this-error-proc-sys-net-bridge-bridge-nf-call-iptables-does-not-exist/24855/2
  3. 安裝 CRI (containerd) 並且遵循 contaienrd 的配置 (透過 docker 的 apt source)
  4. 執行 kubeadm init
 sudo kubeadm init

若以上配置無誤,即可建立 k8s cluster

kubectl get nodes -o wide
NAME          STATUS     ROLES           AGE    VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE           KERNEL-VERSION     CONTAINER-RUNTIME
k8s-master1   NotReady   control-plane   2m9s   v1.31.0   192.168.75.10   <none>        Ubuntu 24.04 LTS   6.8.0-41-generic   containerd://1.7.21

到此還需要安裝 CNI,才能算是可用的 k8s clsuter,待後面的日子再處理

結論

雖然先前有使用 kubeadm 安裝的經驗,但通常都是參考別人寫的文章,仔細看過文章之後,收穫不少,明日來看看如何建立具有 HA 的 k8s cluster

參考

https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

https://docs.docker.com/engine/install/ubuntu/

https://www.fortaspen.com/install-kubernetes-containerd-ubuntu-linux-22-04/

https://discuss.kubernetes.io/t/kubeadmin-join-throws-this-error-proc-sys-net-bridge-bridge-nf-call-iptables-does-not-exist/24855/2


上一篇
Day06 - 一起來看 Kubernetes 官方文件吧!- Production environment 建議
下一篇
Day08 - 一起來看 Kubernetes 官方文件吧!- 使用 kubeadm 安裝 HA-cluster (上)
系列文
一起來看 Kubernetes 官方文件吧!11
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言