news 2026/10/17 5:21:55

手把手拆解K8s:从零部署集群到YAML与排错全攻略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
手把手拆解K8s:从零部署集群到YAML与排错全攻略

手把手拆解 K8s:从零部署一个集群,YAML 和排错指令都给你整理好了

搞 Kubernetes 也有一阵子了,从最初只知道kubectl get pods,到后来被各种组件按在地上摩擦,再到能独立把一套集群从裸机到可选网络插件、从部署应用到排障恢复,这一路踩坑无数。先说说我为什么想写这份手册:市面上讲 K8s 的资料太多了,但要么太深、直接甩源码分析,要么太浅、只教命令不教原理,新手很难找到一个“能照着敲完、敲完能懂”的完整路径。这份手册的定位就是给刚接触 K8s、准备自己动手装集群、或者正在被各种 YAML 折磨的人准备的。我会把组件讲明白、把部署流程捋清楚、把常用 YAML 和排错指令直接给你列出来,你照着操作就能跑起来一套能用的集群。

1. 先建立整体认知:K8s 到底在解决什么问题

很多新手最大的困惑是:我知道 K8s 很火,但它到底是干什么的?我直接docker run不行吗?

说白了,单机跑容器很简单,但你一旦面对几十上百个容器,就会遇到一堆新问题:容器挂了谁拉起?流量来了怎么分发?配置怎么统一管理?存储怎么挂载?滚动更新怎么做?机器故障怎么处理?K8s 就是来解决这一连串问题的。它把“跑容器”这件事抽象成了一套声明式系统——你告诉它“我想要什么状态”,它负责把实标状态收敛到你期望的状态。这个“声明式”的思路是整个 K8s 的灵魂,后面所有 YAML、所有组件、所有控制器,都是围绕这个核心运转的。

有一次我在某公司内部做技术分享,台下有个同事问了一个特别好的问题:”为什么我们要学这么多组件?直接封装成一个二进制启动不行吗?“ 这就要说到 K8s 的设计哲学了——模块化。每个组件只干一件事,组件之间通过 API 通信,这样任何一个模块出问题,你能非常快地定位,而且组件可以独立升级、独立扩展。理解了这个,你就不会被一大堆名词吓到,它们各自的分工其实非常清晰。

1.1 控制平面和数据平面:先分清两拨角色

K8s 集群里的所有节点,天然分成两个角色。

控制平面(Control Plane)是大脑,负责“决策”。它不跑你的业务容器,只负责管理整个集群的状态。生产环境通常会部署三副本实现高可用,但单机学习环境跑一套单节点也就够了。数据平面(Data Plane)是身体,负责“执行”,也就是真正跑业务容器的工作节点(Worker Node)。控制平面的节点叫 Master,数据平面的节点叫 Worker,这两者之间通过 kubelet 建立起稳定的通信链路。

我第一次部署的时候,就在这儿犯过迷糊:为什么控制平面的组件有这么多?为什么 kubelet 每个节点都有?后来我才明白,控制平面是一整套服务,它需要知道集群里发生了什么、期望状态是什么、怎么把差异收敛回来,这四个问题分别由 etcd、API Server、Scheduler、Controller Manager 来回答。而 kubelet 是控制平面伸向每个节点的“触手”,没有它,API Server 对节点就是“瞎的”。

除了这些,还有一个容易被忽略的角色——etcd。它存的是整个集群的“唯一事实来源”:有哪些节点、有哪些 Pod、期望副本数是多少,全部记录在 etcd 里。etcd 一旦不稳定,整个集群都会出问题,所以备份 etcd 是我每次部署完必做的第一件事。

1.2 组件解析:每个角色都在干什么

先花点篇幅把核心组件挨个讲清楚,因为不理解组件,后面的部署和排错基本就是两眼一抹黑。

API Server:整个集群的“门卫 + 收发室”。你敲的每个kubectl命令,本质上都是往 API Server 发 REST 请求。它负责认证、授权、限流,然后把请求写到 etcd。可以说,所有组件之间都不直接通信,全部通过 API Server 中转。这个设计的好处是解耦,坏处是 API Server 成了绝对的单点——它挂了,整个集群的“神经系统”就断了,虽然已经运行的容器还能继续跑,但你无法再做任何变更操作。

