Ubuntu 20.04 环境下 Kubernetes 1.26 集群的部署与配置实践
环境准备与核心组件概述
本文旨在记录在 Ubuntu 20.04 操作系统上部署 Kubernetes 1.26.12 集群的完整流程。该版本选择主要考虑到与 Kubeflow Pipelines v2.0.5 的兼容性(最高支持至 v1.26)。
在开始部署前,需要理解以下核心组件的作用:
- containerd:Kubernetes 默认使用的高性能容器运行时,负责管理容器的生命周期。
- kubelet:运行在每个节点上的代理,负责维护 Pod 的生命周期并确保容器按照预期规格运行。
- kubeadm:用于快速引导和初始化 Kubernetes 集群的命令行工具。
- kubectl:用于与 Kubernetes 集群 API 进行交互的命令行客户端。
- Pod:Kubernetes 调度的最小计算单元,可包含一个或多个紧密耦合的容器。
容器运行时 (containerd) 安装与配置
Kubernetes 通过 CRI (Container Runtime Interface) 与底层容器运行时进行通信。在所有计划加入集群的节点上,必须预先配置好 containerd 及其相关依赖。
配置内核模块与网络转发
为了确保容器网络能够正常工作,需要加载特定的内核模块并开启 IPv4 转发功能。以下脚本统一处理了这些系统级配置:
#!/bin/bash
# 配置内核模块
MODULES_CONF="/etc/modules-load.d/k8s.conf"
echo -e "overlay\nbr_netfilter" | sudo tee "$MODULES_CONF" > /dev/null
sudo modprobe overlay
sudo modprobe br_netfilter
# 配置 sysctl 网络参数
SYSCTL_CONF="/etc/sysctl.d/99-k8s.conf"
cat << 'SYSCTL_EOF' | sudo tee "$SYSCTL_CONF" > /dev/null
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
SYSCTL_EOF
# 应用配置并验证
sudo sysctl --system > /dev/null
sysctl net.ipv4.ip_forward
安装 containerd、runc 与 CNI 插件
通过定义版本变量,可以更方便地管理和安装容器运行时的各个组件。执行以下脚本完成二进制文件的下载与部署:
#!/bin/bash
# 定义组件版本
CONTAINERD_VERSION="1.6.2"
RUNC_VERSION="1.1.4"
CNI_VERSION="1.1.1"
ARCH="amd64"
# 1. 安装 containerd
wget "https://github.com/containerd/containerd/releases/download/v${CONTAINERD_VERSION}/containerd-${CONTAINERD_VERSION}-linux-${ARCH}.tar.gz"
sudo tar -xzf "containerd-${CONTAINERD_VERSION}-linux-${ARCH}.tar.gz" -C /usr/local
# 2. 安装 runc
wget "https://github.com/opencontainers/runc/releases/download/v${RUNC_VERSION}/runc.${ARCH}"
sudo install -m 755 "runc.${ARCH}" /usr/local/sbin/runc
# 3. 安装 CNI 网络插件
sudo mkdir -p /opt/cni/bin
wget "https://github.com/containernetworking/plugins/releases/download/v${CNI_VERSION}/cni-plugins-linux-${ARCH}-v${CNI_VERSION}.tgz"
sudo tar -xzf "cni-plugins-linux-${ARCH}-v${CNI_VERSION}.tgz" -C /opt/cni/bin
配置 systemd cgroup 驱动与镜像加速
在 Linux 系统中,kubelet 和容器运行时必须使用相同的 cgroup 驱动。当系统使用 systemd 作为 init 系统时,应统一配置为 systemd cgroup 驱动。此外,针对国内网络环境,需要替换默认的 sandbox (pause) 镜像地址。
#!/bin/bash
# 生成默认配置文件
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml > /dev/null
# 替换 Sandbox 镜像为阿里云镜像源
sudo sed -i 's|registry.k8s.io/pause:.*|registry.aliyuncs.com/google_containers/pause:3.9"|g' /etc/containerd/config.toml
# 启用 systemd cgroup 驱动
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
# 配置 systemd 服务并启动
sudo wget https://raw.githubusercontent.com/containerd/containerd/main/containerd.service -O /usr/local/lib/systemd/system/containerd.service
sudo systemctl daemon-reload
sudo systemctl enable --now containerd
Kubernetes 核心组件安装
kubeadm、kubelet 和 kubectl 需要安装在集群的所有节点上。我们通过配置 APT 仓库来安装指定版本的组件。
配置 APT 仓库并安装组件
#!/bin/bash
K8S_VERSION="1.26"
KEYRING_PATH="/etc/apt/keyrings/k8s-apt-keyring.gpg"
SOURCES_LIST="/etc/apt/sources.list.d/k8s.list"
# 安装基础依赖
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
# 导入 GPG 密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL "https://pkgs.k8s.io/core:/stable:/v${K8S_VERSION}/deb/Release.key" | sudo gpg --dearmor -o "$KEYRING_PATH"
# 添加 Kubernetes APT 源
echo "deb [signed-by=${KEYRING_PATH}] https://pkgs.k8s.io/core:/stable:/v${K8S_VERSION}/deb/ /" | sudo tee "$SOURCES_LIST" > /dev/null
# 安装并锁定版本
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
配置 kubelet cgroup 驱动
为了确保 kubelet 与 containerd 的 cgroup 驱动保持一致,可以通过配置 drop-in 文件来显式指定参数,而无需修改 kubeadm 的全局配置文件:
#!/bin/bash
# 配置 kubelet 额外参数
cat << 'EOF' | sudo tee /etc/default/kubelet
KUBELET_EXTRA_ARGS="--cgroup-driver=systemd"
EOF
# 重载配置并重启 kubelet
sudo systemctl daemon-reload
sudo systemctl restart kubelet
常见故障排查与解决方案
1. containerd 服务启动失败 (TOML 解析错误)
现象:执行 systemctl start containerd 时,服务进入 failed 状态。查看 /var/log/syslog 发现报错信息为 failed to load TOML... duplicated tables。
原因:在 /etc/containerd/config.toml 文件中存在重复的插件配置块(例如出现了两次 [plugins."io.containerd.grpc.v1.cri".registry])。
解决:检查并清理配置文件中重复的段落,确保每个 plugin key 唯一,然后重启服务。
2. 找不到 containerd.sock 文件
现象:执行 kubectl 或容器命令时报错 dial unix /var/run/containerd/containerd.sock: connect: no such file or directory。
原因:containerd 服务未正常运行或未生成 socket 文件。
解决:检查服务状态并重新启动。
sudo systemctl status containerd
sudo systemctl enable containerd
sudo systemctl restart containerd
3. PV/PVC 资源卡在 Terminating 状态
现象:使用 kubectl delete 删除 PersistentVolume 或 PersistentVolumeClaim 后,资源状态一直停留在 Terminating,无法彻底清除,且无法重新创建同名资源。
原因:Kubernetes 存在数据保护机制,当资源仍被其他组件引用或存在 finalizers 时,会阻止物理删除。
解决:通过 patch 命令强制移除 finalizers,解除保护机制后再执行删除操作。
# 移除 PV 的 finalizers
kubectl patch pv my-data-volume --type merge -p '{"metadata":{"finalizers": null}}'
kubectl delete pv my-data-volume
# 移除 PVC 的 finalizers
kubectl patch pvc my-data-claim --type merge -p '{"metadata":{"finalizers": null}}'
kubectl delete pvc my-data-claim
4. Pod 删除后自动重新创建
现象:手动删除某个 Pod 后,系统立刻又创建了一个相同名称或相似的新 Pod。
原因:该 Pod 是由高级控制器(如 Deployment、StatefulSet)管理的。控制器会持续监控并确保期望的副本数与实际运行的副本数一致。
解决:需要删除管理该 Pod 的上级控制器,而不是直接删除 Pod。可以通过脚本动态获取并删除其 Owner 资源:
#!/bin/bash
POD_NAME="ml-pipeline-visualizationserver-7d8f9b-x2k4l"
NAMESPACE="kubeflow-user-example-com"
# 获取 Pod 的 Owner 名称
OWNER_NAME=$(kubectl get pod "$POD_NAME" -n "$NAMESPACE" -o jsonpath='{.metadata.ownerReferences[0].name}')
OWNER_KIND=$(kubectl get pod "$POD_NAME" -n "$NAMESPACE" -o jsonpath='{.metadata.ownerReferences[0].kind}')
echo "发现上级控制器: $OWNER_KIND/$OWNER_NAME"
# 删除上级控制器
kubectl delete "$OWNER_KIND" "$OWNER_NAME" -n "$NAMESPACE"

