3. Kubernetes核心概念:Pod、Service、Deployment、Namespace、ConfigMap、Secret

好,咱们今天聊聊Kubernetes里最核心的几个概念。说实话,我刚接触K8s那会儿,面对一堆术语确实有点懵。Pod、Service、Deployment……这些到底都是干嘛的?它们之间怎么配合?

别急,我带你一个个捋清楚。搞懂了这些,你就能理解K8s是怎么运作的了。

3.1 Pod:最小的调度单元

Pod是Kubernetes里你能创建和管理的最小计算单元。说白了,它就是一组容器的集合。

为什么要有Pod?

你想想看,有时候两个进程需要共享网络栈、共享存储卷。比如一个应用容器和一个日志收集容器,它们需要紧密协作。如果各自独立调度,网络配置、存储挂载都得重复搞,太麻烦了。

Pod就是解决这个问题的。Pod里的所有容器:

  • 共享同一个网络命名空间(IP和端口)
  • 共享同一个存储卷(Volume)
  • 通过localhost互相通信

核心要点:Pod是K8s调度的原子单位。你永远不会直接调度一个容器,你调度的是一个Pod。

我在项目中遇到过一个问题:有个同事把两个需要共享日志目录的容器放在了不同Pod里,结果日志采集一直对不上。后来改成同一个Pod,用emptyDir卷共享目录,问题就解决了。

来看一个最简单的Pod定义:

apiVersion: v1
kind: Pod
metadata:
  name: my-app-pod
  labels:
    app: my-app
spec:
  containers:
  - name: app-container
    image: nginx:1.21
    ports:
    - containerPort: 80
  - name: sidecar-container
    image: busybox
    command: ["sh", "-c", "tail -f /var/log/nginx/access.log"]
    volumeMounts:
    - name: log-volume
      mountPath: /var/log/nginx
  volumes:
  - name: log-volume
    emptyDir: {}

嗯,这里要注意:Pod里的容器启动顺序是不保证的。如果你的应用容器依赖sidecar先启动,那得用initContainers来解决。

3.2 Deployment:声明式应用管理

直接管理Pod?别傻了。Pod挂了怎么办?版本升级怎么搞?回滚怎么弄?

Deployment就是来干这个的。它帮你管理Pod的声明式更新和扩缩容。

Deployment的核心能力:

  • 滚动更新:逐步替换旧版本Pod,保证服务不中断
  • 回滚:出问题了?一键回到上一个版本
  • 扩缩容:调整副本数,应对流量变化
  • 自愈:Pod挂了自动重建

我个人习惯,生产环境里所有无状态应用都用Deployment来管理。有状态应用?那是StatefulSet的事,后面再聊。

来看一个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的滚动更新策略可以配置。maxSurge控制最多可以多出几个Pod,maxUnavailable控制最多可以有几个Pod不可用。生产环境我一般设maxSurge=25%,maxUnavailable=25%。

3.3 Service:稳定的网络入口

Pod是会飘的。今天在Node A,明天可能就在Node B了。IP也会变。那客户端怎么访问?

Service就是给Pod提供一个稳定的访问入口。它通过Label Selector找到对应的Pod,然后把流量转发过去。

Service的类型:

类型 说明 使用场景
ClusterIP 集群内部IP,外部无法访问 内部服务间调用
NodePort 在每个Node上开一个端口 开发测试、简单对外暴露
LoadBalancer 云厂商提供负载均衡器 生产环境对外暴露
ExternalName 映射到外部DNS名称 访问集群外服务

我曾经踩过一个坑:Service的selector写错了label,结果流量全打到了错误的Pod上。排查了半天才发现是label不匹配。所以,命名规范很重要

Service定义示例:

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: ClusterIP

3.4 Namespace:逻辑隔离

一个K8s集群里可能有多个团队、多个项目。怎么隔离?Namespace就是干这个的。

Namespace提供了一种将集群资源划分为逻辑组的方式。不同Namespace里的资源可以重名,互不干扰。

常见的Namespace使用场景:

  • 按环境分:dev、test、prod
  • 按团队分:team-a、team-b
  • 按项目分:project-x、project-y

注意:Namespace只提供逻辑隔离,不提供安全隔离。如果你需要真正的安全隔离,得用NetworkPolicy或者干脆建多个集群。

查看Namespace:

kubectl get namespaces
# 输出示例:
# NAME              STATUS   AGE
# default           Active   30d
# kube-system       Active   30d
# kube-public       Active   30d
# kube-node-lease   Active   30d

创建Namespace:

apiVersion: v1
kind: Namespace
metadata:
  name: dev-environment

3.5 ConfigMap & Secret:配置管理

应用配置不应该硬编码在镜像里。环境不同,配置不同。ConfigMap和Secret就是用来解耦配置和镜像的。

ConfigMap:存明文配置,比如配置文件、环境变量。

Secret:存敏感信息,比如密码、Token、证书。数据会做Base64编码,但注意这只是编码,不是加密。

我建议:敏感信息一定要用Secret,别图省事放ConfigMap里。我曾经见过有人把数据库密码明文写在ConfigMap里……嗯,后果很严重。

ConfigMap示例:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  app.properties: |
    database.url=jdbc:mysql://db:3306/app
    database.username=app_user
    log.level=INFO

Secret示例:

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:
  password: cGFzc3dvcmQxMjM=  # 这是"password123"的Base64编码

最佳实践:Secret的Base64编码只是障眼法。真正生产环境,建议用SealedSecret、External Secrets Operator或者Vault来管理敏感信息。

在Pod里使用ConfigMap和Secret:

apiVersion: v1
kind: Pod
metadata:
  name: config-pod
spec:
  containers:
  - name: app
    image: my-app:latest
    env:
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: password
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
  volumes:
  - name: config-volume
    configMap:
      name: app-config

3.6 它们是怎么配合的?

好,现在我们把所有概念串起来。一个典型的应用部署流程是这样的:

  1. Deployment 定义应用的期望状态(副本数、镜像版本等)
  2. Deployment通过 ReplicaSet 管理 Pod 的创建和更新
  3. Pod 里运行容器,引用 ConfigMapSecret 获取配置
  4. Service 为Pod提供稳定的网络入口
  5. 所有资源都在某个 Namespace 下逻辑隔离

你想想看,这个组合拳打下来,应用部署、配置管理、网络访问、环境隔离,全搞定了。

最后说一句:这些概念是K8s的基石。搞懂了它们,后面学什么Volume、Ingress、HPA都会轻松很多。别急,咱们一章一章来。