Scheduler(调度器):负责“分活”的。它盯着 API Server,发现有没有新的 Pod 还没被分配到节点。如果有,它就根据各种策略(资源余量、节点亲缘性、污点容忍等)决定这个 Pod 跑在哪台机器上。给新手一个理解方式:它就相当于公司的项目分配专员,来一个任务,看看谁手上资源多、谁机器新旧,分配下去。

Controller Manager(控制器管理器):这名字一听就抽象。它是多个控制器的集合——节点控制器、副本控制器、服务账号控制器等。它的核心逻辑就是一个无限循环:期望状态 vs 实际状态,有差异就调。比如 Deployment 说“我要 3 个副本”,控制器发现现在只有 2 个,它就通过 API Server 再创建一个。你会看到很多关于“控制器模式”的文章,核心就是这句话:调协循环(Reconcile Loop)。

kubelet:每个节点上的“宿管”。它是控制平面在节点上的代理,负责接收 API Server 下发的 Pod 定义,然后真正去把容器跑起来,并且定期向 API Server 上报节点和 Pod 的状态。如果容器崩了,也是它负责根据重启策略拉起。可以说,kubelet 是真正干活的角色。你排障时经常用journalctl -u kubelet查看它的日志,就是因为几乎所有节点侧的问题都能在 kubelet 日志里找到线索。

kube-proxy:每个节点上的“流量规则制定者”。它不负责转发数据(那是 Linux 内核的 iptables/IPVS 在转发),它只负责把这些转发规则配置好。举个例子:一个 Service 有三台后端 Pod,kube-proxy 会在节点上生成规则,让访问 Service 的流量按规则分发到任意一台 Pod。Service 的 ClusterIP 之所以只在集群内部可访问,是因为这些规则就写在每台节点的 iptables/nftables 里。

容器运行时(CRI):K8s 本身不直接 run 容器,它通过 CRI(Container Runtime Interface)和容器运行时打交道。说白了,CRI 是 K8s 和 Docker/containerd 之间的“翻译层”。现在新版本的 K8s 已经不支持直接把 Docker 作为运行时了——你别慌,你装的 containerd 本身就是 Docker 公司出的,以前 Docker 跑容器,在 K8s 里也是 containerd 在干活,只是现在不用再经过 Docker 那一层来 shim 了。你对 Docker 的熟悉对排障依然有用,只是 K8s 视角下容器运行时是 containerd。

讲到这里插一句题外话:网上铺天盖地的 “Docker 被 K8s 抛弃” 的说法,说精准点其实是“dockershim 被移除了”,containerd 依然是标准的容器运行时,它以前也是 Docker 的底层之一。这套概念理清了,你后面看各种报错就不会被绕晕。

1.3 核心资源对象:Pod、Deployment、Service 的关系

组件是骨架,资源对象是血肉。刚入门最容易混淆的就是 Pod、Deployment、Service 这几个词。

Pod 是 K8s 的最小调度单元,一个 Pod 里可以有一个或多个容器。这些容器共享网络命名空间和存储卷,比如主容器写日志、Sidecar 容器采集日志,它们放在同一个 Pod 里就非常合适。但如果你只是跑一个简单应用,一个 Pod 一个容器就是最常见形态。

Deployment 是对 Pod 的“上层管理”。它定义了 Pod 模板、期望副本数、更新策略。靠它,你才能实现滚动更新、回滚、水平扩缩容。你很少直接创建 Pod,都是创建 Deployment,让 Deployment 替你去管理一组 Pod。

Service 是“流量入口”。因为 Pod 是随时可能被重建的,IP 会变,你不能让调用方直接记 Pod 的 IP。Service 提供了一批稳定的虚拟 IP(ClusterIP)和 DNS 名字,流量进来后由 kube-proxy 分发给背后的 Pod。Service 和 Pod 之间通过标签选择器(selector)关联——这个细节后面写 YAML 的时候是核心考点。

用一个生活类比来串一遍:Pod 是饭店里的灶台,Deployment 是老板(规定要有几个灶台、坏了立刻补),Service 是门口的招牌(客人不用知道灶台在哪,照着招牌进店就行)。灶台坏了老板再找一个来,招牌不变,客人不受影响。

2. 集群部署实操:从裸机到能用,照着敲完就能跑

讲完组件,下面进入重头戏——部署。我会以 kubeadm 这个工具为主线。它是官方社区提供的集群部署工具,也是目前最主流、最理解 K8s 原理的部署方式。你可能听说过 RKE、K3s、二进制部署,各有适用场景,但 kubeadm 最平衡:既能让你理解组件怎么协作,又不用像二进制部署那样手工维护一堆 systemd 服务。

