2. 环境准备篇:Docker 与 Kubernetes 环境搭建

容器化部署,说白了就是把你的应用连同依赖打包成一个“集装箱”。Docker 负责造箱子,Kubernetes 负责管箱子。听起来简单,但版本搭不对、网络插件选错,后面全是坑。

我见过太多团队,一上来就装最新版 Docker,然后发现跟 Kubernetes 不兼容。嗯,这里咱们得先理清版本关系。

2.1 Docker 与 Kubernetes 的版本兼容性

Kubernetes 每个版本发布时,都会明确声明支持的容器运行时版本。别信“最新就是最好”的鬼话。

⚠️ 我曾经踩过的坑: 某次生产环境升级,我直接把 Docker 从 19.03 升到 20.10,结果 kubelet 报错说容器运行时接口不匹配。查了半天才发现 Kubernetes 1.19 根本不认 Docker 20.10 的某些 API 变更。最后回滚 Docker 版本才解决。

下面这张表是我整理的主流版本对应关系,建议你保存下来:

Kubernetes 版本 推荐 Docker 版本 containerd 版本 备注
1.24+ 20.10.x 1.6.x+ 已移除 dockershim,建议用 containerd
1.23 20.10.x 1.5.x+ 最后一个内置 dockershim 的版本
1.22 19.03.x / 20.10.x 1.4.x+ 过渡期,两种运行时都行
1.19-1.21 19.03.x 1.4.x 稳定组合,生产环境验证充分
💡 我的建议: 新项目直接上 containerd。Docker 虽然好用,但 Kubernetes 1.24 之后已经不再直接支持 Docker 作为运行时。你想想看,多一层 dockershim 就多一个故障点,何必呢?

2.2 容器运行时的选择:Docker vs containerd vs CRI-O

现在主流的容器运行时就三个:Docker、containerd、CRI-O。我个人的选择逻辑很简单:

  • Docker:开发环境首选,生态最全,调试方便。但生产环境里,它太重了。
  • containerd:生产环境推荐。Docker 底层就是它,但更轻量,直接对接 CRI。
  • CRI-O:Red Hat 系专用,OpenShift 标配。如果你用 CentOS/RHEL,可以考虑。

为什么会这样?因为 Kubernetes 1.24 之后,dockershim 被彻底移除。如果你还硬要用 Docker,就得装 cri-dockerd 这个适配器。多一层转换,性能损耗不说,出问题还不好排查。

🔧 安装 containerd 的关键步骤:
# 1. 加载内核模块
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# 2. 设置 sysctl 参数
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

sudo sysctl --system

# 3. 安装 containerd
sudo apt-get update
sudo apt-get install -y containerd

# 4. 生成默认配置并修改
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml

# 5. 关键:修改 cgroup 驱动为 systemd
# 编辑 /etc/containerd/config.toml,找到:
# [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
# 设置 SystemdCgroup = true

sudo systemctl restart containerd

2.3 Kubernetes 集群搭建:kubeadm 实战

搭建集群的工具很多,kubeadm、kops、kubespray、Rancher。我个人习惯用 kubeadm,原因很简单:它是官方工具,升级路径最清晰。

下面这张图是我总结的 kubeadm 搭建流程:

kubeadm 集群搭建流程 kubeadm 集群搭建核心流程 1. 环境准备 2. 安装容器运行时 3. 安装 kubeadm/kubelet/kubectl 4. kubeadm init 初始化 5. 安装网络插件(CNI) ⚠️ 网络插件必须在 kubeadm init 之后立即安装,否则节点会一直处于 NotReady 状态
💡 初始化命令示例:
# 控制平面节点初始化
sudo kubeadm init \
  --kubernetes-version=v1.28.0 \
  --pod-network-cidr=10.244.0.0/16 \
  --apiserver-advertise-address=192.168.1.100

# 配置 kubectl
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

# 工作节点加入
sudo kubeadm join 192.168.1.100:6443 --token <token> \
  --discovery-token-ca-cert-hash sha256:<hash>

2.4 网络插件选择:Calico vs Flannel vs Cilium

网络插件是 Kubernetes 集群的血管。选错了,后面性能调优、故障排查都痛苦。我个人的经验是:

插件 网络模型 性能 功能特性 适用场景
Flannel Overlay (VXLAN) 中等 简单,仅网络连通 小规模、开发测试环境
Calico 纯三层 (BGP) 高 网络策略、安全隔离 生产环境首选
Cilium eBPF 数据面 极高 可观测性、安全、服务网格 大规模、高性能需求
Weave Overlay (VXLAN) 中等 加密、多播支持 跨云、混合云场景
⚠️ 我曾经踩过的坑: 有次用 Flannel 搭了 50 个节点的集群,业务一上线就发现跨节点通信延迟飙升。查了半天,Flannel 的 VXLAN 封装在大量小包场景下 CPU 开销巨大。后来换成 Calico 的 BGP 模式,延迟直接降了 60%。

为什么会这样?Flannel 的 VXLAN 是在内核里做 UDP 封装,每个包都要多一层头部。Calico 用 BGP 直接路由,没有封装开销。你想想看,生产环境里成千上万的 Pod 在通信,这点差异会被放大到不可接受。

2.5 网络插件安装实战

以 Calico 为例,安装其实就一条命令:

# 安装 Calico(推荐使用 Tigera Operator)
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26/manifests/tigera-operator.yaml

# 等待所有 Pod 就绪
kubectl wait --namespace tigera-operator --for=condition=ready pod --all --timeout=300s

# 验证节点状态
kubectl get nodes
# 应该看到所有节点都是 Ready 状态
🔧 关键配置项:
  • IPIP 模式 vs BGP 模式:BGP 模式性能更好,但需要底层网络支持。云环境里如果 VPC 路由表有限制,用 IPIP 模式更稳妥。
  • MTU 设置:默认 1480(VXLAN 模式),如果底层网络支持巨帧,可以调高到 9000,能显著提升吞吐量。
  • 网络策略默认行为:Calico 默认允许所有流量。生产环境建议先设置默认拒绝策略,再按需放行。
💡 我的建议: 新项目直接上 Calico + BGP 模式。如果团队有 eBPF 经验,Cilium 是更好的选择。Flannel 只适合 10 个节点以下的测试环境。别问我怎么知道的——我在 Flannel 上吃过太多亏了。

2.6 环境验证清单

集群搭完别急着部署业务。先跑一遍验证,确保每个环节都正常:

  1. 节点状态检查:kubectl get nodes 所有节点 Ready
  2. Pod 网络连通性:部署一个 busybox,ping 其他节点的 Pod IP
  3. DNS 解析:kubectl run test --image=busybox -- nslookup kubernetes.default.svc.cluster.local
  4. 网络策略生效:创建一条拒绝策略,验证流量被阻断
  5. 存储卷挂载:部署一个带 PVC 的 Pod,验证读写正常
⚠️ 我曾经踩过的坑: 有次集群搭完,所有节点都是 Ready,Pod 也能跑。但一部署有状态应用,PVC 一直 Pending。查了半天,发现 StorageClass 没装。嗯,这种低级错误,犯过一次就记住了。