目录

Kubernetes-03 核心概念详解

Kubernetes 核心概念详解

系列第三篇。深入理解 K8s 的基本构建块,这些概念贯穿所有后续章节。


目录

  1. Pod
  2. Namespace
  3. Label 与 Selector
  4. Annotation
  5. Node
  6. 资源请求与限制
  7. Init Container
  8. Sidecar Container
  9. 静态 Pod
  10. 小结

1. Pod

Pod 是 K8s 中最小的可部署单元

1.1 Pod 是什么

Pod 不是容器,而是一个或多个容器的集合,这些容器共享:

  • 网络命名空间:同一个 Pod 中的容器共享 IP 和 Port,通过 localhost 互相通信
  • 存储卷(Volume):可以挂载相同的 Volume,实现数据共享
  • Linux namespace 的部分:PID namespace(可配置)、IPC namespace
┌─────────────────────────────────────┐
│                 Pod                  │
│  ┌──────────────┐  ┌─────────────┐  │
│  │  Container A │  │ Container B │  │
│  │  (主应用)    │  │  (sidecar)  │  │
│  └──────────────┘  └─────────────┘  │
│                                      │
│  共享:IP(10.1.2.3) / Port / Volume │
│                                      │
│  ┌──────────────────────────────┐   │
│  │          Volume              │   │
│  └──────────────────────────────┘   │
└─────────────────────────────────────┘

1.2 为什么是 Pod 而不是容器

这是 K8s 的核心设计决策。考虑这个场景:

Nginx + PHP-FPM:Nginx 把请求代理给 PHP-FPM,它们需要共享同一个 socket 文件。把它们放在同一个 Pod 中,通过共享 Volume 实现通信,比在不同容器间建立网络连接更高效。

主应用 + 日志 Agent:主容器写日志到共享 Volume,sidecar 容器读取并上报到日志系统,它们的生命周期一致,一起被调度、一起被销毁。

1.3 Pod 的生命周期

Pending   → 已创建,等待调度或镜像拉取
Running   → 至少一个容器在运行
Succeeded → 所有容器正常退出(exit 0)
Failed    → 至少一个容器非正常退出
Unknown   → 无法获取 Pod 状态(通常是 Node 失联)

容器状态:

Waiting    → 等待某些条件(拉取镜像、等待 ConfigMap)
Running    → 正在运行
Terminated → 已退出(exit code 可能为 0 或非 0)

重启策略(restartPolicy):

spec:
  restartPolicy: Always    # 默认,容器退出后总是重启(Deployment 使用)
  # restartPolicy: OnFailure  # 只有非 0 退出才重启(Job 使用)
  # restartPolicy: Never      # 不重启

1.4 完整 Pod YAML 示例

apiVersion: v1
kind: Pod
metadata:
  name: go-app-pod
  namespace: default
  labels:
    app: go-app
    version: v1.2.0
    env: production
  annotations:
    description: "Go HTTP 服务示例"
    prometheus.io/scrape: "true"
    prometheus.io/port: "9090"
spec:
  # 调度到有 disktype=ssd 标签的节点
  nodeSelector:
    disktype: ssd

  # 镜像拉取密钥(私有仓库需要)
  imagePullSecrets:
  - name: registry-secret

  containers:
  - name: go-app
    image: myregistry.io/go-app:v1.2.0
    imagePullPolicy: IfNotPresent  # Always | IfNotPresent | Never

    ports:
    - name: http
      containerPort: 8080
      protocol: TCP
    - name: metrics
      containerPort: 9090

    env:
    - name: APP_ENV
      value: "production"
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: password
    - name: POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name  # 注入 Pod 自身信息(Downward API)
    - name: POD_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP

    resources:
      requests:
        cpu: "100m"
        memory: "128Mi"
      limits:
        cpu: "500m"
        memory: "512Mi"

    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
      initialDelaySeconds: 10
      periodSeconds: 10

    readinessProbe:
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5

    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
      readOnly: true
    - name: data-volume
      mountPath: /data

    # 安全上下文(最小权限原则)
    securityContext:
      runAsNonRoot: true
      runAsUser: 1000
      readOnlyRootFilesystem: true
      allowPrivilegeEscalation: false

  volumes:
  - name: config-volume
    configMap:
      name: go-app-config
  - name: data-volume
    emptyDir: {}

  # Pod 级别安全上下文
  securityContext:
    fsGroup: 2000

