Kubernetes v1.24.17 全离线部署实战(Containerd + Calico)
适用环境:CentOS 7.9 / Rocky Linux 7.9 |容器运行时:Containerd |网络插件:Calico
架构:1 Master + 2 Node |模式:全离线(Air-Gap)
目录
📖 一、 什么是 Kubernetes (K8s)?
1. 基础定义
2. 它有什么用?
📌 前言
🛠️ 第一阶段:所有节点通用系统初始化(Master + Node1 + Node2)
1. 设置主机名与 Hosts 解析
2. 关闭防火墙与 SELinux
3. 关闭 Swap
4. 加载内核模块与网络参数
5. 时间同步与时区设置
📦 第二阶段:所有节点部署 Containerd**(Master + Node1 + Node2)**
1. 解压离线包并安装 Containerd
2. 配置 Containerd
3. 启动并验证服务
4. 导入离线镜像(核心步骤)
5.确认containerd健康
⚙️ 第三阶段:所有节点安装 K8s 核心组件
1. 导入安装 kubeadm, kubelet, kubectl
2. 版本一致性校验
🚀 第四阶段:仅在 Master 节点初始化集群
1. 清理旧环境(如果是重装)
2. 执行 kubeadm init
3. 配置 kubectl 凭证
4. 验证控制平面
5. 移除 Master 污点 (可选,方便单节点测试)
6. 部署 Calico 网络插件
7. 验证 Master 节点状态
➕ 第五阶段:Worker 节点加入集群
1. 在 Master 生成 Token
2. 在 Node 节点执行 Join 命令
🎉 第六阶段:集群验证与测试
1. 查看节点状态
2. 检查系统 Pod
3. 创建测试 Pod 验证网络
⚠️ 避坑指南(小白必看)
📝 总结
📖 一、 什么是 Kubernetes (K8s)?
在开始部署之前,我们需要先搞清楚:K8s 到底是什么?它能干什么?
1. 基础定义
Kubernetes(简称 K8s,K 和 s 之间有 8 个字母)是一个开源的容器编排引擎。
如果把 Docker 比作“集装箱卡车”(负责运行应用),那么 Kubernetes 就是“港口调度系统”(负责管理成千上万辆卡车)。
2. 它有什么用?
在微服务时代,应用被拆分成无数个小容器。如果没有 K8s,你需要手动去每台服务器启动、停止、重启容器。
K8s 的核心价值在于:
- 自动化部署与回滚:一键发布新版本,出问题自动回退。
- 服务发现与负载均衡:自动分配 IP 和 DNS 名称,流量自动分摊。
- 自我修复:某个容器挂了,K8s 会自动拉起一个新的,保证服务不中断。
- 弹性伸缩:流量大了自动增加容器数量,流量小了自动减少,节省资源。
📌 前言
在生产环境中,服务器往往无法直接访问互联网。本文档记录了从零开始,在完全离线的环境下部署一套高可用、稳定的 Kubernetes v1.24.17 集群的全过程。
集群规划
| IP 地址 | 主机名 | 角色 |
|---|---|---|
| 192.168.30.153 | k8s-master | Master 节点 |
| 192.168.30.154 | k8s-node1 | Worker 节点 |
| 192.168.30.155 | k8s-node2 | Worker 节点 |
**准备工作
**请提前下载好离线包k8s-offline-full.tar.gz,并上传至三台服务器的/root目录。
🛠️ 第一阶段:所有节点通用系统初始化(Master + Node1 + Node2)
注意:以下命令需要在三台机器上分别执行。
1. 设置主机名与 Hosts 解析
**设置主机名
**根据规划,分别设置每台机器的主机名。
# 在 192.168.30.153 上执行 hostnamectl set-hostname k8s-master # 在 192.168.30.154 上执行 hostnamectl set-hostname k8s-node1 # 在 192.168.30.155 上执行 hostnamectl set-hostname k8s-node2**配置 Hosts 文件
**在三台机器上执行相同的命令,确保节点间可以通过主机名互相访问。
cat >> /etc/hosts << EOF 192.168.30.153 k8s-master 192.168.30.154 k8s-node1 192.168.30.155 k8s-node2 EOF**验证解析
**执行以下脚本,确保输出结果中所有项均为✓ 成功。
for node in k8s-master k8s-node1 k8s-node2; do echo "=== 测试节点: $node ===" echo -n "主机名解析: " if ping -c 1 -W 1 $node >/dev/null 2>&1; then echo "✓ 成功"; else echo "✗ 失败"; fi ip=$(grep "$node" /etc/hosts | awk '{print $1}') echo "对应 IP: $ip" echo -n "IP 连通性: " if ping -c 1 -W 1 $ip >/dev/null 2>&1; then echo "✓ 成功"; else echo "✗ 失败"; fi echo -n "hosts 记录: " grep "$node" /etc/hosts || echo "未找到" echo "" done #额外验证:反向测试 for ip in 192.168.30.153 192.168.30.154 192.168.30.155; do echo -n "连接到 $ip: " if ping -c 1 -W 1 $ip >/dev/null 2>&1; then echo "✓ 可达" else echo "✗ 不可达" fi done #检验主机名唯一性 for node in k8s-master k8s-node1 k8s-node2; do printf "%-15s %-20s " "$node" "$(grep $node /etc/hosts | awk '{print $1}')" if ping -c 1 -W 1 $node >/dev/null 2>&1; then echo "✓ 连通正常" else echo "✗ 无法连通" fi done echo "hosts 文件配置验证:" cat /etc/hosts | grep -E "k8s-master|k8s-node1|k8s-node2"2. 关闭防火墙与 SELinux
为了避免网络拦截和权限问题,我们需要关闭防火墙和 SELinux。
# 关闭防火墙 systemctl stop firewalld systemctl disable firewalld # 临时关闭 SELinux setenforce 0 # 永久关闭 SELinux(重启生效) sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config3. 关闭 Swap
Kubernetes 官方强烈建议关闭 Swap 分区以获得更好的性能。
# 临时关闭 swapoff -a # 永久关闭(注释掉 fstab 中的 swap 行) sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab4. 加载内核模块与网络参数
配置网络桥接和流量转发,这是 K8s 网络工作的基础。
# 加载模块 modprobe br_netfilter modprobe overlay # 写入永久配置 cat > /etc/sysctl.d/k8s.conf << EOF net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF # 使配置立即生效 sysctl --system5. 时间同步与时区设置
集群内时间必须一致,误差不能超过几秒。
# 启动并设置开机自启 chronyd 服务 systemctl start chronyd systemctl enable chronyd # 设置时区为上海 timedatectl set-timezone Asia/Shanghai # 查看状态(关键指标 NTP synchronized: yes) timedatectl status /#方法一:使用 chronyc 检查(推荐) # 1. 查看时间同步源 chronyc sources -v # 2. 查看时间同步状态(核心指标) chronyc tracking /#方法二:使用 timedatectl 检查 #这个命令可以一眼看出系统时钟是否已同步。 timedatectl status #验证要点(必须全部满足): #NTP enabled: yes #NTP synchronized: yes #(这是最关键的指标,表示已成功同步) #System clock synchronized: yes #Time zone: Asia/Shanghai #RTC in local TZ: no #(建议设为 no,避免双系统时间错乱)**集群时间一致性校验
**在 Master 节点执行,确保所有节点时间一致:
/# 方法三:集群内多节点一致性校验(For 循环) for node in k8s-master k8s-node1 k8s-node2; do echo -n "$node 时间: " ssh $node "date '+%Y-%m-%d %H:%M:%S'" done📦 第二阶段:所有节点部署 Containerd**(Master + Node1 + Node2)**
注意:以下命令需要在三台机器上分别执行。
1. 解压离线包并安装 Containerd
cd /root tar -xvzf k8s-offline-full.tar.gz cd /root/k8s-offline/rpms/ # 使用 yum localinstall 解决依赖关系 yum localinstall -y containerd.io-1.6.21-3.1.el7.x86_64.rpm container-selinux-2.119.2-1.911c772.el7_8.noarch.rpm # 验证版本 rpm -qa | grep containerd containerd --version2. 配置 Containerd
这是离线部署最容易出错的地方,请务必仔细核对。
# 生成默认配置文件 mkdir -p /etc/containerd containerd config default > /etc/containerd/config.toml # 关键修改1: 将 cgroup 驱动改为 systemd(K8s 推荐) sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml # 关键修改2: 指定本地 pause 镜像(注意版本号必须与离线包内的 pause 镜像一致) sed -i 's#sandbox_image = ".*"#sandbox_image = "registry.k8s.io/pause:3.7"#g' /etc/containerd/config.toml # 验证修改是否生效 grep -E "SystemdCgroup|sandbox_image" /etc/containerd/config.toml3. 启动并验证服务
systemctl daemon-reload systemctl restart containerd systemctl enable containerd # 检查状态 grep -E "SystemdCgroup|sandbox_image" /etc/containerd/config.toml # 应看到 SystemdCgroup = true 和 sandbox_image ="registry.k8s.io/pause:3.7"4. 导入离线镜像(核心步骤)
注意:K8s 使用的是k8s.io命名空间,不是默认的default。
# 导入基础镜像(包含 pause, kube-proxy 等) ctr -n k8s.io images import /root/k8s-offline/k8s-base-images.tar # 导入 Calico 网络插件镜像 ctr -n k8s.io images import /root/k8s-offline/calico-images.tar # 验证镜像列表 ctr -n k8s.io images list5.确认containerd健康
- 确认 containerd 健康状态
在所有节点(Master 和 Node)上完成 containerd 部署后,首先需要验证其运行状态。
- **检查服务状态 **执行以下命令,确认服务处于
active (running)状态。
systemctl status containerd- **检查版本信息 **执行以下命令,确认能正常显示客户端(client)和服务端(server)的版本信息。
ctr version # 能看到 client 和 server 版本所有节点做完后,下一步做什么
当你所有 master + node 都完成了 containerd 的部署,并且 systemctl status
containerd 都是 running 状态后:
- Master 节点执行 kubeadm init … 初始化集群
- Node 节点拿到 master 输出的 kubeadm join … 命令后执行,加入集群
- 在 master 上 kubectl get nodes 能看到 node 状态变成 Ready给小白的几个避坑提醒
⚙️ 第三阶段:所有节点安装 K8s 核心组件
注意:以下命令需要在三台机器上分别执行。
1. 导入安装 kubeadm, kubelet, kubectl
cd /root/k8s-offline/rpms yum localinstall -y \ kubernetes-cni-1.1.1-0.x86_64.rpm \ cri-tools-1.24.0-0.x86_64.rpm \ *kubelet-1.24.17*.rpm \ *kubeadm-1.24.17*.rpm \ *kubectl-1.24.17*.rpm # 设置 kubelet 开机自启(注意:此时 kubelet 尚未启动,等待 init/join 后才会真正运行) systemctl enable kubelet2. 版本一致性校验
确保三台机器的版本完全一致,避免诡异问题。
kubelet --version kubeadm version kubectl version --client预期输出:所有版本均为v1.24.17。
🚀 第四阶段:仅在 Master 节点初始化集群
注意:以下命令仅在
k8s-master(192.168.30.153) 上执行。
1. 清理旧环境(如果是重装)
如果是第一次安装,跳过此步;如果是重装,必须执行。
kubeadm reset -f iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X ipvsadm -C rm -rfv /etc/kubernetes /var/lib/etcd /var/lib/kubelet $HOME/.kube2. 执行 kubeadm init
kubeadm init \ --kubernetes-version=v1.24.17 \ --apiserver-advertise-address=192.168.30.153 \ --image-repository=registry.aliyuncs.com/google_containers \ --pod-network-cidr=10.244.0.0/16 \ --service-cidr=10.96.0.0/12 \ --node-name=k8s-master \ --cri-socket=unix:///run/containerd/containerd.sock3. 配置 kubectl 凭证
初始化成功后,按照终端提示执行以下命令:
mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config4. 验证控制平面
kubectl get pods -n kube-system预期输出:etcd、kube-apiserver、kube-controller-manager、kube-scheduler均为Running。
5.移除 Master 污点 (可选,方便单节点测试)
kubectl taint nodes k8s-master node-role.kubernetes.io/master-6. 部署 Calico 网络插件
由于是离线环境,我们已经有了calico.yaml文件。
# 应用 Calico 配置 kubectl apply -f /root/k8s-offline/calico.yaml #如果出错: rm -f /root/k8s-offline/calico.yaml wget https://docs.projectcalico.org/v3.25/manifests/calico.yaml -O /root/k8s-offline/calico.yaml # 监控 Pod 启动状态(等待几分钟) kubectl get pods -n kube-system -w直到calico-node-xxx和calico-kube-controllers-xxx全部变为Running。
7. 验证 Master 节点状态
kubectl get nodes预期输出:k8s-master状态变为Ready。
➕ 第五阶段:Worker 节点加入集群
注意:以下命令在Node1 和 Node2上执行。
1. 在 Master 生成 Token
如果刚才 Master 初始化时的命令丢了,可以在 Master 上重新生成:
kubeadm token create --print-join-command2. 在 Node 节点执行 Join 命令
重点:必须指定--cri-socket参数指向 containerd。
kubeadm join 192.168.30.153:6443 \ --token xxxxxx.xxxxxxxxxxxxxxxx \ --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \ --cri-socket=unix:///run/containerd/containerd.sock🎉 第六阶段:集群验证与测试
注意:以下命令在Master上执行。
1. 查看节点状态
等待几分钟,直到所有节点状态为Ready。
# Master 验证节点加入(两台 Worker 节点会自动调度 calico-node Pod,随后依次变为 Ready。) kubectl get nodes -w kubectl get nodes -o wide2. 检查系统 Pod
确保所有系统组件运行正常。
kubectl get pods -n kube-system3. 创建测试 Pod 验证网络
# 创建一个 Nginx Pod kubectl run test-nginx --image=nginx # 查看 Pod 是否运行及 IP 分配情况 kubectl get pods -o wide # 进入 Pod 测试网络(可选) kubectl exec -it test-nginx -- curl k8s-master:6443⚠️ 避坑指南(小白必看)
- Pause 镜像版本不一致:
config.toml里的sandbox_image版本必须与k8s-base-images.tar里的 pause 镜像版本严格一致(例如都是3.7),否则 Node 节点会一直NotReady。 - 镜像命名空间错误: 导入镜像时必须加
-n k8s.io。如果导入到了default,K8s 是找不到镜像的,会导致ImagePullBackOff。 - 忘记指定 CRI Socket: 在
kubeadm init和kubeadm join时,如果不指定--cri-socket,新版本 K8s 可能会尝试连接 Docker,导致报错。 - Swap 未关闭: 虽然可以通过参数忽略,但强烈建议物理关闭 Swap,否则可能引发 kubelet 异常。
K8s 核心学术名词解析
在 K8s 的学习和面试中,以下名词是必须掌握的“黑话”:
1. 架构组件类
- Master Node (控制平面):集群的大脑。包含 API Server(唯一入口)、Scheduler(调度器)、Controller Manager(管家)、etcd(数据库)。
- Worker Node (工作节点):干活的苦力。包含 Kubelet(接收指令)、Kube-proxy(网络代理)、Container Runtime(容器运行时)。
- Pod:K8s 的最小调度单位。一个 Pod 可以包含一个或多个容器(通常是 1 个),它们共享网络和存储。
- CNI (Container Network Interface):容器网络接口标准。Calico、Flannel 都是 CNI 插件的实现,负责给 Pod 分配 IP 并打通网络。
2. 控制器与工作负载类
- Deployment:最常用的控制器,用于管理无状态应用(如 Nginx)。它保证指定数量的 Pod 副本一直运行。
- DaemonSet:守护进程集。保证每个(或特定)节点上都运行一个 Pod 副本。常用于日志收集、监控代理、网络插件(如 Calico)。
- Service:服务发现。Pod 是 ephemeral(短暂的,IP 会变),Service 提供一个固定的 VIP(虚拟 IP)来访问一组 Pod。
3. 状态与策略类
- Ready:表示 Pod 已经准备好接收流量。
- CrashLoopBackOff:容器启动后立刻挂掉,K8s 正在尝试指数退避重启。通常是应用配置错误。
- ImagePullBackOff:拉取镜像失败。通常是镜像名写错、仓库没权限或离线环境没导入镜像。
- Taints & Tolerations (污点与容忍):
- 污点:节点说“我不喜欢这类 Pod,别往我这调度”。
- 容忍:Pod 说“我不介意那个污点,我就要去那个节点”。
- 实战应用:Master 节点默认有污点,不允许运行业务 Pod,除非你执行
kubectl taint nodes ...去除它。
📝 总结
至此,一个基于 Containerd、版本为 v1.24.17 的 Kubernetes 三节点集群已全部搭建完成。你可以开始在上面部署你的微服务应用了!
如果觉得这篇文章对你有帮助,请点赞收藏支持一下!如有问题,欢迎在评论区留言讨论。
