从零搭建 Kubernetes 集群:Ubuntu + kubeadm 完整实战

一、Kubernetes 集群搭建全流程讲解

理解了"为什么",这些命令就不用死记硬背了。

环境:Ubuntu 26.04 + Kubernetes v1.30.14 + containerd + Calico,1 个 master + 1 个 worker。

1、整体认知:k8s 集群长什么样

javascript 复制代码
                 ┌─────────────┐
   kubectl  ────▶│   Master    │  大脑:管调度、存数据、发指令
   (管理命令)     │  apiserver  │  唯一入口
                 │  etcd       │  数据库(存集群状态)
                 │  scheduler  │  调度器:决定 Pod 去哪台机器
                 │  controller │  控制器:维持期望状态
                 └──────┬──────┘
                        │ 6443 端口
              ┌─────────┴─────────┐
              ▼                   ▼
        ┌──────────┐        ┌──────────┐
        │ Worker 1 │        │ Worker 2 │  手脚:真正跑应用容器
        │ kubelet  │        │ kubelet  │  每节点一个"代理人"
        │containerd│        │containerd│  容器引擎
        └──────────┘        └──────────┘

本次搭建:1 个 master + 1 个 worker,最小可用集群。

2、流程回顾:为什么按这个顺序做

阶段 1:节点准备(检查 + 修改系统)

k8s 对运行环境有一堆硬性要求,不满足就会在某个环节报莫名其妙的错。先做 7 项检查:

检查项 不满足的后果 实际情况
系统版本 安装命令不兼容 Ubuntu 26.04 ✅
CPU≥2核、内存≥2G kubeadm 预检直接拒绝 3.3G 勉强过(建议 4G+)
hostname 全小写 k8s 节点名规范,大写会被拒 已改 ✅
单网卡/确定用哪块 kubelet 选错 IP,节点互相找不到 ens33 ✅
节点互通、防火墙关闭 6443 等端口被拦,join 失败 ufw 已关 ✅
不直接用 docker 概念性要求

另外三件"提前修"的事:

  1. 关 swap:k8s 调度器需要根据内存精确决定 Pod 放哪台机器,swap 会让内存数据不准,所以强制要求关
  2. /etc/hosts 互写:内网主机名没有 DNS 解析,k8s 组件按名字找对方,必须手动告诉每台机器"谁是谁"
  3. 关防火墙:master/worker 之间要开十几个端口通信,学习阶段直接全关最省事

阶段 2:安装三大组件(每个节点都装)

text 复制代码
kubelet      → k8s 在每个节点上的"代理人",负责创建/管理 Pod
containerd   → 容器引擎,真正拉起容器(k8s 1.24 后官方不再支持 Docker,这是行业标准)
kubeadm      → 集群安装工具,master 用它 init,worker 用它 join
kubectl      → 管理命令行(只有操作集群的地方需要)

为什么 containerd 要改 SystemdCgroup = true

cgroup 是 Linux 限制进程资源(CPU/内存)的机制,有两套驱动(cgroupfs 和 systemd)。

kubelet 用 systemd 驱动,containerd 默认用 cgroupfs,两边不一致会导致资源限制失效、节点状态异常------这是必须对齐的配置。

为什么要开 br_netfilterip_forward

Pod 网络依赖 Linux 网桥和 IP 转发,默认没开,Calico 的虚拟网络会不通。

阶段 3:初始化 master(kubeadm init)

这一步做的事,用大白话说:

  1. 预检:把阶段 1 的所有条件再检查一遍
  2. 拉镜像 :apiserver、etcd、scheduler 等以容器形式运行(k8s 用容器管自己),从阿里云镜像站拉(默认地址国内拉不动)
  3. 发证书:集群内所有通信都要 TLS 加密,生成一整套 CA 和证书
  4. 写配置 :在 /etc/kubernetes/manifests/ 生成几个"静态 Pod 清单"------这是特殊机制:kubelet 启动时自动读取这个目录,把 apiserver、etcd 等拉起来。先有 kubelet 照清单拉容器,才有 apiserver,之后 kubelet 再听命于 apiserver
  5. 生成 join 门票:token + 证书哈希,worker 凭它加入集群