1.5 Pod 常用调试命令

# 查看 Pod 列表
kubectl get pods
kubectl get pods -o wide                    # 显示 IP 和节点
kubectl get pods --sort-by='.status.startTime'  # 按启动时间排序

# 查看详情(重点看 Events 部分)
kubectl describe pod <pod-name>

# 查看日志
kubectl logs <pod-name>
kubectl logs <pod-name> -c <container-name>  # 多容器时指定容器
kubectl logs <pod-name> --previous           # 查看上次崩溃的日志

# 进入容器调试
kubectl exec -it <pod-name> -- bash
kubectl exec -it <pod-name> -c <container-name> -- sh  # 指定容器

# 临时调试容器(不修改原 Pod)
kubectl debug <pod-name> -it --image=busybox --target=<container-name>

# 复制文件
kubectl cp <pod-name>:/path/to/file ./local-file
kubectl cp ./local-file <pod-name>:/path/to/file

# 端口转发
kubectl port-forward pod/<pod-name> 8080:8080

2. Namespace

Namespace(命名空间)是 K8s 中逻辑隔离的机制,用于将一个集群划分为多个虚拟集群。

2.1 Namespace 的作用

  1. 资源隔离:不同 Namespace 的资源互不干扰(名字可以相同)
  2. 访问控制:RBAC 可以限制用户只能访问特定 Namespace
  3. 资源配额:通过 ResourceQuota 限制 Namespace 的资源使用量
  4. 多租户:一个集群为多个团队或环境(dev/staging/prod)服务

2.2 K8s 默认 Namespace

kubectl get namespaces
Namespace 用途
default 未指定 Namespace 时的默认命名空间
kube-system K8s 系统组件(DNS、Dashboard 等)
kube-public 所有用户可读(包括未认证用户)
kube-node-lease 节点心跳续约,提升节点故障检测效率

2.3 创建和管理 Namespace

apiVersion: v1
kind: Namespace
metadata:
  name: team-alpha
  labels:
    team: alpha
    env: production
# 创建
kubectl create namespace team-alpha
# 或
kubectl apply -f namespace.yaml

# 在指定 Namespace 下操作
kubectl get pods -n team-alpha
kubectl apply -f pod.yaml -n team-alpha

# 设置当前上下文的默认 Namespace
kubectl config set-context --current --namespace=team-alpha

# 查看所有 Namespace 的 Pod
kubectl get pods --all-namespaces
kubectl get pods -A  # 简写

2.4 ResourceQuota(资源配额)

限制 Namespace 内的资源总量:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-alpha-quota
  namespace: team-alpha
spec:
  hard:
    # 计算资源
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi
    # 对象数量
    pods: "20"
    services: "10"
    persistentvolumeclaims: "5"
    secrets: "20"
    configmaps: "20"
# 查看配额使用情况
kubectl describe resourcequota -n team-alpha

2.5 LimitRange(默认资源限制)

为 Namespace 中的 Pod/Container 设置默认资源:

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: team-alpha
spec:
  limits:
  - type: Container
    default:          # 未指定 limits 时的默认值
      cpu: "200m"
      memory: "256Mi"
    defaultRequest:   # 未指定 requests 时的默认值
      cpu: "100m"
      memory: "128Mi"
    max:              # 允许的最大值
      cpu: "2"
      memory: "2Gi"
    min:              # 允许的最小值
      cpu: "50m"
      memory: "64Mi"

2.6 哪些资源是 Namespace 级别的

Namespace 级别(有命名空间隔离):

  • Pod、Deployment、StatefulSet、DaemonSet
  • Service、Ingress
  • ConfigMap、Secret
  • PersistentVolumeClaim
  • ServiceAccount、Role、RoleBinding