我的环境是三个节点:1 个 Master(2C4G)、2 个 Worker(2C4G),操作系统为 Ubuntu 22.04。如果你是 CentOS,命令稍微改一下包管理器就行。下面的操作在三个节点上都要做,只有标注“仅在 Master”的部分是单节点的。

2.1 环境准备的四板斧

部署前有四件事必须提前做,否则后面各种奇怪报错。这四条是经验之谈,每条都有血泪教训。

第一,关闭 swap。K8s 默认要求关闭 swap,因为如果启用了 swap,kubelet 的资源管理可能不准。执行swapoff -a后,还要把/etc/fstab里 swap 相关行注释掉,否则重启后 swap 自动打开,你就等着“一脸懵”吧。

第二,加载内核模块并配置 sysctl。需要overlay和br_netfilter这两个模块,前者是容器镜像分层存储的基础,后者是为了让 iptables 能正确处理桥接网络的数据包。配置完之后务必执行sysctl --system让它生效。

第三,设置 hosts 解析。三台机器之间要能通过主机名互通,在/etc/hosts里把三台机器的 IP 和主机名对应写清楚。这一步容易偷懒省掉,但省掉的后果是初始化时节点名解析不了,各种初始化失败,排查半天。

第四,安装容器运行时 containerd。可以直接用 apt 装 containerd,也可以装 docker 后让 kubelet 用 docker 的 containerd。我推荐直接装 containerd,干净的运行时最小化问题。装完以后有一个非常关键的配置:生成默认配置再修改SystemdCgroup = true这一项。Kubernetes 从 1.20 版本左右开始强烈建议使用 systemd 作为 cgroup 驱动,如果你不改,kubelet 和运行时是不同步的,节点会一直 NotReady。

然后安装 kubeadm、kubelet、kubectl 这三个二进制。三个节点都要装 kubeadm 和 kubelet,kubectl 主要用于在控制平面敲命令,但建议三个节点都装上,方便排查。装的时候注意:三件套的版本必须一致,因为版本不一致可能导致控制平面和 kubelet 通信的 API 版本不匹配。我在测试环境里因为偷懒直接装“最新版”,结果 kubeadm init 时提示 kubelet 版本太老,只好卸了重装。

2.2 kubeadm init:初始化控制平面

环境准备就绪后,在 Master 节点执行初始化。我用的初始化参数是:

kubeadm init \ --apiserver-advertise-address=192.168.1.10 \ --image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \ --kubernetes-version v1.28.2 \ --pod-network-cidr=10.244.0.0/16 \ --service-cidr=10.96.0.0/16

解释一下这几个参数,理解了才知道出了问题往哪查:

  • --apiserver-advertise-address:指定 API Server 对外通信的 IP,默认取节点默认网卡 IP,但如果机器多网卡,最好显式指定,否则可能会绑定到错误的网卡上。
  • --image-repository:因为某些网络原因,kubeadm 默认从官方镜像仓库拉镜像大概率超时,这里换成了国内可访问的镜像仓库。你可以根据自己的网络情况选择可用的仓库地址。
  • --pod-network-cidr和--service-cidr:这是两段虚拟网段。Pod 网段给每个 Pod 分配 IP,Service 网段给 Service 分配 ClusterIP。不同网络插件对 Pod 网段有默认要求,比如我后面要装的 flannel 插件默认就用 10.244.0.0/16。如果你在这里写的网段和插件默认网段对不上,装完网络插件 Pod 全都不正常。这点是新手最容易踩的坑。

执行完以后,等一小会儿,看到输出末尾有一段Your Kubernetes control-plane has initialized successfully就算成功。这时候有两件事必须马上做:

第一,按提示执行三条命令配置 kubeconfig:mkdir -p $HOME/.kube、cp -i /etc/kubernetes/admin.conf $HOME/.kube/config、chown $(id -u):$(id -g) $HOME/.kube/config。不配这个,kubectl 无法访问集群,会提示 permission denied。

第二,把输出的kubeadm join命令复制保存下来。这是 Worker 节点加入集群的凭证,里面带有 token 和证书的 SHA256 哈希,过期了要重新生成。

2.3 安装 CNI 网络插件

初始化成功后,Master 节点是 NotReady 状态,因为集群还没有网络插件。没有网络插件,Pod 之间没法互相通信,coredns 也跑不起来,节点会一直处于 NotReady。这一步卡住了大概 80% 的新手。

