Kubernetes服务器集群部署

结论: 部署一套生产可用的 Kubernetes 集群,最短路径是 kubeadm + containerd + CNI 插件三件套:先按角色规划节点并做好 swap/内核参数/时间同步三项前置,再用 kubeadm init 初始化控制平面、kubeadm join 加入工作节点,最后安装 Calico 或 Flannel 让 Pod 网络打通。生产环境控制平面节点至少 3 个,这是 etcd 多数派选举(quorum)的硬性要求,不是冗余建议。

Kubernetes(常简称 K8s)把服务器抽象成了一个资源池:你不关心任务跑在哪台机器上,只声明"要几个副本、要多少 CPU 和内存"。这个抽象很有价值,但它也是部署复杂度的来源——控制平面、容器运行时、CNI 网络、存储、负载均衡这五层,任何一层没配好,集群都会处于"能起来但不能用"的状态。

本文以 Ubuntu 24.04 LTS + Kubernetes 1.33 为例(截至 2026 年,请按 kubeadm 官方支持矩阵选择仍在维护的版本),给出可直接复制执行的完整流程。

集群规划:节点数量、硬件配置与"为什么至少 3 个 master"

结论前置:生产环境控制平面至少 3 个节点,因为 etcd 采用 Raft 一致性算法,需要多数派(n/2+1)存活才能对外提供写入;2 个节点与 1 个节点在容错能力上没有本质区别(都是不容错)。

角色最小生产配置CPU / 内存建议数量建议说明
control-plane(master)2 核 / 2 GB,推荐 4 核 / 8 GB与节点数同步扩展,节点越多 apiserver 压力越大≥ 3(奇数)承载 kube-apiserver、etcd、kube-scheduler、kube-controller-manager
worker2 核 / 2 GB,推荐 4 核 / 16 GB 起按业务 Pod 的 requests 总量上浮 20%~30%≥ 2承载 kubelet、容器运行时与业务 Pod
etcd(独立部署时)4 核 / 8 GB,SSD/NVMeIOPS 是关键指标3 或 5大规模集群通常与 control-plane 分离部署
负载均衡器——1(VIP)或云 LB对外暴露 apiserver 的 6443,实现控制平面高可用

关于节点数量,还有三条实操建议:

  • 控制平面节点必须是奇数:3 节点容忍 1 台故障,5 节点容忍 2 台;4 节点同样只能容忍 1 台,还多耗一台机器。
  • worker 至少 2 个:不是为了高可用,而是为了验证调度、网络跨节点连通与滚动更新是否正常。
  • 磁盘要给足:worker 上镜像层与容器层会持续增长,建议 200 GB 以上并单独挂载 /var/lib/containerd;磁盘写满是 Node NotReady 最常见的原因之一。

前置准备:swap、内核参数与时间同步三件套

结论前置:跳过这三项直接跑 kubeadm,是最常见的失败原因。 以下步骤需要在所有节点(control-plane 与 worker)上执行。

bash
# 1) 关闭 swap 并取消开机挂载(kubelet 默认拒绝在开启 swap 的节点上工作)
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
swapon --show    # 无输出即表示已关闭

# 2) 加载 overlay 与 br_netfilter 内核模块
cat <<'EOF' | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter

# 3) 让 iptables 能够过滤桥接流量,这是 Service 转发与 NetworkPolicy 生效的前提
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
EOF
sudo sysctl --system

# 4) 时间同步:证书校验、日志排序、调度器判定都依赖一致的时钟
sudo apt update && sudo apt install -y chrony
sudo systemctl enable --now chrony
chronyc sources
timedatectl status

另外两项容易被忽略的检查:所有节点的主机名必须唯一且能被 DNS 或 /etc/hosts 解析(否则 apiserver 证书 SAN 校验会失败);确认 SELinux 处于关闭或 permissive 模式(Ubuntu 默认不启用,CentOS/RHEL 系需检查)。

