一、背景介绍
Kubernetes(简称 K8s)是一个开源的容器编排平台,用于自动化容器化应用的部署、扩展和管理。它能够跨主机集群调度容器,提供容器编排、服务发现、负载均衡、自愈能力、配置管理等核心功能,已成为云原生应用的核心基础设施。随着容器技术的普及,搭建稳定、兼容的 K8s 集群成为企业和开发者的必备技能。
本文将提供一套无省略、全细节、逐条标注操作主机的 K8s 集群部署方案,基于 v1.28.2 稳定版本,采用 containerd 作为容器运行时、Calico 作为网络插件,统一使用 systemd cgroup driver,全程使用阿里云镜像源加速,确保部署过程流畅、集群运行稳定。
二、关键词解释
- Kubernetes 组件:
- Master(控制平面):集群核心管理节点,包含 API Server(集群入口)、etcd(数据存储)、Scheduler(调度器)、Controller Manager(控制器)等组件。
- Worker(工作节点):运行容器化应用的节点,包含 kubelet(节点代理)、kube-proxy(网络代理)、容器运行时(本文为 containerd)。
- 容器运行时:负责管理容器生命周期的软件,containerd 是轻量级容器运行时,兼容 OCI 标准,是 K8s 官方推荐的运行时之一(K8s v1.24+ 不再支持 Docker Engine)。
- cgroup driver:用于限制容器资源(CPU、内存)的驱动,systemd 是 Linux 系统初始化系统,K8s 推荐使用 systemd cgroup driver 确保资源管理一致性。
- 网络插件:Calico 是基于 BGP 协议的高性能网络插件,提供容器网络互通、网络策略控制等功能,支持大规模集群部署。
- kubeadm:K8s 集群初始化工具,简化 master 节点初始化和 worker 节点加入流程。
- kubectl:K8s 命令行工具,用于操作集群资源(创建、查看、删除 Pod、Service 等)。
- IPVS:可选的负载均衡模式,相比 iptables 具有更高的性能和稳定性,适合大规模集群场景。
- CNI:容器网络接口标准,用于实现容器之间的网络互通,Calico 是 CNI 插件的一种。
三、环境准备
1. 主机信息(需根据实际环境替换 IP)
| 主机名 | IP 地址 | 角色 |
|---|---|---|
| master | 172.24.221.34 | control-plane(控制平面) |
| worker1 | 172.24.221.35 | worker(工作节点) |
| worker2 | 172.24.221.36 | worker(工作节点) |
2. 硬件要求
- Master 节点:≥2 核 CPU,≥2GB 内存(生产环境推荐 4C8G+)
- Worker 节点:≥1 核 CPU,≥1GB 内存(生产环境推荐 2C4G+)
3. 前置要求
- 三台主机均为 CentOS 7.x 系统(64 位),支持 Rocky Linux 8 / AlmaLinux 8 兼容适配。
- 所有节点配置静态 IP,三台主机之间网络互通(能互相 ping 通),且能访问外网(或已配置镜像缓存)。
- 禁止使用 hostname 包含下划线、大写字母等特殊字符的主机。
- 安全组规则:确保节点间开放以下端口(至少内网互通):6443(API Server)、2379-2380(etcd)、10250(kubelet)、10257/10259(scheduler/controller-manager);若使用 Flannel 需额外开放 8472 端口。
四、部署步骤
🔧 预备步骤:设置主机名与时间同步(在所有三台主机上执行)
K8s 集群对主机名唯一性和节点时间同步性要求极高,必须先完成此步骤。
1. 设置主机名
操作主机:分别在对应主机执行
master 节点:
hostnamectl set-hostname master
worker1 节点:
hostnamectl set-hostname worker1
worker2 节点:
hostnamectl set-hostname worker2
2. 配置主机名解析(建议配置)
操作主机:master、worker1、worker2(分别执行)
# 编辑 hosts 文件
cat <<EOF | sudo tee -a /etc/hosts
172.24.221.34 master
172.24.221.35 worker1
172.24.221.36 worker2
EOF
3. 配置时间同步(必须执行)
K8s 集群节点时间差需控制在 5 秒内,否则会导致证书验证失败、Pod 调度异常等问题。
操作主机:master、worker1、worker2(分别执行)
# 安装 chrony 时间同步工具
yum install -y chrony
# 启动并设置开机自启
systemctl start chronyd
systemctl enable chronyd
# 同步时间
chronyc sources -v
# 验证时间同步状态
timedatectl
✅ 验证:timedatectl 输出中 NTP synchronized 应为 yes,System clock synchronized 应为 yes。
🔧 第一部分:系统初始化(在所有三台主机上执行)
操作主机:master、worker1、worker2(分别登录每台执行以下命令)
# 1. 关闭防火墙(K8s 集群内部通信无需防火墙拦截)
systemctl stop firewalld
systemctl disable firewalld
# 2. 关闭 SELinux(避免权限拦截容器操作)
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
# 3. 关闭 swap(Kubernetes 强制要求,避免内存交换影响性能)
swapoff -a
sed -i '/swap/s/^/#/' /etc/fstab
# 4. 安装必要工具(依赖包、网络工具等)
yum install -y yum-utils device-mapper-persistent-data lvm2 ipset ipvsadm
# 5. 加载必要内核模块(容器网络、IPVS 依赖)
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
EOF
modprobe overlay
modprobe br_netfilter
modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_sh
modprobe nf_conntrack
# 6. 配置 sysctl 参数(开启网络转发、桥接过滤等功能)
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
vm.swappiness = 0
EOF
sysctl --system
✅ 验证:执行完后,每台机器应看到 sysctl: setting key "xxx": OK 类似输出,无报错即成功。
🐳 第二部分:安装 containerd(在所有三台主机上执行)
操作主机:master、worker1、worker2(分别登录每台执行)
# 1. 安装 containerd(默认安装稳定版,兼容 K8s v1.28)
yum install -y containerd.io
# 2. 生成 containerd 默认配置文件
containerd config default > /etc/containerd/config.toml
# 3. 编辑配置文件,启用 SystemdCgroup(关键:与 kubelet cgroup 驱动一致)
# ⚠️ 关于 sed 修改 config.toml 的风险提示
# 虽然 sed -i 's/false/true/' 看似简单,但 TOML 文件中可能存在多个 SystemdCgroup 字段(如旧版本模板),或字段不存在,导致:
# 1. 替换失败(仍为 false) 2. 重复添加(引发解析异常) 3. 缩进错误(虽 TOML 不强制缩进,但易读性差且可能被某些解析器拒绝)
# ✅ 更安全的做法:先备份,再手动编辑
cp /etc/containerd/config.toml /etc/containerd/config.toml.bak
vim /etc/containerd/config.toml
✅ 在 vim 中找到以下段落(约在文件中下部),按要求修改:
toml
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
BinaryName = ""
CriuImagePath = ""
CriuPath = ""
CriuWorkPath = ""
IoGid = 0
IoUid = 0
NoNewKeyring = false
NoPivotRoot = false
Root = ""
ShimCgroup = ""
SystemdCgroup = true # ← 确保仅此处存在该配置,缩进为 12 个空格
保存退出后继续执行:
# 4. 配置镜像加速(针对国内网络环境优化,可选但推荐)
sed -i 's#registry.k8s.io#registry.aliyuncs.com/google_containers#g' /etc/containerd/config.toml
sed -i '/\[plugins."io.containerd.grpc.v1.cri".registry.mirrors\]/a \ [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]\n endpoint = ["https://registry.docker-cn.com", "https://mirror.baidubce.com"]' /etc/containerd/config.toml
# 5. 启动并设置 containerd 开机自启
systemctl restart containerd
systemctl enable containerd
# 6. 配置 crictl 使用 containerd 运行时(避免连接错误)
cat > /etc/crictl.yaml <<EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
EOF
# 7. 验证配置生效(确认 SystemdCgroup 已启用)
crictl info | grep -A5 'SystemdCgroup'
# 验证配置文件无重复字段
grep -c 'SystemdCgroup' /etc/containerd/config.toml # 输出应为 1
✅ 正确输出应包含:
json
"options": {
"SystemdCgroup": true
}
📦 第三部分:安装 kubeadm、kubelet、kubectl(在所有三台主机上执行)
操作主机:master、worker1、worker2(分别登录每台执行)
# 1. 添加 Kubernetes 阿里云 YUM 源(国内加速,避免官方源访问超时)
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
# 2. 安装指定版本(v1.28.2,确保三台主机版本一致)
yum install -y kubelet-1.28.2 kubeadm-1.28.2 kubectl-1.28.2 --disableexcludes=kubernetes
# 3. 配置 kubelet 使用 containerd 运行时及 systemd cgroup 驱动
cat > /etc/default/kubelet <<EOF
KUBELET_EXTRA_ARGS=--cgroup-driver=systemd --container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock
EOF
# 4. 启用 kubelet 开机自启(暂不启动,待集群初始化后自动启动)
systemctl enable kubelet
systemctl daemon-reload
⚙️ 第四部分:验证 kubelet 状态(在所有三台主机上执行)
操作主机:master、worker1、worker2(分别登录每台执行)
# 查看 kubelet 状态
systemctl status kubelet
🧹 第五部分:清理旧集群残留(仅在 master 上执行,如有需要)
操作主机:master(仅此一台)
如果之前在 master 节点安装过 K8s 集群,必须执行以下清理命令,避免残留文件影响新集群初始化:
# 重置 kubeadm 配置
kubeadm reset --force
# 手动删除残留文件(配置文件、数据存储、网络插件配置)
rm -rf /etc/kubernetes/
rm -rf /var/lib/etcd
rm -rf /etc/cni/net.d/
# 重启相关服务
systemctl restart containerd kubelet
# 确认关键端口未被占用(6443:API Server,2379/2380:etcd,10250:kubelet 等)
ss -tulnp | grep -E ':(6443|10259|10257|10250|2379|2380)'
✅ 预期结果:端口检查命令应无任何输出(无占用)。
💡 注意:worker 节点无需执行此步骤,因为它们尚未加入任何集群,无残留文件。
🚀 第六部分:初始化 Kubernetes 控制平面(仅在 master 上执行)
操作主机:master(仅此一台)
1. (可选)预拉取 K8s 核心镜像(网络较差时推荐)
# 创建镜像拉取脚本
cat > pull-k8s-images.sh << 'EOF'
#!/bin/bash
K8S_VERSION=v1.28.2
PAUSE_VERSION=3.9
ETCD_VERSION=3.5.9-0
COREDNS_VERSION=v1.10.1
images=(
kube-apiserver:${K8S_VERSION}
kube-controller-manager:${K8S_VERSION}
kube-scheduler:${K8S_VERSION}
kube-proxy:${K8S_VERSION}
pause:${PAUSE_VERSION}
etcd:${ETCD_VERSION}
coredns:${COREDNS_VERSION}
)
# 使用 crictl 拉取(自动处理命名空间,兼容性更好)
for imageName in ${images[@]}; do
full_image="registry.aliyuncs.com/google_containers/${imageName}"
echo "Pulling $full_image"
crictl pull "$full_image"
done
EOF
# 添加执行权限
chmod +x pull-k8s-images.sh
# 运行脚本拉取镜像
./pull-k8s-images.sh
2. 初始化 master 节点(必须执行)
# 使用kubeadm初始化k8s容器集群,1和2选择一个执行即可
# 1.直接执行初始化命令(推荐,便于查看实时输出)
kubeadm init \
--kubernetes-version=v1.28.2 \
--image-repository=registry.aliyuncs.com/google_containers \
--apiserver-advertise-address=172.24.221.34 \
--pod-network-cidr=192.168.0.0/16 \
--service-cidr=10.96.0.0/12 \
--v=5
# 2.创建集群初始化脚本(可选,也可直接执行命令)
cat > init-master.sh << 'EOF'
#!/bin/bash
kubeadm init \
--kubernetes-version=v1.28.2 \
--image-repository=registry.aliyuncs.com/google_containers \
--apiserver-advertise-address=172.24.221.34 \
--pod-network-cidr=192.168.0.0/16 \
--service-cidr=10.96.0.0/12 \
--v=5
EOF
# 添加执行权限
chmod +x init-master.sh
# 运行初始化脚本
./init-master.sh
⏳ 等待 2~5 分钟(取决于网络速度),直到看到 Your Kubernetes control-plane has initialized successfully! 提示,说明 master 节点初始化成功。
📝 关键步骤:务必记录最后输出的 kubeadm join 命令(你的 token 和 hash 会与示例不同),格式如下:
kubeadm join 172.24.221.34:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
建议复制该命令保存到文本文件(如记事本),后续 worker 节点加入集群时需使用。
💡 若初始化失败:执行 kubeadm reset --force && rm -rf /etc/cni/net.d && systemctl restart containerd 清理后重新执行初始化命令。
🧰 第七部分:配置 kubectl(仅在 master 上执行)
操作主机:master(仅此一台)
kubectl 是 K8s 命令行工具,需配置权限才能操作集群:
# 创建 kubectl 配置目录
mkdir -p $HOME/.kube
# 复制 master 节点的管理员配置文件到用户目录
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# 赋予配置文件正确权限(避免权限不足报错)
sudo chown $(id -u):$(id -g) $HOME/.kube/config
💡 临时使用方案:如果不需要永久配置,可执行 export KUBECONFIG=/etc/kubernetes/admin.conf(仅当前终端有效)。
🌐 第八部分:安装 Calico 网络插件(三台主机全部执行)
操作主机:master,worker1,worker2
K8s 集群初始化后,需安装网络插件才能实现 Pod 之间的网络互通,本文选择 Calico v3.28.0(与 K8s v1.28 兼容):
# 方式一:在线安装(推荐,网络通畅时使用)
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/calico.yaml
# 方式二:离线安装(无网络环境使用)
# 1. 提前下载 calico 镜像包(calico-cni.tar、calico-node.tar)
# 2. 在所有节点导入镜像:ctr images import calico-cni.tar && ctr images import calico-node.tar
# 3. 下载 calico.yaml 本地执行:kubectl apply -f calico.yaml
# 验证 Calico Pod 启动状态(等待 1~2 分钟,直到所有 Calico Pod 运行)
kubectl get pods -n kube-system | grep calico
✅ 预期结果:
- 看到
calico-node-xxxxx(当前仅 master 节点,故 1 个)。 - 看到
calico-kube-controllers-xxxxx(1 个副本)。 - 所有 Calico 相关 Pod 状态均为
Running。
🔍 验证 Calico 网络是否真正就绪即使 calico-node 显示 Running,也可能因 BGP 未建立、IP 分配失败等原因导致 Pod 无法通信。执行以下检查:
# 1. 检查 Calico 节点状态(应显示所有节点为 Ready)
kubectl get nodes -o wide
# 2. 检查 Calico IPAM 是否分配 CIDR 给节点
kubectl get blockaffinities.crd.projectcalico.org -A
# 3. (可选)部署测试 Pod 验证跨节点通信(后续添加 worker 节点后可测试)
kubectl run test-pod --image=busybox --command -- sleep 3600
✅ 验证要点:
blockaffinities输出非空,说明 Calico 已成功为节点分配网段。- 若 blockaffinities 为空,需查看 Calico 日志排查问题:
kubectl logs -n calico-system <calico-node-pod-name>。
若始终拉取calico镜像失败,且确认前面步骤均无问题,只有网络连接不上,则可使用如下方法(先使用docker拉取镜像,然后导入到containerd)(在master执行):
1.使用 Docker 拉取 Calico 镜像
# 拉取 Calico 节点镜像
docker pull calico/node:v3.28.0
# 拉取 Calico CNI 插件镜像
docker pull calico/cni:v3.28.0
# 拉取 Calico 控制器镜像
docker pull calico/kube-controllers:v3.28.0
2.将 Docker 镜像保存为 tar 包(关键:使用实际拉取的镜像名)
# 保存节点镜像
docker save docker.io/calico/node:v3.28.0 -o calico-node.tar
# 保存 CNI 插件镜像
docker save docker.io/calico/cni:v3.28.0 -o calico-cni.tar
# 保存控制器镜像
docker save docker.io/calico/kube-controllers:v3.28.0 -o calico-kube-controllers.tar
3.导入镜像到 containerd(K8s 容器运行时)
# 导入镜像到 k8s.io 命名空间
ctr -n k8s.io images import calico-node.tar
ctr -n k8s.io images import calico-cni.tar
ctr -n k8s.io images import calico-kube-controllers.tar
# 验证镜像导入结果
ctr -n k8s.io images list | grep calico
4.重新部署 Calico 网络插件
# 1.应用 Calico 官方配置
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/calico.yaml
# 2.删除失败的 Calico Pod(触发重建)
kubectl delete pods -n kube-system -l k8s-app=calico-node
kubectl delete pods -n kube-system -l k8s-app=calico-kube-controllers
# 3.检查 Calico Pod 状态
kubectl get pods -n kube-system | grep calico
# 4.验证 K8s 节点状态
kubectl get nodes
然后在worker主机执行
1.在 Worker 节点上导入 Calico 镜像(与 Master 步骤相同)
# 1. 从Master节点拷贝Calico镜像tar包(或重新拉取)
scp root@master:/root/calico-node.tar /root/
scp root@master:/root/calico-cni.tar /root/
scp root@master:/root/calico-kube-controllers.tar /root/
# 2. 导入镜像到containerd
ctr -n k8s.io images import /root/calico-node.tar
ctr -n k8s.io images import /root/calico-cni.tar
2.重启 kubelet 服务
systemctl restart kubelet
👥 第九部分:将 worker1 和 worker2 加入集群
✅ Worker 节点加入前自检清单(务必确认)
在执行 kubeadm join 前,请确保 worker 节点已完成以下检查:
- containerd 已安装并运行:
systemctl status containerd(状态为 active running) - kubelet 已安装并启用:
systemctl is-enabled kubelet(输出 enabled) - /etc/default/kubelet 已配置
--cgroup-driver=systemd:cat /etc/default/kubelet - 能从 worker 节点 ping 通 master 的 172.24.221.34:
ping 172.24.221.34 -c 3 - 能从 worker 节点连通 master 的 6443 端口:
yum install -y telnet
telnet 172.24.221.34 6443
# 或
nc -vz 172.24.221.34 6443
若端口不通,检查 master 防火墙、安全组或 apiserver 是否监听正确 IP。
💡 ⚠️ 重要提示:避免 kubeadm join 命令输入错误
不要手动敲写 kubeadm join 命令!务必直接从 master 节点复制输出结果,以下是更安全的操作方式:
1.在 master 上执行以下命令,直接生成单行可复制命令(即使 token 未过期也推荐):
kubeadm token create --print-join-command
2.输出示例(单行格式,无换行):
kubeadm join 172.24.221.34:6443 --token abcdef.0123456789abcdef --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3.直接全选复制这一整行,在 worker 节点粘贴执行即可,避免任何换行或编辑错误。
🛠️ 若已发生类似 accepts at most 1 arg(s), received X 错误:
- 检查命令中是否包含非法字符(如 ., #, $, 额外空格等)。
- 使用
history | tail -n 5查看实际执行的命令内容,定位错误位置。 - 重新从 master 生成并复制命令,不要手动修改。
9.1 在 worker1 上执行
操作主机:worker1(仅此一台)
粘贴从 master 复制的单行 join 命令(示例如下,替换为你自己的命令):
# 示例命令(请替换为你 master 节点生成的实际命令!)
kubeadm join 172.24.221.34:6443 --token 9hx1dx.hwbjglx3vtkfx5yk --discovery-token-ca-cert-hash sha256:d86fa1adea8221356e5e55655a69f306178ba9c6176841c04c805555c1e7eb55
✅ 成功后会显示:This node has joined the cluster。
9.2 在 worker2 上执行
操作主机:worker2(仅此一台)
粘贴与 worker1 完全相同的单行 join 命令(直接复制,不要修改):
# 示例命令(替换为你自己的实际命令!)
kubeadm join 172.24.221.34:6443 --token 9hx1dx.hwbjglx3vtkfx5yk --discovery-token-ca-cert-hash sha256:d86fa1adea8221356e5e55655a69f306178ba9c6176841c04c805555c1e7eb55
✅ 成功后同样显示:This node has joined the cluster。
💡 常见问题:
- 如果 token 过期(默认 24 小时),可在 master 节点重新生成 join 命令:
kubeadm token create --print-join-command。 - 若加入失败,在 worker 节点执行清理:
kubeadm reset --force && rm -rf /etc/cni/net.d && systemctl restart containerd后重试。
✅ 第十部分:验证集群状态(仅在 master 上执行)
操作主机:master(仅此一台)
1. 查看所有节点状态
kubectl get nodes
✅ 正常输出(3 个节点全部为 Ready 状态):
plaintext
NAME STATUS ROLES AGE VERSION
master Ready control-plane 5m v1.28.2
worker1 Ready <none> 1m v1.28.2
worker2 Ready <none> 1m v1.28.2
2. 查看所有系统 Pod 状态
kubectl get pods -A
✅ 预期结果:
- 每个节点都有
calico-node-xxxxx(共 3 个)。 coredns-xxxxx(2 个副本,DNS 服务)。kube-proxy-xxxxx(3 个,每节点 1 个)。- 所有 Pod 状态均为
Running(无Pending或Error)。
3. 验证跨节点 Pod 通信(补充测试)
# 在 worker1 上找到测试 Pod(若之前未创建则执行 kubectl run test-pod --image=busybox --command -- sleep 3600)
POD_IP=$(kubectl get pods -o wide | grep test-pod | awk '{print $6}')
# 在 worker2 上创建临时 Pod 测试 ping 连通性
kubectl run temp-pod --image=busybox --rm -it --command -- ping $POD_IP -c 3
✅ 预期结果:ping 成功,无丢包。
4. 查看集群信息
kubectl cluster-info
✅ 正常输出应显示 API Server 地址及状态正常提示。
🎯 (可选)允许 Master 调度工作负载(仅测试环境)
操作主机:master(仅此一台)
默认情况下,master 节点为控制平面,不会调度用户 Pod(避免影响集群稳定性)。如果是测试环境,可移除污点允许调度:
# 移除 master 节点污点(生产环境不建议执行!)
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
五、最终确认清单
| 检查项 | 执行命令 | 期望结果 | |
|---|---|---|---|
| 所有节点 Ready | kubectl get nodes | 3 行输出,STATUS 均为 Ready | |
| Calico 网络插件正常 | kubectl get pods -n calico-system | 3 个 calico-node + 1 个 calico-kube-controllers,均为 Running | |
| cgroup 驱动一致 | `crictl info | grep SystemdCgroup`(每台) | 输出 "SystemdCgroup": true |
| kubelet 无报错 | journalctl -u kubelet -n 10(每台) | 无 cgroup 冲突、连接超时等错误 | |
| 系统 Pod 全部运行 | kubectl get pods -A | coredns、kube-proxy 等均为 Running | |
| 集群信息正常 | kubectl cluster-info | 显示 API Server 地址及正常状态提示 | |
| 跨节点 Pod 通信正常 | kubectl run temp-pod --image=busybox --rm -it --command -- ping <PodIP> -c 3 | ping 成功,无丢包 |
六、各主机操作汇总表
| 步骤 | master | worker1 | worker2 |
|---|---|---|---|
| 设置主机名与时间同步 | ✅ | ✅ | ✅ |
| 系统初始化 | ✅ | ✅ | ✅ |
| 安装 containerd | ✅ | ✅ | ✅ |
| 安装 kubeadm/kubelet/kubectl | ✅ | ✅ | ✅ |
| 配置 kubelet 运行时与 cgroup | ✅ | ✅ | ✅ |
| 清理旧集群残留 | ✅ | ❌ | ❌ |
| 拉取 K8s 核心镜像(可选) | ✅ | ❌ | ❌ |
| kubeadm init | ✅ | ❌ | ❌ |
| 配置 kubectl | ✅ | ❌ | ❌ |
| 安装 Calico | ✅ | ✅ | ✅ |
| Worker 节点前置自检 | ❌ | ✅ | ✅ |
| kubeadm join | ❌ | ✅ | ✅ |
| 验证集群状态 | ✅ | ❌ | ❌ |
七、常见问题与故障排除
-
kubelet 启动失败,日志提示
cgroup driver mismatch:- 原因:containerd 未启用 SystemdCgroup,或 kubelet 未配置
--cgroup-driver=systemd。 - 解决:重新执行第二部分第 3 步(手动编辑 containerd 配置)和第三部分第 3 步(配置 kubelet),确保两者 cgroup 驱动一致。
- 原因:containerd 未启用 SystemdCgroup,或 kubelet 未配置
-
Calico Pod 一直处于 Pending 状态:
- 原因:Pod 网络网段与
kubeadm init中--pod-network-cidr不一致,或节点网络不通。 - 解决:确保
kubeadm init时--pod-network-cidr=192.168.0.0/16,且三台主机之间能互相 ping 通。
- 原因:Pod 网络网段与
-
coredns 出现 CrashLoopBackOff:
- 原因:Calico 部署失败,或 Pod 网络未正常初始化。
- 解决:查看 Calico 日志
kubectl logs -n calico-system <calico-node-pod-name>,排查网络配置或镜像拉取问题。
-
worker 节点加入集群失败,提示
container runtime is not running:- 原因:worker 节点未安装或未启动 containerd。
- 解决:在 worker 节点重新执行第二部分(安装并启动 containerd)。
-
kubectl 执行命令提示
The connection to the server xxx:6443 was refused:- 原因:API Server 未启动,或 kubectl 配置文件错误。
- 解决:检查 master 节点
kube-apiserver-xxxxxPod 状态;重新执行第七部分(配置 kubectl)。
-
kubeadm join 提示
accepts at most 1 arg(s), received X:- 原因:命令中存在非法字符(如多余的点号、空格、换行符)。
- 解决:在 master 重新生成单行 join 命令,直接复制粘贴执行,不手动编辑。
八、实战小 Demo:部署 Nginx 应用练手
集群搭建完成后,通过部署简单的 Nginx 应用熟悉 K8s 资源操作,包含 Deployment(部署)、Service(服务)。
一、环境准备(集群就绪)
确保 K8s 集群所有节点(Master+Worker)状态为Ready,网络插件(Calico/Flannel)正常运行:
kubectl get nodes
✅ 正常情况:所有节点状态为Ready,网络插件 Pod(calico-node/flannel)均为Running。
二、正常场景:直接部署 Nginx(无网络 / 镜像限制)
1. 创建 Deployment 配置文件
cat > nginx-deployment.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 2 # 2个Pod副本
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25-alpine # 轻量级Nginx镜像
ports:
- containerPort: 80
resources:
limits:
cpu: "0.5"
memory: "512Mi"
requests:
cpu: "0.2"
memory: "256Mi"
EOF
2. 应用配置文件
kubectl apply -f nginx-deployment.yaml
3. 验证 Deployment 和 Pod
# 查看Deployment状态
kubectl get deployments
# 查看Pod状态
kubectl get pods
✅ 正常结果:Deployment 状态READY 2/2,Pod 自动拉取镜像并启动,状态为Running。
4. 创建 Service 暴露服务
cat > nginx-service.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: NodePort
EOF
kubectl apply -f nginx-service.yaml
5. 访问 Nginx 服务
# 获取NodePort端口
kubectl get svc nginx-service
# 访问服务(示例端口30080)
curl http://<任意节点IP>:30080
✅ 正常结果:返回 Nginx 默认欢迎页面。
三、异常场景:网络 / 镜像限制下的部署(国内环境适配)
1. 手动拉取并分发镜像
(1)在 Master 节点拉取镜像
docker pull nginx:1.25-alpine
docker save nginx:1.25-alpine -o nginx.tar
(2)分发镜像到所有 Worker 节点
scp /root/nginx.tar root@worker1:/root/
scp /root/nginx.tar root@worker2:/root/
(3)所有节点导入镜像到 containerd
# Master/Worker节点均执行
ctr -n k8s.io images import /root/nginx.tar
2. 重新部署 Nginx
kubectl apply -f nginx-deployment.yaml
kubectl delete pods -l app=nginx # 重建Pod使用本地镜像
3. 验证部署结果
kubectl get pods
✅ 修复结果:Pod 使用本地镜像启动,状态为Running。
四、扩展与更新应用(通用步骤)
1. 扩展 Pod 副本数
kubectl scale deployment nginx-deployment --replicas=3
kubectl get pods
2. 更新 Nginx 版本
# 正常场景:直接更新(自动拉取新镜像)
kubectl set image deployment/nginx-deployment nginx=nginx:1.26-alpine
# 异常场景:提前导入新镜像后更新
docker pull nginx:1.26-alpine
docker save nginx:1.26-alpine -o nginx-1.26.tar
# 分发并导入所有节点后执行更新
kubectl set image deployment/nginx-deployment nginx=nginx:1.26-alpine
3. 查看更新状态
kubectl rollout status deployment/nginx-deployment
五、清理资源(通用步骤)
kubectl delete svc nginx-service
kubectl delete deployment nginx-deployment
总结
- 正常场景:外网通畅时可直接部署,K8s 自动拉取镜像并运行;
- 异常场景:国内环境需手动拉取镜像并分发到所有节点,确保 Pod 能使用本地镜像启动;
- 核心差异:镜像获取方式(自动拉取 vs 手动导入),其余部署步骤完全一致。
总结
本文提供了一套从零开始部署三节点 K8s v1.28.2 集群的完整方案,覆盖环境准备、系统配置、容器运行时安装、K8s 组件部署、集群初始化、网络插件安装、节点加入、状态验证及实战 Demo 全流程,特别强化了容错性、可操作性和新手友好度。
核心优化要点:
- 新增
kubeadm join输入安全指南,通过单行命令生成 + 直接复制的方式,避免换行、非法字符等常见输入错误。 - 补充 containerd 配置修改的风险提示,推荐备份 + 手动编辑的安全方式,防止配置文件结构破坏。
- 增强 Calico 网络验证,从单纯查看 Pod 状态升级到 IP 分配检查 + 跨节点通信测试,确保网络真正可用。
- 增加 Worker 节点加入前自检清单,提前排查环境问题,减少 join 失败概率。
- 优化镜像预拉取脚本,使用 crictl 提升兼容性,同时注明仅网络极差时必要。
- 统一所有代码块的语言标识,提升文档可读性和专业性。
按照文中步骤操作,即可获得稳定兼容的 K8s 集群,结合 Nginx 实战 Demo 可快速上手 K8s 应用部署与管理,为后续复杂应用运维打下基础!
3557

被折叠的 条评论
为什么被折叠?