我常用的是 flannel,它配置简单,对新手最友好。

kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml

如果你前面配置的--pod-network-cidr不是 10.244.0.0/16,那你需要先下载这个 YAML 文件,手动修改里面net-conf.json的Network字段,再 apply。为什么?因为 flannel 会按照这个网段给每个节点分配一个子网,比如节点 A 分 10.244.1.0/24,节点 B 分 10.244.2.0/24,这个网段必须和 API Server 配置的 podCIDR 一致,否则 pod 的 IP 会和网络插件的路由规则互相矛盾。

等 flannel 的 Pod 变成 Running 后,执行kubectl get nodes就能看到节点状态变成 Ready。判断网络是否通了,可以跑一个测试 Pod,看它能不能访问到其他节点的 Pod IP。

2.4 节点加入集群

来到 Worker 节点,执行刚才保存的kubeadm join命令。如果命令弄丢了,可以在 Master 上执行kubeadm token create --print-join-command重新生成。

执行完毕后回到 Master,运行kubectl get nodes就能看到新节点加入。等待片刻,新节点状态也应该变成 Ready。如果一直是 NotReady,大概率是网络插件还没在新节点上正常跑起来,用kubectl get pods -n kube-system -o wide能看到 flannel 的 Pod 是不是在这个节点上报错。

这里说明一下,加入集群后 Worker 节点的 kubelet 会自动被 kubeadm 生成的证书和配置管理,你不需要在 Worker 手工配 kubeconfig,只有 Master 上需要。节点加入后 Master 的 kubelet 也统计的是整个集群的节点状态。

2.5 拉取测试应用验证集群

集群跑通后,拉一个最简单的应用验证一下。我喜欢先部署一个nginx,因为在宿主机上也常跑 nginx,对比起来特别直观。

先创建一个 Deployment:

kubectl create deployment nginx-test --image=nginx:1.25

再看看 Pod 状态:

kubectl get pods -o wide

如果能到 Running,说明镜像拉取、容器启动、kubelet 干活这些环节都通了。然后把它暴露成 NodePort 类型的 Service,方便从宿主机直接访问验证流量能够到达 Pod 里:

kubectl expose deployment nginx-test --type=NodePort --port=80 kubectl get service

看到 NodePort 分配的一个高位端口(比如 31485),就用“任意节点 IP + 端口”去访问一下。如果浏览器里能打开 nginx 的欢迎页,说明从 Service 到 kube-proxy 到 Pod 的整条链路是通的。这步验证做完,一套集群就算真正能用了。

3. YAML 编写技巧:从模仿到独立编写

YAML 是 K8s 的“操作语言”,没它你什么都做不了。很多新手一看到缩进和复杂的层级就头大,但其实 K8s 的 YAML 是有固定套路的,只要掌握了核心字段和对应关系,你就能自己写出可用的清单,而不是只会复制别人现成的。

先看一个最常见的 Deployment + Service 组合。为了便于阅读,我把两个资源分开放,实际工作中你可以在同一个文件里用---分隔写多个资源。

3.1 Deployment 清单拆解

apiVersion: apps/v1 kind: Deployment metadata: name: my-app labels: app: my-app spec: replicas: 3 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80 resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m"

有几个细节值得多说几句:

  • apiVersion不是随便写的,不同资源所属的 API 组不同。Deployment 用的是apps/v1(旧的版本是apps/v1beta1),Pod 用v1,Ingress 用networking.k8s.io/v1。写错了 kubectl 会直接报错告诉你认不到这个资源。刚开始如果拿不准,用kubectl explain deployment(或者任意资源)查对应字段和 apiVersion,比去翻网页快得多。

  • spec.selector.matchLabels和spec.template.metadata.labels必须匹配。Deployment 是通过标签选择器来管理它创建的 Pod 的。很多人只改了 template 里的标签,忘了改 selector,结果 Deployment 认为一个 Pod 都不是自己的,创建的 Pod 会变成“孤儿”,永远等不到滚动更新。这两个地方的标签一定保持同步。

  • resources这一项初学者经常省略。省略了不代表没有限制,而是在资源紧张时,调度器不会为它预留资源,也没有明确的驱赶阈值。生产环境别这么干,设置 requests 和 limits 能有效防止某个应用把整台机器吃光。CPU 的单位是“核”,100m代表 0.1 核,内存单位是Mi,是 MiB。