安装容器运行时 containerd 与 kubeadm 三件套

结论前置:containerd 是当前推荐的容器运行时;它的 cgroup driver 必须配置为 systemd,否则 kubelet 与运行时的资源限制口径不一致,会出现节点频繁驱逐 Pod 甚至 NotReady。

bash
# 安装 containerd.io(来自 Docker 官方仓库,版本号以实际仓库为准)
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list
sudo apt-get update
sudo apt-get install -y containerd.io

# 生成默认配置并改用 systemd cgroup driver
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl daemon-reload
sudo systemctl enable --now containerd
sudo ctr version

接着安装 kubeadm、kubelet、kubectl。注意三者的版本要严格一致,且要锁定(hold)防止意外升级:

bash
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
sudo mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key \
  | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /' \
  | sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl cri-tools
sudo apt-mark hold kubelet kubeadm kubectl

# 让 crictl 指向 containerd 套接字(否则排查容器时会连不上运行时)
sudo crictl config runtime-endpoint unix:///var/run/containerd/containerd.sock
sudo crictl ps -a

如果要使用国内镜像代替 registry.k8s.io,可以在 kubeadm init 时用 --image-repository 指定,或在 containerd 配置里设置 registry mirror。不要混用多种镜像源配置,那会导致拉取失败时无法判断到底用的哪个源。

初始化控制平面:kubeadm init 完整命令

结论前置:kubeadm init 的关键参数有三个——--pod-network-cidr(必须与你后面要装的 CNI 插件默认值一致)、--control-plane-endpoint(多 master 时必须配负载均衡入口)、--apiserver-advertise-address(多网卡时必须显式指定)。

bash
# 单控制平面(测试环境)示例
sudo kubeadm init \
  --apiserver-advertise-address=10.0.0.10 \
  --pod-network-cidr=10.244.0.0/16 \
  --service-cidr=10.96.0.0/12 \
  --kubernetes-version=v1.33.0

# 多控制平面(生产)示例:务必加 control-plane-endpoint 指向负载均衡 VIP
sudo kubeadm init \
  --control-plane-endpoint="k8s-api.example.com:6443" \
  --apiserver-advertise-address=10.0.0.10 \
  --pod-network-cidr=10.244.0.0/16 \
  --service-cidr=10.96.0.0/12 \
  --kubernetes-version=v1.33.0 \
  --upload-certs

初始化完成后按提示配置 kubeconfig,并把 join 命令保存好(24 小时后会过期):

bash
mkdir -p "$HOME"/.kube
sudo cp /etc/kubernetes/admin.conf "$HOME"/.kube/config
sudo chown "$(id -u)":"$(id -g)" "$HOME"/.kube/config
kubectl get nodes

# worker 节点加入集群
sudo kubeadm join 10.0.0.10:6443 --token  \
  --discovery-token-ca-cert-hash sha256:

# 令牌过期也不怕,随时重新生成
kubeadm token create --print-join-command

校验健康的快速清单:kubectl get cs 看组件状态、kubectl -n kube-system get pod -o wide 确认 coreDNS 以外的系统 Pod 全部 Running、确认 coreDNS 的 Pod 已就绪(CNI 没装好时它们会一直 Pending)。

CNI 插件:Calico 与 Flannel 怎么选

结论前置:CNI(Container Network Interface,容器网络接口)插件负责 Pod 之间跨节点通信。没有 CNI,节点永远是 NotReady。 小集群和学习环境用 Flannel 图个省事;需要网络策略与更大规模时用 Calico。

对比项FlannelCalico
网络模型overlay 封装(VXLAN 为主,也支持 host-gw)支持 VXLAN / IPIP / BGP 直连路由多种模式
默认 Pod CIDR10.244.0.0/1610.244.0.0/16(可在 Installation CR 中修改)
网络策略不支持 NetworkPolicy原生支持丰富的 NetworkPolicy
简易度部署一条命令,配置极少组件较多(operator + calico-node + typha 等),可配置项丰富
性能VXLAN 模式有封装开销BGP 直连模式接近物理网络性能
适用规模中小集群、边缘场景中大型集群、要求网络隔离与安全策略的场景