集群级别(无命名空间隔离):

  • Node
  • PersistentVolume(PV)
  • StorageClass
  • ClusterRole、ClusterRoleBinding
  • Namespace 本身

3. Label 与 Selector

Label(标签)是附加在 K8s 资源上的键值对,用于标识和组织资源。Selector(选择器)用于根据 Label 过滤资源。

3.1 Label 的规则

metadata:
  labels:
    app: nginx             # 应用名
    version: "1.2.0"       # 版本(值加引号避免被解析为数字)
    env: production        # 环境
    tier: frontend         # 层级
    team: platform         # 所属团队
    release: stable        # 发布通道

键名格式: [prefix/]name

  • prefix 是可选的 DNS 子域名(如 app.kubernetes.io
  • name 部分最长 63 字符,可以包含字母、数字、-_.

K8s 推荐的标准标签(Recommended Labels):

labels:
  app.kubernetes.io/name: mysql
  app.kubernetes.io/instance: mysql-prod
  app.kubernetes.io/version: "8.0"
  app.kubernetes.io/component: database
  app.kubernetes.io/part-of: my-app
  app.kubernetes.io/managed-by: helm

3.2 kubectl 中使用 Label

# 查看 Label
kubectl get pods --show-labels

# 通过 Label 过滤
kubectl get pods -l app=nginx
kubectl get pods -l 'app=nginx,env=production'
kubectl get pods -l 'env in (staging, production)'
kubectl get pods -l 'app!=redis'
kubectl get pods -l '!deprecated'          # 不含某个 key

# 添加 Label
kubectl label pod nginx-pod version=v2

# 修改 Label
kubectl label pod nginx-pod version=v3 --overwrite

# 删除 Label(key 后面加 -)
kubectl label pod nginx-pod version-

3.3 Selector 类型

等式型(Equality-based):

selector:
  matchLabels:
    app: nginx
    env: production

集合型(Set-based,更灵活):

selector:
  matchExpressions:
  - key: app
    operator: In
    values: [nginx, apache]
  - key: env
    operator: NotIn
    values: [development]
  - key: tier
    operator: Exists  # 只检查 key 是否存在
  - key: deprecated
    operator: DoesNotExist

3.4 Label 的重要应用场景

Service → Pod 的流量路由:

# Service 通过 selector 选择后端 Pod
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx      # 将流量路由到所有 app=nginx 的 Pod
  ports:
  - port: 80
    targetPort: 8080

Deployment 管理 Pod:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx    # Deployment 管理所有 app=nginx 的 Pod
  template:
    metadata:
      labels:
        app: nginx  # Pod 的 Label,必须匹配 selector
    spec:
      containers:
      - name: nginx
        image: nginx:alpine

节点选择(nodeSelector):

# 给节点打标签
kubectl label node node-1 disktype=ssd gpu=true
spec:
  nodeSelector:
    disktype: ssd  # 只调度到有此标签的节点

4. Annotation

Annotation(注解)也是键值对,但与 Label 不同:

  • Label:用于选择和过滤,key/value 有格式限制
  • Annotation:用于存储非标识性的元数据,value 可以是任意字符串(包括 JSON/YAML)
metadata:
  annotations:
    # 文档信息
    description: "This is my Go web service"
    owner: "platform-team@company.com"
    documentation: "https://wiki.company.com/go-app"

    # 部署信息
    deployment.kubernetes.io/revision: "3"
    kubernetes.io/change-cause: "Update image to v1.2.0"

    # Prometheus 监控配置
    prometheus.io/scrape: "true"
    prometheus.io/port: "9090"
    prometheus.io/path: "/metrics"

    # Ingress 配置
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"

    # 大型数据(如 kubectl apply 使用的 last-applied-configuration)
    kubectl.kubernetes.io/last-applied-configuration: |
            {"apiVersion":"v1","kind":"Pod",...}

实用场景:

  • 存储 kubectl apply 的配置(kubectl.kubernetes.io/last-applied-configuration
  • 记录变更原因(kubernetes.io/change-cause
  • 工具集成配置(Prometheus、Istio、Ingress Controller 等通过 Annotation 读取配置)
  • 自动化脚本的元数据

5. Node

Node 是 K8s 集群中的工作机器(物理机或虚拟机)。

5.1 查看节点信息

kubectl get nodes
kubectl get nodes -o wide   # 显示更多信息

kubectl describe node <node-name>

describe 输出包含:

  • 节点标签和 Annotation
  • 系统信息(OS、内核版本、容器运行时)
  • 资源容量(Capacity) vs 可分配量(Allocatable)
  • 节点条件(Ready/MemoryPressure/DiskPressure 等)
  • Pods(运行在该节点的所有 Pod)
  • Allocated resources(已分配的资源汇总)
  • Events

5.2 节点条件

Ready          = True  → 节点健康,可以调度 Pod
MemoryPressure = True  → 内存不足
DiskPressure   = True  → 磁盘空间不足
PIDPressure    = True  → 进程数量接近上限
NetworkUnavailable = True → 网络配置异常

5.3 节点标签

K8s 为节点自动添加一些标签:

kubernetes.io/hostname=node-1
kubernetes.io/os=linux
kubernetes.io/arch=amd64
node.kubernetes.io/instance-type=m5.large  # 云环境
topology.kubernetes.io/zone=us-east-1a     # 可用区
topology.kubernetes.io/region=us-east-1    # 区域

5.4 节点维护:Cordon & Drain

# 停止调度新 Pod 到该节点(但不影响现有 Pod)
kubectl cordon node-1

# 驱逐节点上所有 Pod,并停止调度(用于维护前)
kubectl drain node-1 --ignore-daemonsets --delete-emptydir-data

# 维护完成后,恢复调度
kubectl uncordon node-1

6. 资源请求与限制

理解 requestslimits 是 K8s 资源管理的关键。

6.1 概念

resources:
  requests:    # 调度时的保证量(Scheduler 根据此值选择 Node)
    cpu: "100m"
    memory: "128Mi"
  limits:      # 运行时的上限(超出会被限速/OOMKilled)
    cpu: "500m"
    memory: "512Mi"

CPU:

  • 1 = 1 个 CPU 核心
  • 100m = 0.1 CPU(m = millicores,毫核)
  • CPU 超出 limits 时:被限速(throttled),不会被杀死

Memory:

  • Mi = Mebibytes(1Mi = 1024Ki)
  • M = Megabytes(1M = 1000Ki)
  • 内存超出 limits 时:容器被 OOMKilled(Out Of Memory)

6.2 QoS 类别

K8s 根据 requests/limits 自动为 Pod 分配 QoS(Quality of Service)类别:

QoS 类别 条件 含义
Guaranteed requests == limits(CPU 和 Memory 都设置且相等) 最高优先级,Node 内存不足时最后被驱逐
Burstable requests < limits 或只设置了部分 中等优先级
BestEffort 没有设置任何 requests 和 limits 最低优先级,最先被驱逐
# 查看 Pod 的 QoS
kubectl get pod <name> -o jsonpath='{.status.qosClass}'

生产建议:

  • 生产环境核心服务:设置 Guaranteed(requests == limits)
  • 开发/测试环境:可以使用 Burstable
  • 永远不要使用 BestEffort(在生产中)

6.3 CPU 单位详解

# 这三种写法等价
cpu: "0.5"
cpu: "500m"
cpu: 0.5

# Node 有 4 个 CPU 核心,可以运行:
# 40 个 requests.cpu=100m 的容器
# 8 个 requests.cpu=500m 的容器

7. Init Container

Init Container(初始化容器)在主容器启动之前运行,且必须运行成功主容器才会启动。

7.1 使用场景

  • 等待依赖服务就绪(等待数据库、等待某个服务启动)
  • 下载配置文件或初始化数据
  • 执行数据库迁移(配合主容器镜像中的 migrate 工具)
  • 设置权限(修改 Volume 的文件权限)

7.2 示例

spec:
  # Init Container:等待数据库就绪
  initContainers:
  - name: wait-for-db
    image: busybox:1.36
    command:
    - sh
    - -c
    - |
      until nc -z postgres-service 5432; do
        echo "Waiting for database..."
        sleep 2
      done
      echo "Database is ready!"      

  # Init Container:运行数据库迁移
  - name: db-migrate
    image: myapp:v1.0
    command: ["/app/migrate", "--up"]
    env:
    - name: DATABASE_URL
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: url

  # 主容器(Init Container 全部成功后才启动)
  containers:
  - name: go-app
    image: myapp:v1.0
    command: ["/app/server"]

注意:

  • Init Container 顺序执行(一个完成后下一个才开始)
  • Init Container 和主容器共享 Volume,但不共享端口
  • Init Container 重启策略与主容器相同

8. Sidecar Container

Sidecar 是与主容器运行在同一 Pod 中的辅助容器,增强主容器的功能而不修改主容器代码。

8.1 常见 Sidecar 模式

日志采集(Log Agent):

spec:
  containers:
  - name: go-app
    image: go-app:v1
    volumeMounts:
    - name: log-volume
      mountPath: /var/log/app

  - name: log-agent
    image: fluent-bit:latest
    volumeMounts:
    - name: log-volume
      mountPath: /var/log/app
      readOnly: true
    env:
    - name: LOKI_URL
      value: "http://loki:3100"

  volumes:
  - name: log-volume
    emptyDir: {}

服务网格代理(Istio Envoy):

Istio 会自动注入 Envoy sidecar,实现流量管理、mTLS、可观测性,无需修改应用代码。

K8s 1.29+ 原生 Sidecar 支持:

spec:
  initContainers:
  - name: log-agent          # 作为 sidecar 的 init container
    image: fluent-bit:latest
    restartPolicy: Always    # 关键:设置 restartPolicy=Always 即变成 sidecar
  containers:
  - name: go-app
    image: go-app:v1

原生 sidecar 的优势:

  • 与主容器同时启动/停止
  • 主容器结束后 sidecar 才结束(正确的生命周期管理)
  • 在 Job 中也能正常工作

9. 静态 Pod

静态 Pod(Static Pod)是由 kubelet 直接管理的 Pod,不经过 kube-apiserver。

9.1 使用场景

K8s 自己的控制面组件(apiserver、scheduler、controller-manager、etcd)就是静态 Pod!

查看静态 Pod:

kubectl get pods -n kube-system
# kube-apiserver-master-node、etcd-master-node 等

静态 Pod 的配置文件位置:

ls /etc/kubernetes/manifests/
# etcd.yaml
# kube-apiserver.yaml
# kube-controller-manager.yaml
# kube-scheduler.yaml

kubelet 监控这个目录,文件变化时自动更新 Pod。


10. 小结

概念关系图

集群(Cluster)
└── Namespace(命名空间,逻辑隔离)
    ├── Pod(最小部署单元)
    │   ├── Init Container(初始化容器)
    │   ├── Container(主容器)
    │   └── Sidecar Container(辅助容器)
    ├── Service(网络访问入口)
    ├── Deployment(管理 Pod 副本)
    ├── ConfigMap / Secret(配置)
    └── ...

Node(实际运行 Pod 的机器)
└── Pod(被调度到此 Node 上的 Pod)

概念速查

概念 一句话描述
Pod K8s 最小部署单元,包含一个或多个容器
Namespace 逻辑隔离空间,同一集群多环境/多团队
Label 键值对标签,用于选择和组织资源
Selector 根据 Label 筛选资源的查询条件
Annotation 非标识性元数据,存储工具配置等信息
Node 运行 Pod 的工作节点(物理机/虚拟机)
requests 调度时保证的资源量
limits 运行时最大可用资源量
Init Container 主容器启动前运行的初始化容器
Sidecar 与主容器共存的辅助容器