Kubernetes 集群部署

一、集群部署总体思路

Kubernetes(K8s)作为容器编排平台,部署的核心目标是让控制平面(Control Plane)与工作节点(Worker Node)通过安全的 API 通道协同工作。本文采用 kubeadm + 私有镜像仓库 + Flannel 网络插件 的方案,在 4 台主机(1 台 Harbor 镜像仓库 + 1 台 master + 2 台 worker)上完成集群搭建,并同步梳理每一步背后的原理。

1.1 集群组件

角色组件职责
控制平面kube-apiserver集群唯一入口,所有请求(kubectl、组件间通信)都经过它,承担认证、授权与 API 转发
控制平面etcd集群状态的权威存储,保存所有资源对象数据
控制平面kube-controller-manager运行各类控制器,不断把实际状态向期望状态收敛
控制平面kube-scheduler为新 Pod 挑选最合适的节点
工作节点kubelet节点上的管理者,负责 Pod 生命周期与健康检查,并与 apiserver 保持心跳
工作节点kube-proxy维护节点网络规则,实现 Service 的负载均衡与转发
工作节点容器运行时(CRI)真正启停容器,K8s 通过 CRI 接口与运行时解耦

1.2 为什么需要私有镜像仓库

集群几乎所有组件的镜像(kube-apiserver、etcd、coredns、pause……)默认来自 k8s.gcr.io / registry.k8s.io,国内网络环境下拉取困难。因此先在 Harbor 上搭建私有仓库,形成一条镜像链路:

  1. master 节点从国内镜像源(阿里云)拉取官方组件镜像;
  2. 重新打标签(reg.timinglee.org/k8s/xxx)后推送到内网 Harbor;
  3. 所有主机统一从 reg.timinglee.org 拉取组件镜像,既解决网络问题,也实现镜像的集中管理。
    在这里插入图片描述

【截图 2:Harbor Web 界面(登录页 / 项目与镜像列表)】

二、搭建 Harbor 镜像仓库

2.1 安装 Docker 并配置桥接转发

Docker 是 Harbor 的运行时底座。安装后必须开启内核桥接转发(br_netfilter)并允许 IP 转发,否则后续容器与 Pod 流量无法穿过 iptables:

cat > /etc/yum.repos.d/docker.repo <<EOF
[docker]
name = docker
baseurl = https://mirrors.aliyun.com/docker-ce/linux/rhel/9.6/x86_64/stable/
gpgcheck = 0
EOF

dnf install docker-ce-3:28.5.2-1.el9 -y

echo br_netfilter > /etc/modules-load.d/docker_mod.conf
modprobe -a br_netfilter

cat > /etc/sysctl.d/docker.conf <<EOF
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system

systemctl enable --now docker

2.2 生成仓库证书

Harbor 走 HTTPS 访问,需要自签证书,且必须包含仓库域名 SAN(subjectAltName),否则客户端校验证书时会因域名不匹配而失败:

mkdir /data/certs -p
openssl req -newkey rsa:4096 \
  -nodes -sha256 -keyout /data/certs/timinglee.org.key \
  -addext "subjectAltName = DNS:reg.timinglee.org" \
  -x509 -days 365 -out /data/certs/timinglee.org.crt

2.3 配置并安装 Harbor

tar zxf harbor-offline-installer-v2.5.4.tgz -C /opt/
cd /opt/harbor/
cp harbor.yml.tmpl harbor.yml
# 修改 harbor.yml 关键项:
#   hostname: reg.timinglee.org
#   certificate: /data/certs/timinglee.org.crt
#   private_key: /data/certs/timinglee.org.key
#   harbor_admin_password: <自行设置>
./install.sh --with-chartmuseum

2.4 信任证书并验证仓库

mkdir -p /etc/docker/certs.d/reg.timinglee.org/
cp /data/certs/timinglee.org.crt /etc/docker/certs.d/reg.timinglee.org/ca.crt
# /etc/hosts 增加解析:
# 172.25.254.200   reg.timinglee.org

systemctl restart docker
docker compose up -d
docker login reg.timinglee.org -u admin
# 输出 Login Succeeded 即仓库可用

在这里插入图片描述

原理说明:/etc/docker/certs.d/<域名>/ca.crt 是 Docker 客户端信任私有仓库证书的标准位置,放入后无需配置 insecure-registry 即可 HTTPS 登录。整个集群的主机共享同一份证书,就建立起了对私有仓库的统一信任。

三、节点主机规划

主机名IP配置角色
harbor.timinglee.org172.25.254.2001C / 1GHarbor 镜像仓库
master-node172.25.254.1004C / 4G+master:控制平面节点
node1172.25.254.102C / 2Gworker:工作节点
node2172.25.254.202C / 2Gworker:工作节点

