刚入行半年的后端开发小周,前几天刚把自己的个人博客用 Docker 打包成镜像,本地docker run一键启动,访问丝滑流畅。听说现在公司所有线上应用都用 K8s 部署,他兴冲冲把镜像推到了公共仓库,照着网上抄了一段 yaml,执行kubectl apply后,本以为能直接用域名访问博客,结果控制台里的 Pod 一直显示CrashLoopBackOff,重启次数疯狂上涨,浏览器里更是连页面都打不开。

他抱着电脑找运维组的老陈求助,老陈扫了一眼他的控制台,笑着说:“别慌,90% 的新手学 K8s,第一步都死记硬背 yaml 和指令,却没搞懂它的核心心智模型。今天我们就跟着排查这个问题的过程,把 K8s 从 Pod 到 Operator 的所有核心知识点全打通,以后再出问题,你自己就能搞定。”

一、先搞懂底层逻辑:K8s 到底是什么?用来解决什么问题?

很多新手都会像小周一样,把 Docker 和 K8s 混为一谈,这是学习的第一个误区,我们先把两个概念的边界彻底划清:

  • Docker:是容器运行时(Runtime),核心能力是把代码和依赖打包成标准化的容器镜像,解决「代码在我本地能跑,在服务器上跑不起来」的环境一致性问题,它的管理粒度是单个容器。
  • Kubernetes(简称 K8s):是分布式容器编排平台,核心能力是管理成千上百台服务器上的容器,解决「容器大规模部署后,怎么稳定运行、怎么互相访问、怎么故障自愈、怎么弹性扩缩容」的问题,它的管理粒度是Pod,而非单个容器。

而 K8s 的灵魂,也是你必须刻在脑子里的核心心智模型,就是声明式 API + 控制循环:你只需要通过 yaml 文件,告诉 K8s「我期望的集群状态是什么」—— 比如 “我要 3 个博客容器副本始终运行,对外暴露 8080 端口,能通过blog.example.com访问”,K8s 会在后台持续监控集群的实际状态,自动把实际状态调整成你声明的期望状态。哪怕某个容器挂了、某台服务器宕机了,它都会自动重建、重新调度,全程无需人工干预。

我们接下来的所有排查、所有概念、所有指令,都是围绕这个核心心智模型展开的。

二、Pod:K8s 的最小调度单位,90% 新手的第一个认知误区

老陈指着小周控制台里崩溃的 Pod 说:“你第一个踩的坑,就是把 Pod 和容器划了等号。K8s 从来不会直接管理容器,它管理的最小单位是 Pod,这是所有操作的基础。”

1. 核心概念与用途

Pod 是什么:K8s 中最小、不可分割的调度和运行单位,一个 Pod 里可以包含 1 个或多个紧密耦合的容器,这些容器共享同一个网络命名空间、同一个存储卷,就像住在同一间宿舍的室友 —— 可以直接用localhost互相访问,共享同一块磁盘空间,生命周期完全绑定,Pod 销毁,里面的所有容器都会一起销毁。

Pod 用来干嘛:

  • 作为容器的载体,所有的调度、部署、扩缩容、故障自愈,都是以 Pod 为单位执行;
  • 解决紧密耦合容器的协同问题,比如一个业务容器 + 一个日志采集容器,就可以放在同一个 Pod 里,共享网络和存储。

2. 新手必学的 Pod 核心指令(排查故障全靠它)

小周的 Pod 一直崩溃重启,我们就用这几条指令,一步步定位问题,每条指令都讲清楚用途和实操方法,零基础也能直接套用:

  1. 查看所有 Pod 的运行状态

    kubectl get pods
    

    这是最基础的指令,执行后可以看到所有 Pod 的名称、运行状态、重启次数、运行时长。小周执行后,看到自己的博客 Pod 状态是CrashLoopBackOff,重启次数一直在涨,说明 Pod 启动后立刻崩溃,K8s 在不停尝试重启。

  2. 查看 Pod 的详细信息与崩溃原因

    kubectl describe pod <你的Pod名称>
    

    这是排查 Pod 故障的核心指令,可以看到 Pod 的调度过程、事件日志、启动失败的具体原因。小周执行后,在 Events 栏里找到了报错:liveness probe failed: connect: connection refused—— 原来他在健康检查里把博客服务的端口写成了 80,而容器里的服务实际监听的是 8080,K8s 一直认为服务没启动成功,不停重启 Pod。

  3. 查看 Pod 内容器的运行日志

    # 基础用法,查看日志
    kubectl logs <你的Pod名称>
    # 实时跟踪日志,和docker logs -f效果一致
    kubectl logs <你的Pod名称> -f
    

    用来排查代码层面的报错,比如配置加载失败、数据库连接不上这类业务问题,是开发调试的必备指令。

  4. 进入 Pod 内的容器,手动调试

    kubectl exec -it <你的Pod名称> -- /bin/bash
    

    和docker exec -it用法完全一致,进入容器内部,查看配置文件是否正确、端口是否正常监听、网络是否连通,是定位复杂问题的终极手段。

  5. 删除 Pod

    kubectl delete pod <你的Pod名称>
    

    这里有个新手必知的注意点:如果你的 Pod 是通过 Deployment 创建的,删除后 K8s 会立刻自动创建一个新的 Pod—— 因为它要符合你声明的「副本数」要求,这就是控制循环的核心体现。