踩坑实录 ① :kubelet 拉 apiserver 容器前需要基础镜像 pause (每个 Pod 的"地基"),它写死了去 registry.k8s.io 拉------国内连不通。

解法:给镜像"换马甲"------从阿里云拉下来,tag 成官方地址,让 kubelet 误以为"本地已有"。

阶段 4:配置 kubectl + 安装网络插件

bash 复制代码
cp /etc/kubernetes/admin.conf ~/.kube/config   # 告诉 kubectl:集群地址+管理员凭据

为什么装完 Calico 节点才 Ready

k8s 只负责"调度 Pod 到某台机器",Pod 之间的虚拟网络是另一层(CNI 插件)负责的。

没装网络插件时,节点网络状态未就绪,所以一直 NotReady。

Calico 就是给所有 Pod 发虚拟 IP、打通跨节点通信的"交换机系统"。

为什么 Pod 网段必须是 10.100.0.0/16

物理网络是 192.168.152.x,Calico 默认的 192.168.0.0/16 会和它重叠------路由表分不清"去物理机的 192.168.152.5"还是"去 Pod 的 192.168.x.x",网络直接瘫痪。

所以必须改成不冲突的网段,并且 kubeadm 和 Calico 配置两边要一致

踩坑实录 ② :Calico 镜像在 docker.io,国内拉不动。

解法 :给 containerd 配镜像加速(/etc/containerd/certs.d/docker.io/hosts.toml),相当于给它一个"国内中转站"地址。

阶段 5:worker 加入(kubeadm join)

text 复制代码
worker: "我要加入"(出示 token 门票)
  ↓
master 的 apiserver 验证门票 → 批准
  ↓
worker 的 kubelet 自动向 master 申请正式证书(TLS Bootstrap)
  ↓
worker 成为集群一员,master 开始给它派活

worker 上为什么不用配 kubectl :它只是干活的,管理权在 master。

在 worker 上执行 kubectl 报错连 localhost:8080,就是因为它压根没有管理员凭据。

阶段 6:验证

部署一个 nginx,本质是验证三层:

  1. 调度:scheduler 把 Pod 放到某台节点
  2. 网络:浏览器 → master IP:NodePort → kube-proxy 转发 → Pod(跨节点则验证了 Calico 隧道)
  3. 生态:镜像拉取(daocloud 加速)、DNS(coredns)都工作

三、一句话总结整个流程

备好环境(主机名/IP/网络)→ 每台装 kubelet+containerd → master 上 init 建集群 → 装 Calico 让 Pod 通网 → worker 拿 token join → 部署应用验证。

二、Kubernetes 集群搭建命令手册(Ubuntu 26.04 + k8s 1.30.14)

环境约定

  • Master: 192.168.152.135 (chn-k8s-master)
  • Worker: 192.168.152.136 (chn-k8s-worker)
  • k8s 版本: v1.30.14
  • Pod 网段: 10.100.0.0/16
  • 标注【双节点】= master 和 worker 都执行

阶段 1:节点准备【双节点】

bash 复制代码
# 1.1 修改主机名(两台分别执行,改完 exec bash 刷新)
sudo hostnamectl set-hostname chn-k8s-master        # master
sudo hostnamectl set-hostname chn-k8s-worker        # worker
exec bash

# 1.2 静态 IP(worker 换成 192.168.152.136)
sudo nmcli con mod "netplan-ens33" ipv4.method manual ipv4.addresses 192.168.152.135/24 ipv4.gateway 192.168.152.2 ipv4.dns "114.114.114.114 8.8.8.8"
sudo nmcli con down "netplan-ens33" && sudo nmcli con up "netplan-ens33"

# 1.3 关防火墙 / 1.4 关 swap
sudo ufw disable
sudo swapoff -a
sudo sed -i '/swap/s/^/#/' /etc/fstab

# 1.5 hosts 互解析(双节点都执行;先替换旧主机名)
sudo sed -i 's/chn-k8s-master-VMware-Virtual-Platform/chn-k8s-master/' /etc/hosts
sudo sed -i 's/chn-k8s-worker-VMware-Virtual-Platform/chn-k8s-worker/' /etc/hosts
echo -e "192.168.152.135  chn-k8s-master\n192.168.152.136  chn-k8s-worker" | sudo tee -a /etc/hosts

