ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Kubernetes离线部署实战:基于kubeadm与私有镜像仓库的完整指南

Kubernetes离线部署实战:基于kubeadm与私有镜像仓库的完整指南 1. 离线部署的整体思路与方案选型说实话看到这个标题我就感觉是个常见的不能再常见的需求开发测试环境部署Kubernetes但网络环境受限不能直接从公网拉取镜像和软件包。很多团队第一次碰这个场景都会懵因为常规的kubeadm引导流程默认就是去外网下载一堆东西离线环境一上来就卡在第一步。这篇指南基于我实际搭建过的离线开发测试环境全程走的是“能联网机器打包、内网机器导入”的经典路线核心思路一句话在外面把Kubernetes集群运行所需的全部软件包、容器镜像、配置文件一次性备齐然后通过移动介质或内网通道搬运到目标机器最后用本地私有仓库作为镜像来源完成集群初始化。先说一下为什么开发测试环境要单独做离线部署。绝大多数情况是安全要求——测试环境往往部署在隔离网段不能随便访问公网还有一种是生产机房在偏远地区或者客户现场带宽和访问条件都不理想。不管哪种原因离线部署的痛点其实是相通的镜像拉不下来kubeadm初始化直接卡死软件包依赖缺失安装kubelet和containerd的时候报错一串内网没有DNS镜像仓库地址解析不了版本没锁定后来补装组件时和关键组件版本对不上。很多新手误以为离线部署就是把镜像打成一个tar包带进去其实这只是三分之一的工作。真正的离线部署要解决三件事软件仓库离线化rpm/deb包、镜像仓库离线化所有组件镜像、配置和依赖离线化内核参数、模块、hosts映射、导入脚本。这三个维度缺一个后面都会踩坑。在实际的方案选型上我把目前主流的几种离线部署方式拉了个对比方便你做决定方案安装方式离线友好度适用场景备注kubeadm 私有镜像仓库官方原生工具中高需手动准备资源单集群、中小规模、开发测试灵活可控最接近生产部署方式二进制手动部署手动配置所有组件高全离线学习、极端精简环境工作量最大不建议生产或测试集群用sealos一条命令集群高自带离线包快速交付、多集群版本匹配自动化但底层细节黑盒较多KubesprayAnsible自动化中高需离线缓存大规模、多节点对运维人员要求较高适合批量部署我这套指南选择的是kubeadm方案主要原因有三个一是它本身就被官方支持和后续的证书轮换、升级、节点管理兼容性最好二是开发测试环境后面大概率要模拟生产行为kubeadm的集群结构和生产基本一致三是排错容易所有的细节都暴露在日志里对团队学习Kubernetes本身也有帮助。既然锁定了kubeadm方案接下来的每一节都会围绕“内网里需要一个完整的镜像来源”这个核心来展开。你做完这套流程后手里的产出物就是一套可重复使用的离线部署工具包下次再搭新集群时只需拷贝过去直接执行效率会高很多。补充一下开发测试环境还有一个隐藏需求要能够随时推倒重建。配合离线包就能做到什么网络环境都不怕把集群弄坏了直接重新初始化所以整套导入脚本和配置文件我都建议做成幂等的、可重复执行的这在实际体验中会救你很多次命。2. 离线资源准备版本规划与镜像清单整理2.1 锁定版本组合避免“能装但跑不起来”离线部署最怕的就是“临时找版本凑合”因为环境一旦隔离后面任何组件想升级都费劲。所以在动手之前我强烈建议先定好一套经过验证的版本组合把每个组件的版本号钉死。以我最近搭的一套开发测试环境为例版本组合如下组件版本说明Kubernetesv1.28.15稳定版社区支持周期内containerd1.7.20当前开发测试环境的主流容器运行时runc1.1.12含在containerd依赖中calicov3.27.3网络插件功能完善排错资料多corednsv1.10.1随kubeadm默认集群内DNSetcd3.5.12随kubeadm默认集群存储metrics-serverv0.6.4开发测试环境看资源监控必备这个组合我实际验证过kubeadm、containerd、calico三者兼容性很好没有遇到奇奇怪怪的坑。如果你打算用更新的Kubernetes版本比如v1.29、v1.30也是可以的但记得要一起核对containerd和calico对那个版本的兼容性。适合固定下来的版本组合一定是“经过验证的组合”不要单点追新。版本锁定之后第一步就是把Kubernetes相关的二进制包、依赖包全部拉下来。在能联网的机器上通过阿里云镜像源或其他公网镜像源把软件包下载到本地。2.2 离线资源的三类清单我习惯把离线包分为三类来整理这样思路清晰后面出问题也好排查。第一类系统软件包与Kubernetes二进制包对于CentOS/RHEL系统需要准备kubeadm、kubelet、kubectl的rpm包或deb包取决于发行版containerd.io、runc的rpm包cri-tools包含了crictl命令调试容器运行时用得到下载方式通常是通过yum/dnf把rpm包缓存下来。如果你是Ubuntu/Debian系统就把deb包和依赖一起下载好。关键是所有依赖都要齐全最好直接用yumdownloader或者apt-get download把所有依赖一并抓下来少一个包后面就会抓瞎。第二类系统基础配置这部分经常被忽略但在离线环境里特别重要。因为内网目标机器往往没有配置软件源或者系统刚初始化完连基础工具都不全。/etc/hosts映射把所有集群节点的IP和主机名映射写进去内核参数sysctl.conf中需要开启的net.bridge.bridge-nf-call-iptables等内核模块overlay、br_netfilter等Kubernetes运行必需的模块软件源配置如果内网有镜像源服务器提前把repo文件准备好如果没有至少把基础工具链都装齐第三类容器镜像这是离线部署最耗时、最占容量、最容易出错的部分。Kubernetes集群本身运行需要一组基础镜像加上网络插件、存储插件、DNS组件和辅助工具数量不少。以下是核心镜像清单以v1.28.15为例# Kubernetes 核心组件registry.k8s.io 官方镜像 registry.k8s.io/kube-apiserver:v1.28.15 registry.k8s.io/kube-controller-manager:v1.28.15 registry.k8s.io/kube-scheduler:v1.28.15 registry.k8s.io/kube-proxy:v1.28.15 registry.k8s.io/coredns/coredns:v1.10.1 registry.k8s.io/etcd:3.5.12-0 registry.k8s.io/pause:3.9 # 网络插件Calico docker.io/calico/cni:v3.27.3 docker.io/calico/node:v3.27.3 docker.io/calico/kube-controllers:v3.27.3 # 监控插件Metrics Server registry.k8s.io/metrics-server/metrics-server:v0.6.4注意不同Kubernetes版本的组件镜像tag会有些差异比如pause版本从3.8到3.9etcd从3.5.10到3.5.12这些通常在kubeadm init之后才能发现。我的技巧是在联网机器上先执行一次kubeadm init失败也没关系或者使用kubeadm config images list查看所需镜像列表用这条命令直接获得当前版本的镜像清单然后一次性拉取。命令用起来非常简单kubeadm config images list --kubernetes-versionv1.28.15这条命令会把kubeadm初始化时需要的所有镜像名和tag列得清清楚楚是离线准备阶段省时间的好帮手。同理calico和metrics-server的所需镜像也提前在yaml文件里能看到直接照着拉即可。另外记得给每个节点预留足够的磁盘空间。一套最小化开发测试集群的核心镜像大概需要3-4GB加上Jupyter、Redis、MySQL这类测试应用的镜像会更多建议在所有节点上确保根分区剩余容量至少有20GB。2.3 传输方式不要只依赖一种通道离线包准备好之后还有一个被低估的环节怎么把资源传送到内网机器。我见过很多团队在这一点上浪费时间比如U盘在服务器上不识别或者共享目录权限配错折腾半天。实用的传输方式有三种内网共享目录NFS、Samba适合有共享存储或文件服务器的场景一次性放置所有节点都能直接访问。移动介质U盘、移动硬盘适合节点数量少的场景但要注意格式Linux服务器最好用exFAT或ext4NTFS有时会有权限问题。HTTP文件服务如果内网有Web服务器把离线包放在某个目录下节点用wget下载这是节点多时的最佳方案。我一般采用的是第三种在一台“跳板机”上起一个极简的HTTP服务cd /data/k8s-offline python3 -m http.server 8080其他节点就能直接wget http://192.168.50.10:8080/k8s-offline.tar.gz简单高效不用纠结NFS权限的问题。这种方式在批量初始化20台节点的时候特别省事。3. 私有镜像仓库搭建与镜像同步3.1 为什么不能直接用tar包导入本地镜像很多新手会问“既然kubelet本身有containerd为什么不直接把镜像load到每个节点的本地非要搭一个私有仓库”答案很简单Kubernetes调度是动态的Pod可能被调度到任意一个节点上如果每个节点都预先load一遍镜像不仅浪费时间而且像DaemonSet这类组件更新镜像时你根本没法自动同步到全部节点。在Kubernetes里镜像必须通过统一的镜像仓库来分发节点按需拉取。所以离线部署Kubernetes一定要有一个内网私有镜像仓库。开发测试环境规模不大我建议直接用Harbor虽然它本身比较复杂但胜在稳定可靠而且自带Web UI开发同学也能直观看到有哪些镜像。如果你只想快速验证用registry:2也可以但没有UI管理和排错都不太方便。3.2 搭建Harbor私有仓库离线版Harbor本身的安装包是离线友好的官网提供一个包含所有依赖的离线安装包你在联网机器上下载好传到内网的仓库服务器上解压安装即可。安装过程大致如下# 下载 Harbor offline installer例如 v2.10.0 wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz # 解压并修改配置文件 tar xzvf harbor-offline-installer-v2.10.0.tgz cd harbor cp harbor.yml.tmpl harbor.yml # 编辑 harbor.yml重点是 hostname 和 harbor_admin_password vi harbor.ymlharbor.yml里必改的几项hostname: 设为内网机器的IP或域名建议直接用IP开发测试环境配DNS不值当harbor_admin_password: 改成你自己的强密码http.port: 默认80建议改成18080这类高位端口避免和业务冲突改好后直接跑./install.shHarbor默认会自带docker registry、chartmuseum和数据库等组件安装完成后它自己会拉取一组镜像来启动这些服务。所以确保这台仓库服务器至少有外网或能手动导入镜像的能力。实在不行就在联网机器上装好Harbor把Harbor容器镜像save出来带到内网load进去。这个过程比较繁琐但一次性做完就一劳永逸。3.3 镜像同步的三种姿势镜像准备好、Harbor也启动后接下来就是把所有离线镜像推送到私有仓库。这一步有几种做法我逐个说一下。方式一全手动 docker/nerdctl 命令最直观适合镜像少的情况在联网机器上# 拉取镜像 docker pull registry.k8s.io/kube-apiserver:v1.28.15 # 打上内网仓库的tag docker tag registry.k8s.io/kube-apiserver:v1.28.15 192.168.50.10:18080/library/kube-apiserver:v1.28.15 # 推送到内网仓库 docker push 192.168.50.10:18080/library/kube-apiserver:v1.28.15这个方式简单但镜像一多就痛苦。如果你用的是containerd而没装docker可以用nerdctl命令用法和docker几乎一样。方式二save/load批量搬运最稳妥这是我最推荐的方式。在联网机器上把所有镜像导出成一个tar文件带到内网再load进来# 打包一次打包所有镜像 docker save -o k8s-images-v1.28.15.tar \ registry.k8s.io/kube-apiserver:v1.28.15 \ registry.k8s.io/kube-controller-manager:v1.28.15 \ registry.k8s.io/kube-scheduler:v1.28.15 \ registry.k8s.io/kube-proxy:v1.28.15 \ registry.k8s.io/coredns/coredns:v1.10.1 \ registry.k8s.io/etcd:3.5.12-0 \ registry.k8s.io/pause:3.9 \ docker.io/calico/cni:v3.27.3 \ docker.io/calico/node:v3.27.3 \ docker.io/calico/kube-controllers:v3.27.3到了内网仓库机器上docker load -i k8s-images-v1.28.15.tar然后批量打tag和push。这里可以用一个简单的shell循环for img in kube-apiserver kube-controller-manager kube-scheduler kube-proxy; do docker tag registry.k8s.io/$img:v1.28.15 192.168.50.10:18080/library/$img:v1.28.15 docker push 192.168.50.10:18080/library/$img:v1.28.15 done方式三skopeo直接复制适合跨架构或处理大镜像skopeo是一个不用启动docker daemon就能复制镜像的工具它绕过了docker的中间层在处理大镜像时更稳定、速度也更快。skopeo copy docker://registry.k8s.io/kube-apiserver:v1.28.15 docker://192.168.50.10:18080/library/kube-apiserver:v1.28.15 --dest-creds admin:YourPassword经过这三种方式中的任意一种你的Harbor仓库里就有了Kubernetes集群需要的全套镜像。后面的kubeadm初始化、calico安装、metrics-server部署都直接指向这个内网地址不再依赖外网。一个小建议把镜像清单和对应的脚本一并保存下来做成shell脚本文件sync-images.sh。这样以后新增节点、重建集群的时候直接跑脚本就能确保镜像同步完整不用手工一条条敲命令。4. kubeadm离线安装集群从节点准备到集群初始化4.1 节点基础准备所有节点都要做在初始化之前先把所有节点的系统环境统一调好。这一步偷懒后面必然会出幺蛾子。我整理了检查清单1. 主机名和hosts解析hostnamectl set-hostname k8s-master01 # 编辑 /etc/hosts 添加所有节点 cat EOF /etc/hosts 192.168.50.10 k8s-master01 192.168.50.11 k8s-node01 192.168.50.12 k8s-node02 EOF开发测试环境主机名建议直接按角色起名后面模拟生产环境、做权限控制都方便。2. 关闭swap和SELinuxswapoff -a sed -i /swap/s/^/#/ /etc/fstab setenforce 0 sed -i s/^SELINUXenforcing/SELINUXpermissive/ /etc/selinux/configKubernetes 1.8以后对swap的态度越来越严格虽然新版已经放开了一部分NodeSwap但开发测试环境还是尽量关掉免得碰到莫名其妙的性能问题。3. 加载内核模块cat EOF | tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF modprobe overlay modprobe br_netfilter4. 配置内核参数cat EOF | 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 vm.swappiness 0 EOF sysctl --system这几个参数不配好最明显的表现就是Calico的Pod一直创建不起来或者集群内Pod互相访问不通。我见过有同事跳过了br_netfilter结果Calico状态显示running但实际上Pod间通信全挂。5. 安装containerd并修改镜像加速配置装好containerd后最关键的是修改配置文件里的sandbox镜像地址。因为默认的pause镜像地址是registry.k8s.io/pause:3.9在内网环境必须改成你自己的私有仓库地址。mkdir -p /etc/containerd containerd config default | tee /etc/containerd/config.toml然后编辑/etc/containerd/config.toml把这段[plugins.io.containerd.grpc.v1.cri] sandbox_image registry.k8s.io/pause:3.9改成sandbox_image 192.168.50.10:18080/library/pause:3.9还要检查SystemdCgroup是否为true对开发测试环境来说这个配置影响资源隔离稳定性直接设成true是对的[plugins.io.containerd.runtime.v1.linux] runtime_type io.containerd.runc.v2 [plugins.io.containerd.cri.cri] systemd_cgroup true改完重启containerdsystemctl restart containerd systemctl enable containerd4.2 安装kubeadm/kubelet/kubectl这一步在离线环境里就是在本地软件包目录下执行安装。CentOS上用rpm -ivh或者配置好本地repo后yum install。我建议把这几个包放在同一个目录下然后用一条命令搞定rpm -ivh kubeadm-1.28.15*.rpm kubelet-1.28.15*.rpm kubectl-1.28.15*.rpm cri-tools*.rpm如果有依赖顺序问题就多执行一次。装的时候注意版本号我见过有人把kubelet装成比kubeadm高很多的小版本一跑就报KubeletVersion不一致的错误。安装完后先启动kubelet这时候它会因为没有配置文件而处于failed状态这是正常的不用慌systemctl enable kubelet systemctl start kubelet # 此时状态可能是 activating (auto-restart)没关系kubeadm init 后它会正常4.3 kubeadm init核心参数的离线适配这是所有步骤中最关键的一步。在离线环境里kubeadm init需要显式指定镜像仓库地址并且所有参数都通过配置文件的方式一次性传给它避免交互式提问。我在master节点上创建kubeadm-config.yamlapiVersion: kubeadm.k8s.io/v1beta3 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.50.10 bindPort: 6443 nodeRegistration: criSocket: unix:///var/run/containerd/containerd.sock name: k8s-master01 taints: - effect: NoSchedule key: node-role.kubernetes.io/master --- apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: v1.28.15 imageRepository: 192.168.50.10:18080/library networking: podSubnet: 10.244.0.0/16 serviceSubnet: 10.96.0.0/12 dnsDomain: cluster.local --- apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration cgroupDriver: systemd几个关键点解释一下imageRepository如果不修改默认是registry.k8s.io离线环境肯定拉不了这里改成你自己的Harbor地址kubeadm会从该仓库下拼接出kube-apiserver、etcd、coredns等镜像全名。podSubnet要和你后续安装的网络插件保持一致。我用的是Calico默认的10.244.0.0/16实际上Calico的默认IP池配置是192.168.0.0/16这里要和你实际网络规划一致如果不匹配后面Pod的IP会乱套Service访问也会出问题。cgroupDriver建议显式设为systemd和containerd的配置对齐否则会报failed to run Kubelet: failed to run kubelet: misconfiguration: kubelet cgroup driver: systemd is different from docker cgroup driver: cgroupfs之类的错误。配置写好后直接执行kubeadm init --config kubeadm-config.yaml --upload-certs这个过程大概2-3分钟。如果之前所有镜像都已经push到了Harbor这里应该一路畅通。初始化成功后按提示执行mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config然后用kubectl get nodes查看master状态此时应该是NotReady因为网络插件还没装。4.4 安装Calico网络插件离线方式Calico的离线安装本质上就是把它的yaml文件里的镜像地址替换成内网地址然后apply。你可以在联网机器上下载calico的yamlcurl -O https://raw.githubusercontent.com/projectcalico/calico/v3.27.3/manifests/calico.yaml然后把calico.yaml里所有docker.io/calico/开头的镜像名改成你的私有仓库地址比如192.168.50.10:18080/library/calico/cni:v3.27.3。这一步可以用sed批量替换sed -i s|docker.io/calico|192.168.50.10:18080/library/calico|g calico.yaml再检查一下CALICO_IPV4POOL_CIDR这个环境变量默认值是192.168.0.0/16如果和你的podSubnet不一致就要改成一样的。我前面用的10.244.0.0/16所以这里就要改- name: CALICO_IPV4POOL_CIDR value: 10.244.0.0/16改好后一条命令搞定kubectl apply -f calico.yaml等一两分钟再观察kubectl get pods -n kube-system kubectl get nodes正常的话所有系统组件都应该是Running节点状态变成Ready。4.5 工作节点加入集群master初始化成功后会输出一串kubeadm join命令记得保存下来。工作节点只需要做两件事把环境准备完整、安装kubelet和containerd然后执行join命令。kubeadm join 192.168.50.10:6443 --token token \ --discovery-token-ca-cert-hash sha256:hash \ --cri-socket unix:///var/run/containerd/containerd.sock在开发测试环境里如果token过期了也别急着重新初始化用下面的命令重新生成tokenkubeadm token create --print-join-command节点加入后在master上确认kubectl get nodes不出意外能看到k8s-node01和k8s-node02的状态变成Ready。整个集群就算初步建立起来了。5. 开发测试环境特化配置与验证集群起好只是第一步开发测试环境要做的事情其实比生产环境更“杂”因为用户是开发同学他们希望最大限度自由同时又不能影响到其他人。所以我会额外做几件事。5.1 命名空间划分与资源配额开发测试环境最大的痛点是“资源被某个人的测试应用吃光”所以我强烈建议一开始就建立多租户概念。根据团队情况划分命名空间比如frontend、backend、>apiVersion: v1 kind: ResourceQuota metadata: name: dev-quota namespace: backend spec: hard: requests.cpu: 4 requests.memory: 8Gi limits.cpu: 8 limits.memory: 16Gi persistentvolumeclaims: 4 pods: 20再配合一个默认的LimitRange防止开发同学忘记给Pod设置资源限制apiVersion: v1 kind: LimitRange metadata: name: dev-limit-range namespace: backend spec: limits: - default: cpu: 500m memory: 512Mi defaultRequest: cpu: 100m memory: 128Mi type: Container用kubectl apply -f分别应用。效果是开发同学创建Pod时如果不写资源会自动套用默认值如果超过配额API Server直接拒绝。这一点虽然没有生产环境那么严格但能保证整个测试环境不因为某一个人的应用把集群拖垮。5.2 本地动态存储开发测试不需要集中式存储开发测试环境最头痛的是存储。生产通常上Ceph或云盘测试环境上Ceph太重云盘又不一定有。我在开发测试环境里的方案是用本机存储 Local Persist Volume简单高效。做法是装一个sig-storage-local-static-provisioner或者更朴素一点直接用hostPath在测试场景里凑合。但hostPath没法限制单节点磁盘配额所以我更推荐装一个NFS或者其他轻量共享存储。不过如果你的测试环境只有两三个节点直接在Pod里用emptyDir或者hostPath问题也不大不用纠结。集群装完后我至少会在每个节点上把本地目录准备好mkdir -p /data/k8s-localpv然后通过一个Local PV的provisioner或者在开发测试环境里简单创建一个StorageClassapiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: local-storage provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer开发同学需要存储时用local-storage申请PVPod调度到哪个节点就用哪个节点的目录。这套方案的好处是延迟低、部署简单、不依赖额外硬件缺点是数据分散在节点上但对于测试环境已经足够。5.3 安装Dashboard和Metrics Server开发测试环境必须有可视化界面否则开发同学会天天找你捞日志。两个组件必装Dashboard和Metrics Server。Metrics Server的安装方式和Calico类似先在联网机器上下载curl -O https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.4/components.yaml然后改两处第一处镜像地址改成内网仓库第二处由于开发测试环境通常没有有效的TLS证书需要在metrics-server的Deployment中加启动参数spec: template: spec: containers: - name: metrics-server args: - --kubelet-insecure-tls改完apply再验证kubectl top nodes如果能看到每个节点的CPU/内存使用率说明Metrics Server正常。Dashboard的安装稍微复杂一点但思路一致下载yaml、改镜像地址、apply。为了开发测试方便创建Service的时候可以直接用NodePort暴露kubectl -n kubernetes-dashboard edit service kubernetes-dashboard # 把 type 改为 NodePort并指定 nodePort: 30090然后通过https://任意节点IP:30090访问使用token登录。5.4 开发测试环境的镜像拉取策略默认情况下Kubernetes在节点上如果已经存在同名的镜像tag是latest时不会重新拉取。开发测试环境里开发同学天天改镜像往往遇到“明明push了新镜像Pod里还是旧代码”的问题。我给出的实用建议是在开发测试环境统一要求用非latest标签或者给Deployment加上imagePullPolicy: Always设置。spec: template: spec: containers: - name: app image: 192.168.50.10:18080/backend/user-service:v2.0.1 imagePullPolicy: IfNotPresent如果镜像仓库在内网拉取速度很快就算每次都能从头拉也没压力。从这里也能看出私有镜像仓库在开发测试环境里的必要性——不只是为了Kubernetes系统组件它天然就是整个团队CI/CD链路里的镜像中心。5.5 集群健康验证清单到这里我习惯跑一遍完整的健康检查做一个测试应用确认整个链路是通的。用下面这几条命令快速验证# 节点状态 kubectl get nodes -o wide # 系统组件Pod状态 kubectl get pods -n kube-system # DNS解析测试 kubectl run -it --rm test-pod --image192.168.50.10:18080/library/busybox:1.36 -- nslookup kubernetes.default # 调度测试 kubectl create deployment nginx --image192.168.50.10:18080/library/nginx:1.25 --replicas2 kubectl expose deployment nginx --port80 --typeNodePort kubectl get svc nginx如果DNS解析正常、deployment能跑起来、Service能访问那这套离线集群基本就合格了。再补充一个加速开发调试的小技巧在开发测试环境里可以把kube-controller-manager的NodePort范围扩大默认是30000-32767改成10000-32767可以让开发同学有更多可用端口。修改方式编辑/etc/kubernetes/manifests/kube-controller-manager.yaml在命令行参数里加上--service-node-port-range10000-32767改完后kube-controller-manager会自动重启。6. 问题排查速查与避坑指南离线部署Kubernetes的问题和在线部署不太一样很多坑是由“内网没有外网”这个前提导致的。我把实际遇到的高频问题整理了一张速查表方便你现场对照。现象可能原因排查命令/方法解决方案kubeadm init拉镜像超时imageRepository没改成内网地址kubeadm config images list查看镜像仓库地址修改配置里的imageRepositorycontainerd无法拉取pause镜像sandbox_image没改crictl pull 192.168.50.10:18080/library/pause:3.9修改/etc/containerd/config.toml并重启containerdNode状态一直NotReadyCalico没装或podSubnet不一致kubectl get pods -n kube-system检查calico Pod状态核对IP池配置kubelet启动一直“activating”缺少配置文件或cgroup驱动错误journalctl -u kubelet -f确认kubeadm init成功后再关注kubelet状态CoreDNS Pod一直Pending缺少网络插件或节点资源不足kubectl describe pod -n kube-system coredns-xxx安装网络插件检查节点CPU/内存/污点跨节点Pod互访不通br_netfilter未加载或iptables内核参数没开lsmodgrep br_netfilterDashboard无法登录没有创建token或SA权限不足kubectl -n kubernetes-dashboard get secret创建admin用户并获取tokenkubectl top报错Metrics不可用没装Metrics Server或镜像拉取失败kubectl get pods -n kube-system检查metrics-server Pod状态确认增加参数节点重启后集群起不来containerd或kubelet未设置开机自启systemctl status containerd kubeletsystemctl enable --now containerd kubelet私有仓库TLS证书问题导致拉取失败Harbor使用自签名证书crictl pull时收到x509错误在每个节点配置Harbor证书信任或使用insecure registry配置有几个问题我想再多说两句因为它们在开发测试环境里遇到概率极高。关于私有仓库自签名证书的问题。如果你用的Harbor有TLS证书而且这个证书没有下发到所有节点那每个节点在拉取镜像时都会报x509证书错误。最省事的方式是在/etc/containerd/certs.d/目录下配置私有仓库的证书信任registry的hosts或者如果只是测试环境也可以在Harbor配置里关闭TLS走http然后containerd的config.toml里配置[plugins.io.containerd.grpc.v1.cri.registry.mirrors.192.168.50.10:18080]设置endpoint [http://192.168.50.10:18080]。这样containerd就不会尝试用TLS连接了。关于CoreDNS一直Pending或者CrashLoopBackOff。大部分情况是网络插件还没装、Pod网段冲突或者某个节点的/etc/resolv.conf有问题比如配置了一个内网不存在的DNS地址导致CoreDNS探测失败。可以用kubectl describe pod -n kube-system coredns-xxx看事件如果看到nameserver 10.96.0.10:53: no such host之类的就去检查节点的resolv.conf把地址改成一个能访问的DNS然后再重启CoreDNS。关于开发测试环境节点重启之后整个集群失联。我在多次实践中发现很多开发测试集群挂掉不是因为Kubernetes本身坏了而是因为节点重启后kubelet、containerd没起来或者防火墙规则变了以及私有仓库服务没启动。建议在系统层面把关键服务全设为开机自启并且写一个启动后自检脚本在/etc/rc.local里批量检查systemctl enable --now containerd kubelet systemctl enable --now docker再有时间的话把kubeadm init时生成的/etc/kubernetes/目录备份一下万一集群挂了你至少有证书和配置文件可以恢复。最后一个我觉得很重要的避坑点离线包的管理要版本化、文档化。我见过有人把镜像tar包放在一台服务器上过了半年以后再想搭新集群发现连里面装的是K8s哪个版本都不知道了。建议创建一个README.md把版本、镜像清单、安装步骤、关键命令全部写进去和离线包放在一起。这比什么都强也就是我开头说的“人肉可复现”。如果你能做到这一步那你的开发测试环境Kubernetes已经不只是“能用”了而是一套可以反复建设、逐步演进的基础设施。后面可以考虑接入GitLab CI、ArgoCD让开发同学自助发版体验会再上一个台阶。我个人这两年的体会是离线部署这个事越往后越值钱因为你准备的那套离线包和脚本实际上就是一套“离线交付方案”。内网环境、客户现场、甚至应急灾备场景都直接拿过去就能用。这套方法论一旦沉淀下来团队里任何人都能照着文档拓一套新集群出来。
返回列表