tips:master节点至少3G内存

四、所有节点通用配置

4.1 关闭 swap

kubelet 默认要求节点禁用 swap(否则 kubelet 无法启动),且 /etc/fstab 中的 swap 行必须注释,否则重启后 swap 会重新启用:

systemctl disable --now swap.target
systemctl mask swap.target
sed '/swap/s/^/#/g' -i /etc/fstab
# 重启后验证:swapon -s 无任何输出

4.2 安装 Docker 并信任私有仓库

# 安装 docker(步骤同 2.1)
mkdir -p /etc/docker/certs.d/reg.timinglee.org/
# 从 harbor 主机向各节点分发证书
for i in 100 10 20; do
  scp /data/certs/timinglee.org.crt root@172.25.254.$i:/etc/docker/certs.d/reg.timinglee.org/ca.crt
done

# 配置镜像加速,统一走私有仓库
cat > /etc/docker/daemon.json <<EOF
{ "registry-mirrors":["https://reg.timinglee.org"] }
EOF
systemctl restart docker
docker info   # Registry Mirrors 中出现 reg.timinglee.org

在这里插入图片描述

4.3 主机名解析

所有主机写入彼此的主机名解析,保证 kubeadm join、证书校验等环节按主机名通信不报错:

cat >> /etc/hosts <<EOF
172.25.254.100     master
172.25.254.10      node1
172.25.254.20      node2
172.25.254.200     reg.timinglee.org
EOF

4.4 配置 Kubernetes 软件源

使用阿里云镜像保持 kubelet / kubeadm 版本一致(本实验为 v1.35):

cat > /etc/yum.repos.d/kubernetes.repo <<EOF
[kubernetes]
name = kubernetes
baseurl = https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.35/rpm/
gpgcheck = 0
EOF
dnf list kubelet   # 能列出即为源可用

五、kubeadm 部署流程

5.1 安装 cri-dockerd(运行时适配层)

Kubernetes 自 1.24 起移除了内置的 dockershim,Docker 引擎不再被 CRI 直接支持。cri-dockerd 是 Docker 与 CRI 之间的适配层:对外暴露 CRI 接口 /var/run/cri-dockerd.sock,对内调用 Docker API,让仍以 Docker 为运行时的集群可以平滑过渡。

rpm -ivh cri-dockerd-0.3.14-3.el8.x86_64.rpm libcgroup-0.41-19.el8.x86_64.rpm

# 修改 /lib/systemd/system/cri-docker.service 的 ExecStart:
# /usr/bin/cri-dockerd --container-runtime-endpoint fd:// \
#   --network-plugin=cni \
#   --pod-infra-container-image=reg.timinglee.org/k8s/pause:3.10.1

ll /var/run/cri-dockerd.sock   # 套接字存在即启动成功

【截图 5:cri-dockerd 服务状态与 /var/run/cri-dockerd.sock】

5.2 安装 kubelet / kubeadm / kubectl

# master 节点安装三件套;node 节点仅需 kubelet + kubeadm
dnf install kubelet kubeadm kubectl -y
systemctl enable --now kubelet.service

# master 节点补全命令行补全
echo "source <(kubectl completion bash)" >> ~/.bashrc
echo "source <(kubeadm completion bash)" >> ~/.bashrc
source ~/.bashrc

5.3 拉取镜像并推送私有仓库

kubeadm 可自动列出并拉取集群所需镜像。这里先从阿里云镜像站拉取,再统一打标签推送到 Harbor,全程无需访问境外源:

kubeadm config images pull \
  --image-repository registry.aliyuncs.com/google_containers \
  --kubernetes-version v1.35.3 \
  --cri-socket=unix:///var/run/cri-dockerd.sock

# 重新打标签(google_containers/xxx → reg.timinglee.org/k8s/xxx)
docker images --format "{{.Repository}}:{{.Tag}}" |
  awk -F "/" '/google/{system("docker tag "$0" reg.timinglee.org/k8s/"$3)}'

# 批量推送
docker images --format "{{.Repository}}:{{.Tag}}" |
  awk -F "/" '/timinglee/{system("docker push "$0)}'

5.4 初始化集群(master 节点)

kubeadm init --pod-network-cidr=10.244.0.0/16 \
  --image-repository reg.timinglee.org/k8s \
  --kubernetes-version v1.35.3 \
  --cri-socket=unix:///var/run/cri-dockerd.sock

参数原理:

  • --image-repository reg.timinglee.org/k8s:指定组件镜像从私有仓库拉取,路径与 5.3 推送结果一致;
  • --pod-network-cidr=10.244.0.0/16:声明 Pod 网段,必须与后续网络插件(Flannel 默认 10.244.0.0/16)保持一致,否则跨节点 Pod 无法互通;
  • --cri-socket=unix:///var/run/cri-dockerd.sock:指定 CRI 运行时为 cri-dockerd。

