# 全離線安裝 Kubeadm K8s ## 目標 在離線環境上安裝 3m2w 的 K8s,詳細資訊如下 1. k8s 版本 `1.33.2` 2. containerd 版本 `2.1.3` 3. runc 版本 `1.3.0` 4. CNI: calico `3.29.4` 注意: 本版資訊會隨時間更動 ## 事前檔案準備 在一台可上網環境的機器,且有安裝 `docker` 或 `podman` ``` $ mkdir -p work/{harbor,k8s} ``` ### 準備 harbor(如果客戶已有 harbor 可以跳過此步驟) ```! $ cd ~/work/harbor $ wget https://github.com/goharbor/harbor/releases/download/v2.7.0/harbor-offline-installer-v2.7.0.tgz ``` ```! # 準備 docker $ sudo wget https://download.docker.com/linux/static/stable/x86_64/docker-28.3.0.tgz # 準備 docker-compose $ sudo wget https://github.com/docker/compose/releases/download/1.18.0/docker-compose-Linux-x86_64 ``` * 下載自簽憑證 script ``` $ wget https://raw.githubusercontent.com/cooloo9871/SelfSigned-RootCA/master/mk $ chmod +x mk ``` * 做成壓縮包 ``` $ cd .. $ ls -l harbor total 1716872 -rw-r--r-- 1 root root 81874097 Jun 24 23:55 docker-28.3.0.tgz -rw-r--r-- 1 root root 8479184 Dec 7 2021 docker-compose-Linux-x86_64 -rw-rw-r-- 1 bigred bigred 789527572 Dec 19 2022 harbor-offline-installer-v2.7.0.tgz -rw-rw-r-- 1 bigred bigred 878174181 Jun 25 06:17 harbor.tar.zst -rwxrwxr-x 1 bigred bigred 1515 Jun 25 06:33 mk $ tar --zstd -cvf harbor.tar.zst -C ~/work harbor ``` ``` $ ls -l ~/work total 857316 drwxrwxr-x 2 bigred bigred 4096 Jun 25 11:19 harbor -rw-rw-r-- 1 bigred bigred 877875781 Jun 25 14:08 harbor.tar.zst drwxrwxr-x 2 bigred bigred 4096 Jun 25 14:03 k8s ``` ### 準備 k8s ``` $ cd ~/work/k8s ``` * 下載 master 套件 ``` $ wget https://dl.k8s.io/v1.33.2/kubernetes-server-linux-amd64.tar.gz ``` * 下載 worker 套件 ``` $ wget https://dl.k8s.io/v1.33.2/kubernetes-node-linux-amd64.tar.gz ``` * 下載 containerd ``` $ wget https://github.com/containerd/containerd/releases/download/v2.1.3/containerd-2.1.3-linux-amd64.tar.gz $ wget https://raw.githubusercontent.com/containerd/containerd/main/containerd.service ``` * 下載 runC ``` $ wget https://github.com/opencontainers/runc/releases/download/v1.3.0/runc.amd64 ``` * 下載 cni ``` $ curl -sL "$(curl -sL https://api.github.com/repos/containernetworking/plugins/releases/latest | \ jq -r '.assets[].browser_download_url' | grep 'linux-amd64.*.tgz$')" -o cni-plugins.tgz ``` * 下載 crictl ``` # 根據 k8s 版本指定 $ VERSION="v1.33.0" $ wget https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-amd64.tar.gz ``` * 下載 `calico 3.29.4` yaml ``` $ curl -sL https://raw.githubusercontent.com/projectcalico/calico/v3.29.4/manifests/calico.yaml -o calico.yaml ``` * 下載 `metrics-server` yaml ``` $ wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml ##- --kubelet-insecure-tls 加這行是告訴 kubelet 不要安全模式,告訴kubelet封包不要加密。 $ nano components.yaml .......... spec: containers: - args: - --cert-dir=/tmp - --secure-port=4443 - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname - --kubelet-use-node-status-port - --metric-resolution=15s - --kubelet-insecure-tls # 新增這行 image: k8s.gcr.io/metrics-server/metrics-server:v0.7.2 imagePullPolicy: IfNotPresent ``` * 取得 `kube-vip` 版本代號 ``` $ export KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name") # 檢查 kube-vip 版本 $ echo $KVVERSION v0.9.1 # 因此 kube-vip image 就是 ghcr.io/kube-vip/kube-vip:v0.9.2 ``` * 安裝 kubeadm 查看所需要的 image ``` $ wget https://dl.k8s.io/v1.33.2/kubernetes-server-linux-amd64.tar.gz $ tar -xzvf kubernetes-server-linux-amd64.tar.gz $ cd kubernetes/server/bin $ sudo cp kubeadm /usr/bin/ ``` * 透過 kubeadm 可以先查看 `1.33.2` 以及其他版本所需的 image ``` $ kubeadm config images list --kubernetes-version=v1.33.2 registry.k8s.io/kube-apiserver:v1.33.2 registry.k8s.io/kube-controller-manager:v1.33.2 registry.k8s.io/kube-scheduler:v1.33.2 registry.k8s.io/kube-proxy:v1.33.2 registry.k8s.io/coredns/coredns:v1.12.0 registry.k8s.io/pause:3.10 registry.k8s.io/etcd:3.5.21-0 $ kubeadm config images list --kubernetes-version=v1.33.1 registry.k8s.io/kube-apiserver:v1.33.1 registry.k8s.io/kube-controller-manager:v1.33.1 registry.k8s.io/kube-scheduler:v1.33.1 registry.k8s.io/kube-proxy:v1.33.1 registry.k8s.io/coredns/coredns:v1.12.0 registry.k8s.io/pause:3.10 registry.k8s.io/etcd:3.5.21-0 $ kubeadm config images list --kubernetes-version=v1.33.0 registry.k8s.io/kube-apiserver:v1.33.0 registry.k8s.io/kube-controller-manager:v1.33.0 registry.k8s.io/kube-scheduler:v1.33.0 registry.k8s.io/kube-proxy:v1.33.0 registry.k8s.io/coredns/coredns:v1.12.0 registry.k8s.io/pause:3.10 registry.k8s.io/etcd:3.5.21-0 ``` * 編寫下載 image script ``` $ nano pull.sh #!/bin/bash #set -x RED='\033[1;31m' # alarm GRN='\033[1;32m' # notice YEL='\033[1;33m' # warning NC='\033[0m' # No Color [[ ! -f ./images.txt ]] && printf "${RED}images.txt file not found${NC}\n" && exit 1 image_name=$(paste -sd' ' images.txt) docker_command() { while read line do sudo docker pull $line &>/dev/null if [[ "$?" == 0 ]]; then printf "${GRN}download $line success${NC}\n" else printf "${RED}download $line fail${NC}\n" fi done < images.txt sudo docker save $image_name > k8s_images.tar tar --zstd -cf images.tar.zst k8s_images.tar rm -rf k8s_images.tar printf "${GRN}All images have been saved as images.tar.zst${NC}\n" } podman_command() { while read line do sudo podman pull $line &>/dev/null if [[ "$?" == 0 ]]; then printf "${GRN}download $line success${NC}\n" else printf "${RED}download $line fail${NC}\n" fi done < images.txt sudo podman save -m $image_name > k8s_images.tar tar --zstd -cf images.tar.zst k8s_images.tar rm -rf k8s_images.tar printf "${GRN}All images have been saved as images.tar.zst${NC}\n" } if ! which docker &>/dev/null && ! which podman &>/dev/null; then printf "${RED}docker and podman command not found${NC}\n" && exit 1 fi sudo -n true &>/dev/null if [[ "$?" != "0" ]]; then printf "${RED}Passwordless sudo is NOT enabled${NC}\n" && exit 1 fi if which docker &>/dev/null; then docker_command else podman_command fi ``` * 以下 image 是根據本次測試所需,需依照不同環境準備 ``` $ nano images.txt registry.k8s.io/kube-apiserver:v1.33.0 registry.k8s.io/kube-controller-manager:v1.33.0 registry.k8s.io/kube-scheduler:v1.33.0 registry.k8s.io/kube-proxy:v1.33.0 registry.k8s.io/kube-apiserver:v1.33.1 registry.k8s.io/kube-controller-manager:v1.33.1 registry.k8s.io/kube-scheduler:v1.33.1 registry.k8s.io/kube-proxy:v1.33.1 registry.k8s.io/kube-apiserver:v1.33.2 registry.k8s.io/kube-controller-manager:v1.33.2 registry.k8s.io/kube-scheduler:v1.33.2 registry.k8s.io/kube-proxy:v1.33.2 registry.k8s.io/coredns/coredns:v1.12.0 registry.k8s.io/pause:3.10 registry.k8s.io/etcd:3.5.21-0 docker.io/calico/cni:v3.29.4 docker.io/calico/node:v3.29.4 docker.io/calico/kube-controllers:v3.29.4 registry.k8s.io/metrics-server/metrics-server:v0.7.2 ghcr.io/kube-vip/kube-vip:v0.9.2 ``` * 開始下載 image,並自動打包 ``` $ chmod +x pull.sh $ ./pull.sh ``` 做成 `k8s.tar.zst` 打包檔 ``` $ cd .. $ ls -l k8s/ total 1244756 -rw-rw-r-- 1 bigred bigred 325176 Jun 25 06:19 calico.yaml -rw-rw-r-- 1 bigred bigred 55901748 Jun 25 08:51 cni-plugins.tgz -rw-rw-r-- 1 bigred bigred 4340 Jun 25 06:20 components.yaml -rw-rw-r-- 1 bigred bigred 33200838 Jun 19 22:39 containerd-2.1.3-linux-amd64.tar.gz -rw-rw-r-- 1 bigred bigred 1248 Jun 25 06:19 containerd.service -rw-rw-r-- 1 bigred bigred 20370694 Apr 22 07:51 crictl-v1.33.0-linux-amd64.tar.gz -rw-rw-r-- 1 bigred bigred 637987968 Jun 26 01:38 images.tar.zst -rw-rw-r-- 1 bigred bigred 767 Jun 26 01:37 images.txt -rw-rw-r-- 1 bigred bigred 135110634 Jun 18 17:53 kubernetes-node-linux-amd64.tar.gz -rw-rw-r-- 1 bigred bigred 379831997 Jun 18 17:53 kubernetes-server-linux-amd64.tar.gz -rwxrwxr-x 1 bigred bigred 1247 Jun 25 07:59 pull.sh -rw-rw-r-- 1 bigred bigred 11862624 Apr 29 04:43 runc.amd64 $ tar --zstd -cvf k8s.tar.zst -C ~/work k8s ``` #### 將 `harbor.tar.zst` 和 `k8s.tar.zst` 帶至客戶環境做安裝 ``` $ ls -l total 2901648 drwxrwxr-x 2 bigred bigred 4096 Jun 25 06:17 harbor -rw-rw-r-- 1 bigred bigred 1755574653 Jun 25 06:17 harbor.tar.zst drwxrwxr-x 2 bigred bigred 4096 Jun 25 06:25 k8s -rw-rw-r-- 1 bigred bigred 1215692757 Jun 25 06:30 k8s.tar.zst ``` ## 開始離線安裝 ### 安裝 harbor * 將 `harbor.tar.zst` 上傳到 harbor 主機,然後解壓縮 ``` $ tar --zstd -xf harbor.tar.zst $ ls -l harbor total 1716868 -rw-r--r-- 1 bigred bigred 81874097 Jun 25 07:55 docker-28.3.0.tgz -rw-r--r-- 1 bigred bigred 8479184 Dec 7 2021 docker-compose-Linux-x86_64 -rw-rw-r-- 1 bigred bigred 789527572 Dec 19 2022 harbor-offline-installer-v2.7.0.tgz -rw-rw-r-- 1 bigred bigred 878174181 Jun 25 14:17 harbor.tar.zst -rwxrwxr-x 1 bigred bigred 1515 Jun 25 14:33 mk ``` * 安裝 docker ``` $ cd harbor/ $ sudo tar -xvf docker-28.3.0.tgz $ sudo cp docker/* /usr/bin/ $ sudo nano /etc/systemd/system/docker.service [Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com After=network-online.target firewalld.service Wants=network-online.target [Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker ExecStart=/usr/bin/dockerd ExecReload=/bin/kill -s HUP $MAINPID # Having non-zero Limit*s causes performance problems due to accounting overhead # in the kernel. We recommend using cgroups to do container-local accounting. LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity # Uncomment TasksMax if your systemd version supports it. # Only systemd 226 and above support this version. #TasksMax=infinity TimeoutStartSec=0 # set delegate yes so that systemd does not reset the cgroups of docker containers Delegate=yes # kill only the docker process, not all processes in the cgroup KillMode=process # restart the docker process if it exits prematurely Restart=on-failure StartLimitBurst=3 StartLimitInterval=60s [Install] WantedBy=multi-user.target ``` * 啟動 docker ``` $ sudo chmod +x /etc/systemd/system/docker.service $ sudo systemctl daemon-reload $ sudo systemctl enable --now docker $ sudo docker version Client: Version: 28.3.0 API version: 1.51 Go version: go1.24.4 Git commit: 38b7060 Built: Tue Jun 24 15:43:00 2025 OS/Arch: linux/amd64 Context: default Server: Docker Engine - Community Engine: Version: 28.3.0 API version: 1.51 (minimum version 1.24) Go version: go1.24.4 Git commit: 265f709 Built: Tue Jun 24 15:44:17 2025 OS/Arch: linux/amd64 Experimental: false containerd: Version: v1.7.27 GitCommit: 05044ec0a9a75232cad458027ca83437aae3f4da runc: Version: 1.2.6 GitCommit: v1.2.6-0-ge89a299 docker-init: Version: 0.19.0 GitCommit: de40ad0 ``` * 安裝 docker-compose ``` $ sudo mv docker-compose-Linux-x86_64 /usr/bin/docker-compose $ sudo chmod 755 /usr/bin/docker-compose ``` * 將 harbor 解壓縮,並自簽憑證 ``` $ tar xvf harbor-offline-installer-v2.7.0.tgz;cd harbor/ $ cp harbor.yml.tmpl harbor.yml $ mkdir ssl;mv ../mk ssl;cd ssl # 確認名稱解析正確 $ host harbor.example.com harbor.example.com has address 172.20.7.89 # 產生憑證 $ ./mk create harbor.example.com 172.20.7.89 Certificate request self-signature ok subject=CN = example $ ls -l total 32 -rw------- 1 bigred bigred 3434 Jun 25 15:32 ca-key.pem -rw-rw-r-- 1 bigred bigred 2009 Jun 25 15:32 ca.pem -rw-rw-r-- 1 bigred bigred 41 Jun 25 15:32 ca.srl -rw-rw-r-- 1 bigred bigred 1582 Jun 25 15:32 cert.csr -rw------- 1 bigred bigred 3272 Jun 25 15:32 cert-key.pem -rw-rw-r-- 1 bigred bigred 1960 Jun 25 15:32 cert.pem -rw-rw-r-- 1 bigred bigred 83 Jun 25 15:32 extfile.cnf -rwxrwxr-x 1 bigred bigred 1515 Jun 25 14:33 mk $ pwd /home/bigred/harbor/harbor/ssl ``` * 設定 `hostname` * 設定憑證位置 ``` $ cd .. $ nano harbor.yml # Configuration file of Harbor # The IP address or hostname to access admin UI and registry service. # DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients. hostname: harbor.example.com # http related config http: # port for http, default is 80. If https enabled, this port will redirect to https port port: 80 # https related config https: # https port for harbor, default is 443 port: 443 # The path of cert and key files for nginx certificate: /home/bigred/harbor/harbor/ssl/cert.pem # 設定憑證絕對路徑 private_key: /home/bigred/harbor/harbor/ssl/cert-key.pem # 設定憑證絕對路徑 ...... ``` * 設定 docker 可以免信任登入 harbor ``` $ sudo mkdir /etc/docker/ $ sudo nano /etc/docker/daemon.json { "log-level": "warn", "log-driver": "json-file", "insecure-registries": ["172.22.7.89","harbor.example.com"], "log-opts": { "max-size": "10m", "max-file": "5" } } $ sudo systemctl daemon-reload $ sudo systemctl restart docker ``` * 啟動 harbor ``` $ sudo ./install.sh --with-trivy ``` ``` $ sudo docker-compose ps Name Command State Ports ------------------------------------------------------------------------------------------------------------- harbor-core /harbor/entrypoint.sh Up harbor-db /docker-entrypoint.sh 13 Up harbor-jobservice /harbor/entrypoint.sh Restarting harbor-log /bin/sh -c /usr/local/bin/ ... Up 127.0.0.1:1514->10514/tcp harbor-portal nginx -g daemon off; Up nginx nginx -g daemon off; Up 0.0.0.0:80->8080/tcp, 0.0.0.0:443->8443/tcp redis redis-server /etc/redis.conf Up registry /home/harbor/entrypoint.sh Up registryctl /home/harbor/start.sh Up trivy-adapter /home/scanner/entrypoint.sh Up ``` ### 設定 harbor 開機自動啟用 * 須注意 docker-compose 與 docker-compose.yml 絕對路徑是否正確 ``` $ which docker-compose /usr/bin/docker-compose $ pwd docker-compose.yml /home/bigred/harbor/harbor ``` ``` $ cat <<EOF | sudo tee /usr/lib/systemd/system/harbor.service [Unit] Description=Harbor start at boot After=docker.service systemd-networkd.service systemd-resolved.service Requires=docker.service [Service] Type=simple Restart=on-failure RestartSec=5 ExecStart=/usr/bin/docker-compose -f /home/bigred/harbor/harbor/docker-compose.yml up ExecStop=/usr/bin/docker-compose -f /home/bigred/harbor/harbor/docker-compose.yml down [Install] WantedBy=multi-user.target EOF ``` ``` $ sudo systemctl enable --now harbor.service ``` * 登入 harbor > 帳號: admin 密碼: Harbor12345 ![image](https://hackmd.io/_uploads/S1NODQYNgl.png) ## 上傳 image * 將 `k8s.tar.zst` 上傳到有 docker 或 podman 指令的主機上,並解壓縮 ``` $ tar --zstd -xf k8s.tar.zst $ ls -l k8s total 1244756 -rw-rw-r-- 1 bigred bigred 325176 Jun 25 06:19 calico.yaml -rw-rw-r-- 1 bigred bigred 55901748 Jun 25 08:51 cni-plugins.tgz -rw-rw-r-- 1 bigred bigred 4340 Jun 25 06:20 components.yaml -rw-rw-r-- 1 bigred bigred 33200838 Jun 19 22:39 containerd-2.1.3-linux-amd64.tar.gz -rw-rw-r-- 1 bigred bigred 1248 Jun 25 06:19 containerd.service -rw-rw-r-- 1 bigred bigred 20370694 Apr 22 07:51 crictl-v1.33.0-linux-amd64.tar.gz -rw-rw-r-- 1 bigred bigred 637987968 Jun 26 01:38 images.tar.zst -rw-rw-r-- 1 bigred bigred 767 Jun 26 01:37 images.txt -rw-rw-r-- 1 bigred bigred 135110634 Jun 18 17:53 kubernetes-node-linux-amd64.tar.gz -rw-rw-r-- 1 bigred bigred 379831997 Jun 18 17:53 kubernetes-server-linux-amd64.tar.gz -rwxrwxr-x 1 bigred bigred 1247 Jun 25 07:59 pull.sh -rw-rw-r-- 1 bigred bigred 11862624 Apr 29 04:43 runc.amd64 $ cd k8s ``` * 先登入 harbor ``` $ sudo docker login harbor.example.com Username: admin Password: WARNING! Your credentials are stored unencrypted in '/root/.docker/config.json'. Configure a credential helper to remove this warning. See https://docs.docker.com/go/credential-store/ Login Succeeded ``` * 編寫 push script ``` $ nano push.sh #!/bin/bash # set -x RED='\033[1;31m' # alarm GRN='\033[1;32m' # notice YEL='\033[1;33m' # warning NC='\033[0m' # No Color registry="$1" [[ ! -f ./images.txt ]] && printf "${RED}images.txt file not found${NC}\n" && exit 1 image_name=$(paste -sd' ' images.txt) docker_command() { tar --zstd -xf images.tar.zst sudo docker load < k8s_images.tar &>/dev/null while read line do img="${line##*/}" sudo docker tag $line $registry/library/$img &>/dev/null sudo docker push $registry/library/$img &>/dev/null if [[ "$?" == 0 ]]; then printf "${GRN}push $line success${NC}\n" else printf "${RED}push $line fail${NC}\n" fi done < images.txt printf "${GRN}All images have been successfully uploaded to Harbor.${NC}\n" } podman_command() { tar --zstd -xf images.tar.zst sudo podman load < k8s_images.tar &>/dev/null while read line do img="${line##*/}" sudo podman tag $line $registry/library/$img &>/dev/null sudo podman push $registry/library/$img &>/dev/null if [[ "$?" == 0 ]]; then printf "${GRN}push $line success${NC}\n" else printf "${RED}push $line fail${NC}\n" fi done < images.txt printf "${GRN}All images have been successfully uploaded to Harbor.${NC}\n" } help() { cat <<EOF Usage: push.sh [harbor domain] for example: push.sh harbor.example.com EOF exit } if ! which docker &>/dev/null && ! which podman &>/dev/null; then printf "${RED}docker and podman command not found${NC}\n" && exit 1 fi sudo -n true &>/dev/null if [[ "$?" != "0" ]]; then printf "${RED}Passwordless sudo is NOT enabled${NC}\n" && exit 1 fi if [[ "$#" < 1 ]]; then help fi if which docker &>/dev/null; then docker_command else podman_command fi ``` * 開始上傳 image 到 harbor ``` $ chmod +x push.sh $ ./push.sh harbor.example.com ``` * 在 harbor 上查看 library repo 已成功上傳 image ![image](https://hackmd.io/_uploads/S14DNEKVgg.png) ## 安裝 k8s ### 在每個節點先安裝 containerd、runc、cni、crictl 套件 * 將 `k8s.tar.zst` 上傳到每個節點,並解壓縮 ``` $ tar --zstd -xf k8s.tar.zst $ cd k8s $ ls -l total 1244756 -rw-rw-r-- 1 bigred bigred 325176 Jun 25 06:19 calico.yaml -rw-rw-r-- 1 bigred bigred 55901748 Jun 25 08:51 cni-plugins.tgz -rw-rw-r-- 1 bigred bigred 4340 Jun 25 06:20 components.yaml -rw-rw-r-- 1 bigred bigred 33200838 Jun 19 22:39 containerd-2.1.3-linux-amd64.tar.gz -rw-rw-r-- 1 bigred bigred 1248 Jun 25 06:19 containerd.service -rw-rw-r-- 1 bigred bigred 20370694 Apr 22 07:51 crictl-v1.33.0-linux-amd64.tar.gz -rw-rw-r-- 1 bigred bigred 637987968 Jun 26 01:38 images.tar.zst -rw-rw-r-- 1 bigred bigred 767 Jun 26 01:37 images.txt -rw-rw-r-- 1 bigred bigred 135110634 Jun 18 17:53 kubernetes-node-linux-amd64.tar.gz -rw-rw-r-- 1 bigred bigred 379831997 Jun 18 17:53 kubernetes-server-linux-amd64.tar.gz -rwxrwxr-x 1 bigred bigred 1247 Jun 25 07:59 pull.sh -rw-rw-r-- 1 bigred bigred 11862624 Apr 29 04:43 runc.amd64 ``` * 確認每個節點都可以解析到 harbor ``` $ host harbor.example.com harbor.example.com has address 172.20.7.89 ``` ### 安裝 containerd ``` $ sudo tar Cxzvf /usr/local containerd-2.1.3-linux-amd64.tar.gz $ sudo mkdir -p /usr/local/lib/systemd/system $ sudo mv containerd.service /usr/local/lib/systemd/system/containerd.service $ sudo systemctl daemon-reload $ sudo systemctl enable --now containerd ``` ``` $ sudo systemctl status containerd.service ● containerd.service - containerd container runtime Loaded: loaded (/usr/local/lib/systemd/system/containerd.service; enabled; preset: enabled) Active: active (running) since Tue 2025-06-10 06:17:14 UTC; 9s ago Docs: https://containerd.io Process: 1162 ExecStartPre=/sbin/modprobe overlay (code=exited, status=0/SUCCESS) ``` ### 安裝 runc ``` $ sudo install -m 755 runc.amd64 /usr/local/sbin/runc ``` ``` $ runc -v runc version 1.3.0 commit: v1.3.0-0-g4ca628d1 spec: 1.2.1 go: go1.23.8 libseccomp: 2.5.6 ``` ### 安裝 cni 套件 ``` $ sudo mkdir -p /opt/cni/bin $ sudo tar xf cni-plugins.tgz -C /opt/cni/bin ``` ``` $ sudo ls -l /opt/cni/bin total 96188 -rwxr-xr-x 1 root root 5033580 Apr 25 20:58 bandwidth -rwxr-xr-x 1 root root 5694447 Apr 25 20:58 bridge -rwxr-xr-x 1 root root 13924938 Apr 25 20:58 dhcp -rwxr-xr-x 1 root root 5247557 Apr 25 20:58 dummy -rwxr-xr-x 1 root root 5749447 Apr 25 20:58 firewall -rwxr-xr-x 1 root root 5163089 Apr 25 20:58 host-device -rwxr-xr-x 1 root root 4364143 Apr 25 20:58 host-local -rwxr-xr-x 1 root root 5269812 Apr 25 20:58 ipvlan -rw-r--r-- 1 root root 11357 Apr 25 20:58 LICENSE -rwxr-xr-x 1 root root 4263979 Apr 25 20:58 loopback -rwxr-xr-x 1 root root 5305057 Apr 25 20:58 macvlan -rwxr-xr-x 1 root root 5125860 Apr 25 20:58 portmap -rwxr-xr-x 1 root root 5477120 Apr 25 20:58 ptp -rw-r--r-- 1 root root 2343 Apr 25 20:58 README.md -rwxr-xr-x 1 root root 4488703 Apr 25 20:58 sbr -rwxr-xr-x 1 root root 3736370 Apr 25 20:58 static -rwxr-xr-x 1 root root 5332257 Apr 25 20:58 tap -rwxr-xr-x 1 root root 4352498 Apr 25 20:58 tuning -rwxr-xr-x 1 root root 5267833 Apr 25 20:58 vlan -rwxr-xr-x 1 root root 4644777 Apr 25 20:58 vrf ``` ### 安裝 crictl ``` # 根據 k8s 版本指定 $ VERSION="v1.33.0" $ sudo tar zxvf crictl-$VERSION-linux-amd64.tar.gz -C /usr/local/bin $ rm -f crictl-$VERSION-linux-amd64.tar.gz ``` * 設定 crictl ``` $ sudo nano /etc/crictl.yaml runtime-endpoint: unix:///run/containerd/containerd.sock image-endpoint: unix:///run/containerd/containerd.sock timeout: 10 ``` ### 生成 containerd 設定檔 ``` $ sudo mkdir /etc/containerd $ sudo containerd config default | sudo tee /etc/containerd/config.toml ``` * 設定 containerd 設定連接 Harbor Bypass TLS * 建立目錄,`harbor.example.com` 是 harbor 的 domain,此目錄可以任意取名 * 在 `hosts.toml` 設定 `skip_verify = true` 跳過 tls 驗證 ``` $ sudo mkdir -p /etc/containerd/certs.d/harbor.example.com $ sudo nano /etc/containerd/certs.d/harbor.example.com/hosts.toml server = "https://harbor.example.com" [host."https://harbor.example.com"] capabilities = ["pull", "resolve", "push"] skip_verify = true ``` * 修改 `config.toml` * 新增 `SystemdCgroup = true` * 新增 `config_path = '/etc/containerd/certs.d'` * 修改預設要拉 pause image 的位置 `harbor.example.com/library/pause:3.10` ``` $ sudo nano /etc/containerd/config.toml ...... [plugins.'io.containerd.cri.v1.images'.pinned_images] sandbox = 'harbor.example.com/library/pause:3.10' [plugins.'io.containerd.cri.v1.images'.registry] config_path = '/etc/containerd/certs.d' ...... [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes] [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc] ...... [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options] SystemdCgroup = true ...... [plugins."io.containerd.grpc.v1.cri".registry] config_path = "/etc/containerd/certs.d" ``` ![image](https://hackmd.io/_uploads/H1qsxEqVel.png) ![image](https://hackmd.io/_uploads/r1pK9VtEex.png) * 重啟 containerd ``` $ sudo systemctl restart containerd.service ``` ### master 節點安裝 kubelet kubeadm kubectl ``` $ tar -xzvf kubernetes-server-linux-amd64.tar.gz $ cd kubernetes/server/bin $ sudo cp kubeadm kubelet kubectl /usr/bin/ ``` ``` $ kubeadm version kubeadm version: &version.Info{Major:"1", Minor:"33", EmulationMajor:"", EmulationMinor:"", MinCompatibilityMajor:"", MinCompatibilityMinor:"", GitVersion:"v1.33.2", GitCommit:"a57b6f7709f6c2722b92f07b8b4c48210a51fc40", GitTreeState:"clean", BuildDate:"2025-06-17T18:39:42Z", GoVersion:"go1.24.4", Compiler:"gc", Platform:"linux/amd64"} ``` ### 設定 kubelet service * 如果有自己更換 cri 需要再更改 ``` $ cat <<EOF | sudo tee /etc/systemd/system/kubelet.service [Unit] Description=kubelet: The Kubernetes Node Agent Documentation=https://kubernetes.io/docs/ After=containerd.service Requires=containerd.service [Service] ExecStart=/usr/bin/kubelet Restart=always StartLimitInterval=0 RestartSec=10 [Install] WantedBy=multi-user.target EOF $ sudo mkdir /etc/systemd/system/kubelet.service.d $ cat << EOF | sudo tee /etc/systemd/system/kubelet.service.d/10-kubeadm.conf [Service] Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf" Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml" # This is a file that "kubeadm init" and "kubeadm join" generate at runtime, populating # the KUBELET_KUBEADM_ARGS variable dynamically EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env # This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, # the user should use the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. # KUBELET_EXTRA_ARGS should be sourced from this file. EnvironmentFile=-/etc/default/kubelet ExecStart= ExecStart=/usr/bin/kubelet \$KUBELET_KUBECONFIG_ARGS \$KUBELET_CONFIG_ARGS \$KUBELET_KUBEADM_ARGS \$KUBELET_EXTRA_ARGS EOF ``` ``` $ sudo systemctl enable --now kubelet.service ``` ### worker 節點安裝 kubelet kubeadm ``` $ tar -xzvf kubernetes-node-linux-amd64.tar.gz $ cd kubernetes/node/bin $ sudo cp kubeadm kubelet /usr/bin/ ``` ``` $ kubeadm version kubeadm version: &version.Info{Major:"1", Minor:"33", EmulationMajor:"", EmulationMinor:"", MinCompatibilityMajor:"", MinCompatibilityMinor:"", GitVersion:"v1.33.2", GitCommit:"a57b6f7709f6c2722b92f07b8b4c48210a51fc40", GitTreeState:"clean", BuildDate:"2025-06-17T18:39:42Z", GoVersion:"go1.24.4", Compiler:"gc", Platform:"linux/amd64"} ``` ### 設定 kubelet service * 如果有自己更換 cri 需要再更改 ``` $ cat <<EOF | sudo tee /etc/systemd/system/kubelet.service [Unit] Description=kubelet: The Kubernetes Node Agent Documentation=https://kubernetes.io/docs/ After=containerd.service Requires=containerd.service [Service] ExecStart=/usr/bin/kubelet Restart=always StartLimitInterval=0 RestartSec=10 [Install] WantedBy=multi-user.target EOF $ sudo mkdir /etc/systemd/system/kubelet.service.d $ cat << EOF | sudo tee /etc/systemd/system/kubelet.service.d/10-kubeadm.conf [Service] Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf" Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml" # This is a file that "kubeadm init" and "kubeadm join" generate at runtime, populating # the KUBELET_KUBEADM_ARGS variable dynamically EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env # This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, # the user should use the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. # KUBELET_EXTRA_ARGS should be sourced from this file. EnvironmentFile=-/etc/default/kubelet ExecStart= ExecStart=/usr/bin/kubelet \$KUBELET_KUBECONFIG_ARGS \$KUBELET_CONFIG_ARGS \$KUBELET_KUBEADM_ARGS \$KUBELET_EXTRA_ARGS EOF ``` ``` $ sudo systemctl enable --now kubelet.service ``` ## 初始化 k8s * 設定 kube-vip ``` $ cd ~/k8s # 安裝 kube-vip Set configuration details # IP 要改成叢集外的新 IP $ export VIP=172.20.7.100 # 宣告網卡名稱 $ export INTERFACE=ens18 # 注意這裡要更換 kube-vip image 位置 $ alias kube-vip="sudo ctr -n k8s.io image pull --hosts-dir "/etc/containerd/certs.d" harbor.example.com/library/kube-vip:v0.9.2;sudo ctr -n k8s.io run --rm --net-host harbor.example.com/library/kube-vip:v0.9.2 vip /kube-vip" $ sudo mkdir -p /etc/kubernetes/manifests/ $ kube-vip manifest pod \ --address $VIP \ --interface $INTERFACE \ --controlplane \ --arp \ --leaderElection | sudo tee /etc/kubernetes/manifests/kube-vip.yaml ``` * 更換 `kube-vip.yaml` yaml 的 image 位置 ``` $ sudo sed -i 's|ghcr.io/kube-vip/kube-vip:v0.9.2|harbor.example.com/library/kube-vip:v0.9.2|g' /etc/kubernetes/manifests/kube-vip.yaml ``` * 確認更改 ``` $ cat /etc/kubernetes/manifests/kube-vip.yaml | grep image: image: harbor.example.com/library/kube-vip:v0.9.2 ``` * 1.29 以後需要調整權限,只有第一台 master 需要修改 ``` $ sudo sed -i 's|path: /etc/kubernetes/admin.conf|path: /etc/kubernetes/super-admin.conf|g' /etc/kubernetes/manifests/kube-vip.yaml ``` * `advertiseAddress` 需更換為自己的 master ip * `controlPlaneEndpoint` 要指定 vip 的位置 ``` $ nano init-config.yaml apiVersion: kubeadm.k8s.io/v1beta3 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 172.20.7.90 # change from Master node IP bindPort: 6443 nodeRegistration: criSocket: unix:///run/containerd/containerd.sock imagePullPolicy: IfNotPresent name: m1 # change from Master node hsotname taints: [] --- apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: 1.33.2 controlPlaneEndpoint: 172.20.7.100:6443 apiServer: timeoutForControlPlane: 4m0s certificatesDir: /etc/kubernetes/pki clusterName: topgun # set your clusterName controllerManager: extraArgs: bind-address: "0.0.0.0" secure-port: "10257" scheduler: extraArgs: bind-address: "0.0.0.0" secure-port: "10259" etcd: local: dataDir: /var/lib/etcd # imageRepository: harbor.example.com/library # imageTag: 3.5.15-0 extraArgs: listen-metrics-urls: "http://0.0.0.0:2381" dns: {} #imageRepository: harbor.example.com/library #imageTag: v1.11.3 imageRepository: harbor.example.com/library # 更換為內部 harbor 位置 networking: dnsDomain: cluster.local # DNS domain used by Kubernetes Services. podSubnet: 10.244.0.0/16 # the subnet used by Pods. serviceSubnet: 10.96.0.0/16 # subnet used by Kubernetes Services. --- apiVersion: kubeproxy.config.k8s.io/v1alpha1 kind: KubeProxyConfiguration metricsBindAddress: "0.0.0.0:10249" --- apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration maxPods: 110 shutdownGracePeriod: 30s shutdownGracePeriodCriticalPods: 10s systemReserved: memory: "1Gi" kubeReserved: memory: "2Gi" ``` 開始安裝 * `--upload-certs` 將 `control-plane` 節點所需的金鑰和憑證上傳到 `kubeadm-certs Secret` 中,以供其他 `control-plane` 節點下載使用。 ``` $ sudo kubeadm init --upload-certs --config=init-config.yaml ``` 輸出結果並記錄註冊指令: ``` ...... You can now join any number of control-plane nodes running the following command on each as root: kubeadm join 172.20.7.100:6443 --token ma5zm7.1rc9i2qjybt5uve5 \ --discovery-token-ca-cert-hash sha256:cefd410656e767c60f84b2e394c9837326ca03380cb6d07bad9a0fd03d971044 \ --control-plane --certificate-key 126e9fc8daeb3e304187383a4d00999ae2f6cd09e196b662d81755a66a2a0415 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 172.20.7.100:6443 --token ma5zm7.1rc9i2qjybt5uve5 \ --discovery-token-ca-cert-hash sha256:cefd410656e767c60f84b2e394c9837326ca03380cb6d07bad9a0fd03d971044 ``` * 設定 kubeconfig ``` $ mkdir -p $HOME/.kube; sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config; sudo chown $(id -u):$(id -g) $HOME/.kube/config ``` ### 部屬 calico 3.29.4 * 將 calico.yaml 改為 harbor 位置 ``` $ sed -i \ -e 's|docker.io/calico/cni:v3.29.4|harbor.example.com/library/cni:v3.29.4|g' \ -e 's|docker.io/calico/node:v3.29.4|harbor.example.com/library/node:v3.29.4|g' \ -e 's|docker.io/calico/kube-controllers:v3.29.4|harbor.example.com/library/kube-controllers:v3.29.4|g' \ calico.yaml ``` * 檢查 image 位置都已更換 ``` $ cat calico.yaml|grep image image: harbor.example.com/library/cni:v3.29.4 imagePullPolicy: IfNotPresent image: harbor.example.com/library/cni:v3.29.4 imagePullPolicy: IfNotPresent image: harbor.example.com/library/node:v3.29.4 imagePullPolicy: IfNotPresent image: harbor.example.com/library/node:v3.29.4 imagePullPolicy: IfNotPresent image: harbor.example.com/library/kube-controllers:v3.29.4 imagePullPolicy: IfNotPresent ``` ``` $ kubectl apply -f calico.yaml ``` ### 環境檢查 ``` $ kubectl get po -A NAMESPACE NAME READY STATUS RESTARTS AGE kube-system calico-kube-controllers-7b67c89ff4-cx42g 1/1 Running 0 27s kube-system calico-node-45fjd 1/1 Running 0 27s kube-system coredns-6b8f4f6974-6685s 1/1 Running 0 10m kube-system coredns-6b8f4f6974-jxt4b 1/1 Running 0 10m kube-system etcd-m1 1/1 Running 0 10m kube-system kube-apiserver-m1 1/1 Running 0 10m kube-system kube-controller-manager-m1 1/1 Running 0 10m kube-system kube-proxy-k8s8s 1/1 Running 0 10m kube-system kube-scheduler-m1 1/1 Running 0 10m kube-system kube-vip-m1 1/1 Running 0 10m ``` * k8s 安裝好後再將 `kube-vip` 權限調整回來 ``` $ sudo sed -i 's|path: /etc/kubernetes/super-admin.conf|path: /etc/kubernetes/admin.conf|g' /etc/kubernetes/manifests/kube-vip.yaml $ sudo systemctl daemon-reload $ sudo systemctl restart kubelet ``` ## 加入 m2 master node #### 設定 kube-vip * 在 m2 執行以下命令 ``` $ cd ~/k8s # 安裝 kube-vip Set configuration details # IP 要改成叢集外的新 IP $ export VIP=172.20.7.100 # 宣告網卡名稱 $ export INTERFACE=ens18 # 注意這裡要更換 kube-vip image 名稱位置 $ alias kube-vip="sudo ctr -n k8s.io image pull --hosts-dir "/etc/containerd/certs.d" harbor.example.com/library/kube-vip:v0.9.2;sudo ctr -n k8s.io run --rm --net-host harbor.example.com/library/kube-vip:v0.9.2 vip /kube-vip" $ sudo mkdir -p /etc/kubernetes/manifests/ $ kube-vip manifest pod \ --address $VIP \ --interface $INTERFACE \ --controlplane \ --arp \ --leaderElection | sudo tee /etc/kubernetes/manifests/kube-vip.yaml ``` * 更換 `kube-vip.yaml` yaml 的 image 位置 ``` $ sudo sed -i 's|ghcr.io/kube-vip/kube-vip:v0.9.2|harbor.example.com/library/kube-vip:v0.9.2|g' /etc/kubernetes/manifests/kube-vip.yaml ``` * 確認更改 ``` $ cat /etc/kubernetes/manifests/kube-vip.yaml | grep image: image: harbor.example.com/library/kube-vip:v0.9.2 ``` * 在 m2 開始安裝 k8s ``` $ sudo kubeadm join 172.20.7.100:6443 --token ma5zm7.1rc9i2qjybt5uve5 \ --discovery-token-ca-cert-hash sha256:cefd410656e767c60f84b2e394c9837326ca03380cb6d07bad9a0fd03d971044 \ --control-plane --certificate-key 126e9fc8daeb3e304187383a4d00999ae2f6cd09e196b662d81755a66a2a0415 ``` ## 加入 m3 master node #### 設定 kube-vip * 在 m3 執行以下命令 ``` $ cd ~/k8s # 安裝 kube-vip Set configuration details # IP 要改成叢集外的新 IP $ export VIP=172.20.7.100 # 宣告網卡名稱 $ export INTERFACE=ens18 # 注意這裡要更換 kube-vip image 名稱位置 $ alias kube-vip="sudo ctr -n k8s.io image pull --hosts-dir "/etc/containerd/certs.d" harbor.example.com/library/kube-vip:v0.9.2;sudo ctr -n k8s.io run --rm --net-host harbor.example.com/library/kube-vip:v0.9.2 vip /kube-vip" $ sudo mkdir -p /etc/kubernetes/manifests/ $ kube-vip manifest pod \ --address $VIP \ --interface $INTERFACE \ --controlplane \ --arp \ --leaderElection | sudo tee /etc/kubernetes/manifests/kube-vip.yaml ``` * 更換 `kube-vip.yaml` yaml 的 image 位置 ``` $ sudo sed -i 's|ghcr.io/kube-vip/kube-vip:v0.9.2|harbor.example.com/library/kube-vip:v0.9.2|g' /etc/kubernetes/manifests/kube-vip.yaml ``` * 確認更改 ``` $ cat /etc/kubernetes/manifests/kube-vip.yaml | grep image: image: harbor.example.com/library/kube-vip:v0.9.2 ``` * 在 m3 開始安裝 k8s ``` $ sudo kubeadm join 172.20.7.100:6443 --token ma5zm7.1rc9i2qjybt5uve5 \ --discovery-token-ca-cert-hash sha256:cefd410656e767c60f84b2e394c9837326ca03380cb6d07bad9a0fd03d971044 \ --control-plane --certificate-key 126e9fc8daeb3e304187383a4d00999ae2f6cd09e196b662d81755a66a2a0415 ``` ## 加入 w1、w2 worker node 如果沒記錄到指令,可以在 m1 使用以下指令產出 `worker` 註冊指令 ``` $ sudo kubeadm token create --print-join-command ``` ``` $ sudo kubeadm join 172.20.7.100:6443 --token ma5zm7.1rc9i2qjybt5uve5 \ --discovery-token-ca-cert-hash sha256:cefd410656e767c60f84b2e394c9837326ca03380cb6d07bad9a0fd03d971044 ``` w1、w2 貼上標籤,都是叫 worker ``` $ kubectl label node w1 node-role.kubernetes.io/worker=; kubectl label node w2 node-role.kubernetes.io/worker= ``` ## 環境檢查 ``` $ kubectl get no -owide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME m1 Ready control-plane 151m v1.33.2 172.20.7.90 <none> Ubuntu 24.04.2 LTS 6.8.0-60-generic containerd://2.1.3 m2 Ready control-plane 5m12s v1.33.2 172.20.7.91 <none> Ubuntu 24.04.2 LTS 6.8.0-60-generic containerd://2.1.3 m3 Ready control-plane 2m8s v1.33.2 172.20.7.92 <none> Ubuntu 24.04.2 LTS 6.8.0-60-generic containerd://2.1.3 w1 Ready worker 42s v1.33.2 172.20.7.93 <none> Ubuntu 24.04.2 LTS 6.8.0-60-generic containerd://2.1.3 w2 Ready worker 39s v1.33.2 172.20.7.94 <none> Ubuntu 24.04.2 LTS 6.8.0-60-generic containerd://2.1.3 ``` ## 安裝 metrics-server 更換 `metrics-server` yaml 的 image 位置 ``` $ sudo sed -i 's|registry.k8s.io/metrics-server/metrics-server:v0.7.2|harbor.example.com/library/metrics-server:v0.7.2|g' components.yaml ``` ``` $ kubectl apply -f components.yaml ``` 驗證功能 ``` $ kubectl -n kube-system get po -l k8s-app=metrics-server NAME READY STATUS RESTARTS AGE metrics-server-7c9dbfcd55-th6b2 1/1 Running 0 74s $ kubectl top no NAME CPU(cores) CPU(%) MEMORY(bytes) MEMORY(%) m1 50m 1% 1534Mi 17% m2 54m 1% 890Mi 10% m3 39m 0% 833Mi 9% w1 14m 0% 480Mi 5% w2 16m 0% 505Mi 5% ``` ## 驗證 Apiserver HA 容錯 查看 `plndr-cp-lock` 目前是 m1 提供當 vip ``` $ kubectl -n kube-system get lease NAME HOLDER AGE apiserver-276wpfzo55z6xlhwmv7sebbpdm apiserver-276wpfzo55z6xlhwmv7sebbpdm_f501be5a-c4c4-474f-9879-df21f6a12370 152m apiserver-adkfkrghmfikf7izpjatkklyyi apiserver-adkfkrghmfikf7izpjatkklyyi_bb70aa21-49bb-4cf6-b3c7-7f5060a1badc 6m3s apiserver-ormoeicu2rhguypboutgrrqply apiserver-ormoeicu2rhguypboutgrrqply_e1755620-b109-4212-9d1d-56e98ef38c01 3m3s kube-controller-manager m1_dfb51065-5982-421d-86f6-20284b80a1b2 152m kube-scheduler m1_e1eb91aa-d316-4dc5-8e53-91ce3316847e 152m plndr-cp-lock m1 152m ``` 將 m1 關機 ``` bigred@m1:~$ sudo poweroff ``` 在外部管理主機還是可以控制 k8s,並且確認 vip 轉移到 m2 上 ``` $ kubectl get no NAME STATUS ROLES AGE VERSION m1 NotReady control-plane 154m v1.33.2 m2 Ready control-plane 7m25s v1.33.2 m3 Ready control-plane 4m21s v1.33.2 w1 Ready worker 2m55s v1.33.2 w2 Ready worker 2m52s v1.33.2 $ kubectl -n kube-system get lease NAME HOLDER AGE apiserver-276wpfzo55z6xlhwmv7sebbpdm apiserver-276wpfzo55z6xlhwmv7sebbpdm_f501be5a-c4c4-474f-9879-df21f6a12370 154m apiserver-adkfkrghmfikf7izpjatkklyyi apiserver-adkfkrghmfikf7izpjatkklyyi_bb70aa21-49bb-4cf6-b3c7-7f5060a1badc 7m51s apiserver-ormoeicu2rhguypboutgrrqply apiserver-ormoeicu2rhguypboutgrrqply_e1755620-b109-4212-9d1d-56e98ef38c01 4m51s kube-controller-manager m2_70fa2776-6126-4884-b0b9-e29e4e180ed2 154m kube-scheduler m3_f814c532-52b9-48bb-bbc5-33048cae7070 154m plndr-cp-lock m2 154m ```