Kubernetes生产集群从零搭建实战:基于kubeadm的完整部署指南 📅 发布时间:2026/9/20 1:14:12 👁 浏览次数: 1. 先聊聊这次实战的定位1.1 为什么从零搭建一套生产级集群绝大多数人接触 Kubernetes第一站都是 minikube 或者 kind在笔记本上起个单节点集群跑几个 demo然后觉得“我会 K8s 了”。但真到了生产环境情况完全不一样网络怎么规划、镜像仓库怎么搭、证书怎么签、监控告警怎么接、节点挂了怎么处理这些问题在单机环境里根本遇不到。我这次做的事情就是从一台全新的 CentOS 服务器开始手动部署一套多节点 Kubernetes 集群并把一个真实的 Web 服务通过 Ingress 暴露到公网整个流程完整走一遍生产部署链路。这篇文章适合两类人一类是已经看过 Kubernetes 官方文档和《Kubernetes 权威指南》但对“企业项目实战”还没什么概念的人另一类是公司里马上要上线 K8s需要自己从零搭环境、踩一遍坑的运维或后端工程师。这里讲的是怎么从一块“干净的服务器”开始一步步变成能承载线上流量的集群。1.2 目标架构与整体规划先说明这套环境的最终形态3 个节点1 个 Master控制平面和 2 个 Worker工作节点操作系统是 CentOS 7.9容器运行时用 containerdKubernetes 版本选 1.28.x网络插件用 CalicoIngress Controller 用 Ingress-Nginx镜像仓库用 Harbor监控部分先用 kube-prometheus-stack 跑起来。版本这块我要多说两句。kubeadm 安装时Kubernetes 对容器运行时、CNI 插件、内核参数都是有版本要求的不是随便搭的。我最初试过 1.26 配 containerd 1.6后来又升到 1.28整体体验下来1.28 在稳定性上已经比较成熟对初学者也更友好。另外所有节点在部署前都做了内核参数优化和时间同步这个提前做好后面能省掉一堆莫名其妙的问题。节点角色 主机名 IP 地址 配置 Master k8s-master 192.168.1.10 4C8G Worker-1 k8s-node1 192.168.1.11 4C8G Worker-2 k8s-node2 192.168.1.12 4C8G这套架构没什么花哨的但它就是目前中小企业里最常见的样子一个控制平面、两到三个工作节点、一套网络方案、一个入口。你把它吃透了后面再扩到多 Master、加负载均衡、接云厂商的托管集群思路都是一样的。2. Kubernetes 生产部署的核心思路2.1 为什么选择 kubeadm 而不是二进制或发行版部署 K8s 主要有三条路kubeadm、二进制手动部署、直接用发行版比如 RKE、Kubesphere。二进制部署能让你对每个组件都看得清清楚楚但步骤极其繁琐etcd、kube-apiserver、kube-controller-manager、kube-scheduler、kubelet、kube-proxy 每一样都要手动配证书、写 systemd 文件、处理启动参数一套下来光排错就得花掉大半天。kubeadm 把控制平面的组件做成了静态 Pod自动处理证书签发和组件配置但又不是完全黑盒你依然可以通过kubeadm init --config自定义很多核心参数。生产环境里 kubeadm 也是官方推荐的方式包括很多企业内部都在用它做基线。发行版虽然省事但往往会封装掉太多底层细节出了问题比较难排查而且如果你后续想自己维护集群不理解底层逻辑会很吃亏。2.2 核心组件体系控制平面、工作节点、etcd 与 CNIKubernetes 的架构可以拆成三大块理解控制平面、工作节点、分布式存储。控制平面上跑着四个关键进程kube-apiserver 是所有请求的唯一入口相当于整个集群的“总前台”kube-controller-manager 负责维持集群的期望状态比如某个 Deployment 应该跑 3 个副本它会保证一直有 3 个副本少了就补kube-scheduler 决定新 Pod 应该调度到哪台节点主要看资源余量和亲和性规则etcd 则是整个集群的“数据库”所有状态数据都存在里面。工作节点上的核心组件有两个kubelet 是每个节点上最核心的 agent负责管理 Pod、容器、存储和网络kube-proxy 负责写入 iptables 或 IPVS 规则实现 Service 的负载均衡。容器运行时则负责真正的容器启停、镜像拉取、资源隔离。CNI 网络插件是很多新手容易忽略的一环。集群要能正常工作Pod 之间必须能互通Pod 和服务之间也必须能互通这靠的就是 CNI 插件。Calico 用 BGP 协议在三层网络上转发性能好策略能力强是生产环境的主流选择。Flannel 则是覆盖网络方案配置简单适合快速验证。我这次用 Calico是因为它除了打通网络还能做 NetworkPolicy 网络策略生产环境更实用。2.3 生产环境应提前做好的准备清单如果你想直接照着做我建议先把下面这些准备工作做完再开始部署否则后面每一步都会遇到环境问题。所有节点设置好静态 IP并修改/etc/hosts写入所有节点的 IP 和主机名映射。关闭防火墙或放行 K8s 所需端口生产中建议在安全组/防火墙层面只放行必要端口。关闭 SELinux或者设置为 permissive否则 kubelet 经常会出现权限问题。开启内核模块overlay和br_netfilter并配置net.bridge.bridge-nf-call-iptables等参数。所有节点时间同步推荐 chrony时间不一致会导致证书验证、日志排查非常痛苦。如果服务器有 swap 分区一定要关闭kubelet 默认不允许在 swap 开启时工作。提示很多安装报错比如“kubelet 启动失败”“容器运行时不可用”根因都是准备工作没做干净。不要跳过这一节也不要只在一台机器上做所有节点都要做。3. 从零开始搭建集群完整操作实录3.1 初始化节点环境内核参数、主机名、时间同步拿到一台全新的 CentOS 7.9 服务器我的习惯是先做一套“统一初始化”保证所有节点的基线一致。这里的每一条命令都不是随便执行的下面逐个解释。先设置主机名和 hosts 解析hostnamectl set-hostname k8s-master cat /etc/hosts EOF 192.168.1.10 k8s-master 192.168.1.11 k8s-node1 192.168.1.12 k8s-node2 EOF为什么一定要配 hosts因为 Kubernetes 组件之间会通过主机名互相访问证书里的 SAN 也包含主机名。如果你不配 hostsapiserver 的证书在做节点认证时经常出现 “x509: certificate signed by unknown authority” 这种报错。接着关闭防火墙和 SELinuxsystemctl stop firewalld systemctl disable firewalld setenforce 0 sed -i s/^SELINUXenforcing/SELINUXpermissive/ /etc/selinux/configSELinux 在生产环境不是不能开但开了之后需要给 kubelet 配很多额外的布尔值大多数团队嫌麻烦直接关掉了。我这里也选择关闭以便把排查重心放在 K8s 本身。然后写入内核模块和内核参数cat EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF modprobe overlay 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 sysctl --system这几个参数里bridge-nf-call-iptables是让桥接的流量也经过 iptables 规则如果不设置kube-proxy 写入的 iptables 规则对 Pod 网络内部的流量不生效Service 转发就会出问题。ip_forward是开启内核 IP 转发Pod 跨节点通信依赖它。最后配置时间同步yum install -y chrony systemctl enable chronyd systemctl start chronyd chronyc sources -vK8s 集群太依赖证书了所有组件之间的通信都是 TLS如果节点间时间差超过 5 分钟证书验证直接失败排错非常隐蔽。我见过很多次 “certificate has expired or is not yet valid” 的报错最后发现只是时钟偏了。3.2 安装 containerd容器运行时的选择与配置Docker 从 Kubernetes 1.24 开始不再被默认支持现在主流选择是 containerd。你可以把它理解成一个“更精简的 Docker 引擎”只负责容器生命周期管理和镜像管理没有 Docker CLI、Swarm 这些外围功能性能更好资源占用更少。安装 containerdyum install -y yum-utils yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum install -y containerd.io装好之后先别急着启动要改配置文件。Kubernetes 要求 containerd 使用 SystemdCgroup 驱动因为 kubelet 在管理容器 cgroup 时需要和容器运行时保持一致。mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml然后编辑/etc/containerd/config.toml找到 SystemdCgroup 这一行修改[plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc] ... [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc.options] SystemdCgroup true同时建议把沙箱镜像源改为国内源否则默认会去registry.k8s.io拉镜像国内网络环境经常超时[plugins.io.containerd.grpc.v1.cri] sandbox_image registry.aliyuncs.com/google_containers/pause:3.9启动 containerdsystemctl daemon-reload systemctl enable containerd systemctl start containerd crictl version注意修改 config.toml 后必须重启 containerd 才能生效。而且SystemdCgroup true这个配置千万别漏漏了之后 Pod 虽然能创建但随时可能出现 cgroup 相关的间歇性故障非常难排查。3.3 kubeadm、kubelet、kubectl 安装与版本选择安装 K8s 三大命令行工具直接配置阿里云 yum 源比从 Google 源快得多cat EOF /etc/yum.repos.d/kubernetes.repo [kubernetes] nameKubernetes baseurlhttps://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/ enabled1 gpgcheck1 repo_gpgcheck1 gpgkeyhttps://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg EOF yum install -y kubelet-1.28.2 kubeadm-1.28.2 kubectl-1.28.2 systemctl enable kubelet这里有个经验三个组件的版本必须一致。kubelet 版本如果和 apiserver 版本差太多节点加入集群时会报 “Kubelet version ... is too old” 之类的错误。用yum install -y kubelet-1.28.2 kubeadm-1.28.2 kubectl-1.28.2这种方式固定版本是最稳的做法。注意不要拉最新版。有些新版本刚发布时可能有潜在 bug生产环境一般选择最近几个月的稳定版本。我选 1.28.2是因为它在 1.28 系列里已经经过了几个补丁版本的验证配合 Calico 和 Ingress-Nginx 都兼容得很好。3.4 初始化 Master 控制平面在所有节点装好 containerd 和 kubeadm 后先在 Master 上执行初始化。先准备 kubeadm 配置文件比直接传一堆命令行参数更直观、更可维护cat kubeadm-init.yaml EOF apiVersion: kubeadm.k8s.io/v1beta3 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.1.10 bindPort: 6443 --- apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: 1.28.2 controlPlaneEndpoint: 192.168.1.10:6443 networking: podSubnet: 10.244.0.0/16 serviceSubnet: 10.96.0.0/12 EOF kubeadm init --config kubeadm-init.yaml这里最关键的是podSubnet和serviceSubnet两个网段。Pod 网段必须和后面 Calico 配置的网段一致否则网络插件创建的 Pod 会一直处于 ContainerCreating报 IP 分配失败。Service 网段则是一个虚拟 IP 池它不需要绑定到任何物理网卡只在 kube-proxy 转发的规则里生效。初始化成功后命令行会输出一大段内容包括控制平面初始化成功的提示往$HOME/.kube/config写入 kubectl 配置的命令工作节点加入集群的kubeadm join完整命令先把 kubectl 配置好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。这是正常的因为还没装网络插件。3.5 安装 Calico 网络插件Calico 是 Kubernetes 集群的“神经系统”。没有它Pod 之间的网络是不通的节点的 NotReady 状态也永远不会好转。安装 Calico 的推荐方式是使用它提供的 manifest 文件curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml kubectl apply -f calico.yaml如果之前 kubeadm 配置的podSubnet不是默认的 192.168.0.0/16需要修改 calico.yaml 里 CALICO_IPV4POOL_CIDR 这个环境变量为你自己的网段。怎么判断对不对看 calico.yaml 里这个 env 的值是否和 kubeadm-init.yaml 里的一样。- name: CALICO_IPV4POOL_CIDR value: 10.244.0.0/16等几分钟后检查kubectl get pods -n kube-system kubectl get nodes当你看到所有节点的状态从 NotReady 变成 Ready说明网络通了这一步基本算完成。这个阶段要多点耐心Calico 的 Pod 需要从仓库拉镜像根据网络情况可能要一两分钟。3.6 工作节点加入集群在 Worker 节点上执行 Master 初始化时输出的 join 命令。如果当初没保存也可以在 Master 上重新生成 tokenkubeadm token create --print-join-command执行结果类似这样kubeadm join 192.168.1.10:6443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:xxxxxx在 node1 和 node2 上分别执行然后到 Master 上kubectl get nodes正常情况下会看到三个节点都处于 Ready 状态。如果节点状态一直 NotReady先看journalctl -u kubelet -f常见的坑是 token 过期24 小时有效或者是证书 hash 不对重新执行kubeadm token create --print-join-command拿最新的就行。3.7 验证集群可用性节点全部 Ready 后不要急着部署应用先做一个基础验证kubectl create deployment test-nginx --imagenginx kubectl expose deployment test-nginx --port80 --typeNodePort kubectl get svc如果看到 Service 的 NodePort 被分配了端口比如 30080那么通过任意节点 IP 加端口访问能出现 nginx 欢迎页说明集群网络、DNS、调度、服务发现这些核心链路全部正常。我用经典nginx镜像做验证是因为它体积极小、启动快不存在拉镜像失败的问题。验证完成之后为了不占用资源建议把测试资源删掉kubectl delete deployment test-nginx kubectl delete svc test-nginx4. 生产部署从镜像打包到对外提供服务4.1 镜像仓库选型Harbor 私有化部署生产环境里镜像不能随便放在 Docker Hub 上公开尤其是企业内部的业务镜像。Harbor 是目前最主流的私有镜像仓库方案它内置了镜像签名、漏洞扫描、访问控制和多租户等能力比裸跑一个 registry 容器专业得多。Harbor 的安装其实不复杂因为它官方提供了离线安装包。整个过程就是解压、改配置文件、执行 install.sh。关键配置在harbor.yml里要设置 hostname、管理员密码以及可选配置 HTTPS 证书hostname: registry.example.com http: port: 80 harbor_admin_password: YourStrongPassword database: password: YourDBPassword data_volume: /data/harbor生产环境强烈建议给 Harbor 配 HTTPS。因为 Kubernetes 节点在处理imagePullSecrets时如果仓库是 HTTP很多容器运行时会直接拒绝拉取除非在 containerd 里配置[plugins.io.containerd.grpc.v1.cri.registry.mirrors]的insecure_skip_verify true。多一事不如少一事直接上 HTTPS 证书。4.2 构建业务镜像并推送到 Harbor以一个 Spring Boot 应用为例我一般先在项目根目录写一个 DockerfileFROM openjdk:11-jre-slim COPY target/app.jar /app.jar EXPOSE 8080 ENTRYPOINT [java, -jar, /app.jar]然后在有 Docker 的构建机上docker build -t registry.example.com/demo/order-service:1.0.0 . docker push registry.example.com/demo/order-service:1.0.0镜像名的前缀也就是仓库地址决定了它会推送到哪个 Harbor 项目。demo是项目名order-service是镜像名1.0.0是标签。规范做法是把版本号作为标签而不是一律用latest否则生产环境回滚根本不知道回哪个版本。Workers 节点上的 containerd 从 Harbor 拉取私镜像前需要配置认证信息。最直接的方法是创建 Secretkubectl create secret docker-registry harbor-secret \ --docker-serverregistry.example.com \ --docker-usernameadmin \ --docker-passwordYourPassword \ --namespaceprod然后 Deployment 的 YAML 里通过imagePullSecrets引用这个 Secret这样 kubelet 在拉取镜像时会自动携带认证信息。4.3 编写 Deployment 与 Service生产部署应用第一步是编写资源清单。拿订单服务举例下面的 YAML 是一个比较标准的模板apiVersion: apps/v1 kind: Deployment metadata: name: order-service namespace: prod spec: replicas: 3 selector: matchLabels: app: order-service template: metadata: labels: app: order-service spec: imagePullSecrets: - name: harbor-secret containers: - name: order-service image: registry.example.com/demo/order-service:1.0.0 ports: - containerPort: 8080 resources: requests: cpu: 250m memory: 512Mi limits: cpu: 500m memory: 1Gi readinessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 15 periodSeconds: 10 livenessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 30 periodSeconds: 20 --- apiVersion: v1 kind: Service metadata: name: order-service namespace: prod spec: selector: app: order-service ports: - port: 80 targetPort: 8080 type: ClusterIP这里面几个点值得展开说replicas: 3三个副本分布在两个 Worker 节点上即使有一台节点宕机Pod 还会在另一台上运行。resources一定要写。不写的话Kubernetes 不知道你的容器要多少资源调度是盲目的一个内存泄漏的应用可能把整台宿主机打挂。探针非常重要。readinessProbe决定流量会不会打到某个 Pod如果接口没就绪Service 就不会把请求转发给它livenessProbe决定容器如果僵死是不是会被自动重启。4.4 配置 Ingress 对外暴露服务Service 默认是 ClusterIP 类型只能在集群内部访问。想对外提供服务有两种常见方案NodePort 和 Ingress。NodePort 每次会占用所有节点的某个端口端口多了很难管理。Ingress 更适合 7 层 HTTP 路由可以把多个服务统一用一个入口暴露出去。安装 Ingress-Nginx Controllerkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.5/deploy/static/provider/cloud/deploy.yaml等它变成 Running 之后创建 Ingress 规则apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: order-service-ingress namespace: prod spec: ingressClassName: nginx rules: - host: order.example.com http: paths: - path: / pathType: Prefix backend: service: name: order-service port: number: 80然后把order.example.com这个域名解析到任意一台节点的 IP或者放到负载均衡器的后端。访问http://order.example.com请求链路是这样用户 DNS 解析到节点 IP → 节点的 80 端口被 Ingress-Nginx Controller 监听 → Controller 根据域名和路径把请求转发给对应的 Service → Service 再负载均衡到后端的 Pod。这个链路是整个生产环境最核心的流量路径理解它就能理解 K8s 对外暴露服务的完整逻辑。4.5 使用 Kubernetes Dashboard 管理集群与发布新服务命令行能完成所有操作但很多团队还是希望有一个 Web 界面可以快速查看集群状态、日志和资源使用情况。Kubernetes Dashboard 就是一个官方的 Web 管理界面。安装 Dashboardkubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml默认创建的 Service 类型是 ClusterIP外部没法直接访问。可以通过 kubectl 的 port-forward 临时访问kubectl port-forward -n kubernetes-dashboard service/kubernetes-dashboard 8443:443然后浏览器打开https://localhost:8443。Dashboard 虽然没有对外暴露的 Service但在集群内部它就是一个普通的 Deployment 加 Service。如果你想把一个“新服务”发布到集群里最直观的方式就是点击右上角的加号选择“从文件创建”或“从输入框中创建”粘贴我们刚才写好的 Deployment YAML 即可。从文件创建的方式非常接近日常工作流所以这个功能才一直那么热门。Dashboard 的登录方式推荐用 Token。创建一个专门的服务账号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然后拿到 Tokenkubectl -n kubernetes-dashboard create token admin-user现在的 Dashboard 对集群的管控能力已经比较完整可以看到节点状态、Pod 的调度情况、日志也可以直接编辑资源清单是新手理解 K8s 很不错的一扇窗口。但要注意生产环境里不建议给普通同事发 cluster-admin 权限最好基于 namespace 做 RBAC 授权。5. 监控与运维集群“可观测”才是生产开始5.1 kube-prometheus-stack一站式监控方案没有监控的集群是不敢上生产的。这里我推荐直接用 kube-prometheus-stack一个 Helm Chart把 Prometheus、Alertmanager、Grafana、各种 exporter 和告警规则全部打包在一起是当前社区最主流的一站式方案。添加 Helm 仓库并安装helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update kubectl create ns monitoring helm install prometheus-stack prometheus-community/kube-prometheus-stack \ --namespace monitoring \ --set grafana.adminPasswordYourGrafanaPassword装完之后可以看到在monitoring命名空间下有一堆 Pod。这里面有几个比较关键的组件prometheus-operator管理 Prometheus、Alertmanager 等实例prometheus采集端从各类 exporter 和 ServiceMonitor 里抓取指标grafana可视化看板自带很多现成的 Dashboardalertmanager负责把告警发送到钉钉、邮件、Slack 等kube-state-metrics 和 node-exporter分别暴露集群对象状态和节点资源指标5.2 配置 Grafana 看板与钉钉告警Grafana 默认账号密码是 admin/grafana.adminPassword设置的值。登录后点击左侧 Dashboard在 Import 里输入 ID 就能导入现成的看板。比较常用的有三个Kubernetes 集群监控大屏ID315集群整体资源、节点状态、Pod 数量Node Exporter 服务器监控ID1860CPU、内存、磁盘、网络等宿主机指标K8s 资源利用率ID893更细粒度的资源分配和实际使用对比告警这块钉钉机器人接入最简单。创建钉钉群后添加一个自定义机器人拿到 Webhook 地址然后配置 AlertmanagerapiVersion: v1 kind: Secret metadata: name: alertmanager-main namespace: monitoring stringData: alertmanager.yaml: | route: group_by: [alertname, cluster] group_wait: 10s group_interval: 10s repeat_interval: 1h receiver: dingtalk receivers: - name: dingtalk webhook_configs: - url: https://oapi.dingtalk.com/robot/send?access_tokenyour_token send_resolved: true告警规则的核心指标你至少要关注几个Pod 重启次数、CPU 使用率超过 85%、节点磁盘使用率超过 85%、Pod 卡在 Pending 超过 5 分钟。这些在 kube-prometheus-stack 的默认 alert rules 里其实已经包含了可以直接用。5.3 日常运维命令清单最后整理一套我日常用得最多的命令供你参考。不需要背遇到问题多敲几次就熟了。# 查看所有命名空间的资源 kubectl get all -A # 进入某个 Pod 排查问题 kubectl exec -it pod-name -n namespace -- /bin/sh # 查看 Pod 日志历史 kubectl logs pod-name -n namespace --tail200 # 查看 Pod 详细信息事件、状态变化 kubectl describe pod pod-name -n namespace # 查看节点资源使用率需要 metrics-server kubectl top node kubectl top pod -n namespace # 临时将某个服务暴露到本地访问 kubectl port-forward svc/service-name -n namespace 8080:80 # 从 YAML 文件应用到集群 kubectl apply -f deployment.yaml # 动态查看 Pod 变化 kubectl get pods -n namespace -w6. 常见坑位与故障排查实录6.1 节点一直 NotReady 的排查思路节点 NotReady这是新手遇到最多的坑。先别慌按这个顺序排查第一步看节点状态和事件kubectl describe node node-name第二步看 kubelet 日志journalctl -u kubelet -f第三步确认网络插件Pod 是否正常运行kubectl get pods -n kube-system大多数情况是 Calico 没装好或镜像拉不下来或 containerd 配置不对。记住核心逻辑节点 NotReady 通常代表 kubelet 和 apiserver 通信正常但某个系统组件不健康。6.2 镜像拉取失败的几个原因镜像拉取失败ImagePullBackOff常见原因有这么几类第一类是网络问题。默认从 Docker Hub 拉镜像没问题但从 gcr.io、k8s.gcr.io 拉就是超时。解决方案是配置镜像加速器或者用 containerd 的 hosts.toml 替换镜像源。第二类是镜像不存在或版本标签写错。先在本地 crictl 拉一把试试能验证到底是网络问题还是镜像本身问题。第三类是私有仓库认证失败。检查 imagePullSecrets 的 Secret 是否创建成功以及 docker-server 的地址是否和镜像仓库地址完全一致。6.3 证书和 Token 过期问题kubeadm 的证书有效期默认是一年。一年后如果你继续用 kubeadm 维护集群就要定期检查证书有效期kubeadm certs check-expiration如果确实过期了执行kubeadm certs renew all然后重启控制平面组件kubectl -n kube-system delete pod -l componentkube-apiserver关于 Token 过期kubeadm join的 token 默认 24 小时有效过期后不要去翻老命令直接kubeadm token create --print-join-command拿新的就行。6.4 日志采集建议日志这块生产环境建议引入 Loki 或者 EFK。因为 Pod 重建后日志就没了盯着kubectl logs排问题只是一时的办法。我现在用的是 Loki 加 Promtail 的组合相对轻量配合 Grafana 直接查历史日志比进入 Pod 翻文件高效得多。7. 最后的几点个人经验这套集群从规划到最终能扛流量我前后花了大概两天时间中间差不多有一半时间耗在环境初始化和网络插件上。回头总结最想提醒你的是三件事。第一准备工作一定要做干净。关闭 SELinux、同步时间、配置 hosts、加载内核模块这些看起来琐碎但少了任何一项后面都会以各种奇怪的报错出现到时候排查成本远高于你提前准备的十分钟。第二生产环境不要死守默认参数。Pod 的 requests 和 limits 要写探针要配副本数至少 3 个私有镜像仓库一定要上 HTTPS这些都是血泪教训换来的标配。第三把“可观测性”当基础设施来做。没有监控之前集群出问题完全靠猜上了 Prometheus 和 Alertmanager 之后Pod 重启、节点磁盘满这些问题都能提前收到通知再也不用等用户先发现故障。Kubernetes 的学习曲线确实陡峭但只要你完整地部署过一遍生产集群再回头看那些概念就会觉得它们都是顺理成章的。接下来你就可以按自己的需求去扩展多 Master 高可用、HPA 自动伸缩、GitOps 发布流程、服务网格每一条路都够你走很远。