初始化成功后输出 join 凭证(每次都不同):

kubeadm join 172.25.254.100:6443 --token tdwjoc.8d1yw3wl4r4tm6c4 \
  --discovery-token-ca-cert-hash sha256:6b5950ef2cdba85d6dfdb564ee90d4187fa3d341767dc9852cbdd5c9dee4f927

原理说明:join 凭证由两部分构成——bootstrap token(默认 24 小时有效的一次性准入凭证)与 discovery-token-ca-cert-hash(apiserver 根证书 SHA256 指纹,防止节点加入时被中间人欺骗)。token 过期后可在 master 上执行 kubeadm token create --print-join-command 重新生成。

配置 kubectl 环境并查看节点:

echo "export KUBECONFIG=/etc/kubernetes/admin.conf" > ~/.bash_profile
source ~/.bash_profile
kubectl get nodes
# NAME     STATUS     ROLES           AGE    VERSION
# master   NotReady   control-plane   102s   v1.35.3

5.5 工作节点加入集群

在 node1 / node2 上执行 join 命令(注意追加 --cri-socket 指向 cri-dockerd):

kubeadm join 172.25.254.100:6443 --token jl4ztx.cax3iysvu7onsh5s \
  --discovery-token-ca-cert-hash sha256:6b5950ef2cdba85d6dfdb564ee90d4187fa3d341767dc9852cbdd5c9dee4f927 \
  --cri-socket=unix:///var/run/cri-dockerd.sock

此时节点均为 NotReady —— 节点已成功入群,但集群网络尚未打通(缺少 CNI 插件),这是部署的正常中间态。

5.6 安装 Flannel 网络插件

CNI(Container Network Interface)是容器网络的标准接口。Flannel 基于 VXLAN 覆盖网络,在现有物理网络上隧道化传输 Pod 流量,实现跨节点 Pod 互通,且无需改动底层网络设备:
tips:网络通信出现问题可以
在这里插入图片描述

docker load -i flannel-0.28.1.tar

# flannel 主程序与 CNI 插件镜像推送到私有仓库
docker tag ghcr.io/flannel-io/flannel:v0.28.1 reg.timinglee.org/flannel-io/flannel:v0.28.1
docker push reg.timinglee.org/flannel-io/flannel:v0.28.1
docker tag ghcr.io/flannel-io/flannel-cni-plugin:v1.9.0-flannel1 reg.timinglee.org/flannel-io/flannel-cni-plugin:v1.9.0-flannel1
docker push reg.timinglee.org/flannel-io/flannel-cni-plugin:v1.9.0-flannel1

# 修改 kube-flannel.yml 中的 image 为私有仓库地址
vim kube-flannel.yml
kubectl apply -f kube-flannel.yml

【截图 9:kubectl apply -f kube-flannel.yml 输出】

六、集群验证

kubectl get nodes
# NAME     STATUS   ROLES           AGE     VERSION
# master   Ready    control-plane   13m     v1.35.3
# node1    Ready    <none>          9m44s   v1.35.3
# node2    Ready    <none>          9m36s   v1.35.3

三个节点全部 Ready,集群部署完成。
在这里插入图片描述

七、常见问题

现象原因解决
节点一直 NotReady网络插件未安装,或插件网段与 pod-network-cidr 不一致安装 Flannel / Calico 并核对网段
join 提示 token 无效bootstrap token 默认 24h 过期master 执行 kubeadm token create --print-join-command
初始化中途失败参数错误 / 网络问题kubeadm reset --cri-socket=unix:///var/run/cri-dockerd.sock 重置后重新 init,并清理 $HOME/.kube

8.8 命令速记表

目的常用命令
看节点kubectl get nodes -o wide
看全部 Podkubectl get pods -A -o wide
查 Pod 事件kubectl describe pod <pod> -n <ns>
查容器日志kubectl logs <pod> -n <ns>
看服务后端kubectl get endpointslices -n <ns>
发布状态kubectl rollout status deployment/<name> -n <ns>
回滚发布kubectl rollout undo deployment/<name> -n <ns>
应用配置kubectl apply -f <file>
预览差异kubectl diff -f <file>
查事件kubectl get events -A --sort-by=.lastTimestamp
进容器kubectl exec -it <pod> -n <ns> -- /bin/sh
临时端口转发kubectl port-forward svc/<svc> 8080:80 -n <ns>

掌握这些命令后,日常操作可以归纳为三类:

  • 观察:用 get 快速查看集群状态
  • 定位:用 describe、logs、events 排查问题
  • 调整:用 apply、rollout、scale 更新期望状态

更多推荐