3、Kubernetes核心概念:Pod、Service、Deployment、ConfigMap、Secret
好,咱们进入正题。Kubernetes 的概念很多,但真正每天都要打交道的,其实就这几个:Pod、Service、Deployment、ConfigMap、Secret。说白了,它们是整个容器编排的基石。我刚开始接触 K8s 时,也花了不少时间才把这些概念串起来。今天我就用我的理解,帮你把它们理清楚。
3.1 Pod:最小的调度单元
Pod 是 K8s 里你能创建和部署的最小单位。它不是单个容器,而是一个或多个容器的组合。这些容器共享网络栈、存储卷,以及一些资源限制。
你可能会问:为什么不用单个容器?嗯,这里有个场景。比如你的应用需要边写日志边做日志解析,这两个进程如果放在两个 Pod 里,通信就得走网络,延迟高不说,管理也麻烦。放在同一个 Pod 里,它们可以通过 localhost 直接通信,共享同一个 Volume,效率高得多。
核心要点:
- Pod 内的容器共享 IP 和端口空间
- Pod 内的容器可以通过 localhost 互相访问
- Pod 是临时性的,随时可能被销毁重建
我在项目中遇到过一个问题:有个团队把多个业务容器塞进同一个 Pod,结果一个容器内存泄漏,整个 Pod 都被 OOM Kill 了。所以记住:Pod 里的容器应该高度耦合,比如 sidecar 模式(日志收集、监控代理),而不是把无关的服务硬塞在一起。
3.2 Service:稳定的网络入口
Pod 是临时性的,IP 会变。那客户端怎么找到它?这就是 Service 的作用。Service 为一组 Pod 提供稳定的网络入口,不管 Pod 怎么漂,Service 的 IP 和端口不变。
Service 的类型主要有三种:
| 类型 | 说明 | 适用场景 |
|---|---|---|
| ClusterIP | 集群内部可访问,外部不可达 | 内部服务间调用 |
| NodePort | 在每个节点上开放一个端口,外部可通过节点IP+端口访问 | 开发测试环境,或简单对外暴露 |
| LoadBalancer | 云厂商提供负载均衡器,自动分配公网IP | 生产环境对外暴露服务 |
我个人习惯,生产环境尽量用 LoadBalancer 或 Ingress,NodePort 只用来做调试。为什么?因为 NodePort 会占用宿主机端口,而且没有健康检查,万一 Pod 挂了,流量还是会打过去。
小技巧:Service 通过 label selector 匹配 Pod。你可以在 Pod 上打多个 label,Service 用组合条件筛选。比如 app=nginx, env=prod,这样就能精确控制流量。
3.3 Deployment:声明式更新与扩缩容
Deployment 是管理 Pod 的控制器。你告诉它「我要跑 3 个 nginx 副本」,它就会帮你创建 3 个 Pod,并持续保证这个数量。如果某个 Pod 挂了,它会自动重建。
Deployment 最强大的地方在于滚动更新。你更新镜像版本时,它会逐步替换旧 Pod,而不是一次性全部干掉。我曾经在生产环境遇到过一个问题:有个同事直接删了所有旧 Pod,然后创建新 Pod,结果新版本有 bug,服务直接挂了 5 分钟。用 Deployment 的话,你可以先更新一个 Pod,观察没问题再继续,或者直接回滚。
一个典型的 Deployment 定义:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
注意:Deployment 只管理无状态应用。有状态应用(如数据库)要用 StatefulSet,否则 Pod 重建后,数据就丢了。
3.4 ConfigMap:配置与代码分离
ConfigMap 是用来存储非敏感配置的。比如数据库地址、日志级别、环境变量等。把这些配置从镜像里抽出来,好处很明显:同一个镜像,在不同环境(开发、测试、生产)可以加载不同的 ConfigMap,不用重新打包。
我见过最坑的做法:把配置硬编码在 Dockerfile 里,然后每个环境打一个镜像。结果生产环境出了 bug,开发环境复现不了,因为配置不一样。用 ConfigMap 之后,镜像只包含代码,配置由运维统一管理,清爽多了。
ConfigMap 的使用方式有两种:
- 环境变量注入:Pod 启动时读取 ConfigMap 的值作为环境变量
- 挂载为文件:把 ConfigMap 挂载到 Pod 的某个目录,应用直接读文件
我个人更推荐挂载为文件的方式。为什么?因为环境变量在 Pod 运行期间无法动态更新,而挂载的文件可以热更新(虽然需要应用自己监听文件变化)。
3.5 Secret:敏感信息的保险箱
Secret 和 ConfigMap 很像,但专门用来存敏感信息:密码、Token、证书等。它的值在存储和传输时会被加密(Base64 只是编码,不是加密,但 K8s 支持 etcd 加密)。
你可能会想:直接用 ConfigMap 存密码不行吗?嗯,理论上可以,但 ConfigMap 的值是明文存储的,谁都能看。Secret 至少提供了基础的保护,而且可以配合 RBAC 控制谁有权访问。
我曾经犯过一个错误:把数据库密码直接写在 YAML 文件里,然后提交到了 Git 仓库。虽然仓库是私有的,但后来团队扩张,权限没控制好,密码泄露了。从那以后,我强制要求所有敏感信息必须用 Secret,并且用外部工具(如 Sealed Secrets 或 Vault)管理。
创建 Secret 的示例:
kubectl create secret generic db-secret \
--from-literal=username=admin \
--from-literal=password='S3cur3P@ss'
最佳实践:
- 不要手动编写 Secret 的 YAML,用 kubectl create secret 命令
- 生产环境启用 etcd 加密
- 考虑使用外部密钥管理服务(如 AWS Secrets Manager、HashiCorp Vault)
3.6 它们如何协同工作?
最后,咱们把这些概念串起来。一个典型的应用部署流程是这样的:
- 用 ConfigMap 和 Secret 定义配置和敏感信息
- 用 Deployment 定义 Pod 的副本数、镜像版本、更新策略
- Deployment 创建 Pod,Pod 引用 ConfigMap 和 Secret 获取配置
- 用 Service 为这些 Pod 提供稳定的访问入口
- 外部流量通过 Ingress 或 LoadBalancer 到达 Service,再转发到 Pod
说白了,ConfigMap 和 Secret 是「配置中心」,Deployment 是「调度器」,Pod 是「工作单元」,Service 是「网络代理」。它们各司其职,组合起来就能构建出高可用的云原生应用。
嗯,这一章的内容就到这里。下一章咱们聊聊 K8s 的存储抽象,那是另一个容易踩坑的地方。