3.2 Service 清单拆解

apiVersion: v1 kind: Service metadata: name: my-app-svc spec: type: ClusterIP selector: app: my-app ports: - port: 80 targetPort: 80

Service 的selector.app必须能匹配到 Pod 的标签。它会自动找到所有带app: my-app标签且运行中的 Pod,把它们的 IP 汇总成后端列表。

这里的port是 Service 对外暴露的端口,targetPort是容器内的端口。如果你在 Deployment 里定义了containerPort: 80,那targetPort就填 80。初学者容易搞混:port是给集群里其他服务访问用的,targetPort是给 kube-proxy 转发到具体容器时的目标端口。你可以让port是 8080,targetPort是 80,这样外部访问用 8080,实际请求到了容器里是 80 端口,灵活一点没问题。

3.3 kubectl create 与 apply 的选择

新手经常问:kubectl create -f和kubectl apply -f有什么区别?

简单说:create是“创建”,如果资源已经存在,会报错;apply是“声明式”,如果资源不存在就创建,存在就更新。apply是 K8s 生态的主流用法,因为它能记录上一次应用的字段,你只改 YAML 中的差分部分,apply 会计算并打补丁。这意味着你可以工程化地管理配置——Git 里存一份 YAML,改哪儿就提交到 Git,然后 apply 到位。这也是 GitOps 的雏形。

日常操作中,我几乎只用apply。需要删除的时候才用delete。

3.4 多环境与命名空间管理

每个项目、每个环境(dev、prod)最好用独立的命名空间隔离,避免互相干扰。

apiVersion: v1 kind: Namespace metadata: name: dev

创建命名空间后,可以在metadata下加namespace: dev,或者用kubectl -n dev apply -f xxx.yaml。注意:如果没有显式指定 namespace,所有操作默认在default命名空间里。用kubectl get pods -A可以查看所有命名空间的 Pod——排障的时候这个命令频率极高。

一个好的习惯是:一个完整的应用,把 Deployment、Service、ConfigMap、Namespace 等等全部写在一个 YAML 文件里,用---分隔,然后用一条kubectl apply -f整体部署。这样能避免多文件之间版本互相错位的问题。

4. 排错指令与常见问题排查

这部分是做 K8s 绕不开的部分,也是我前面说“踩坑无数”的根源。新手最需要的是排障的“顺序感”:你拿到了一个异常状态,第一步该看什么、第二步该看什么。而不是把几十条命令瞎敲一遍。

我用一个从外到内的排查路径来讲:状态看kubectl get,详情看kubectl describe,日志看kubectl logs,深入容器看kubectl exec,节点系统问题看journalctl -u kubelet。

4.1 常用排错指令速查

先列一个我日常高频使用的速查表。这个表几乎覆盖了我 90% 的排障动作:

指令作用使用场景
kubectl get pods -A查看所有命名空间的 Pod 状态先确认故障范围和对象
kubectl get events --sort-by=.metadata.creationTimestamp按时间查看集群事件快速定位最近发生了什么异常
kubectl describe pod <pod-name> -n <ns>查看 Pod 详情和事件Pod 没起来时看为什么没起来
kubectl logs <pod-name> -n <ns> --tail=100查看容器日志应用崩溃、启动报错的根基排查
kubectl logs <pod-name> -c <container-name>查看指定容器日志多容器 Pod 里单独看某个容器的日志
kubectl exec -it <pod-name> -n <ns> -- /bin/sh进入容器内部调试看环境变量、网络通不通、配置文件
kubectl get svc -n <ns>查看 Service 和端口排查流量进不来时看 NodePort 分配
journalctl -u kubelet -f实时查看 kubelet 日志节点 NotReady、容器始终拉不起来
crictl ps/crictl logs <container-id>用 CRI 工具查看容器kubelet 操作不了容器时
kubectl get nodes查看节点状态集群整体健康检查

4.2 我实际踩过的一个 Pod 启动失败实例

我举个具体的例子,这是新手最容易遇到的:Pod 一直是ContainerCreating状态卡住不动。

排障顺序:先kubectl get pods -A看到状态,然后kubectl describe pod <pod-name> -n <ns>,重点看 Events 段。大概率出现以下几种:

