先说结论:你缺的不是技术,是翻译
学 Docker 的人第一次打开 Kubernetes(以下简称 K8s)文档,普遍会有一种被背叛的感觉:镜像还是那个镜像,容器还是那个容器,可满屏的 Pod、Deployment、Service、Ingress、ConfigMap 全是生词,YAML 一写就是上百行,跑个最简单的应用比写业务代码还累。很多人卡在这里,不是因为 K8s 本身有多难,而是因为没人把新概念翻译回他们已经懂的语言。
这篇文章就是来做这件翻译工作的。主线很简单:
- 先泼一盆冷水,讲清 K8s 的真实定位和成本,帮你判断自己到底需不需要它;
- 用一张核心概念对照大表,把 K8s 的每个核心对象映射回 Docker 和 Compose 里的对应物;
- 拿一个完整的 Compose 例子,逐段翻译成 K8s 的 YAML,让你亲眼看到「同一件事的两种写法」;
- 给一份 kubectl 生存命令对照表、一条本地体验路线和一张选型判断表。
读完你不一定会立刻去搭集群,但至少再看 K8s 的文章和文档时,每个名词你都能在脑子里对上号。至于 Compose 本身的进阶用法(环境变量、健康检查、多环境),可以先看本系列的 Docker Compose 进阶,那是理解这篇的全部前置知识。
一、心态先行:K8s 不是更高级的 Docker
最常见的误解,是把 K8s 理解成「Docker 的高级版」或者「更强的 Compose」。这个定位从一开始就错了:
K8s 不是更高级的 Docker,而是一套集群操作系统。Docker 解决的是「在一台机器上怎么把应用装进容器跑起来」,K8s 解决的是「在几十上百台机器组成的集群里,怎么调度、编排、自愈、扩缩这些容器」。两者的抽象层级完全不同:Docker 面对的是一台机器,K8s 面对的是一个机房。
这个区别决定了 K8s 的一切「繁琐」都有出处:
- 你只有一台机器时,「容器挂了重启一下」是一句
restart: unless-stopped;在集群里,机器本身都可能整台宕机,应用必须能自动漂移到别的机器上,这就需要调度器、控制器、健康探针一整套机制; - 你只有一台机器时,服务发现就是「容器名当主机名」;在集群里,容器的 IP 天天变,必须有一层稳定的访问入口,这就是 Service 存在的理由;
- 你只有一台机器时,配置就是
.env文件;在集群里,配置要能统一下发、滚动更新、区分敏感与非敏感,于是有了 ConfigMap 和 Secret。
所以先把成本算清楚。单机个人项目上 K8s,成本清单大概是这样的:
| 成本项 | 单机 Docker/Compose | 单机硬上 K8s |
|---|---|---|
| 部署一个应用的配置量 | 一个 compose 文件,几十行 | Deployment、Service、Ingress 等多个 YAML,上百行 |
| 集群本身的资源占用 | 无额外开销 | 控制平面组件常驻,先吃掉一部分 CPU 和内存 |
| 出问题时的排查链路 | 看容器日志基本够了 | 要分清是 Pod、节点、网络插件还是存储的问题 |
| 升级维护 | 换镜像、重建容器 | 还要管 K8s 自身的版本升级与组件兼容 |
| 学习曲线 | 一两天上手 | 概念体系庞大,摸到门道要以周计 |
WARNING个人单机、两三台小服务器的场景,硬上 K8s 属于典型的用运维复杂度换根本用不上的能力:你为高可用、自愈、弹性扩缩付出了全部学习与维护成本,而你的流量和规模根本触发不了这些能力。先把 Compose 用透,收益高得多。
泼冷水不是劝退。K8s 是当下云原生生态的事实标准,托管服务、CI/CD、监控、服务网格全都围着它转,理解它的概念对任何做后端和运维的人都只有好处。但「理解它」和「在自己的小服务器上养一套它」是两回事。这篇的态度就是:先用对照法把概念学明白,什么时候真该上,后文有明确的判断表。
二、核心概念对照大表
先上全篇最重要的一张表。建议先通读一遍有个整体印象,后面每一节都会展开其中几行。
| 你已经会的东西 | K8s 里的对应物 | 关键区别说明 |
|---|---|---|
| 镜像 Image | Image(完全同名同物) | 没有任何区别,K8s 用的就是 Docker 镜像格式,从同样的仓库拉取 |
| 容器 Container | Pod 里的一个容器 | 容器在 K8s 里不是最小单位,它被装进 Pod 里运行 |
docker run 起一个容器 | Pod | Pod 是最小调度单位,可以装一个或多个容器 |
| Compose 的一个 service | Deployment + Service | Deployment 管「跑几个副本、怎么更新」,Service 管「怎么被访问」,一个职责拆成两个对象 |
| docker-compose.yml | 一堆 YAML 文件(或一个文件多段) | 每个对象一段 YAML,用 --- 分隔,靠 kubectl apply 一起提交 |
| 数据卷 Volume | PV(持久卷)+ PVC(持久卷声明) | 多了一层抽象:PVC 是「我要一块 10Gi 的盘」的申请,PV 是集群实际供给的那块盘 |
| Docker 自定义网络+容器名互访 | Service + 集群 DNS | 容器名换成 Service 名,跨命名空间还能带后缀,原理还是 DNS 解析 |
| Nginx 反向代理 | Ingress + Ingress Controller | Ingress 只是规则声明,真正干活的 Controller(如 ingress-nginx)要自己装 |
.env 环境变量 | ConfigMap | 存非敏感配置,键值对形式,可挂成环境变量或文件 |
| 写在 compose 里的密码 | Secret | 存敏感配置,Base64 编码存储(注意:只是编码,不是加密) |
restart: unless-stopped | 控制器自愈(Deployment 托管 Pod) | 不是容器自己重启,而是控制器发现副本数不对,重新拉起新 Pod |
docker compose up -d | kubectl apply -f xxx.yaml | 都是声明「我要什么」,让系统去达成 |
docker ps | kubectl get pods | 看的不是容器列表,而是 Pod 列表 |
逐行说几个容易卡住的点。
**镜像是唯一零成本迁移的东西。**你在 Dockerfile 里构建的镜像、在私有仓库里存的镜像,到了 K8s 里原样使用,一个字都不用改。这是整个迁移里最让人安心的一点:你的构建资产全部保值。
**Compose 的一个 service,在 K8s 里被拆成了两个对象。**这是初学者最困惑的地方。Compose 里写一个 service,运行和访问两件事都齐了;K8s 把它拆开:Deployment 只负责「这个应用跑几个副本、镜像是哪个版本、挂了怎么补」,Service 只负责「给这组副本一个稳定的访问地址」。拆开的原因是职责确实不同:一组 Pod 可以被多个 Service 暴露(对内一个、对外一个),一个应用也可以只跑不被访问(后台任务)。理解了这个拆分,K8s 一半的对象就通了。
**存储多了一层「申请与供给」。**Docker 里写个 volumes 映射,盘就是你的。K8s 里应用只能提需求(PVC:我要 10Gi、可读写),至于这块盘最终是云盘、NFS 还是本地目录,由集群的 PV 供给机制决定。应用不关心盘从哪来,这正是集群抽象的意义:换个集群,YAML 一行不用改。
**Ingress 本身不干活。**这点和很多人想的不一样:Ingress 只是一份「域名+路径 → 转发给哪个 Service」的规则声明,集群里必须额外装一个 Ingress Controller(最常见的是 ingress-nginx)来读规则并真正做反向代理。类比一下:Ingress 相当于你写好的 Nginx 配置文件,Controller 相当于 Nginx 进程本身,光有配置文件,没有进程读它,什么都不会发生。
WARNINGSecret 只是 Base64 编码,不是加密。任何能读到 Secret 的人都能一条命令解出明文。把 Secret 当保险箱、把含 Secret 的 YAML 随手提交到公开仓库,属于把密码明文发到全世界。生产环境要配合 RBAC 权限控制,有条件再上外部密钥管理或静态加密。
三、Pod 为什么要多一层
对照表里最核心的新概念就是 Pod。它是 K8s 的最小调度单位,理解了它为什么存在,其余概念都是顺水推舟。
在 Docker 的世界里,容器就是最小单位,你想跑什么就 docker run 什么。K8s 在容器外面包了一层 Pod,主要为了解决两个问题:
**第一,同 Pod 内容器共享网络。**同一个 Pod 里的所有容器共用一个网络命名空间,也就是共享同一个 IP 地址和端口空间,彼此之间用 localhost 就能互访。这意味着一组必须「贴身协作」的容器可以当成一个整体调度:它们永远落在同一台机器上,生一起生、死一起死,不会出现主容器在这台机器、辅助容器在另一台机器的尴尬。
**第二,同 Pod 内容器共享存储。**Pod 可以定义卷,挂给 Pod 内的多个容器共同读写,适合主进程写日志、辅助进程收集日志这类配合。
最常见的多容器模式叫 sidecar(边车):主容器跑业务,旁边挂一个辅助容器干杂活,比如收集日志、做代理转发、同步配置。像服务网格里的流量代理,就是以 sidecar 形式注入到每个业务 Pod 里的。
当然,绝大多数情况下一个 Pod 里就一个容器。单容器 Pod 你完全可以近似理解成「K8s 版的容器」,只是外面多了一层壳,多了标签、注解、探针这些集群管理需要的元数据。下面看一个最简单的 Pod 长什么样:
apiVersion: v1kind: Podmetadata: name: my-nginx labels: app: nginxspec: containers: - name: nginx image: nginx:1.27 ports: - containerPort: 80对照着 Docker 看:image 还是那个镜像,containerPort 就是你熟悉的容器端口,containers 是个列表——这就是为多容器留的位置。实际工作中你很少直接写裸 Pod,因为裸 Pod 挂了没人管,真正用的是下一节的 Deployment。
四、声明式思维:从「过程」到「期望状态」
如果说 Pod 是概念上最核心的新东西,那声明式就是思想上最核心的新东西。
Compose 其实已经是半声明式了:你写「我要跑这三个服务」,docker compose up 负责把现状调整成文件里写的样子。但 Compose 的自愈能力到容器级为止:容器挂了靠 restart 策略原地重启,机器挂了,上面的一切都没了。
K8s 是彻底的声明式。你提交 YAML,描述的是期望状态:我要这个应用跑 3 个副本,用这个镜像,对外暴露这个端口。集群里的控制器会持续地对比「期望状态」和「实际状态」,发现不一致就动手修正,永远向期望靠拢。你不需要写任何「如果挂了就重启」的逻辑,因为自愈不是某个功能,而是声明式的自然结果。
这个差别,光说不如动手看一遍。下面这条演示命令链,建议你在本地体验环节亲手跑一次,冲击力比看十篇文章都强:
# 部署一个 3 副本的应用kubectl create deployment demo --image=nginx:1.27 --replicas=3
# 查看 Pod,可以看到 3 个副本都在运行kubectl get pods
# 手动删掉其中一个 Pod(模拟它突然崩溃)kubectl delete pod <上面任意一个Pod的名字>
# 立刻再看:一个新的 Pod 已经被自动创建出来补位kubectl get pods
# 查看副本数,始终维持在 3kubectl get deployment demo你删掉的那个 Pod 没有「重启」,而是 Deployment 控制器发现「期望 3 个、实际 2 个」,立刻新建了一个补上。注意新 Pod 的名字和 IP 都变了——在 K8s 的世界里,Pod 是随时可替换的消耗品,身份不重要,数量和状态才重要。也正因为 Pod 朝生暮死,才必须有 Service 这一层稳定入口兜底,否则调用方根本追不上天天变的 Pod IP。
理解了这一点,很多 K8s 的设计就都顺理成章了:滚动更新是「逐步把旧 Pod 换成新 Pod 并维持期望副本数」,扩缩容是「改一个数字,控制器去增删 Pod」,节点宕机恢复是「控制器发现一整台机器的 Pod 没了,在别的机器上重建」。全是同一套机制的不同表现。
五、完整对照实战:把一个 Compose 例子翻译成 K8s
下面进入全篇的重头戏。先看一个你已经很熟悉的 Compose 例子:一个后端应用加一个 Nginx 前置,Nginx 把流量反代给后端。
Compose 版本(docker-compose.yml):
services: web: image: nginx:1.27 ports: - "8080:80" depends_on: - app app: image: myapp:1.0 environment: - APP_ENV=prod deploy: replicas: 2翻译成 K8s,需要三个对象:app 的 Deployment、app 的 Service、web(Nginx)的 Deployment 加对外 Service。逐段来。
第一段,app 的 Deployment,对应 Compose 里 app 的「跑什么、跑几个」:
apiVersion: apps/v1kind: Deploymentmetadata: name: appspec: replicas: 2 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: app image: myapp:1.0 ports: - containerPort: 8080 env: - name: APP_ENV value: "prod"对照着看:replicas: 2 就是 Compose 里的副本数;template 里描述的就是 Pod 本人,image、containerPort、env 全部是你认识的东西,只是组织方式变了。selector.matchLabels 和 template.metadata.labels 这对标签是 Deployment 认领 Pod 的凭据,两边必须一致,这是新手最常写错的地方之一,记住「控制器靠标签找自己的孩子」就行。
第二段,app 的 Service,对应 Compose 里「别的服务用名字 app 就能访问它」这件事:
apiVersion: v1kind: Servicemetadata: name: appspec: selector: app: myapp ports: - port: 80 targetPort: 8080Service 靠 selector 标签选中 app 的那组 Pod,给它们一个稳定的虚拟 IP 和 DNS 名。集群内任何地方访问 http://app 都会被转到某个 app Pod 的 8080 端口——和 Compose 里用服务名互访是一模一样的体验,只是实现从 Docker 内置 DNS 换成了集群 DNS + Service 转发。
第三段,Nginx 前置。Compose 里 Nginx 既是应用又负责对外发布端口,K8s 里照样拆成 Deployment + Service 两件:
apiVersion: apps/v1kind: Deploymentmetadata: name: webspec: replicas: 1 selector: matchLabels: app: web template: metadata: labels: app: web spec: containers: - name: nginx image: nginx:1.27 ports: - containerPort: 80---apiVersion: v1kind: Servicemetadata: name: webspec: type: LoadBalancer selector: app: web ports: - port: 80 targetPort: 80这里的 Service 用了 type: LoadBalancer,对应 Compose 里的 ports: "8080:80" 对外发布:在云厂商的托管 K8s 上,它会自动给你配一个云负载均衡器和公网 IP;在本地 kind/minikube 里这个类型拿不到真正的外部 IP,后文体验环节会说明替代办法。另外,Nginx 反代后端的配置里,upstream 写 http://app 即可,和 Compose 里写服务名的习惯无缝衔接。
三段 YAML 放进一个文件(段与段之间用 --- 分隔),一条命令提交:
kubectl apply -f app.yamlkubectl get pods,svc把两边并排总结一下,翻译关系就彻底清楚了:
| Compose 里的写法 | K8s 里的对应写法 |
|---|---|
services.app.image | Deployment 的 template.spec.containers[].image |
deploy.replicas | Deployment 的 spec.replicas |
environment | 容器 env 字段,或抽到 ConfigMap/Secret 引用 |
ports: "8080:80" | Service 的 port/targetPort,对外则选 LoadBalancer 或 Ingress |
服务名互访(http://app) | Service 名互访(http://app),机制换成集群 DNS |
depends_on | 无直接对应,靠应用自己重试或初始化容器解决 |
docker compose up -d | kubectl apply -f |
最后一行值得多说一句:depends_on 在 K8s 里没有对应物,这不是功能缺失,而是设计哲学不同——集群环境里依赖的服务随时可能重启漂移,应用必须自己具备「连不上就重试」的能力,而不是指望编排工具保证启动顺序。往 K8s 迁移时,这是应用代码层面最常见的改造点。
六、kubectl 生存命令对照表
操作层面,kubectl 就是 K8s 的 docker 命令行。下面这张表覆盖日常九成的动作,左边是你已经会的,右边是对应写法:
| 你想干什么 | Docker/Compose | Kubernetes |
|---|---|---|
| 看运行中的实例 | docker ps | kubectl get pods |
| 看所有资源概览 | docker compose ps | kubectl get all |
| 部署/更新 | docker compose up -d | kubectl apply -f app.yaml |
| 看详细信息 | docker inspect <容器> | kubectl describe pod <名字> |
| 看日志 | docker logs -f <容器> | kubectl logs -f <Pod> |
| 进容器执行命令 | docker exec -it <容器> sh | kubectl exec -it <Pod> -- sh |
| 扩缩容 | docker compose up -d --scale app=3 | kubectl scale deployment app --replicas=3 |
| 更新镜像版本 | 改 compose 文件后 up -d | kubectl set image deployment/app app=myapp:2.0 |
| 看滚动更新状态 | 无(直接替换) | kubectl rollout status deployment/app |
| 回滚版本 | 改回旧镜像再 up -d | kubectl rollout undo deployment/app |
| 删掉一个实例 | docker rm -f <容器> | kubectl delete pod <名字>(托管 Pod 会自动补新) |
| 删除整套应用 | docker compose down | kubectl delete -f app.yaml |
| 看资源占用 | docker stats | kubectl top pods(需装 metrics-server) |
| 把本地端口转发到服务 | 靠 ports 发布 | kubectl port-forward svc/web 8080:80 |
| 看配置文件原文 | cat docker-compose.yml | kubectl get deployment app -o yaml |
有三个差异点要特别适应一下:
第一,kubectl 的一切操作都围绕「资源对象」而不是「容器」。你 describe 的是 Pod、Deployment、Service,日志、执行命令也是先定位到 Pod。刚开始会觉得隔了一层,用久了会发现按对象思考正是集群管理的方式。
第二,kubectl delete pod 对新手是个陷阱:删掉 Deployment 托管的 Pod,它立刻补一个新的出来,看起来像「删不掉」。这恰恰是自愈在工作。要真正停掉应用,删的是 Deployment 或者把副本数调到 0。反过来,这也意味着在生产集群里随手 delete pod 是危险动作,你以为在清理,它以为在故障恢复,流量可能被打到刚启动还没就绪的新 Pod 上。
第三,kubectl port-forward 是本地调试的神器:它能把集群里任意 Service 或 Pod 的端口转发到你本机,效果类似临时做了一条 SSH 隧道,不用为了调试就把服务暴露到公网。
七、本地体验路线:先在自己电脑上玩起来
理解 K8s 的正确姿势是先在本地起一个玩具集群,把第五节的 YAML 真跑一遍。本地工具有两个主流选择,二选一即可:
| 工具 | 特点 | 适合 |
|---|---|---|
| kind | 把集群节点跑在 Docker 容器里,轻量、起停快、贴合 CI 场景 | 已经装好 Docker、想快速反复重建的人 |
| minikube | 功能全,支持多种驱动,自带仪表盘和插件生态 | 想顺带体验插件、Ingress 等完整功能的人 |
本系列读者都装了 Docker,所以推荐 kind。完整体验流程如下:
# 1. 安装 kind(Linux 示例,其他系统去 kind 官网看对应方式)curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.24.0/kind-linux-amd64chmod +x ./kindsudo mv ./kind /usr/local/bin/kind
# 2. 创建一个单节点集群(节点本身就是个 Docker 容器)kind create cluster --name learn
# 3. 确认 kubectl 能连上kubectl cluster-infokubectl get nodes
# 4. 跑一遍第四节的自愈演示kubectl create deployment demo --image=nginx:1.27 --replicas=3kubectl get pods -w
# 5. 把第五节的 app.yaml 存好并部署kubectl apply -f app.yamlkubectl get pods,svc
# 6. web 的 Service 是 LoadBalancer 类型,本地没有云厂商给它分配外部 IP# 改用端口转发在本机访问验证kubectl port-forward svc/web 8080:80# 浏览器打开 http://localhost:8080 即可
# 7. 玩完销毁集群,不留任何残留kind delete cluster --name learn跑这一圈时重点观察三件事:一是删 Pod 自动补位的全过程,二是 kubectl describe 一个 Pod 时里面记录的事件(调度到哪个节点、镜像拉取进度、探针结果都在里面,这是 K8s 最主要的排障入口),三是 Service 的 DNS 名在容器内真实可用——可以 kubectl exec 进任意 Pod 用 curl http://app 验证。
如果本地机器配置紧张,也完全可以直接用云厂商的托管 K8s 试用集群练手,概念完全一致,只是别忘了练完释放资源。
八、选型判断:什么时候该上,什么时候别上
学归学,真到给自己的项目做选型时,用下面这张表对照着判断:
| 判断维度 | Compose 就够了 | 该考虑 Swarm | 该考虑 K8s |
|---|---|---|---|
| 机器数量 | 1 台 | 2–5 台 | 5 台以上,或弹性伸缩的云环境 |
| 应用数量 | 十几个服务以内 | 十几个到几十个 | 几十上百个服务、多团队共用 |
| 高可用要求 | 单机挂了人工恢复可接受 | 希望单机故障自动漂移 | 要求节点级、可用区级容灾 |
| 发布频率 | 一天几次以内 | 每天多次 | 多团队高频发布、需要灰度/金丝雀 |
| 运维人力 | 个人或兼职 | 一两个人 | 有专职平台/运维团队,或买托管版 |
| 生态需求 | 基本没有 | 基本没有 | 需要服务网格、精细监控、云厂商深度集成 |
三条经验线可以直接套用:
- 个人项目、自用服务、一台小服务器:Compose 就是最优解,别犹豫。这也是本系列前十几篇一直在深耕 Compose 的原因——它覆盖了绝大多数个人和小团队场景。
- 有三五台机器、想要基本的故障漂移和滚动更新,但没人愿意养 K8s:可以看看 Docker Swarm,它和 Compose 共用一套心智模型,学习成本几乎为零,代价是生态和上限都有限。
- 团队规模、多台机器、发布频繁、且有人能专职维护(或者愿意为托管版付费):K8s 的投入开始回本。特别是用云厂商托管 K8s 时,控制平面不用你管,成本会降一大截,这是现在大多数团队上 K8s 的实际姿势。
WARNING最忌讳的选型理由是「简历上好看」和「别人都在用」。K8s 的复杂度是真金白银的日常成本:每一次排障、每一次升级、每一个新同事入职都要为它付费。规模没到、团队没到,上了 K8s 等于给自己请了个全职麻烦。反过来,规模真的到了还硬扛 Compose,人工运维的成本同样会反噬。选型没有高下,只有匹配与否。
九、排障小节:新手最常撞的几个坑
**Pod 一直是 Pending 状态。**意思是调度器找不到能放它的节点。先 kubectl describe pod <名字> 看 Events,常见原因是集群资源不够(本地 kind 只有一个节点,副本开太多、资源请求写太大就会这样),或者 PVC 没有可用的 PV 供给,Pod 在等存储。
**Pod 反复重启,状态是 CrashLoopBackOff。**Pod 起来了但进程立刻退出,K8s 按退避策略反复拉起。用 kubectl logs <Pod> 看当前日志、kubectl logs <Pod> --previous 看上一次崩溃的日志,九成是应用本身的问题:配置错、依赖连不上、启动命令写错。记住这不是 K8s 的故障,是你的应用在集群里把在 Docker 里也会犯的错又犯了一遍,只是换了个状态名。
**ImagePullBackOff 拉不到镜像。**同样先看 describe 的 Events。常见原因:镜像名或标签写错、私有仓库没配拉取凭证(imagePullSecrets)、本地 kind 集群里用了只存在于你本机 Docker 的镜像——kind 需要用 kind load docker-image <镜像> --name learn 把本地镜像灌进集群节点,这是本地体验时最容易卡住的一步。
**Service 访问不通。**按链路逐段查:kubectl get svc 确认 Service 存在,kubectl get endpoints <Service名> 确认它背后挂上了 Pod(为空说明 selector 标签和 Pod 标签对不上,这是最常见的原因),再确认 Service 的 targetPort 和容器实际监听端口一致。整条链路就是「DNS 名 → Service → 标签选 Pod → 端口转发」,断在哪段查哪段。
**apply 了 YAML 却没生效。**先确认改的是同一个对象(名字、命名空间是否一致,kubectl 默认操作 default 命名空间,跨命名空间要用 -n 指定),再用 kubectl get <资源> -o yaml 把集群里的实际状态拉出来和文件逐字段对。声明式的好处是状态可查,别靠猜。
十、学习路线图
最后给一条不折腾的进阶路线,按顺序走,每一步都能在前一步的基础上小步验证:
- 概念期:吃透这篇的对照表,特别是 Pod、Deployment、Service、Ingress、ConfigMap/Secret 这六个对象的职责边界。能对着一张架构图说清每个对象干什么,这一期就毕业了。
- 本地期:用 kind 把第七节的流程完整跑两遍,第二遍试着自己改副本数、换镜像版本、删 Pod 看自愈、给应用加上 ConfigMap 管理配置。把第六节的 kubectl 命令都亲手敲过一遍。
- 托管期:在任意云厂商开一个最小规格的托管 K8s,把一个自己真实的小项目迁上去,完整经历域名解析、Ingress 配 HTTPS、镜像仓库凭证这些「玩具集群里没有的真实问题」。
- 进阶期:再往后才是 Helm(包管理)、探针与资源配额调优、监控告警体系、灰度发布这些话题。每一个都是大题目,按需学,不要提前囤。
WARNING千万别一上来就啃 K8s 源码或者试图自建生产集群。控制平面的组件(API Server、etcd、Scheduler、Controller Manager)各自都是一门学问,在没跑过托管版之前自建集群,学到的主要是踩坑而不是概念。先当好使用者,再决定要不要当建设者。
小结
- K8s 不是更高级的 Docker,而是面向集群的操作系统;它的全部复杂度,都是为「多机调度、自愈、弹性」付的账,规模没到就不要替它买单。
- 翻译关系记住三条主线:Pod 是容器的壳,Compose 的一个 service 拆成 Deployment(管运行)+ Service(管访问),存储多了一层 PVC 申请、PV 供给。
- 声明式是 K8s 的灵魂:你只描述期望状态,控制器负责无限逼近它,自愈、滚动更新、扩缩容都是同一机制的表现。
- kubectl 的操作对象是资源而不是容器,
describe看事件、logs看日志、apply提交期望,是日常排障的铁三角。 - 选型只看匹配度:单机个人项目用 Compose,三五台机器求轻量集群看 Swarm,规模与团队都到位再上 K8s,且优先托管版。
把这篇的对照表存好,下次再看到任何 K8s 名词,先回表里查它对应你熟悉的哪个东西——发怵的感觉,基本就消了。