1. 离线K8S集群部署概述
在企业级生产环境中,出于安全合规或网络隔离要求,经常需要在完全离线的内网环境中部署Kubernetes集群。与常规在线安装相比,离线部署面临三大核心挑战:
- 依赖包完整性问题:需要预先下载所有相关软件包(包括系统依赖、容器运行时、K8S组件等)并确保版本兼容性
- 镜像分发难题:所有容器镜像(系统组件、网络插件、监控工具等)必须通过离线方式导入
- 配置复杂度高:缺乏互联网访问时,所有配置(如镜像仓库地址、网络参数等)必须手动指定
本次部署采用的技术栈为:
- Kubernetes v1.26(当前长期支持版本)
- Containerd作为容器运行时(已取代Docker成为K8S默认推荐)
- Calico v3.25作为网络插件(支持NetworkPolicy等高级功能)
- 三节点架构:1个master + 2个worker节点
2. 环境准备与系统配置
2.1 硬件资源规划
| 节点类型 | IP地址 | 主机名 | 最低配置要求 |
|---|---|---|---|
| Master | 192.168.10.100 | k8s-master | 2核CPU/4GB内存/50GB存储 |
| Worker1 | 192.168.10.101 | k8s-node1 | 4核CPU/8GB内存/100GB存储 |
| Worker2 | 192.168.10.102 | k8s-node2 | 4核CPU/8GB内存/100GB存储 |
关键提示:生产环境建议master节点配置不低于4核8GB,且采用奇数个master实现高可用
2.2 离线软件包准备
需提前下载以下软件包并传输到各节点:
bash复制# 基础依赖
conntrack-tools-1.4.4-7.el7.x86_64.rpm
socat-1.7.3.2-2.el7.x86_64.rpm
# K8S核心组件
kubeadm-1.26.0-0.x86_64.rpm
kubectl-1.26.0-0.x86_64.rpm
kubelet-1.26.0-0.x86_64.rpm
cri-tools-1.26.0-0.x86_64.rpm
kubernetes-cni-0.8.7-0.x86_64.rpm
# Containerd配置
containerd.io-1.6.9-3.1.el7.x86_64.rpm
下载技巧:
bash复制# 在有网络的机器上使用yum缓存功能
yum -y --downloadonly --downloaddir=./packages install conntrack-tools socat
2.3 系统基础配置
所有节点需执行以下配置:
bash复制# 设置主机名(分别在各节点执行)
hostnamectl set-hostname k8s-master # master节点
hostnamectl set-hostname k8s-node1 # node1节点
hostnamectl set-hostname k8s-node2 # node2节点
# 关闭防火墙和SELinux
systemctl stop firewalld && systemctl disable firewalld
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
# 关闭swap分区
swapoff -a
sed -i '/swap/s/^/#/' /etc/fstab
# 配置内核参数
cat <<EOF | tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
cat <<EOF | tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system
常见问题:若未关闭swap,kubelet服务将无法正常启动,报错"Failed to start kubelet: misconfiguration: kubelet cgroup driver: "systemd" is different from docker cgroup driver: "cgroupfs""
3. 容器运行时与K8S组件安装
3.1 Containerd安装与配置
bash复制# 安装containerd
rpm -ivh --nosignature --nodeps containerd.io-*.rpm
# 生成默认配置文件
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
# 修改关键配置
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sed -i 's|k8s.gcr.io|registry.cn-hangzhou.aliyuncs.com/google_containers|' /etc/containerd/config.toml
# 启动服务
systemctl enable containerd && systemctl start containerd
3.2 K8S组件安装
bash复制# 安装基础依赖
rpm -ivh conntrack-tools-*.rpm socat-*.rpm
# 解决libreadline兼容性问题
ln -sf /usr/lib64/libreadline.so.7 /usr/lib64/libreadline.so.8
echo 'export LD_PRELOAD=/usr/lib64/libreadline.so.8' >> /etc/profile
source /etc/profile
# 安装K8S组件
rpm -ivh kubelet-*.rpm kubectl-*.rpm kubeadm-*.rpm cri-tools-*.rpm kubernetes-cni-*.rpm
# 启动kubelet
systemctl enable kubelet && systemctl start kubelet
经验技巧:使用
rpm -ivh --nosignature --nodeps参数可避免签名验证导致的安装失败,适合离线环境
4. Master节点初始化
4.1 准备kubeadm配置文件
创建kubeadm-config.yaml:
yaml复制apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.10.100
bindPort: 6443
nodeRegistration:
criSocket: unix:///var/run/containerd/containerd.sock
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.26.0
imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers
networking:
serviceSubnet: 10.96.0.0/16
podSubnet: 192.169.0.0/16
4.2 初始化Master节点
bash复制# 预先拉取镜像(在可联网机器执行)
kubeadm config images pull --config=kubeadm-config.yaml
# 将镜像打包传输到离线环境后加载
ctr -n=k8s.io images import kube-apiserver.tar
ctr -n=k8s.io images import kube-controller-manager.tar
ctr -n=k8s.io images import kube-scheduler.tar
ctr -n=k8s.io images import kube-proxy.tar
ctr -n=k8s.io images import pause.tar
ctr -n=k8s.io images import etcd.tar
ctr -n=k8s.io images import coredns.tar
# 执行初始化
kubeadm init --config=kubeadm-config.yaml
初始化成功后,按照提示配置kubectl:
bash复制mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
4.3 重置技巧
若初始化失败需要重置:
bash复制kubeadm reset -f --cri-socket unix:///var/run/containerd/containerd.sock
rm -rf /etc/kubernetes /var/lib/kubelet /var/lib/etcd
crictl --runtime-endpoint unix:///var/run/containerd/containerd.sock rmi -a
systemctl restart containerd
5. Worker节点加入集群
5.1 准备工作
在所有worker节点执行:
bash复制# 添加master主机名解析
echo "192.168.10.100 k8s-master" >> /etc/hosts
# 确保containerd和kubelet已正确安装并运行
systemctl restart containerd && systemctl enable containerd
systemctl restart kubelet && systemctl enable kubelet
5.2 获取加入命令
在master节点查看加入令牌:
bash复制kubeadm token create --print-join-command
输出示例:
code复制kubeadm join 192.168.10.100:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:1234...cdef
5.3 执行加入操作
在worker节点运行上述命令:
bash复制kubeadm join 192.168.10.100:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:1234...cdef \
--cri-socket unix:///var/run/containerd/containerd.sock
排障提示:若token过期(默认24小时),在master节点执行
kubeadm token create --print-join-command生成新token
6. 网络插件部署
6.1 Calico离线安装
- 在有网络环境下载Calico镜像:
bash复制docker pull calico/cni:v3.25.0
docker pull calico/node:v3.25.0
docker pull calico/kube-controllers:v3.25.0
docker save -o calico-images.tar calico/cni:v3.25.0 calico/node:v3.25.0 calico/kube-controllers:v3.25.0
- 传输到离线环境后加载:
bash复制ctr -n=k8s.io images import calico-images.tar
- 修改calico.yaml关键配置:
yaml复制# 修改pod CIDR与kubeadm配置一致
- name: CALICO_IPV4POOL_CIDR
value: "192.169.0.0/16"
# 指定网卡名称(根据实际网卡修改)
- name: IP_AUTODETECTION_METHOD
value: "interface=eth.*"
- 部署Calico:
bash复制kubectl apply -f calico.yaml
6.2 网络验证
bash复制# 查看节点状态
kubectl get nodes -o wide
# 检查Calico Pod状态
kubectl get pods -n kube-system -l k8s-app=calico-node
# 测试网络连通性
kubectl run test-nginx --image=nginx --restart=Never
kubectl exec test-nginx -- curl -I http://www.google.com
7. 可选组件:Dashboard部署
7.1 离线镜像准备
bash复制# 在有网络环境下载
docker pull kubernetesui/dashboard:v2.7.0
docker pull kubernetesui/metrics-scraper:v1.0.8
docker save -o dashboard-images.tar kubernetesui/dashboard:v2.7.0 kubernetesui/metrics-scraper:v1.0.8
# 离线环境加载
ctr -n=k8s.io images import dashboard-images.tar
7.2 部署Dashboard
使用修改后的recommended.yaml:
yaml复制apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard
---
# 其余部分使用官方recommended.yaml内容
部署命令:
bash复制kubectl apply -f recommended.yaml
# 修改服务类型为NodePort
kubectl patch svc kubernetes-dashboard -n kubernetes-dashboard -p '{"spec":{"type":"NodePort"}}'
7.3 访问Dashboard
- 获取访问令牌:
bash复制kubectl -n kubernetes-dashboard create token admin-user
- 获取NodePort端口:
bash复制kubectl get svc -n kubernetes-dashboard
- 浏览器访问:
https://<node-ip>:<node-port>
安全提示:生产环境建议配置Ingress + TLS证书替代直接NodePort暴露
8. 运维与排障指南
8.1 常见问题排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| kubelet无法启动 | swap未关闭 | 执行swapoff -a并注释/etc/fstab中的swap行 |
| Pod一直处于Pending状态 | 网络插件未正确安装 | 检查Calico/kube-proxy Pod状态,确认podCIDR配置正确 |
| 节点NotReady | 容器运行时异常 | 检查containerd状态,执行crictl ps -a查看容器运行状态 |
| 镜像拉取失败 | 镜像仓库配置错误 | 检查/etc/containerd/config.toml中的mirrors配置 |
| 服务无法跨节点访问 | 网络策略限制 | 检查Calico NetworkPolicy,临时禁用测试kubectl delete networkpolicy --all |
8.2 关键维护命令
bash复制# 查看集群状态
kubectl get nodes -o wide
kubectl get pods -A -o wide
# 检查组件健康状态
kubectl get cs
# 查看事件日志
kubectl get events -A --sort-by='.metadata.creationTimestamp'
# 容器运行时诊断
crictl ps -a
crictl images
ctr -n k8s.io images list
# 服务暴露检查
kubectl get svc -A
kubectl get endpoints -A
8.3 备份与恢复建议
- 关键配置文件备份:
bash复制# etcd数据
cp -r /var/lib/etcd /backup/etcd
# kubeconfig
cp /etc/kubernetes/admin.conf /backup
# 网络插件配置
kubectl get -n kube-system cm/calico-config -o yaml > /backup/calico-config.yaml
- 使用etcdctl备份集群状态:
bash复制ETCDCTL_API=3 etcdctl \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot save /backup/etcd-snapshot.db
9. 生产环境优化建议
-
镜像仓库私有化:
- 部署Harbor作为私有仓库
- 配置containerd使用私有仓库:
toml复制[plugins."io.containerd.grpc.v1.cri".registry.mirrors] [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] endpoint = ["https://registry.example.com"]
-
节点高可用:
- 部署至少3个master节点
- 使用外部etcd集群
- 配置负载均衡器对接多个master节点
-
安全加固:
- 启用PodSecurityPolicy/PSA
- 配置NetworkPolicy限制Pod间通信
- 定期轮换证书(kubeadm certs renew)
-
监控告警:
- 部署Prometheus-Operator
- 配置NodeExporter监控主机指标
- 设置关键指标告警(节点NotReady、Pod崩溃等)
-
日志收集:
- 部署EFK/ELK栈
- 配置Fluentd收集容器日志
- 设置日志保留策略
10. 版本升级策略
离线环境升级需特别注意:
-
准备阶段:
bash复制# 在有网络环境下载新版本rpm包和镜像 yum -y --downloadonly --downloaddir=./kube1.27 install kubeadm-1.27 kubelet-1.27 kubectl-1.27 kubeadm config images list --kubernetes-version v1.27.0 -
升级master节点:
bash复制# 升级kubeadm rpm -Uvh kubeadm-1.27*.rpm # 执行升级计划 kubeadm upgrade plan kubeadm upgrade apply v1.27.0 -
升级worker节点:
bash复制# 逐个节点执行 kubectl drain <node> --ignore-daemonsets rpm -Uvh kubelet-1.27*.rpm kubectl-1.27*.rpm systemctl restart kubelet kubectl uncordon <node>
重要提示:升级前务必完整备份etcd数据,并在测试环境验证升级流程