一个是 “Failed to pull image”。原因可能是指定的镜像 tag 不存在、镜像仓库需要认证、或者网络不通拉不下来。解决办法就是手动在节点上crictl pull <image>验证一下拉取是否可行,同时检查镜像名是否正确。我曾经在配置里把nginx:1.25写成了nginx:1.25-alpine-perl,那个镜像 tag 根本不存在,导致卡了很久,教训就是先确认镜像是否存在再写 YAML。

再一个是 “Failed to create pod sandbox”。这多半是网络插件或者容器运行时配置的问题。检查节点上crictl ps -a能看到 sandbox 容器反复创建失败,再往下看 kubelet 日志,通常是 cni 插件报错或者 containerd 的 cgroup 配置没改。这个问题在前面步骤里如果你把 containerd 的SystemdCgroup = true改了,一般不会遇到。

还有一个是 “0/1 nodes are available: 1 Insufficient cpu”。这说明 Pod 申请的 CPU 请求量超过了节点可分配容量。你kubectl describe node <node-name>看 Allocated resources 那段就知道节点上已经分出去多少、还剩多少。删掉一些负载或者调低 requests 就能解决。

4.3 节点 NotReady 排查套路

节点 NotReady 是另一个高频问题。我在测试环境里就经常把 Master 节点当 Worker 一样猛跑,结果资源耗尽了节点就挂了。

排查步骤:先kubectl get nodes,看到哪个节点 NotReady。注意 NotReady 不代表节点“物理挂了”,只是 API Server 在一定时间内(默认 40 秒)没收到 kubelet 的心跳,被标记为 NotReady。

然后去那个节点上,执行journalctl -u kubelet -f看实时日志。一般情况下,能看到的几种情况:kubelet 无法连接 API Server(网络问题或证书问题)、容器运行时没启动(systemctl status containerd 看一下)、节点磁盘/内存/CPU 资源耗尽(df -h、free -g 先看物理资源)。

一个特别容易忽略的点:节点时间是否同步。kubelet 上报心跳依赖时间,如果节点时间和其他节点差太多,证书校验会失败,状态也会异常。所以生产环境务必配置 NTP 时间同步,新手初期可以手动date对一下。

4.4 数据与状态的快速备份

排障过程中你会意识到,数据的可用性比任何操作技巧都重要。K8s 集群的“数据”核心就是 etcd。

我建议在集群跑起来、部署任何有状态应用之前,先配置 etcd 快照备份。etcd 提供了内置的快照接口,你可以用etcdctl snapshot save命令把集群当前的状态保存下来。有了快照,在集群配置搞坏了、误删了某个重要资源、或者升级失败需要回滚的时候,你都能通过快照恢复。

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-$(date +%Y%m%d).db

恢复流程是把节点停掉,用etcdctl snapshot restore恢复到一个新目录,然后重启 etcd。这个操作涉及停机,如果你是一套只用来学习的单节点集群,折腾这个画面会很有“现场感”,但真在生产环境做,务必先演练几遍恢复过程再上。

5. 把集群变成开发环境的三件套

集群装好、基础资源弄明白之后,你会立刻发现,光有 K8s 还不够,它还缺一些“生态级”的便利设施。我自己在部署完一套集群后,一定会接上三个东西,让日常开发调试效率翻倍:Dashboard(可视化面板)、Metrics Server(资源指标)和 Ingress Controller(HTTP 路由)。这三样装完,你才算真正把“能用”的集群升级成了“好用”的集群。

5.1 装一个可视化面板,新手友好度直接翻倍

很多人觉得 K8s 命令行很酷,但对新手来说,有一个可视化界面能极大帮助理解“资源之间的关系”。

官方推荐的是 Kubernetes Dashboard。安装命令很简单:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml

但这里有个坑:新版 Dashboard 默认只允许通过 HTTPS 访问,而且默认账号没有登录权限,需要手动创建一个管理员 ServiceAccount(服务账号)。创建过程不算复杂:

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

从kubernetes-dashboard里把这个 ServiceAccount 的 token 拿到,登录时填上去就能进去。Dashboard 能看到 Deployment、Pod、Service、PVC 等资源的运行状态,也能直接查看容器日志,点击操作即可完成常见变更。对于新手来说,它会帮你在脑子里把“抽象组件”和“实际资源”对应起来。

5.2 Metrics Server:让 kubectl top 命令可用

kubectl top nodes这个命令新手经常用,但会报错 “Metrics API not available”。原因是你没安装 Metrics Server。

