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 搭建流程:
💡 初始化命令示例:
# 控制平面节点初始化
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 环境验证清单
集群搭完别急着部署业务。先跑一遍验证,确保每个环节都正常:
- 节点状态检查:
kubectl get nodes所有节点 Ready - Pod 网络连通性:部署一个 busybox,ping 其他节点的 Pod IP
- DNS 解析:
kubectl run test --image=busybox -- nslookup kubernetes.default.svc.cluster.local - 网络策略生效:创建一条拒绝策略,验证流量被阻断
- 存储卷挂载:部署一个带 PVC 的 Pod,验证读写正常
⚠️ 我曾经踩过的坑: 有次集群搭完,所有节点都是 Ready,Pod 也能跑。但一部署有状态应用,PVC 一直 Pending。查了半天,发现 StorageClass 没装。嗯,这种低级错误,犯过一次就记住了。