# 1.6 验证: hostname / ip a (无dynamic) / ping 对端主机名

阶段 2:安装组件【双节点】

bash 复制代码
# 2.1 containerd
sudo apt update && sudo apt install -y containerd
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd && sudo systemctl enable containerd

# 2.2 内核模块与参数
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay && sudo modprobe br_netfilter
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

# 2.3 kubelet/kubeadm/kubectl(阿里云源)
sudo apt install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.30/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://mirrors.aliyun.com/kubernetes-new/core/stable/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt update
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
sudo systemctl enable kubelet

# 2.4 镜像预处理(国内防坑)
sudo ctr -n k8s.io images pull registry.aliyuncs.com/google_containers/pause:3.10.1
sudo ctr -n k8s.io images tag registry.aliyuncs.com/google_containers/pause:3.10.1 registry.k8s.io/pause:3.10.1

sudo mkdir -p /etc/containerd/certs.d/docker.io
sudo tee /etc/containerd/certs.d/docker.io/hosts.toml <<'EOF'
server = "https://docker.io"
[host."https://docker.m.daocloud.io"]
  capabilities = ["pull", "resolve"]
EOF
sudo sed -i "s#config_path = ''#config_path = '/etc/containerd/certs.d'#" /etc/containerd/config.toml
sudo systemctl restart containerd

阶段 3:初始化 Master【仅 master】

bash 复制代码
sudo kubeadm init \
  --kubernetes-version=v1.30.14 \
  --image-repository registry.aliyuncs.com/google_containers \
  --apiserver-advertise-address=192.168.152.135 \
  --pod-network-cidr=10.100.0.0/16

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

阶段 4:Calico 网络插件【仅 master】

bash 复制代码
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/calico.yaml
sed -i -e 's/^            # - name: CALICO_IPV4POOL_CIDR/            - name: CALICO_IPV4POOL_CIDR/' \
       -e 's/^            #   value: "192.168.0.0\/16"/              value: "10.100.0.0\/16"/' calico.yaml
grep -A1 CALICO_IPV4POOL_CIDR calico.yaml
kubectl apply -f calico.yaml
watch kubectl get pods -n kube-system
kubectl get nodes    # Ready

阶段 5:Worker 加入【仅 worker】

bash 复制代码
sudo kubeadm join 192.168.152.135:6443 --token <token> \
    --discovery-token-ca-cert-hash sha256:<hash>
# 重新生成: master 上执行 kubeadm token create --print-join-command

阶段 6:验证【master】

bash 复制代码
kubectl get nodes
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get svc nginx
curl http://192.168.152.135:3xxxx
kubectl delete deployment nginx && kubectl delete svc nginx

维护与排错

bash 复制代码
sudo kubeadm reset -f && rm -rf $HOME/.kube     # 重置集群
kubectl get pods -A                              # 谁不正常
kubectl describe pod <pod> -n <ns> | tail -20    # 看 Events
kubectl logs <pod> -n <ns>                       # 看日志
相关推荐
fb_123451 小时前
Docker入门-第3章-容器镜像深度解析
运维·docker·容器
IT摆渡者3 小时前
基于 Docker 部署 Nextcloud 私有云盘(外挂 Windows 共享)项目实践
运维·docker·容器
Jeromefromhk3 小时前
我把所有服务搬上 Kubernetes,又全部搬了回来
kubernetes·devops
墨香幽梦客4 小时前
Kubernetes+Istio实现CRM系统弹性伸缩:服务网格下的流量治理与熔断策略
容器·kubernetes·istio
新时代牛马4 小时前
单机 docker run 管不住了?从编排需求、期望状态到调度/自愈闭环讲透
运维·docker·容器
binqian5 小时前
Docker Desktop(WSL2 后端)三层网络互通技术文档
网络·docker·容器
金色熊族5 小时前
windows11 + wsl2 上安装ubuntu20.04
ubuntu·windows11·wsl2
WX _ jishuwu19906 小时前
esmfold gpu模式 批量预测蛋白三级结构实况记录 - 供参考
人工智能·ubuntu·三代测序·亚细胞定位,·deeploc·protcompv9
闲云野鹤在人间6 小时前
Docker入门|第1章 容器生态系统完整解析
运维·服务器·docker·容器·centos