Metrics Server 是一个聚合 API 扩展,它从每个节点的 kubelet 上采集 CPU 和内存使用数据,供 HPA(水平Pod自动扩缩容)、kubectl top这类场景使用。其实很多人不需要它也能跑应用,但没有它,你连最基本的资源使用率都看不了,调优和排障都无从谈起。

安装命令一般是:

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

装完以后稍微等一两分钟,然后就能kubectl top nodes了。如果发现 Pod 一直 CrashLoopBackOff,排查发现 Metrics Server 需要打开--kubelet-insecure-tls参数(因为自签证书的问题),在部署的 YAML 里找到 args 段加一下即可。这也是新手经常卡在一半的地方。

5.3 Ingress Controller:用域名访问你的服务

Service 的类型有 ClusterIP、NodePort、LoadBalancer。NodePort 只能给你一个随机端口,LoadBalancer 在裸机上很难直接实现,那想用域名优雅地访问怎么办?答案就是 Ingress。

Ingress 本身就是一组路由规则,真正实现这些规则的是 Ingress Controller,比如 Nginx Ingress Controller。你可以理解成:Ingress 定义了“哪个域名、哪个路径,应该转到哪个 Service”,Ingress Controller 把规则变成实际的流量转发配置(就是 Nginx 的配置)。

安装 Nginx Ingress Controller 的一般方式:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.0/deploy/static/provider/baremetal/deploy.yaml

然后你可以写一份 Ingress 清单:

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-app-ingress spec: rules: - host: app.example.com http: paths: - path: / pathType: Prefix backend: service: name: my-app-svc port: number: 80

配置好后,在/etc/hosts里把app.example.com指向你集群的任何一个节点 IP,就能通过域名 + 80 端口访问到你的应用了。这一步做完,新手才能真正体会“为什么说 K8s 适合跑 Web 服务”——域名、路由、负载均衡规则都统一在一个系统里管理,你不需要再手动改 Nginx 配置。

6. 一个更适合实战的部署方式参考:容器化部署

上面讲的是经典的 kubeadm 方式。如果你是在本地开发环境,或者想更快速验证一套集群,还有另一种非常适合的部署方式:用 Docker 容器直接模拟集群节点,或者直接使用 Kind(Kubernetes in Docker)。我自己在本地开发时用的就是 Kind,但需要强调:这种方式的网络模型和资源设计跟生产环境有差异,只适合本地测试,不适合承载真实流量。

用 Kind 创建一个单节点集群的命令极其简单:

kind create cluster --name dev

它会自动拉起控制平面容器和 worker 节点容器,然后生成 kubeconfig。一分钟不到,一个可用的 K8s 集群就横空出世。安装 services 和网络插件也是一样的kubectl apply -f ...。

如果你想模拟多节点:

kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane - role: worker - role: worker

保存为kind-config.yaml,然后kind create cluster --config kind-config.yaml,就能得到一个伪“多节点”集群(实际上这些节点都是 Docker 容器)。对学习多节点调度逻辑、观察控制器行为,比单节点直观太多了。

Kind 还有几个非常实用的特性:可以指定 K8s 版本、可以让宿主机端口映射到集群里的 NodePort、可以很方便地导出/导入本地镜像。这一点在测试新版本镜像、做项目 Demo 时特别顺手。

如果你在 Windows 或者 Mac 本地开发,Docker Desktop 自带 Kubernetes 开关,也对应着这个容器化部署的思路,适合入门尝鲜,但真到学习“部署流程”这件事,kubeadm 才是正统路径。两种方式按需选择,别把 Kind 当作生产环境的替代品。

7. 实战学习路径建议与我的踩坑心得

写到这里,K8s 的基础脉络已经梳理完了。我看到很多新人学 K8s 的顺序是:先背命令、再写 YAML、然后装个工具搞集群,最后看排毒——这个顺序其实有点痛苦。我更推荐把这个手册当成一条“以任务驱动的学习路线”:先搞懂组件,然后亲手部署集群,再把日常场景(部署、扩容、滚动更新、暴露服务)逐一实现。每实现一个场景,把 YAML 反反复复写几遍,把排障指令从头到尾跑一遍。做完这轮,你对 K8s 的体感比看十篇教程都强。