安装 Flannel(要求 init 时使用默认的 10.244.0.0/16):

bash
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
kubectl -n kube-flannel get pod -o wide

安装 Calico(Operator 方式,版本需与 Kubernetes 版本匹配,请查官方兼容矩阵后替换版本号):

bash
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.0/manifests/tigera-operator.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.0/manifests/custom-resources.yaml
kubectl get tigerastatus

如果需要自定义 Pod 网段,在安装前确认 Installation 资源的 spec.calicoNetwork.ipPools[0].cidr 与 kubeadm 的 --pod-network-cidr 完全一致;网上很多人只剩一行 kubectl get po 就以为装好了,其实网段对不上时 Pod 能 Running 但跨节点 ping 不通。

部署第一个应用:Deployment、Service 与 Ingress

结论前置:Kubernetes 里跑应用的三层分别是 Deployment(管副本与滚动更新)、Service(提供稳定的访问入口与负载均衡)、Ingress(按域名/路径把外部 HTTP(S) 流量引入集群)。

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.27-alpine
          ports:
            - containerPort: 80
          readinessProbe:            # 未就绪的 Pod 不会进入 Service 转发列表
            httpGet: { path: /, port: 80 }
            initialDelaySeconds: 5
            periodSeconds: 10
          resources:
            requests: { cpu: "100m", memory: "128Mi" }
            limits:   { cpu: "500m", memory: "256Mi" }
---
apiVersion: v1
kind: Service
metadata:
  name: web-svc
spec:
  type: NodePort               # 生产建议改为 LoadBalancer 或由 Ingress 承接
  selector:
    app: web
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 30080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
spec:
  ingressClassName: nginx      # 需先安装对应 Ingress Controller
  rules:
    - host: web.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web-svc
                port:
                  number: 80
bash
kubectl apply -f web.yaml
kubectl rollout status deployment/web
kubectl get pod,svc,ingress -o wide

# 集群内快速联通测试(临时Pod,测完即删)
kubectl run curl-test --rm -it --image=curlimages/curl:8.10.1 -- \
  curl -sS -o /dev/null -w '%{http_code}\n' http://web-svc.default.svc.cluster.local

Ingress 本身只是一组规则,真正干活的是 Ingress Controller(如 ingress-nginx、Traefik、APISIX Ingress),需要单独安装并以 DaemonSet/Deployment + Service 暴露 80/443。常见做法是把它做成 DaemonSet 并配合 hostNetwork 或 NodePort + 外部负载均衡器,避免多一层 NAT 导致源 IP 丢失。

kubectl 常用命令速查表

结论前置:这张表覆盖日常 80% 的操作,建议贴在终端旁边。

命令作用
kubectl get node -o wide查看节点状态、内网 IP 与 kubelet 版本
kubectl describe node 查看节点资源分配、污点(Taint)与事件
kubectl -n kube-system get pod -o wide检查系统组件是否全部就绪
kubectl get pod -A -o wide跨命名空间查看所有 Pod 落点与 IP
kubectl describe pod 排查 Pending/ImagePullBackOff 的第一手信息
kubectl logs -c --previous查看上一次崩溃容器的日志
kubectl exec -it -- sh进入容器排查(生产慎用)
kubectl scale deployment/web --replicas=5手动扩缩容
kubectl rollout undo deployment/web回滚到上一个版本
kubectl top pod -A查看实际资源占用(需 metrics-server)
kubectl cordon / drain 停止调度 / 驱逐节点上的 Pod(维护前必做)
kubectl get events -A --sort-by=.metadata.creationTimestamp按时间查看集群事件,排障通用入口