资讯详情

K8s新手实战手册:从零部署集群到YAML编写与排错

📅 2026/10/17 5:24:01 | 华诺云谱 👁 阅读
K8s新手实战手册:从零部署集群到YAML编写与排错
搞了这么多年基础设施见过太多人在 K8s 门口徘徊理论看了一堆一动手就懵YAML 抄过来改个镜像名就敢往上扔报错了连从哪儿查都不知道。其实 Kubernetes 这东西说复杂也复杂说简单也简单——你只要把它拆成“谁在管事儿”“谁在干活儿”“出事儿找谁问”这三层再对着这套思路把集群拉起来、把配置写对、把排查命令背熟新手也能在一天之内从零跑通一个真正能用的集群。这份手册就是奔着这个目标写的。我把 K8s 最核心的组件关系、从零部署集群的完整流程、常用 YAML 的写法要点、还有平时排错百分之八十会用到的基础指令全部揉在一起整理成文。内容按我的实际经验来排先讲清楚为什么这么设计再告诉你每一步怎么操作最后把踩坑记录也一并交代。适合刚上手 K8s 的开发者、需要自建环境的运维同学以及那些“会用 docker 但还没摸过 K8s”的进阶人群。跟着抄一遍你就能拥有一个自己的集群并且知道它出了问题该往哪儿看。1. 组件拆解先把集群的“组织架构”看明白1.1 控制平面集群的“管理层”Kubernetes 从架构上分成两大部分控制平面Control Plane和工作节点Worker Node。控制平面就是整个集群的大脑负责做决策、管状态、对外提供 API工作节点就是真正扛活儿的“手脚”在上面跑你的业务容器。控制平面里第一个要认识的是kube-apiserver。它是整个集群的唯一入口你敲的每个kubectl命令、内部组件之间的每次通信全部都要经过它。它只做一件事校验请求、授权、然后把这个请求的“结果预期”写进数据库。你可以把它理解成一个公司的前台——所有事情都从这扇门进出想绕过它直接操作底层门儿都没有。第二个是etcd。这是一个分布式的键值数据库集群里所有的状态数据都存在这里有哪些节点、有哪些 Pod、期望的副本数是多少、当前的实时状态又是什么全部靠 etcd 背书。etcd 挂了集群就成了“植物人”——看起来还在其实什么决策都做不了。生产环境里 etcd 一定要单独做备份最好放在独立的磁盘上别跟系统盘挤在一起。然后是kube-scheduler排课表的那位。它盯着 API Server 里还没被绑定节点的 Pod综合节点资源余量、亲和性规则、数据局部性等因素给每个待调度的 Pod 选一个最合适的节点去落地然后把“我推荐这个 Pod 跑在 node-01 上”这个结论写回 API Server。注意它只管“选”不管“执行”。最后是kube-controller-manager干的是纠偏的活。它内置了一堆控制器比如 Node 控制器管理节点健康状态、ReplicaSet 控制器保证副本数与你期望的一致。你要是定义了“我要 3 个副本”结果其中 1 个挂了Controller Manager 就会立刻安排调度器去补一个新的让集群状态不断向你的期望值收敛。1.2 数据平面真正干活的“手脚”工作节点上跑着三个关键组件缺一不可。kubelet是节点上的“总督”。它负责接收 API Server 下发的指令管理本节点上所有 Pod 的生命周期容器该启动就启动、该重启就重启、该销毁就销毁。它还定时向 API Server 上报本节点的资源情况和 Pod 的运行状态。kubelet 基本只认容器运行时而容器运行时Container Runtime就是真正创建和运行容器进程的工具最常用的就是 containerd。你以前用的 docker 到了 K8s 里其实也是通过 containerd 间接参与1.24 之后原生对 docker 的兼容就彻底移除了直接用 containerd 是最省心的选择。kube-proxy则是网络转发层面的大管家。它负责实现 Service 的虚拟 IP 访问能力把发往 Service IP 的流量转发到对应的后端 Pod 上默认用的 iptables 模式规则简单可靠但节点数量大了会有点性能损耗。IPVS 模式性能更好适合规模较大的集群只需要在 kube-proxy 启动参数里加一行配置就可以切换。这三者配合的效果用一句话说清你写一个 Deployment 的 YAML把它交给 API ServerController Manager 看到期望副本数是 3调度器帮这 3 个 Pod 分别选了合适的节点各节点的 Kubelet 收到指令让 containerd 把容器拉起来跑容器跑起来了kube-proxy 保证外部能通过 Service 稳定地访问到它们。这条链路里任何一个环节掉链子问题都会在某一层的日志里留下痕迹——所以排错的核心套路就是顺着这条链路一层层去翻日志。2. 集群部署前的关键准备不做好这些后面全是坑2.1 节点规划与硬件建议集群规模没有标准答案但规划逻辑是固定的控制平面至少准备一台独立节点叫 master 节点也行工作节点看业务量决定。凡事量力而行如果你只是学习和测试一台 4C8G 的虚拟机就能“一鱼多吃”控制平面和工作节点部署在同一台上也就是常说的单机集群。配置高一点就留 2 台 worker把 master 单独属出来做双节点集群这样能完整体会到调度和网络跨节点的复杂行为。硬件上 CPU 和内存是王道磁盘必须尽量用 SSD。etcd 的写入压力很大机械盘会拖垮整个集群的控制面性能。操作系统我建议用较新的 Ubuntu Server 或 CentOS/Rocky Linux内核版本不要太老这直接决定了 iptables、网络插件兼容性这些底层能力。swap 必须关掉这个是 K8s 的硬性要求否则 kubelet 会启动报错不同版本对 swap 的配置要求也是个大坑下面实操我会带着你把它处理干净。2.2 版本选型与网络方案版本选择这种事不要追求最新。K8s 每个小版本大概每季度发一次升到最新往往意味着周边生态容器运行时、网络插件、Ingress Controller的兼容矩阵还没跟上。我一般选“n-1 或 n-2”的小版本也就是当前最新发行版本往倒数几个的稳定版比如某个时间节点上下一个稳定支线的 Patch 版。选 Patch 版是因为它修复了该小版本主干上的关键 bug同时又不会引入太多新特性适合稳字当头的集群环境。网络插件是部署的关键决策点。K8s 本身对 Pod 网络不做具体实现需要你选一个 CNI 插件来打通跨节点通信。Flannel 最轻量化配置也最简单适合新手和中小规模集群Calico 支持网络策略性能也更稳适合生产环境Cilium 基于 eBPF功能最强但学习曲线也最陡。我自己的建议是第一遍学习用 Flannel 最快跑通如果是生产环境直接上 Calico它可以在后续扩展网络策略时让你少走弯路。选好了插件后面部署完控制面后第一时间装它那个步骤卡住了节点纷纷变成 NotReady 八成都是它的锅。2.3 基础环境配置清单三台机器一台 master两台 worker的操作系统都换成 Ubuntu 22.04 LTS关闭 swap、配置好 hostname 和 hosts 文件、开放必要的防火墙端口这些是一揽子准备工作我会在部署实操里逐步带跑。除此之外还有一个容易忽视的点确保每台机器上的时间同步在正常工作。K8s 组件之间的通信严重依赖时间戳时间差得多了证书校验都会出问题表面上看起来是“连接被拒”实际是时钟偏移在捣乱。3. 集群部署完整实操从裸机到多节点集群跑通下面这段直接上流程我按我常用的部署路线走一遍保证你能顺利复现。假设你有三台 Ubuntu 22.04 的虚拟机或裸机每个节点都分配好了静态 IP比如 192.168.1.10master、192.168.1.11worker-01、192.168.1.12worker-02。这个环境的网络互通性在部署前一定先测一遍最怕装到一半发现 ping 不通——大概率是安全组或防火墙的锅。3.1 三节点基础环境初始化三台机器都先做相同的操作# 修改主机名每台机器改成自己的名字 hostnamectl set-hostname k8s-master01 # 关闭 swap并在 /etc/fstab 里注释掉 swap 行否则重启后 swap 又回来了 swapoff -a sed -i / swap / s/^/#/ /etc/fstab # 开启内核网络转发与桥接过滤 cat EOF | tee /etc/modules-load.d/containerd.conf overlay br_netfilter EOF modprobe overlay modprobe br_netfilter cat EOF | tee /etc/sysctl.d/99-kubernetes.conf net.bridge.bridge-nf-call-iptables 1 net.ipv4.ip_forward 1 net.bridge.bridge-nf-call-ip6tables 1 EOF sysctl --system这些参数看起来杂核心就两件事容器网络要用的模块提前加载好内核转发要保持开启否则 Pod 之间跨节点通信会被内核默认策略给挡下来。3.2 安装 containerd 并配置 systemd cgroup 驱动这一步是新手最常踩坑的地方。K8s 自 1.24 之后默认用 containerd 作为运行时但 containerd 系统默认的 cgroup 驱动往往和 kubelet 需要的不是一套你直接在配置里把SystemdCgroup改为 true 才能保证两者使用同一套 cgroup 驱动否则节点起来几秒就被标记为 NotReady。# 安装 containerd apt-get update apt-get install -y containerd.io # 生成默认配置 mkdir -p /etc/containerd containerd config default | tee /etc/containerd/config.toml # 把 SystemdCgroup 改为 true如果镜像源需要加速也一并改 sandbox_image sed -i s/SystemdCgroup false/SystemdCgroup true/ /etc/containerd/config.toml systemctl restart containerd systemctl enable containerd这里多叮嘱一句如果你的环境拉取 gcr.io 镜像特别慢可以把sandbox_image的值替换成国内可访问的镜像地址。这是拉取 pause 根镜像的源头改好了会省下本来会卡住计划的第一块时间。3.3 安装 kubeadm、kubelet 和 kubectlK8s 的这几个二进制工具可以从官方源直接安装。我建议三个组件版本保持一致避免出现 API 版本不匹配之类的坑apt-get install -y kubelet kubeadm kubectl apt-mark hold kubelet kubeadm kubectlapt-mark hold这行命令很重要作用是锁定版本防止无意的系统升级把 K8s 组件带到不兼容的新版本。我就因为忘了这行有一次不小心升级了集群组件结果插件全炸。记着安装完之后立刻打好锁。3.4 初始化控制平面节点在 master 节点上执行 kubeadm init。这行命令是整套部署流程里最能决定生死的一步各个参数必须交代清楚kubeadm init \ --apiserver-advertise-address192.168.1.10 \ --pod-network-cidr10.244.0.0/16 \ --service-cidr10.96.0.0/12--apiserver-advertise-address就是 master 节点的 IP其他节点要往这个地址上报状态填错了 worker 永远 join 不进来。--pod-network-cidr是给 Pod 预留的网段必须要和你选的网络插件保持一致。比如这里用 10.244.0.0/16 就是 Flannel 的默认网段。你后面要是换 Calico那这段要根据 Calico 的默认配置改成192.168.0.0/16。--service-cidr是给 Service 预留的虚拟 IP 网段不是特殊需求就不用动保持默认就可以。初始化结束会有一段提示告诉你集群部署成功并给出两段关键内容管理集群用的 kubeconfig 配置命令。让 worker 节点加入集群的kubeadm join完整命令。这行命令包含了 token 和证书哈希务必保存好token 的有效期默认是 24 小时超时了要用kubeadm token create --print-join-command重新生成。初始化完成后立刻执行如下命令配置 kubectlmkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config然后验证控制平面状态kubectl get nodes此时 master 节点的状态应该还是 NotReady别慌这是正常的。因为 Pod 网络还没就绪。3.5 安装 Pod 网络插件网络插件是让所有 Pod 之间能跨节点通信的关键组件。这里我以 Calico 为例操作kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/master/manifests/calico.yaml这条命令会创建一批资源包括 DaemonSet 形式的 calico-node、Deployment 形式的 calico-kube-controllers还有对应的 CRD 和 RBAC。安装完成后可以观察一下 calico 相关 Pod 的状态kubectl get pods -n kube-system等所有 Pod 都变成 Running再回头看节点状态kubectl get nodes如果几次刷新下来节点全部 Ready那控制平面就完全就绪了。这里有个很常见的坑calico.yaml 里的 Pod 网段如果不匹配Calico 的 Pod 会反复 CrashLoopBackOff此时用kubectl logs -n kube-system calico-pod去翻日志多半会看到“IP pool conflict”或者网段不匹配的报错。3.6 工作节点加入集群worker 节点这边操作很简单把之前保存的 join 命令拿过来执行即可kubeadm join 192.168.1.10:6443 --token 你的token --discovery-token-ca-cert-hash sha256:你的哈希join 成功后回到 master 节点上再查看一下节点状态kubectl get nodes -o wide如果看到两个 worker 节点都变成 Ready整个多节点集群就宣告落地了。这期间如果 join 报错多数逃不开三类原因token 过期、网络不通、master 的 6443 端口没被防火墙放行。逐个排查耐心点不要一失败就重装系统。3.7 部署验证跑一个真正的应用集群有了随手部署一个 nginx 验证全链路kubectl create deployment nginx-demo --imagenginx:1.27 kubectl expose deployment nginx-demo --port80 --typeNodePort kubectl get svc nginx-demo拿到 NodePort 暴露的端口号一般在 30000-32767 区间比如 30080然后从任意一台节点上用 curl 访问http://节点IP:30080能看到 nginx 默认欢迎页整套集群链路就通了可以祝贺自己正式入了门。4. YAML 实战写资源配置文件的正确姿势4.1 从最小 Pod 到 Deployment别写废 YAML很多新手接触 YAML 第一步就栽在缩进上。K8s 的 YAML 遵循一套严格的 schema两空格缩进直接当成约定俗成的规范TAB 是绝对禁用的否则直接解析报错。我建议写完 YAML 先不急着 apply先干一件事kubectl apply --dry-runclient -f xxx.yaml这个命令只做语法和 schema 校验不会真正创建资源能帮你筛掉一大半低级错误。最小 Pod 的形态长这样apiVersion: v1 kind: Pod metadata: name: demo-pod spec: containers: - name: nginx image: nginx:1.27apiVersion和kind确定了资源的类型和 API 版本metadata.name是资源的唯一标识spec描述你期望的状态这里就是一个 nginx 容器。Pod 是最小调度单元但在实际生产里你很少直接创建 Pod更多是用 Deployment 来管理。用 Deployment 的好处是可以声明副本数、支持滚动更新、故障自动恢复apiVersion: apps/v1 kind: Deployment metadata: name: nginx-demo labels: app: nginx-demo spec: replicas: 3 selector: matchLabels: app: nginx-demo template: metadata: labels: app: nginx-demo spec: containers: - name: nginx image: nginx:1.27 ports: - containerPort: 80selector.matchLabels和template.metadata.labels必须匹配Deployment 才知道管理哪些 Pod。这一对标签像是“寻亲启事”不匹配的话你可能创建出一堆“没妈管”的孤儿 Pod。4.2 Service 与配置类资源应用内外互联互通Deployment 创建的 Pod IP 是临时的换个节点或者重建一次就变了。要对外提供稳定访问入口就要用 Service。最常用的类型有三种ClusterIP只能在集群内部访问默认类型通常配合内部服务调用。NodePort通过节点 IP 端口对外暴露适合测试环境快速访问。LoadBalancer需要云厂商的负载均衡器配合生产环境最常用。一个完整的 NodePort Service 示例apiVersion: v1 kind: Service metadata: name: nginx-demo-svc spec: type: NodePort selector: app: nginx-demo ports: - port: 80 targetPort: 80 nodePort: 30080port是 Service 自己的虚拟端口targetPort是后端 Pod 里容器的端口nodePort是对外暴露的宿主机端口。这里最容易被问倒的问题是为什么selector要写app: nginx-demo因为它要找到带有这个标签的所有 Pod然后把流量转给它们这就是 Service 和 Pod 之间的“绑定契约”。生产实践里更常见的配套资源还有 ConfigMap 和 Secret。ConfigMap 放非敏感配置比如环境变量、配置文件内容Secret 放敏感数据比如密码和 token。应用里常见的“配置和镜像耦合”问题正确的解法就是把配置外置到 ConfigMap镜像保持纯净可复用。4.3 Ingress最后一公里的流量入口Service 的 NodePort 方式不适合直接暴露给公网一是端口范围有随机性二是每多一个 Service 就多占一个宿主机端口管理会乱。Ingress 就是在集群内部做七层路由的流量网关把 HTTP/HTTPS 请求按域名或路径转发到不同 Service。需要先装一个 Ingress Controller生产里最常用的是 ingress-nginxkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/namespace.yaml然后写一个 Ingress 规则apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: demo-ingress spec: rules: - host: demo.local http: paths: - path: /nginx pathType: Prefix backend: service: name: nginx-demo-svc port: number: 80这样访问http://节点IP/nginx时Ingress 会把请求按规则转发到 nginx-demo-svc:80。实际使用中还要配 Ingress Controller 的访问方式可以用 NodePort 或 LoadBalancer。这套链路学会之后你就能把任何自研应用用标准的“Deployment Service Ingress”三件套推上集群这也是 K8s 世界里最经典的应用部署模式。5. 排错指令集掌握这套解决 80% 的问题5.1 观察类命令与日志定位“出问题先看 get看不明白就看 describe再不行就看 logs”这句话基本覆盖了日常排查的逻辑顺序。先看整体状态kubectl get all -n namespace kubectl get nodes -o wide看状态不够还需要看事件kubectl describe pod pod-name -n namespacedescribe是排错最重要的命令之一它会把 Pod 生命周期里的所有关键事件列出来包括镜像拉取失败、调度失败、探针失败、端口冲突等。你在 events 部分看到的红色 Error 提示往往能直接一击命中问题所在。容器日志则是最后一层真相kubectl logs pod-name -n namespace kubectl logs pod-name -n namespace --previous--previous参数非常实用如果容器一直在重启当前日志通常看不了历史而--previous能拿到崩溃前容器的日志CrashLoopBackOff 的现场就这么抓到的。5.2 高频故障速查与快解下面这些是我在帮人排障时遇到最多的问题类型整理成表按图索骥效率最高现象可能原因排查与解法Pod 一直 Pending资源不足、调度器没法满足、污点限制kubectl describe pod看 eventskubectl describe node看资源余量给节点加 label 或用 nodeSelectorPod 反复 CrashLoopBackOff启动即崩溃、配置错误、探针失败kubectl logs pod --previous看崩溃前输出检查 command 和 env检查 liveness/readiness 探针的路径写得对不对ImagePullBackOff镜像名错、镜像不存在、仓库需要认证kubectl describe pod看 events 里 401/404 的详细信息先手动 docker pull 验证配置 imagePullSecrets节点 NotReadykubelet 异常、网络插件没起、资源耗尽到节点上执行systemctl status kubelet和journalctl -u kubelet -f检查 calico/flannel 的 Pod 状态Service 无法访问selector 没匹配上 Pod、端口写错、没装网络插件kubectl get ep service看 Endpoints 是否为空为空就说明 selector 有问题检查 Deployment 的 labels这几个场景覆盖了新手期常见的 90% 报错。你要是掌握了kubectl get/describe/logs三个命令以及journalctl看 kubelet 系统日志的方法排错就已经建立了基本盘。5.3 一些“劝退”我自己的实战经验排错这节最后分享几条我用几次加班熬夜换来的体会。不要一上来就删 Pod。很多新手看到 CrashLoopBackOff 第一反应是kubectl delete pod删完它又拉了一个一模一样的问题压根没解决还丢了崩溃前的现场。正确做法是先logs --previous抓日志再describe看事件最后才考虑是不是要删。节点级的疑难杂症记得上 journalctl。kubelet 是 systemd 管理的它的日志不在容器里。你kubectl describe node看到 kubelet 报的一些异常时一定亲自去节点上敲一句journalctl -u kubelet -f把滚动的日志先看完再判断方向。很多“集群失联”“节点反复 NotReady”的问题根源就是 kubelet 和 API Server 的通信出了问题而这个过程只有 kubelet 的系统日志会准确记载。改完配置要 verify不要想当然。比如改了 kube-proxy 的模式或者换了网络插件不要光看相关 Pod 起来了就算完事。建议在集群里创建一个简单的双 Pod 服务用 busybox 去 curl 一下另一个 Service 的 ClusterIP把网络全链路验证一遍再把老配置清干净。实测下来这一步能帮你省掉后面和网络相关的无数隐藏 bug。6. 从“会用”到“能用”集群维护的几个必备意识部署完只是开始日常维护的琐碎才是重头戏。很多人搭好集群之后热情高涨跑了几天遇到一个小问题就慌了原因在于缺少一套“例行维护清单”。以我自己的使用习惯为例优先级高的这么几件事每天看一次节点状态和关键 Namespace 的 Pod 状态、定期在非业务低峰期备份 etcd、留意镜像仓库里有没有 CVE 漏洞及时更新有高危漏洞的镜像。etcd 备份的具体操作不复杂但有模板可以遵循在 master 节点上执行 etcdctl 的 snapshot save。如果你的 etcd 是 kubeadm 方式部署的需要用 etcd 的证书参数。网上模板很多关键点是备份出来的文件要拷贝到集群之外的机器上保存一份否则集群真炸了备份文件也跟着没了那就等于白干。备份恢复这个动作建议在测试环境先完整演练一遍别等到需要的时候再去读文档。还有一件事一定要养成习惯Namespace 别乱用默认值。生产环境我见过有人在 default 命名空间里混着部署了几十个应用彼此不隔离不限制一个失控的应用把整个集群的 CPU 都吃光了。如果从一开始就按业务域划分命名空间甚至节点池配合 ResourceQuota 做资源限制集群的稳定性能高出一个数量级。7. 写在最后这套手册你可以怎么用这份手册从头到尾把 K8s 从组件认知、环境准备、集群部署、资源编写到问题排查串了一遍也是我摸索过程中沉淀下来的一套“最小可行路径”。你自己上手时建议先按第一节的架构图把组件讲给自己听一遍再照着第三节的步骤把集群拉起来然后尝试部署自己的第一个应用最后把排错表贴在工位上随时查。再给个我的个人习惯平时新建测试环境我会直接把之前沉淀好的基础配置脚本 YAML 模板拿来改名字和镜像不做重复劳动。你也应该尽早建立自己的 K8s 模板库和笔记库把每次踩坑的结论沉淀进去。等你的笔记攒到二三十条你就会发现自己已经成了身边人眼里“懂 K8s”的专家。那时候回看今天对着 YAML 一头雾水的自己大概只剩一个念头——先把基础打牢再谈花活这条路一直是最快的。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