最后分享几个我在这条路上踩过的、并在本手册里已经隐含提到的坑,单独列出来:

  • 第一,组件版本务必统一。kubeadm、kubelet、kubectl、K8s 的 version 必须对齐,否则会出现各种“隐形的兼容性报错”。找问题的方式很简单——日志里只要看到version、dial tcp、certificate这三个词,大概率是版本或证书问题。

  • 第二,安装 containerd 或 docker 之后,一定确认SystemdCgroup = true是否设置。这个设置我建议在装完容器运行时后立刻验证一次,别等到节点一直 NotReady 才发现。

  • 第三,不要随意修改控制平面组件容器的宿主机端口映射。默认情况下 API Server 监听 6443,etcd 监听 2379。我见过有人为了“省资源”把 master 组件都塞进一个容器里,结果出问题了连定位都困难。组件分开跑,出了问题你能快速用journalctl或者crictl logs看到底是谁在报错。

  • 第四,使用kubectl explain比搜索引擎可靠得多。拿不准字段怎么写,直接在终端里kubectl explain deployment.spec一层层往下看,字段说明、类型、默认值全都有,而且保证和你的集群版本一致。

  • 第五,etcd 快照备份从第一天就做。不管你认为是“测试环境无所谓”,还是“正式环境我小心点就行”,数据这东西,真的出事的时候没有后悔药。快照不是保险,是你恢复现场唯一的手段。

我现在回头看,自己就是从这套路径里一步步走过来的——从看不懂组件,到能独立排障,再到能帮别人搞定集群问题。K8s 学习曲线确实陡,但只要把关键概念吃透,把核心操作练熟,剩下的都是水到渠成的事。希望这份手册能帮你少走一些弯路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 5:21:53

NVD API 2.0与CPE匹配:Python实现漏洞预警自动抓取与影响面分析

搞漏洞监控的人都有个共同感受&#xff1a;CVE编号满天飞&#xff0c;但真正能落到自家系统上的预警&#xff0c;靠的是结构化的数据。NVD&#xff08;美国国家漏洞库&#xff09;的API 2.0是我日常拉取漏洞数据的首选&#xff0c;它不只给一个CVE编号&#xff0c;还会附带CPE&…

作者头像 李华
网站建设 2026/10/17 5:20:52

TensorFlow迁移学习实战:VGG16图像分类微调全流程

先聊个真实的场景。我之前接到一个图像分类的任务&#xff0c;数据只有五千多张图、十个类别&#xff0c;设备也只是一块普通的消费级显卡。如果从零开始训一个残差网络&#xff0c;大概率是过拟合加训练时间漫长&#xff0c;调参调到怀疑人生。但同样是这个任务&#xff0c;换…

作者头像 李华
网站建设 2026/10/17 5:20:48

Claude Code模板实战:用CLAUDE.md与斜杠命令驯服AI编程助手

用了两个多月 claude-code&#xff0c;我最大的感触不是它能写多少代码&#xff0c;而是没有模板的 claude-code&#xff0c;约等于一匹脱缰的野马。今天让它看一段代码&#xff0c;它给你写成一篇分析报告&#xff1b;明天让它重构一个模块&#xff0c;它顺手把无关文件也改了…

作者头像 李华
网站建设 2026/10/17 5:19:57

Windows/Linux/macOS彻底停止所有Python进程的速查指南

说实话&#xff0c;每个做开发的人电脑里都积压过一堆没退干净的 Python 进程。跑着的爬虫脚本停不下来&#xff0c;Jupyter 内核残留、FastAPI 调试进程挂在那儿&#xff0c;甚至还会出现“明明关闭了 IDE&#xff0c;但是项目端口还被占用”的诡异情况。Windows、Linux、macO…

作者头像 李华
网站建设 2026/10/17 5:18:34

异构编程实战:从核函数到访存优化的关键思路

在高性能计算异构编程这个方向上摸爬滚打了好几年&#xff0c;我最大的感受是&#xff1a;很多人把它想成“把代码搬到显卡上跑一跑”&#xff0c;但真正动手之后才发现&#xff0c;搬过去只是一个开始。异构编程改变的不只是代码的运行位置&#xff0c;更是你思考并行问题的方…

作者头像 李华
网站建设 2026/10/17 5:18:18

考研数据结构真题答案整理:从解题思路到代码验证的完整指南

1. 一份考研真题答案的整理思路与整体设计1.1 为什么选择整理《数据结构》真题答案每年考研季结束&#xff0c;总有一批人会把自己做过的真题答案整理出来。有人是为了复盘&#xff0c;有人是为了给学弟学妹留点资料&#xff0c;也有人纯粹是强迫症发作&#xff0c;觉得不做完整…

作者头像 李华