小周把健康检查的端口改成 8080,重新执行kubectl apply更新配置,不到 10 秒,Pod 的状态就变成了Running。他兴冲冲地在浏览器里输入 Pod 的 IP,结果还是打不开页面,老陈笑着说:“别急,Pod 跑起来了,不代表就能访问到,我们接下来搞定 K8s 的网络核心。”

三、Service + Ingress:K8s 网络模型,解决「怎么访问 Pod」的核心问题

老陈给小周解释:“Pod 是临时的、有生命周期的,重启、扩容、缩容、节点宕机,都会导致 Pod 的 IP 发生变化,而且 Pod 的 IP 只能在 K8s 集群内部访问,外网根本连不上。你直接访问 Pod 的 IP,就算这次能通,下次 Pod 重启 IP 变了,就又访问不了了。要解决这个问题,就要用到 Service 和 Ingress。”

1. Service:给 Pod 一个固定的访问入口

核心概念与用途:Service 是 K8s 为一组 Pod 提供固定访问入口、负载均衡的资源对象,它的生命周期和 Pod 完全解耦,不管背后的 Pod 怎么变化、IP 怎么更新,Service 的固定 IP 和域名永远不会变。

它的核心用途有三个:

  • 给 Pod 提供固定的访问地址,解决 PodIP 动态变化的问题;
  • 给多个 Pod 做 4 层负载均衡,把请求自动分发到健康的 Pod 上;
  • 实现集群内部的服务发现,不同服务之间可以通过 Service 的域名互相访问,不用硬编码 IP。

新手必学的 Service 类型:

  • ClusterIP:默认类型,只能在集群内部访问,适合微服务之间的内部调用;
  • NodePort:在集群的每台节点上开放一个固定端口,通过「节点 IP + 端口」就能访问服务,适合测试环境使用;
  • LoadBalancer:对接云厂商的负载均衡器,给服务分配公网 IP,适合生产环境对外暴露服务。

Service 核心常用指令:

# 查看所有Service,简写svc
kubectl get svc
# 查看Service的详细信息,确认后端关联的Pod是否正确
kubectl describe svc <你的Service名称>
# 删除Service
kubectl delete svc <你的Service名称>

小周给博客 Pod 创建了一个 NodePort 类型的 Service,把容器的 8080 端口映射到节点的 30080 端口,apply 之后,用「节点 IP+30080」终于能正常访问博客了。他刚想松口气,老陈又说:“NodePort 只能用 IP + 端口访问,生产环境要给用户提供域名访问,还要做 HTTPS、多服务路由,这就要用到 Ingress。”

2. Ingress:集群的流量网关,统一管理外网访问

核心概念与用途:Ingress 是 K8s 集群的「反向代理 / 流量网关」,相当于集群的大门,所有外网流量都先经过 Ingress,再根据你配置的规则,转发到对应的后端 Service 上。它能实现域名路由、HTTPS 证书终止、路径转发、限流等能力,不用给每个服务都单独配置公网 IP。

这里有个新手必踩的坑:Ingress 只是一套流量规则配置,必须部署 Ingress Controller(比如 Nginx Ingress Controller)才能生效,就像你写了 Nginx 配置文件,必须要有 Nginx 进程运行,配置才能起作用。

Ingress 核心常用指令:

# 查看所有Ingress,简写ing
kubectl get ingress
# 查看Ingress的详细配置与事件
kubectl describe ingress <你的Ingress名称>
# 删除Ingress
kubectl delete ingress <你的Ingress名称>

