第4章:Kubernetes核心概念:Pod、Service、Deployment、ConfigMap、Secret详解

好,咱们进入正题。Kubernetes 这东西,说白了就是一套容器编排系统。但很多新手一上来就被各种概念搞懵了。Pod、Service、Deployment……这些到底都是啥?

我刚开始接触 K8s 的时候,也觉得头大。后来在项目中踩了不少坑,才慢慢理清楚。今天我就用我的理解,把这些核心概念给你讲透。

4.1 Pod:最小的调度单元

Pod 是 K8s 里你能创建和管理的最小计算单元。你可以把它理解成一个“容器盒子”。

一个 Pod 里可以放一个或多个容器。 但实践中,我建议一个 Pod 只放一个主容器。除非你有特别强的耦合需求,比如 sidecar 模式。

核心要点: Pod 里的容器共享网络栈和存储卷。它们可以通过 localhost 互相通信。

我在项目中遇到过一个问题:两个容器放在同一个 Pod 里,结果其中一个日志爆了,把共享的 emptyDir 卷写满了,导致另一个容器也挂了。嗯,这就是共享存储带来的风险。

Pod 的典型 YAML

apiVersion: v1
kind: Pod
metadata:
  name: my-app-pod
  labels:
    app: my-app
spec:
  containers:
  - name: my-container
    image: nginx:1.21
    ports:
    - containerPort: 80

你看,定义很简单。但实际生产中,我们很少直接创建 Pod。为什么?因为 Pod 挂了就真的挂了,没人管它。这时候就需要 Deployment 出场了。

4.2 Deployment:声明式更新与扩缩容

Deployment 是管理 Pod 的“高级管家”。你告诉它“我要跑 3 个 nginx”,它就会帮你创建 3 个 Pod,并且持续保证这个数量。

Deployment 的核心能力:

  • 滚动更新:逐步替换旧版本 Pod,保证服务不中断
  • 回滚:更新出问题了?一键回到上一个版本
  • 扩缩容:流量大了,把副本数从 3 调到 10

我的习惯: 每次更新 Deployment 时,我都会设置 revisionHistoryLimit 为 5。保留太多历史版本没意义,还占 etcd 空间。

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

这里有个关键点:selector.matchLabels 必须和 template.metadata.labels 匹配。我曾经因为 label 写错了一个字母,结果 Deployment 创建的 Pod 全都不受管控……排查了半天。

4.3 Service:稳定的网络入口

Pod 是动态的,随时可能被销毁、重建。那客户端怎么访问?IP 地址一直在变啊。

Service 就是来解决这个问题的。它提供一个稳定的虚拟 IP(ClusterIP),背后代理一组 Pod。

Service 的类型:

类型 说明 使用场景
ClusterIP 集群内部可访问 内部服务调用
NodePort 通过节点 IP + 端口访问 开发测试环境
LoadBalancer 云厂商提供负载均衡器 生产环境对外暴露

注意: 别把 NodePort 用在生产环境。端口范围有限(30000-32767),而且暴露了节点 IP,不安全。

我个人习惯用 ClusterIP 配合 Ingress 对外暴露服务。这样更灵活,也更容易管理证书和路由规则。

4.4 ConfigMap 与 Secret:配置管理

应用配置不能写死在镜像里。否则换个环境就得重新打包,太蠢了。

ConfigMap 用来存非敏感配置,比如数据库地址、日志级别。Secret 用来存敏感信息,比如密码、API Key。

ConfigMap 示例

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  app.properties: |
    db.host=mysql-service
    db.port=3306
    log.level=INFO

Secret 示例

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:
  password: bXlwYXNzd29yZA==  # base64 编码后的值

重要提醒: Secret 的 base64 编码不是加密!它只是防眼瞎。真正安全要用外部密钥管理工具,比如 HashiCorp Vault 或云厂商的 KMS。

我曾经犯过一个错:把数据库密码直接写在 ConfigMap 里,结果同事不小心把 YAML 提交到了公开仓库……嗯,那晚我加班到凌晨三点改密码。

4.5 它们如何协同工作?

咱们把整个流程串起来看看:

  1. 你创建一个 Deployment,声明要跑 3 个 nginx Pod
  2. Deployment 通过 ReplicaSet 创建 3 个 Pod
  3. Pod 里挂载 ConfigMapSecret,读取配置和密码
  4. 你创建一个 Service,选择器匹配 Pod 的 label
  5. 客户端通过 Service 的 ClusterIP 访问 nginx 服务

你看,这几个概念环环相扣。缺一个,整个系统就跑不起来。

避坑指南: 我曾经在更新 ConfigMap 后,发现 Pod 里的配置没变。为什么?因为 ConfigMap 更新后,Pod 不会自动重新加载。你需要手动重启 Pod,或者用一些工具(比如 Reloader)来自动触发滚动更新。

4.6 小结

今天咱们聊了 K8s 的五个核心概念:

  • Pod:最小调度单元,一个盒子装一个或多个容器
  • Deployment:管理 Pod 的生命周期,支持滚动更新和扩缩容
  • Service:提供稳定的网络入口,屏蔽 Pod 的动态变化
  • ConfigMap:存非敏感配置
  • Secret:存敏感信息,但别依赖它的安全性

说实话,这些概念光看文档是不够的。你最好自己搭个集群,亲手创建几个 Pod、Deployment、Service,再改改 ConfigMap 看看效果。实践出真知嘛。

下一章咱们聊聊存储,PersistentVolume 和 PersistentVolumeClaim。到时候我会分享一个我在生产环境遇到的存储坑,保证让你印象深刻。