小周配置了一条 Ingress 规则,把blog.example.com域名转发到博客的 Service 上,再把域名解析到集群节点,终于能用域名正常访问博客了。

四、Controller 模式:K8s 自动化的核心,让应用实现故障自愈

老陈看着小周的配置,又提了一个问题:“你现在直接创建了一个 Pod,要是这个 Pod 所在的节点宕机了,或者 Pod 意外崩溃了,会发生什么?” 小周试了试手动删除 Pod,发现 Pod 没了,再也不会自动重建,博客直接访问不了了。

“这就是为什么生产环境永远不会直接创建「裸 Pod」”,老陈说,“K8s 的故障自愈、扩缩容、滚动更新这些核心能力,都是通过 Controller(控制器)实现的。Controller 就是控制循环的执行者,它会持续监控你的应用状态,一旦不符合期望,就立刻调整,让应用始终保持你声明的状态。”

我们重点讲解开发中最常用的 4 种 Controller,每个都讲清楚用途和核心指令:

1. Deployment:最常用的无状态应用控制器

核心概念与用途:Deployment 是 K8s 中最核心、使用频率最高的控制器,专门用来管理无状态应用(比如前端页面、后端 API、博客这类,实例之间没有区别、没有持久化数据的应用)。它在底层的 ReplicaSet(副本控制器)基础上,增加了滚动更新、版本回滚、弹性扩缩容、暂停恢复等能力,是日常开发部署的首选。

它能帮你做这些事:

  • 管理 Pod 的副本数,保证始终有你声明数量的健康 Pod 运行,实现故障自愈;
  • 滚动更新:发布新版本时,逐个替换旧版本 Pod,全程不会导致服务中断;
  • 版本回滚:新版本出现 bug,一键回滚到之前的历史版本;
  • 一键扩缩容:访问量上涨时,一条指令就能完成副本数扩容。

Deployment 核心常用指令:

# 查看所有Deployment,简写deploy
kubectl get deploy
# 查看Deployment的详细信息与发布事件
kubectl describe deploy <你的Deployment名称>
# 一键扩缩容副本数,比如把博客从1个副本扩到3个
kubectl scale deploy <你的Deployment名称> --replicas=3
# 滚动更新镜像,发布新版本
kubectl set image deploy <你的Deployment名称> <容器名>=<新镜像地址>
# 查看发布历史
kubectl rollout history deploy <你的Deployment名称>
# 一键回滚到上一个版本
kubectl rollout undo deploy <你的Deployment名称>
# 删除Deployment
kubectl delete deploy <你的Deployment名称>

小周把自己的博客改成了 Deployment 管理,声明 3 个副本,apply 之后,集群里立刻创建了 3 个博客 Pod。他手动删除其中一个,不到 1 秒,K8s 就自动创建了一个新的 Pod,始终保持 3 个副本运行,彻底解决了单点故障的问题。

2. 其他常用 Controller 快速入门

  • DaemonSet:保证集群的每一个节点上都运行一个相同的 Pod 副本,新增节点时自动创建 Pod,删除节点时自动清理 Pod。适合部署日志采集(Filebeat)、节点监控(Node Exporter)、网络插件这类集群级守护进程。
  • StatefulSet:专门用来管理有状态应用的控制器,比如 MySQL、Redis、Kafka 这类数据库和中间件。它创建的 Pod 有固定的名称、固定的域名、有序的部署更新顺序,配合持久化存储,保证有状态应用的数据不丢失、集群身份不混乱。
  • Job/CronJob:Job 用来处理一次性的离线任务,比如数据备份、数据迁移;CronJob 用来处理定时任务,比如每天凌晨的日志清理、定时报表生成,是 K8s 中处理离线任务的核心控制器。

五、ConfigMap + Secret:配置与敏感信息管理,实现配置与代码解耦

解决了部署和访问的问题,老陈又给小周提了一个新问题:“你的博客要对接数据库,数据库的地址、账号密码,你总不能写死在代码里,打包到镜像里吧?要是换个环境,难道还要重新构建镜像?”

这就是云原生应用的核心原则之一:配置与代码分离,而 K8s 专门提供了两个资源对象,来解决配置管理的问题。

1. ConfigMap:管理非敏感配置

核心概念与用途:ConfigMap 专门用来存储非敏感的配置信息,比如环境变量、配置文件、服务地址、启动参数等。你可以把配置从镜像中抽离出来,不同环境用不同的 ConfigMap,修改配置不用重新构建镜像,只需要重启 Pod 就能生效。

它的两种核心用法:

  • 把 ConfigMap 中的内容以环境变量的形式,注入到 Pod 的容器中;
  • 把 ConfigMap 挂载成容器内的配置文件,比如 Nginx 的配置文件、应用的 yaml 配置。

ConfigMap 核心常用指令:

# 查看所有ConfigMap,简写cm
kubectl get cm
# 查看ConfigMap里的具体配置内容
kubectl describe cm <你的ConfigMap名称>
# 从本地配置文件创建ConfigMap
kubectl create cm <配置名称> --from-file=本地配置文件路径
# 删除ConfigMap
kubectl delete cm <你的ConfigMap名称>

2. Secret:管理敏感配置信息

核心概念与用途:Secret 专门用来存储敏感信息,比如数据库账号密码、API 密钥、HTTPS 证书、镜像仓库密钥等,数据以 base64 编码存储,用法和 ConfigMap 几乎一致,专门用来避免敏感信息泄露。

生产环境中,绝对不要把敏感信息写在代码、yaml 文件里,必须用 Secret 管理,还可以对接外部密钥管理系统,进一步提升安全性。

Secret 核心常用指令:

# 查看所有Secret
kubectl get secret
# 查看Secret的详细信息
kubectl describe secret <你的Secret名称>
# 创建存储账号密码的Secret
kubectl create secret generic <Secret名称> --from-literal=username=admin --from-literal=password=123456
# 删除Secret
kubectl delete secret <你的Secret名称>

六、Operator:当基础 Controller 不够用时的进阶方案

搞定了配置管理,小周的博客已经能在生产环境稳定运行了。他好奇地问老陈:“我们部署一个博客就用了 Deployment、Service、Ingress、ConfigMap 这么多资源,那要是部署一个 MySQL 主从集群、Redis 集群,岂不是要写一大堆 yaml,还要自己处理主从同步、故障切换、备份这些运维操作?”

老陈点点头:“没错,这就是 Operator 要解决的问题。基础的 Controller 只能处理通用的部署逻辑,而复杂的有状态应用,需要大量的领域运维知识,Operator 就是把这些运维知识写成代码,做成 K8s 里的「专业运维机器人」。”

核心概念与用途

Operator 是什么:Operator 是 K8s 的扩展能力,由两部分组成:

  1. CRD(自定义资源定义):扩展 K8s 的 API,比如你可以定义一个MySQLCluster资源,就像 Deployment、Pod 一样,能通过 kubectl 直接管理;
  2. 自定义 Controller:监控你创建的 CRD 实例,按照你声明的期望状态,自动执行对应的运维操作。

简单来说,你只需要声明「我要一个 3 节点的 MySQL 8.0 主从集群,开启自动备份」,MySQL Operator 就会自动帮你创建 StatefulSet、Service、ConfigMap、Secret,自动配置主从同步、自动故障切换、自动备份、自动版本升级,全程无需人工干预。

Operator 核心常用指令

# 查看集群中所有的CRD
kubectl get crd
# 查看自定义资源的实例,比如查看所有MySQL集群
kubectl get mysqlclusters
# 查看自定义资源的详细信息
kubectl describe mysqlclusters <集群名称>

七、核心总结与新手必备通用指令

最后,老陈给小周做了一个核心总结,帮他彻底摆脱死记硬背的误区:

  1. K8s 的本质永远是声明式 API + 控制循环,你只需要定义期望状态,剩下的交给 K8s 的控制器,这是它和 Docker Compose 最核心的区别;
  2. 核心资源的层级关系:Operator/Deployment → ReplicaSet → Pod → 容器,上层管理下层,生产环境永远不要直接创建裸 Pod;
  3. 外网访问链路:用户 → Ingress → Service → Pod,每层各司其职,不要越级配置;
  4. 配置管理原则:非敏感配置用 ConfigMap,敏感配置用 Secret,永远不要把配置写死在镜像里。

最后给所有新手整理了万能通用 kubectl 指令,忘了具体用法的时候,直接用这几条就能解决 90% 的问题:

# 查看指定类型的所有资源,支持所有K8s资源类型
kubectl get <资源类型>
# 查看资源的详细信息,排查问题的核心指令
kubectl describe <资源类型> <资源名称>
# 从yaml文件创建/更新资源,声明式管理的核心
kubectl apply -f 文件名.yaml
# 从yaml文件删除资源
kubectl delete -f 文件名.yaml
# 查看指令的帮助文档,比网上搜教程更快
kubectl <指令> --help

更多推荐