Skip to content

Kubernetes 速查表

用于自动化部署和扩展的容器编排平台。

01

入门

kubectl 基础

kubectl 是 Kubernetes 的命令行工具。get 列出资源,create 创建新资源,expose 创建 Service,scale 修改副本数。describe 提供资源的详细信息。

kubernetes
# cluster info
kubectl cluster-info

# list nodes
kubectl get nodes

# list pods (all namespaces)
kubectl get pods --all-namespaces

# create a deployment
kubectl create deployment nginx --image=nginx

# expose deployment as service
kubectl expose deployment nginx --port=80 --type=LoadBalancer

# scale deployment
kubectl scale deployment nginx --replicas=3

# get detailed info
kubectl describe pod <pod-name>

# view logs
kubectl logs <pod-name>

输出格式化

-o 标志控制输出。yaml/json 显示完整资源规格;jsonpath 和 custom-columns 提取特定字段用于脚本;-w 实时监视变化。脚本中使用 --no-headers 可去掉列名。

kubernetes
# wide format (more columns)
kubectl get pods -o wide

# YAML output
kubectl get pod nginx -o yaml

# JSON output
kubectl get pod nginx -o json

# jsonpath (extract specific fields)
kubectl get pods -o jsonpath='{.items[*].metadata.name}'

# custom columns
kubectl get pods -o custom-columns=NAME:.metadata.name,STATUS:.status.phase

# show labels
kubectl get pods --show-labels

# watch for changes
kubectl get pods -w

上下文与配置

一个上下文捆绑了集群地址、用户凭证和命名空间。kubeconfig 文件(默认 ~/.kube/config)存储这些信息。可通过 KUBECONFIG 环境变量组合多个文件来管理多个集群。

kubernetes
# view current config
kubectl config view

# list contexts
kubectl config get-contexts

# switch context
kubectl config use-context my-cluster

# set default namespace for current context
kubectl config set-context --current --namespace=dev

# show current context
kubectl config current-context

# KUBECONFIG with multiple files
export KUBECONFIG=~/.kube/config:~/.kube/prod-config

explain 与 API 资源

api-resources 列出集群支持的资源;explain 显示任意资源的 OpenAPI 模式——在终端内编写 YAML 时非常实用。使用 --recursive 可转储完整的嵌套结构。

kubernetes
# list all resource types
kubectl api-resources

# list namespaced vs cluster-scoped
kubectl api-resources --namespaced=true
kubectl api-resources --namespaced=false

# explain a resource's fields
kubectl explain pod
kubectl explain pod.spec.containers
kubectl explain deployment.spec.strategy

# explain with recursion (all nested fields)
kubectl explain pod --recursive

# include description
kubectl explain pod.spec.containers.resources --api-version=apps/v1

Dry Run 与生成 YAML

--dry-run=client -o yaml 是从命令式命令生成清单的标准方法。--dry-run=server 会与真实 apiserver 校验(准入 webhook、模式)但不持久化。非常适合引导声明式 YAML。

kubernetes
# generate YAML without applying
kubectl create deployment nginx --image=nginx --dry-run=client -o yaml

# pipe generated YAML straight to a file
kubectl create deployment nginx --image=nginx --dry-run=client -o yaml > nginx.yaml

# apply the generated manifest
kubectl apply -f nginx.yaml

# dry-run against the server (validates with apiserver)
kubectl apply -f nginx.yaml --dry-run=server

# generate a service from a deployment
kubectl create service clusterip my-svc --tcp=80:80 --dry-run=client -o yaml

帮助与自动补全

每个 kubectl 命令都支持 --help 并附示例。Shell 补全能极大减少输入并暴露子命令。alias k=kubectl 在从业者中近乎通用——配合补全使用体验最佳。

kubernetes
# top-level help
kubectl --help

# subcommand help
kubectl create --help
kubectl explain --help

# generate bash completion
kubectl completion bash > /etc/bash_completion.d/kubectl

# zsh completion
source <(kubectl completion zsh)

# alias k=kubectl with completion
alias k=kubectl
complete -o default -F __start_kubectl k

# shorthand: kubectl -> k
echo 'alias k=kubectl' >> ~/.bashrc
02

Pod

Pod 清单

Pod 是最小可部署单元,持有一个或多个共享网络和存储的容器。同一 Pod 内的容器总是共同调度到同一节点。很少直接创建 Pod——应使用 Deployment 或 Job。

kubernetes
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
    - name: nginx
      image: nginx:1.25
      ports:
        - containerPort: 80
      resources:
        requests:
          cpu: 100m
          memory: 128Mi
        limits:
          cpu: 200m
          memory: 256Mi
  restartPolicy: Always

多容器 Pod(Sidecar)

多容器 Pod 共享网络(相同 IP、端口空间)和卷。常见模式:sidecar(辅助)、adapter(转换输出)、ambassador(代理)。共享的 emptyDir 卷让 sidecar 读取主容器写入的日志。

kubernetes
apiVersion: v1
kind: Pod
metadata:
  name: web-with-logs
spec:
  containers:
    - name: app
      image: nginx
      volumeMounts:
        - name: shared-logs
          mountPath: /var/log/nginx
    - name: log-shipper
      image: busybox
      command: ["sh", "-c", "tail -f /var/log/nginx/access.log"]
      volumeMounts:
        - name: shared-logs
          mountPath: /var/log/nginx
          readOnly: true
  volumes:
    - name: shared-logs
      emptyDir: {}

Pod 生命周期与阶段

Pod 的 phase 是高层级状态(Pending、Running、Succeeded、Failed)。容器状态(Waiting/Running/Terminated)给出真正细节——例如 CrashLoopBackOff 表示容器反复退出。检查重启次数和事件来诊断。

kubernetes
# pod phases: Pending | Running | Succeeded | Failed | Unknown
kubectl get pod nginx

# show status including container states
kubectl get pod nginx -o jsonpath='{.status}'

# container states: Waiting | Running | Terminated
kubectl describe pod nginx

# common Waiting reasons: ImagePullBackOff, CrashLoopBackOff, CreateContainerConfigError
kubectl get pods --field-selector=status.phase=Pending

# restart count reveals crash loops
kubectl get pods -o jsonpath='{.items[*].status.containerStatuses[*].restartCount}'

Pod 状态与事件

事件是集群对资源的审计日志——调度、拉取、拉取错误、存活探针失败。它们会过期(默认约 1 小时),所以调试时要及时捕获。describe 将事件与资源规格打包,便于快速分诊。

kubernetes
# full describe (includes Events at the bottom)
kubectl describe pod nginx

# list cluster events sorted by time
kubectl get events --sort-by=.lastTimestamp

# events for a specific namespace
kubectl get events -n default

# watch events live
kubectl get events -w

# filter events by type
kubectl get events --field-selector type=Warning

# events for a specific pod
kubectl get events --field-selector involvedObject.name=nginx

exec 与端口转发

exec 在容器内运行命令;-it 为 shell 分配 TTY。port-forward 将本地端口隧道到 Pod/Service 而不对外暴露——从笔记本调试数据库或 Web UI 的必备手段。

kubernetes
# open an interactive shell
kubectl exec -it nginx -- sh

# run a one-off command
kubectl exec nginx -- ls /etc/nginx

# specify container in a multi-container pod
kubectl exec -it web-with-logs -c log-shipper -- sh

# forward a local port to a pod port
kubectl port-forward pod/nginx 8080:80

# forward to a service / deployment
kubectl port-forward svc/nginx 8080:80
kubectl port-forward deployment/nginx 8080:80

# forward to a random local port
kubectl port-forward pod/nginx :80

删除与强制删除

删除受 Deployment/StatefulSet 管理的 Pod 会立即触发重建。--force --grace-period=0 跳过 TERM 信号宽限期,可能留下残留资源——谨慎使用。卡在 Terminating 的 Pod 通常需要移除 finalizer。

kubernetes
# delete a pod (controller will recreate it)
kubectl delete pod nginx

# force delete immediately (bypasses graceful shutdown)
kubectl delete pod nginx --grace-period=0 --force

# delete by label
kubectl delete pods -l app=nginx

# delete all pods in a namespace
kubectl delete pods --all -n default

# delete a pod and wait for it to be gone
kubectl delete pod nginx --wait

# delete with a timeout
kubectl delete pod nginx --timeout=30s
03

Deployment

Deployment 清单

Deployment 管理 ReplicaSet,并提供声明式滚动更新和回滚。spec.selector 必须匹配 spec.template.metadata.labels。template 定义要推出的 Pod 规格。

kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.25
          ports:
            - containerPort: 80

滚动更新策略

RollingUpdate(默认)逐步替换 Pod 实现零停机。maxSurge/maxUnavailable 控制推出速度和可用性。Recreate 在创建新 Pod 前先杀掉所有旧 Pod——用于应用不能同时运行两个版本时(如单卷写入者)。

kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 10
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 25%        # extra pods above replicas during update
      maxUnavailable: 25%  # pods allowed down during update
  # alternative: recreate (kills all, then starts new)
  # strategy:
  #   type: Recreate
  selector:
    matchLabels:
      app: nginx
  template:

回滚

每次对 Pod 模板的修改创建一个 ReplicaSet 版本。undo 将流量切回之前的 ReplicaSet。pause 让你在金丝雀增量之间做多次修复。用 --record(已弃用)或注解跟踪变更原因。

kubernetes
# view rollout history
kubectl rollout history deployment/nginx

# see details of a specific revision
kubectl rollout history deployment/nginx --revision=2

# undo to the previous revision
kubectl rollout undo deployment/nginx

# undo to a specific revision
kubectl rollout undo deployment/nginx --to-revision=2

# pause/resume a rollout (for canary pauses)
kubectl rollout pause deployment/nginx
kubectl rollout resume deployment/nginx

# check rollout status
kubectl rollout status deployment/nginx

扩缩容与 HPA

HPA 基于 CPU/内存或自定义指标扩缩副本数。CPU/内存需要 metrics-server。minReplicas 和 maxReplicas 限定扩缩范围。v2 API 支持多指标和 behavior(缩容稳定化)。

kubernetes
# scale manually
kubectl scale deployment/nginx --replicas=5

# horizontal pod autoscaler (CPU target)
kubectl autoscale deployment nginx --min=2 --max=10 --cpu-percent=80

# list HPA
kubectl get hpa

# HPA manifest (v2 with custom metrics)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: nginx
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 80

更新镜像与重启

set image 触发新的 ReplicaSet 和滚动更新。rollout restart 是拉取最新镜像或刷新配置的最干净方式——它以相同规格创建新 ReplicaSet。edit 打开 $EDITOR 做临时修复。

kubernetes
# update container image
kubectl set image deployment/nginx nginx=nginx:1.26

# update from a specific container
kubectl set image deployment/nginx container=nginx:1.26 --record

# trigger a rollout restart (same image, recreate pods)
kubectl rollout restart deployment/nginx

# edit a deployment in editor
kubectl edit deployment/nginx

# patch a single field
kubectl patch deployment/nginx -p '{"spec":{"replicas":5}}'

# apply a manifest change
kubectl apply -f nginx-deployment.yaml

Deployment 状态

Deployment 拥有 ReplicaSet;只有一个处于活跃状态(replicas>0)。旧 ReplicaSet 缩到 0 以备回滚。pod-template-hash 标签为每个 Pod 标记版本。检查 status.conditions 看 Available、Progressing、ReplicaFailure 信号。

kubernetes
# deployment status
kubectl get deployment nginx

# watch rollout
kubectl rollout status deployment/nginx

# show ReplicaSets owned by the deployment
kubectl get rs -l app=nginx

# show pods across all revisions
kubectl get pods -l app=nginx --show-labels

# pod-template-hash label distinguishes revisions
# kubectl get pods -l app=nginx,pod-template-hash=xxxx

# conditions: Available, Progressing, ReplicaFailure
kubectl get deployment nginx -o jsonpath='{.status.conditions}'
04

Service

Service 类型

Service 提供稳定的 IP/DNS,在一组 Pod 间负载均衡。ClusterIP 是默认(仅集群内)。NodePort 和 LoadBalancer 对外暴露。ExternalName 是 DNS 别名,非代理。

kubernetes
# four service types:
# - ClusterIP (default): reachable inside the cluster
# - NodePort: exposed on each node's IP at a static port
# - LoadBalancer: cloud-provisioned external LB
# - ExternalName: DNS CNAME to an external host

# quick create
kubectl expose deployment nginx --port=80 --type=ClusterIP
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl expose deployment nginx --port=80 --type=LoadBalancer

# external name (no proxying, pure DNS)
kubectl create service externalname my-svc --external-name=db.example.com

ClusterIP Service

ClusterIP 在集群内提供稳定的虚拟 IP 和 DNS 名。selector 匹配 Pod 标签;kube-proxy 编程 iptables/IPVS 在端点间负载均衡。通过 <svc>.<ns>.svc.cluster.local 或直接 <svc> 解析。

kubernetes
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  type: ClusterIP
  selector:
    app: nginx
  ports:
    - name: http
      port: 80          # service port
      targetPort: 80    # container port
      protocol: TCP
# DNS: nginx.default.svc.cluster.local
# short names also work: nginx, nginx.default
# kube-dns / CoreDNS resolves the service VIP

NodePort Service

NodePort 在每个节点上开放相同的静态端口(30000-32767)。访问任意 node:nodePort 的流量都会到达某个 Pod(kube-proxy 可能重定向到其他节点上的 Pod)。在无法配置云 LB 时有用;配合外部 LB 实现 HA。

kubernetes
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30080   # optional, 30000-32767 range
# reachable at <any-node-ip>:30080
# also still reachable via clusterIP:80

# get assigned nodePort
kubectl get svc nginx -o jsonpath='{.spec.ports[*].nodePort}'

LoadBalancer Service

LoadBalancer 请求云提供商配置指向节点的外部负载均衡器。externalTrafficPolicy: Local 保留客户端源 IP(无 SNAT)但跳过跨节点负载均衡。就绪后 STATUS 显示分配的外部 IP。

kubernetes
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  type: LoadBalancer
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 80
  # cloud-specific annotations
  # annotations:
  #   service.beta.kubernetes.io/aws-load-balancer-type: nlb
  #   service.beta.kubernetes.io/azure-load-balancer-internal: "true"
  # externalTrafficPolicy: Local preserves client IP
  externalTrafficPolicy: Local
# status.ingress shows the external IP/hostname

Headless Service

Headless Service(clusterIP: None)没有 VIP——DNS 直接返回 Pod IP。StatefulSet 必需它,以便每个 Pod 拥有稳定 DNS 名(pod-0.svc、pod-1.svc)。也用于想自行发现所有后端的客户端。

kubernetes
apiVersion: v1
kind: Service
metadata:
  name: nginx-headless
spec:
  clusterIP: None       # makes it headless
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 80
# DNS returns pod IPs directly (not a VIP)
# A records: nginx-headless.default.svc.cluster.local
#   -> 10.1.0.5, 10.1.0.6, 10.1.0.7
# used by StatefulSet for stable pod DNS:
#   <pod-name>.<svc-name>.default.svc.cluster.local

Endpoints 与 EndpointSlices

Endpoints/EndpointSlices 列出真正接收流量的 Pod IP——只有 Ready 的 Pod 才会出现。如果 Service 没有端点,说明 Pod 未匹配 selector 或未 Ready。EndpointSlices(v1)对大型 Service 扩展性更好,是默认选择。

kubernetes
# view endpoints backing a service
kubectl get endpoints nginx

# endpoint slices (newer, more scalable)
kubectl get endpointslices -l kubernetes.io/service-name=nginx

# endpoints track pods that match the selector
# AND pass readiness checks
kubectl describe endpoints nginx

# a service with no ready pods has no endpoints
# - check pod readiness if traffic is refused
# - EndpointSlices are grouped by address type (IPv4/IPv6)

# manually managed endpoints (selector-less service)
05

ConfigMap

创建 ConfigMap

ConfigMap 以键值对存储非敏感配置。--from-literal 用于内联值,--from-file 嵌入整个文件(文件名成为 key)。用于将配置与镜像解耦而无需重新构建。

kubernetes
# from literal values
kubectl create configmap app-config \
  --from-literal=LOG_LEVEL=debug \
  --from-literal=ENABLE_FEATURE=true

# from a file (key = filename, value = contents)
kubectl create configmap app-config --from-file=app.properties

# from a directory (one key per file)
kubectl create configmap app-config --from-file=configs/

# from an env file
kubectl create configmap app-config --from-env-file=app.env

# from a file with a custom key
kubectl create configmap app-config --from-file=custom-key=app.properties

ConfigMap 清单

data 存储字符串值(每个 key 在挂载时成为环境变量或文件)。多行字符串使用 YAML 块标量(|)。binaryData 接受 base64 二进制数据。每个 ConfigMap 总大小限制为 1 MiB。

kubernetes
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  LOG_LEVEL: "debug"
  ENABLE_FEATURE: "true"
  application.yml: |
    server:
      port: 8080
    logging:
      level: debug
binaryData:
  # base64-encoded binary values
  logo.png: iVBORw0KGgoAAAANSUhEUg...

作为环境变量消费

envFrom 一次性注入 ConfigMap 的所有 key 为环境变量。env 配 configMapKeyRef 挑选单个 key。optional: true 让 Pod 在 ConfigMap 不存在时也能启动。ConfigMap 更新不会刷新运行中 Pod 的环境变量。

kubernetes
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
    - name: app
      image: myapp:1.0
      env:
        - name: LOG_LEVEL
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: LOG_LEVEL
      envFrom:
        - configMapRef:
            name: app-config      # injects all keys as env vars
              optional: true      # pod starts even if CM missing

作为卷消费

将 ConfigMap 作为卷挂载会把每个 key 投射为文件。ConfigMap 更新最终会反映到挂载文件中(由 kubelet 同步周期决定)——但应用必须重新读取。subPath 挂载固定单个 key 且不会更新。

kubernetes
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
    - name: app
      image: myapp:1.0
      volumeMounts:
        - name: config
          mountPath: /etc/config
          readOnly: true
  volumes:
    - name: config
      configMap:
        name: app-config
        items:                       # optional: pick subset
          - key: application.yml
            path: app.yml            # rename file
        defaultMode: 0644
# each ConfigMap key becomes a file under /etc/config

更新与重载

挂载的 ConfigMap 文件会自动刷新(kubelet 同步后),但环境变量在 Pod 生命周期内不可变——需重启 Pod 才能获取环境变量变更。rollout restart 是向 Deployment 传播配置更新的最干净方式。

kubernetes
# edit the configmap
kubectl edit configmap app-config

# patch a single key
kubectl patch configmap app-config \
  --type merge -p '{"data":{"LOG_LEVEL":"info"}}'

# mounted files update within ~kubelet sync period (default 60s)
# but env vars do NOT update in running pods

# force pods to pick up new config by rolling them
kubectl rollout restart deployment/app

# verify the new value on a pod
kubectl exec app -- printenv LOG_LEVEL

不可变 ConfigMap

设置 immutable: true 冻结 ConfigMap——任何修改都需要删除 + 重建。这极大减少了大型稳定配置的 kubelet-apiserver watch 流量(规模化时的重大可扩展性收益)。生产中常用于与镜像版本绑定的应用配置。

kubernetes
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
immutable: true
data:
  LOG_LEVEL: "debug"
# once immutable, the only change allowed is delete + recreate
# benefits: kubelet does not watch it, lower apiserver load
# useful for large, stable configs in production

# make it mutable again
kubectl patch configmap app-config -p '{"immutable":false}'
# (this fails if currently immutable — must delete instead)
06

Secret

创建 Secret

Secret 以 base64 编码存储敏感数据(默认未加密静止存储——生产环境应启用 encryption at rest)。generic/Opaque 用于任意数据,docker-registry 用于镜像拉取,tls 用于 Ingress TLS。切勿将 Secret YAML 提交到 git。

kubernetes
# generic (opaque) from literals
kubectl create secret generic db-creds \
  --from-literal=username=admin \
  --from-literal=password='S3cur3!'

# from a file (e.g. SSH key, certificate)
kubectl create secret generic ssh-key --from-file=ssh-privatekey=~/.ssh/id_rsa

# docker registry secret (for private image registries)
kubectl create secret docker-registry regcred \
  --docker-server=registry.example.com \
  --docker-username=user \
  --docker-password=pass \
  [email protected]

# TLS secret from cert/key files
kubectl create secret tls my-tls \
  --cert=fullchain.pem \
  --key=privkey.pem

Secret 清单

data 值必须 base64 编码(echo -n 'value' | base64)。stringData 是接受明文的便捷方式,apply 时合并到 data。type Opaque 是默认;专用类型(kubernetes.io/tls、kubernetes.io/dockerconfigjson)会校验 key。

kubernetes
apiVersion: v1
kind: Secret
metadata:
  name: db-creds
type: Opaque
data:
  username: YWRtaW4=         # base64 of "admin"
  password: UzNjdXIzIQ==     # base64 of "S3cur3!"
# stringData accepts plaintext (auto-encoded on apply)
stringData:
  api-key: "live-key-xyz"
# encode on the command line:
# echo -n 'admin' | base64
# decode:
# echo 'YWRtaW4=' | base64 -d

作为环境变量使用 Secret

将 Secret 作为环境变量消费与 ConfigMap 相同,但使用 secretKeyRef/secretRef。注意环境变量可通过 /proc/1/environ 及容器内任何进程可见——高度敏感数据建议改用卷挂载。

kubernetes
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
    - name: app
      image: myapp:1.0
      env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-creds
              key: password
      envFrom:
        - secretRef:
            name: db-creds      # injects all keys
              optional: true

作为卷使用 Secret

挂载的 Secret 以文件形式投射到 tmpfs(内存)卷——从不写入节点磁盘。defaultMode 0400 限制访问。挂载的 Secret 在 Secret 变更时( kubelet 同步后)会更新,与环境变量型 Secret 不同。

kubernetes
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
    - name: app
      image: myapp:1.0
      volumeMounts:
        - name: secrets
          mountPath: /etc/secrets
          readOnly: true
  volumes:
    - name: secrets
      secret:
        secretName: db-creds
        defaultMode: 0400       # restrict permissions
        items:
          - key: password
            path: db-password   # written to /etc/secrets/db-password
# memory-backed tmpfs, never written to disk on the node

ImagePullSecret

imagePullSecrets 在拉取镜像时向私有仓库认证。附加到 ServiceAccount 会自动应用于使用该 SA 的每个 Pod——这是推荐模式。docker-registry secret 类型自动生成正确的 .dockerconfigjson 负载。

kubernetes
# attach to a pod
apiVersion: v1
kind: Pod
metadata:
  name: private-app
spec:
  imagePullSecrets:
    - name: regcred
  containers:
    - name: app
      image: registry.example.com/myapp:1.0

# attach to a service account (auto-applied to all pods using it)
kubectl patch serviceaccount default \
  -p '{"imagePullSecrets":[{"name":"regcred"}]}'

# verify
kubectl get sa default -o jsonpath='{.imagePullSecrets}'

Secret 类型

专用 secret 类型启用校验和集成:tls 用于 Ingress,dockerconfigjson 用于镜像拉取,service-account-token 自动挂载到 Pod。使用正确类型可确保 key 被校验并被正确的控制器消费。

kubernetes
# Opaque (default) — arbitrary key-value
type: Opaque

# kubernetes.io/service-account-token — auto for SAs
type: kubernetes.io/service-account-token

# kubernetes.io/dockerconfigjson — registry auth
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: <base64>

# kubernetes.io/tls — for Ingress TLS
type: kubernetes.io/tls
data:
  tls.crt: <base64>
  tls.key: <base64>

# kubernetes.io/basic-auth
type: kubernetes.io/basic-auth
stringData:
  username: admin
  password: pass
07

Namespace

创建 Namespace

Namespace 为多团队或多环境(dev/stage/prod)划分集群。资源名在同一 namespace 内必须唯一。某些资源(Node、PV、StorageClass)是集群作用域,不属于 namespace。

kubernetes
# imperative
kubectl create namespace dev

# declarative
apiVersion: v1
kind: Namespace
metadata:
  name: dev
  labels:
    environment: development
    team: platform

# apply
kubectl apply -f namespace.yaml

# list namespaces
kubectl get namespaces

# set default namespace for current context
kubectl config set-context --current --namespace=dev

ResourceQuota

ResourceQuota 限定 namespace 内的资源总用量——CPU/内存 requests/limits 总量、对象计数(Pod、PVC、Service、Deployment)。多租户集群必备,防止一个团队饿死其他团队。设置配额后未显式设 requests 的 Pod 会被拒绝。

kubernetes
apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: dev
spec:
  hard:
    requests.cpu: "10"
    requests.memory: 20Gi
    limits.cpu: "20"
    limits.memory: 40Gi
    pods: "50"
    services.loadbalancers: "2"
    persistentvolumeclaims: "10"
    count/deployments.apps: "5"
# limits total aggregate resource use in the namespace

LimitRange

LimitRange 设置单资源的默认值和边界:为未指定的 Pod 提供默认 requests/limits,并用 min/max 约束极端值。与 ResourceQuota 配对——没有默认 requests,配额会拒绝所有忘记设置的 Pod。

kubernetes
apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: dev
spec:
  limits:
    - type: Container
      default:               # default limits (if unset)
        cpu: 500m
        memory: 512Mi
      defaultRequest:        # default requests (if unset)
        cpu: 100m
        memory: 128Mi
      max:                   # max allowed limits
        cpu: "2"
        memory: 2Gi
      min:                   # min allowed requests
        cpu: 50m
        memory: 64Mi
    - type: PersistentVolumeClaim
      max:
        storage: 100Gi
      min:
        storage: 1Gi

删除 Namespace 与 Finalizer

删除 namespace 会级联删除其所有资源。卡在 Terminating 的 namespace 通常有无法完成的 finalizer——APIService 不可用(如 metrics-server 被移除)或 CRD 的控制器已消失。移除 finalizer 可强制完成,但可能泄漏外部资源。

kubernetes
# delete a namespace (cascades all resources in it)
kubectl delete namespace dev

# if stuck in Terminating, inspect finalizers
kubectl get namespace dev -o yaml

# remove finalizer to force completion (DANGEROUS)
kubectl patch namespace dev -p '{"metadata":{"finalizers":null}}'

# resources that block deletion:
# - APIService unavailable (metrics-server removed)
# - custom resources whose CRD is gone
# - PVCs with attached PVs

# check what's still in the namespace
kubectl api-resources --verbs=list --namespaced -o name \
  | xargs -n 1 kubectl get -n dev --ignore-not-found

默认 Namespace

kube-system 运行控制平面和附加组件(DNS、kube-proxy、CNI)。kube-public 存放未认证用户可读的引导数据。kube-node-lease 以 Lease 对象存储节点心跳以提升性能。未指定 namespace 时,工作负载落在 default。

kubernetes
# built-in namespaces
kubectl get namespaces
# NAME              STATUS   AGE
# default           Active   30d   <- user workloads land here
# kube-system       Active   30d   <- control plane / addons
# kube-public       Active   30d   <- publicly readable (bootstrap)
# kube-node-lease   Active   30d   <- node heartbeats (leases)

# kube-system holds:
# - kube-dns / CoreDNS
# - kube-proxy
# - metrics-server
# - CNI, CSI, cloud provider controllers

# kube-public is readable by all (used for cluster info discovery)

Namespace 作用域 vs 集群作用域

大多数工作负载资源是 namespace 作用域;基础设施(Node、PV、StorageClass、ClusterRole)是集群作用域。Service 只能针对同 namespace 的 Pod。-A 是 --all-namespaces 的简写——对集群全局可见性至关重要。

kubernetes
# which resources are namespaced?
kubectl api-resources --namespaced=true
kubectl api-resources --namespaced=false

# namespaced: pods, services, deployments, configmaps, secrets
# cluster-scoped: nodes, namespaces, PVs, StorageClasses, ClusterRoles

# access across namespaces:
# - a Service selector only matches pods in the SAME namespace
# - cross-namespace refs require special controllers (e.g. external-dns)

# list resources across all namespaces
kubectl get pods --all-namespaces
kubectl get pods -A   # shorthand
08

标签与选择器

标签语法

标签是用于识别和分组资源的键值对。key 可有可选前缀(DNS 子域名,如 app.kubernetes.io/)。标签用于查询/过滤,而注解用于任意非标识性元数据。

kubernetes
# labels are key=value pairs
# key: prefix (optional DNS subdomain) + name
# value: string, up to 63 chars

metadata:
  labels:
    app: nginx
    tier: frontend
    env: prod
    app.kubernetes.io/name: nginx
    app.kubernetes.io/version: "1.25"

# view labels
kubectl get pods --show-labels

# add/overwrite a label
kubectl label pod nginx env=prod
kubectl label pod nginx env=staging --overwrite

# remove a label (trailing dash)
kubectl label pod nginx env-

等式与集合选择器

两种选择器:等式(=、==、!=)和集合(in、notin、exists、!exists)。多个逗号分隔的条件为 AND。Service 和 Deployment 在 YAML 中用等式选择器;kubectl -l 支持两者。

kubernetes
# equality-based: = == !=
kubectl get pods -l app=nginx
kubectl get pods -l env!=dev
kubectl get pods -l 'app=nginx,env=prod'   # AND of conditions

# set-based: in, notin, exists
kubectl get pods -l 'env in (prod,staging)'
kubectl get pods -l 'env notin (dev)'
kubectl get pods -l 'tier'                 # key exists
kubectl get pods -l '!canary'              # key does not exist

# combine equality and set-based
kubectl get pods -l 'app=nginx,env in (prod,staging)'

为资源打标签

label 修改标识性元数据——用于选择器应匹配的任何内容。annotate 用于非标识性元数据(owner、工单、描述、工具提示)。节点常被标记拓扑或硬件提示来驱动调度。

kubernetes
# label a pod
kubectl label pod nginx app=nginx tier=web

# label all pods matching a selector
kubectl label pods -l app=oldapp app=newapp --overwrite

# label a node (for scheduling hints)
kubectl label node node-1 disktype=ssd

# remove a node label
kubectl label node node-1 disktype-

# list nodes by label
kubectl get nodes -l disktype=ssd

# annotate (non-identifying metadata)
kubectl annotate pod nginx owner=alice
kubectl annotate pod nginx description="web server"

清单中的选择器

YAML 中选择器使用 matchLabels(等式)和 matchExpressions(集合,operator 为 In/NotIn/Exists/DoesNotExist)。对 Deployment,选择器创建后不可变——且 Pod 模板标签必须匹配它。Service 仅支持 matchLabels。

kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:            # equality-based
      app: nginx
    matchExpressions:       # set-based (optional)
      - key: env
        operator: In
        values: [prod, staging]
      - key: tier
        operator: Exists
  template:
    metadata:
      labels:
        app: nginx          # MUST match selector
        env: prod
        tier: web

注解

注解持有工具使用的非标识性元数据——kubectl apply 存储上次应用的配置,cert-manager 读取 issuer 提示,Prometheus 读取采集配置,控制器存储推出状态。与标签不同,注解值可以是大型 JSON 块。

kubernetes
metadata:
  annotations:
    kubernetes.io/change-cause: "bump nginx to 1.26"
    prometheus.io/scrape: "true"
    prometheus.io/port: "9090"
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1",...}
    cert-manager.io/cluster-issuer: "letsencrypt-prod"

# view annotations
kubectl get pod nginx -o jsonpath='{.metadata.annotations}'

# annotate
kubectl annotate pod nginx owner=team-platform

# remove an annotation (trailing dash)
kubectl annotate pod nginx owner-

推荐标签

app.kubernetes.io/* 标签是共享词汇表,让工具(Helm、operator、仪表盘)能将一个应用的所有资源分组。name+instance 唯一标识一个发布;component/part-of 描述层级;managed-by/created-by 跟踪所有权。

kubernetes
# shared recommended labels (app.kubernetes.io/*)
metadata:
  labels:
    app.kubernetes.io/name: nginx
    app.kubernetes.io/instance: nginx-prod
    app.kubernetes.io/version: "1.25"
    app.kubernetes.io/component: web
    app.kubernetes.io/part-of: storefront
    app.kubernetes.io/managed-by: helm
    app.kubernetes.io/created-by: controller-manager

# Helm applies these automatically; kubectl doesn't.
# They unify how tooling identifies an application's resources
# across Deployments, Services, Ingresses, ConfigMaps, etc.
09

ReplicaSet

ReplicaSet 清单

ReplicaSet 维护一组匹配选择器的稳定副本 Pod——在 Pod 被删除或失败时重建它们。几乎总是用 Deployment 代替,它包装 ReplicaSet 并增加滚动更新和回滚。

kubernetes
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.25
# kubectl get rs
# kubectl describe rs nginx

ReplicaSet 工作原理

ReplicaSet 控制器用选择器调和期望与实际 Pod 数。每个 Pod 有指向 RS 的 ownerReference——这就是 kubectl get pod 显示 'Owned by ReplicaSet/nginx' 的原因。扩缩容只是改变期望数。

kubernetes
# the controller loop:
# 1. count pods matching selector
# 2. if fewer than replicas -> create from template
# 3. if more than replicas -> delete excess (arbitrary order)

# owned-by reference on each pod
kubectl get pod -l app=nginx -o jsonpath='{.items[*].metadata.ownerReferences}'

# if you delete a pod, the RS creates a new one immediately
kubectl delete pod <pod-name>
kubectl get pods -l app=nginx

# scale by editing replicas
kubectl scale rs nginx --replicas=5

ReplicaSet vs ReplicationController

ReplicationController(原始 v1 原语)仅支持等式选择器,已弃用。ReplicaSet(apps/v1)增加集合选择器。实践中应使用 Deployment——它替你管理 ReplicaSet 并提供滚动更新/回滚。

kubernetes
# ReplicationController (v1, legacy): equality-only selectors
# ReplicaSet (apps/v1, modern): set-based selectors (in, notin, exists)

# ReplicationController is deprecated; do not use.
apiVersion: v1
kind: ReplicationController      # legacy
# ...
# ReplicaSet is the successor:
apiVersion: apps/v1
kind: ReplicaSet                 # modern
# ...
# Deployment wraps ReplicaSet and is the recommended primitive:
apiVersion: apps/v1
kind: Deployment                 # use this in practice

手动扩缩容

kubectl scale 修改 replicas 字段。如果 HPA 针对同一资源,它会在下次调和中覆盖手动扩缩。一次性操作优先用 kubectl scale,持续弹性工作负载用 HPA。

kubernetes
# scale a replicaset directly
kubectl scale rs nginx --replicas=5

# scale via patch
kubectl patch rs nginx -p '{"spec":{"replicas":5}}'

# scale multiple resources at once
kubectl scale deployment nginx deployment web --replicas=3

# scale by referencing a file
kubectl scale --replicas=5 -f nginx.yaml

# the autoscaler (HPA) will override manual scaling
# if it targets the same resource

模板变更与接管

与 Deployment 不同,裸 ReplicaSet 不会推出 Pod 模板变更——只有新创建的 Pod(删除/扩容后)才用新规格。ReplicaSet 会接管匹配其选择器的任何孤立 Pod,这可能导致意外行为。

kubernetes
# changing the pod template does NOT update existing pods
# (unlike a Deployment, a bare ReplicaSet won't roll out)
kubectl edit rs nginx   # change image -> new pods use it, old ones don't

# delete old pods to force them onto the new template
kubectl delete pods -l app=nginx

# a ReplicaSet will ADOPT existing pods that match its selector
# even pods created independently — useful (and dangerous)

# orphaned pods (no owner) matching the selector are taken over
kubectl get pods -l app=nginx --show-kind

从 ReplicaSet 移除 Pod

要删除 Pod 而不让 ReplicaSet 重建它,要么先把 RS 缩到 0,要么清除 Pod 的 ownerReferences 使 RS 不再拥有它。用于调试特定实例或在清理前提取日志。

kubernetes
# detaching a pod from its ReplicaSet (so it isn't replaced)
kubectl patch pod <pod-name> \
  -p '{"metadata":{"ownerReferences":[]}}'

# now deleting this pod won't trigger a replacement,
# because the RS no longer owns it

# or scale the RS to 0 first, then delete
kubectl scale rs nginx --replicas=0
kubectl delete pod <pod-name>

# useful for debugging a specific failing pod instance
# without the RS immediately recreating it
10

StatefulSet

StatefulSet 清单

StatefulSet 为 Pod 提供稳定标识(名、主机名、存储)和有序的部署/扩缩。需要 headless serviceName。volumeClaimTemplates 为每个 Pod 创建专用 PVC——所以即使 pod-0 被重新调度,它也会重新挂载同一卷。

kubernetes
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql          # required: headless service
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8
          ports:
            - containerPort: 3306
          volumeMounts:
            - name: data
              mountPath: /var/lib/mysql
  volumeClaimTemplates:       # one PVC per pod
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 10Gi

稳定标识

每个 Pod 有稳定的序号名(mysql-0、mysql-1、…)和通过 headless service 的稳定 DNS 名。节点故障时,pod-0 被调度到别处但保留名称并重新挂载卷——对依赖稳定成员关系的集群数据库至关重要。

kubernetes
# pods are named <statefulset-name>-<ordinal>
# mysql-0, mysql-1, mysql-2
kubectl get pods -l app=mysql

# each pod has stable DNS (via the headless service):
#   mysql-0.mysql.default.svc.cluster.local
#   mysql-1.mysql.default.svc.cluster.local

# stable hostname inside the pod:
kubectl exec mysql-0 -- hostname
# -> mysql-0

# ordinal index also exposed:
kubectl exec mysql-0 -- sh -c 'echo $HOSTNAME'
# -> mysql-0

# pod identity persists across reschedules

稳定存储

volumeClaimTemplates 为每个 Pod 生成一个可预测名称的 PVC(data-mysql-0、…)。PVC 在 Pod 和 StatefulSet 删除后仍存在——这防止数据丢失,但也意味着必须显式删除 PVC 才能回收存储。同一卷总是重新挂载到同一序号 Pod。

kubernetes
# one PVC per pod, named <volumeClaimTemplate-name>-<pod-name>
kubectl get pvc
# NAME        STATUS   VOLUME       CAPACITY   ...
# data-mysql-0   Bound   pvc-aaa      10Gi
# data-mysql-1   Bound   pvc-bbb      10Gi
# data-mysql-2   Bound   pvc-ccc      10Gi

# when pod-0 is rescheduled, it re-binds data-mysql-0
# deleting the StatefulSet does NOT delete PVCs by default
# (protects from accidental data loss)

# to actually delete the data:
kubectl delete pvc data-mysql-0 data-mysql-1 data-mysql-2

有序部署与 Pod 管理

OrderedReady(默认)严格按 0→1→2 顺序创建 Pod,按相反顺序删除——需要主节点先于副本引导的系统需要此模式。Parallel 同时创建/删除所有 Pod——对对称分片存储(Cassandra、Elasticsearch)更快。

kubernetes
spec:
  podManagementPolicy: OrderedReady   # default: strict order
  # podManagementPolicy: Parallel      # create/delete all at once

  replicas: 3
  # OrderedReady: create pod-0, then pod-1, then pod-2 (each waits for Ready)
  # deletion is reverse: pod-2, pod-1, pod-0

  # Parallel: all pods created/deleted simultaneously
  # identity and storage remain stable either way

# check policy
kubectl get statefulset mysql -o jsonpath='{.spec.podManagementPolicy}'

# parallel is great for sharded stores that don't need bootstrap order

滚动更新

StatefulSet 滚动更新按逆序(N-1 到 0)进行。partition 让你先金丝雀最高序号的 Pod。OnDelete 暂停更新直到你手动删除 Pod——用于受控迁移。由于有序性,推出比 Deployment 慢。

kubernetes
spec:
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      partition: 2          # only pods with ordinal >= 2 update
      maxUnavailable: 1     # (default 1) allowed down
  # type: OnDelete  -> only update when pod is manually deleted

# partition enables canaries: set partition=N to update
# only the top N pods; lower to 0 to roll out to all.

kubectl rollout status statefulset/mysql
# waits for all pods to be updated

# StatefulSets also support rollout history/undo,
# but only when the change is in the pod template

Headless Service 关联

spec.serviceName 引用的 headless service(clusterIP: None)是使稳定每 Pod DNS 工作的关键。没有它 StatefulSet 不会创建 Pod。客户端解析 service 名获得轮询,或 pod-0.svc 固定到主节点。别忘了创建 Service。

kubernetes
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  clusterIP: None         # headless
  selector:
    app: mysql
  ports:
    - port: 3306
---
# StatefulSet references this service via spec.serviceName
# this gives each pod a stable DNS:
#   mysql-0.mysql.default.svc.cluster.local

# clients can:
# - resolve mysql -> any pod IP (load-balanced by DNS round-robin)
# - resolve mysql-0.mysql -> pod-0's IP (pin to a specific replica)

# required: serviceName MUST match the headless service name
11

DaemonSet

DaemonSet 清单

DaemonSet 在每个(匹配调度约束的)节点上运行恰好一个 Pod。适合节点级代理:日志采集、监控、存储、CNI、Ingress 控制器。新节点自动获得 Pod;删除节点时其 Pod 被垃圾回收。

kubernetes
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: log-agent
  namespace: kube-system
  labels:
    app: log-agent
spec:
  selector:
    matchLabels:
      app: log-agent
  template:
    metadata:
      labels:
        app: log-agent
    spec:
      containers:
        - name: agent
          image: fluent-bit:2.2
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
      # one pod per (matching) node automatically

节点调度

nodeSelector 是最简单的约束(所有 key=value 必须匹配)。nodeAffinity 增加 In/NotIn/Exists 运算符和 preferred/required 规则。DaemonSet 像任何 Pod 一样遵守这些——配合 tolerations 也可在被污染的控制平面节点上运行代理。

kubernetes
spec:
  template:
    spec:
      nodeSelector:                # simplest: must match all
        disktype: ssd

      # more flexible affinity
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: kubernetes.io/os
                    operator: In
                    values: [linux]

      # only run on nodes labeled role=logging
      nodeSelector:
        role: logging

      tolerations:                 # tolerate tainted nodes
        - key: node-role.kubernetes.io/control-plane
          operator: Exists

更新策略

RollingUpdate(默认)逐节点更新 Pod,受 maxUnavailable 约束(可为数字或百分比)。OnDelete 暂停更新直到你手动删除每个 Pod——用于需要逐节点控制时。maxSurge 默认 0(DaemonSet 极少需要额外 Pod)。

kubernetes
spec:
  updateStrategy:
    type: RollingUpdate           # default
    rollingUpdate:
      maxUnavailable: 1           # how many nodes update at once
      maxSurge: 0                 # (default 0) no extra pods
  # type: OnDelete               # only update when old pod is deleted

# trigger an update (e.g. new image)
kubectl set image daemonset/log-agent agent=fluent-bit:2.3

# watch rollout
kubectl rollout status daemonset/log-agent -n kube-system

# rollout restart (recreate pods on every node)
kubectl rollout restart daemonset/log-agent -n kube-system

污点与容忍

污点排斥 Pod;容忍让特定 Pod 忽略污点。控制平面节点被污染 NoSchedule 以阻止用户工作负载落地——节点级代理容忍它以在各处运行。NoExecute 还会驱逐已运行的非容忍 Pod。

kubernetes
# inspect a node's taints
kubectl describe node node-1 | grep Taints
# Taints: node-role.kubernetes.io/control-plane:NoSchedule

# tolerate control-plane so the agent runs there too
spec:
  template:
    spec:
      tolerations:
        - key: node-role.kubernetes.io/control-plane
          operator: Exists
          effect: NoSchedule
        - key: node.kubernetes.io/disk-pressure
          operator: Exists
          effect: NoExecute

# taint effects: NoSchedule | NoExecute | PreferNoSchedule

DaemonSet 使用场景

DaemonSet 是节点级基础设施的标准部署形态。它们常需要特权访问(hostNetwork、hostPID、hostPath)来完成工作——有意识地授予且仅授予受信任镜像。切勿用 DaemonSet 部署应水平扩展的应用工作负载。

kubernetes
# classic DaemonSet workloads (node-level agents):
# - log collection:        fluent-bit, filebeat, promtail
# - monitoring:            node-exporter, datadog-agent
# - networking:            kube-proxy, CNI plugins, ingress controllers
# - storage:               CSI node plugins, Rook/Ceph
# - security:              Falco, Tetragon, runtime security
# - GPU/FPGA drivers:      nvidia-device-plugin

# storage / device plugins often need:
spec:
  template:
    spec:
      hostNetwork: true        # use node network namespace
      hostPID: true            # see node processes
      hostPath:                # mount node paths
        - path: /var/log
        - path: /var/lib/docker/containers

DaemonSet 状态

DESIRED 等于匹配调度约束的节点数;CURRENT/READY 显示存在并通过就绪检查的 Pod 数。-o wide 是查看每个 Pod 落在哪个节点的最简单方式。DaemonSet 像 Deployment 一样支持 rollout history/undo。

kubernetes
# desired = number of matching nodes
kubectl get daemonset log-agent -n kube-system
# NAME         DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE
# log-agent    5         5         5       5            5

# show which nodes a DaemonSet pod landed on
kubectl get pods -n kube-system -l app=log-agent -o wide

# rollout history
kubectl rollout history daemonset/log-agent -n kube-system

# rollback
kubectl rollout undo daemonset/log-agent -n kube-system

# check a per-node pod's logs
kubectl logs -n kube-system log-agent-abcde
12

Job 与 CronJob

Job 清单

Job 运行 Pod 直到指定数量成功完成(completions)。restartPolicy 必须是 Never 或 OnFailure(不是 Always——那是长期运行工作负载)。backoffLimit 限制重试;activeDeadlineSeconds 限制总运行时间。

kubernetes
apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  completions: 1              # how many successful pods needed
  parallelism: 1              # how many run concurrently
  backoffLimit: 6             # retries before marking Failed
  activeDeadlineSeconds: 600  # hard timeout
  template:
    spec:
      restartPolicy: Never    # OnFailure | Never
      containers:
        - name: pi
          image: perl
          command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
# kubectl get jobs
# kubectl logs job/pi

Job 完成数与并行度

completions = 满足 Job 所需的成功 Pod 数;parallelism = 同时运行多少。Indexed Job 为每个 Pod 分配序号(环境变量 JOB_COMPLETION_INDEX)——适合每个 Pod 处理一个分片的分批处理。NonIndexed(默认)只需任意 N 次成功。

kubernetes
spec:
  completions: 5         # 5 successful pods total
  parallelism: 2         # 2 pods run at a time
  backoffLimit: 4
  # default completionMode: NonIndexed (any 5 successes)
  completionMode: Indexed
  # Indexed: pods get 0..N-1 in JOB_COMPLETION_INDEX env,
  # useful for sharded work (each pod handles one shard)

  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - name: worker
          image: worker:1.0

# set via kubectl
kubectl create job pi --image=perl -- perl -Mbignum=bpi -wle "print bpi(2000)"

Job 退避与超时

backoffLimit 重试失败的 Pod(指数退避)。activeDeadlineSeconds 是硬上限——若达到,即使还有重试次数,Job 也标记为 Failed。ttlSecondsAfterFinished 自动清理完成的 Job。podFailurePolicy(1.31+)让你对特定退出码快速失败或忽略自愿驱逐。

kubernetes
spec:
  backoffLimit: 6            # default 6, retries on failure
  activeDeadlineSeconds: 3600  # hard wall, even if retries remain
  ttlSecondsAfterFinished: 86400  # auto-delete Job 1 day after done
  startingDeadlineSeconds: 300  # (CronJob only) miss window

  # pod failure handling (v1.31+):
  podFailurePolicy:
    rules:
      - action: FailJob
        onExitCodes:
          operator: In
          values: [42]      # exit 42 -> don't retry, fail fast
      - action: Count
        onPodConditions:
          - type: DisruptionTarget   # don't count voluntary evictions

  template:

CronJob 清单

CronJob 按 cron 计划创建 Job(5 个字段:分 时 日 月 周)。concurrencyPolicy 控制重叠运行:Forbid 在上次仍在运行时跳过新运行;Replace 杀掉旧的启动新的。timeZone(1.27+)免除了 UTC 换算。

kubernetes
apiVersion: batch/v1
kind: CronJob
metadata:
  name: backup
spec:
  schedule: "0 2 * * *"          # 5-field cron: 02:00 daily
  timeZone: "Asia/Shanghai"
  concurrencyPolicy: Forbid      # Allow | Forbid | Replace
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 1
  startingDeadlineSeconds: 200
  jobTemplate:
    spec:
      backoffLimit: 2
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: backup
              image: backup:1.0
# kubectl get cronjob
# kubectl get jobs

CronJob 挂起与历史

suspend: true 暂停 CronJob 而不删除——在事件期间很方便。历史限制保持 Job 列表可管理(默认 3 成功 / 1 失败)。kubectl create job --from=cronjob/X 立即运行模板,适合手动触发或回填错过的运行。

kubernetes
spec:
  schedule: "*/5 * * * *"
  suspend: true                # pause without deleting the CronJob
  successfulJobsHistoryLimit: 3   # default 3
  failedJobsHistoryLimit: 1       # default 1

# toggle suspend
kubectl patch cronjob backup -p '{"spec":{"suspend":true}}'
kubectl patch cronjob backup -p '{"spec":{"suspend":false}}'

# trigger a one-off run immediately
kubectl create job --from=cronjob/backup manual-backup

# clean up old jobs manually
kubectl delete jobs -l job-name=backup

CronJob 计划与边界情况

标准 5 字段 cron。当 day-of-month 和 day-of-week 同时被限制时,cron 在任一匹配时触发(OR 语义)——经典陷阱。若 CronJob 的计划时间错过超过 startingDeadlineSeconds,该运行会被跳过而非回填。

kubernetes
# cron syntax (5 fields):
# ┌───────────── minute (0-59)
# │ ┌───────────── hour (0-23)
# │ │ ┌───────────── day of month (1-31)
# │ │ │ ┌───────────── month (1-12)
# │ │ │ │ ┌───────────── day of week (0-6, Sun=0)
# "*/5 * * * *"      every 5 minutes
# "0 2 * * *"        daily at 02:00
# "0 0 * * 0"        weekly Sunday midnight
# "0 0 1 * *"        monthly on the 1st
# "30 3-5 * * *"     03:30, 04:30, 05:30

# gotchas:
# - day-of-month AND day-of-week both set => OR (not AND)
# - if startingDeadlineSeconds is missed, the run is skipped
# - control-plane restart can skip a tick if the schedule is missed
# - cron interprets literal fields; prefer timeZone over UTC math
13

Ingress

Ingress 清单

Ingress 将集群外的 HTTP/HTTPS 路由暴露给 Service,由 Ingress 控制器(nginx、traefik、ALB…)管理。ingressClassName 选择哪个控制器处理它。每条规则将 host + path 映射到 service+port 后端。

kubernetes
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api
                port:
                  number: 8080

带 TLS 的 Ingress

tls 条目将 TLS secret(类型 kubernetes.io/tls,持有 tls.crt + tls.key)绑定到一个或多个 host。Ingress 控制器终止 TLS 并将明文 HTTP 代理到后端。cert-manager 可基于 cluster-issuer 注解自动签发和轮换 Let's Encrypt 证书。

kubernetes
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-tls
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - app.example.com
        - www.example.com
      secretName: web-tls-secret   # kubernetes.io/tls secret
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80

# auto-issue certs with cert-manager:
# annotations:
#   cert-manager.io/cluster-issuer: letsencrypt-prod

Ingress 规则与默认后端

defaultBackend 处理不匹配任何规则的流量(无 host 或未匹配的 path)。多条规则让一个 Ingress 路由多个虚拟主机。每条规则可有多个 path 后端——单个 Ingress 可前端整个应用的路由拓扑。

kubernetes
spec:
  ingressClassName: nginx
  defaultBackend:                # catch-all for unmatched traffic
    service:
      name: default-svc
      port:
        number: 80
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service: { name: api, port: { number: 8080 } }
    - host: blog.example.com     # different host -> different svc
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service: { name: blog, port: { number: 80 } }

IngressClass

IngressClass 声明一个控制器(如 k8s.io/ingress-nginx)。Ingress 通过 spec.ingressClassName 引用它,使多个控制器共存。恰好一个类可用 is-default-class 注解标记为默认——未显式指定类的新 Ingress 使用它。

kubernetes
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: nginx
  annotations:
    ingressclass.kubernetes.io/is-default-class: "true"
spec:
  controller: k8s.io/ingress-nginx

# an Ingress picks a class via spec.ingressClassName
# (replaces the deprecated kubernetes.io/ingress.class annotation)

# multiple IngressClasses in one cluster:
# - nginx    (community ingress-nginx)
# - traefik  (Traefik controller)
# - alb      (AWS ALB)
# only one IngressClass can be marked default

路径类型

Exact 精确匹配路径;Prefix 匹配整个路径段(/api 匹配 /api 和 /api/foo 但不匹配 /apix)。ImplementationSpecific 委托给控制器——如 nginx 正则。始终优先 Prefix 或 Exact 以获得可移植行为;ImplementationSpecific 会绑定到单一控制器。

kubernetes
spec:
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /api/v1
            pathType: Exact        # only /api/v1 (exact match)
            backend: ...
          - path: /api
            pathType: Prefix       # /api, /api/, /api/x (prefix match)
            backend: ...
          - path: /old
            pathType: ImplementationSpecific  # controller decides
            backend: ...

# Prefix matches path segments, not raw string prefix:
# /api   matches /api, /api/, /api/x  but NOT /apix
# Exact  matches the path verbatim
# ImplementationSpecific defers to the controller

注解(Nginx 控制器)

控制器特定注解配置标准 Ingress 规格之外的行为。ingress-nginx 有数十个:rewrite-target、ssl-redirect、body-size、超时、CORS、基本认证、配置片段。它们是控制器特定的——迁移到另一控制器意味着重写它们。

kubernetes
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  annotations:
    kubernetes.io/ingress.class: nginx          # legacy form
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "50m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/cors-allow-origin: "https://app.example.com"
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "X-Frame-Options: DENY";
spec:
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /v1(/|$)(.*)
            pathType: ImplementationSpecific
            backend:
              service: { name: api, port: { number: 8080 } }
14

存储卷(PV/PVC)

PersistentVolume 清单

PersistentVolume(PV)是集群作用域的存储,由管理员预置或由 StorageClass 动态供应。accessModes 描述如何挂载。reclaimPolicy 控制 PVC 释放后存储的处理方式。

kubernetes
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-1
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce        # RWO: one node R/W
  persistentVolumeReclaimPolicy: Retain   # Retain | Delete | Recycle
  storageClassName: manual
  hostPath:                # for dev only (single node)
    path: /mnt/data
  # nfs:
  #   server: 10.0.0.1
  #   path: /export/data
  # csi:
  #   driver: ebs.csi.aws.com
  #   volumeHandle: vol-xxxx

PersistentVolumeClaim 清单

PersistentVolumeClaim(PVC)是 namespace 作用域的存储请求。控制器将它绑定到匹配的 PV(accessModes、足够容量、相同 StorageClass)。若有默认 StorageClass,storageClassName 留空会触发动态供应。

kubernetes
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: manual
  resources:
    requests:
      storage: 5Gi
  volumeMode: Filesystem     # Filesystem | Block
  selector:                  # optional: filter PVs by labels
    matchLabels:
      disktype: ssd
# kubectl get pvc
# STATUS: Pending -> Bound once a matching PV is found

访问模式

accessModes 描述挂载语义——但实际支持取决于存储后端。EBS/GCE PD/Azure Disk 仅支持 RWO。RWX(多节点读写)需要 NFS、CephFS 或分布式文件系统。RWOP(1.27+)即使在同一节点也限制为单 Pod。

kubernetes
# four access modes (support is driver-specific):
# - ReadWriteOnce  (RWO):  mounted R/W by ONE node
# - ReadOnlyMany   (ROX):  mounted R/O by MANY nodes
# - ReadWriteMany  (RWX):  mounted R/W by MANY nodes
# - ReadWriteOncePod (RWOP): mounted R/W by ONE pod (1.27+)

# examples by backend:
# AWS EBS, GCE PD, Azure Disk:  RWO only
# NFS:                          RWO, ROX, RWX
# CephFS, Portworx:             RWO, RWX
# Block volumes:                RWO

# RWX is required for pods on different nodes
# to share the same volume (e.g. read-only assets)

回收策略

Retain 保留数据以策安全——必须手动擦除并重新绑定 PV。Delete(动态供应默认)在 PVC 删除时擦除 PV 和底层存储。Recycle 已弃用。Retain 下 Released 的 PV 需清除 claimRef 才能重新绑定。

kubernetes
# what happens when a PVC is deleted:
# - Retain:   PV stays, data preserved; PV must be manually
#             reclaimed (delete data, then delete PV) before reuse
# - Delete:   PV and the underlying storage are deleted (dynamic only)
# - Recycle:  deprecated; ran scrub on the volume

# change policy on an existing PV
kubectl patch pv pv-1 -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'

# a released PV (PVC deleted, policy Retain) is stuck:
#   phase=Released, claimRef still set
# to reuse: clear claimRef
kubectl patch pv pv-1 --type json -p '[{"op":"remove","path":"/spec/claimRef"}]'

在 Pod 中使用 PVC

通过 persistentVolumeClaim.claimName 像任何卷一样挂载 PVC。subPath 挂载子目录——便于在多个 Pod/路径间共享一个卷。RWO 卷可被多个 Pod 挂载但仅在相同节点;跨节点挂载会导致 multi-attach 错误。

kubernetes
apiVersion: v1
kind: Pod
metadata:
  name: db
spec:
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: data-claim
  containers:
    - name: db
      image: postgres:16
      volumeMounts:
        - name: data
          mountPath: /var/lib/postgresql/data
          subPath: pgdata       # mount a subdirectory of the volume

# a PVC is namespaced and bound to ONE PV
# RWO PVCs can be mounted by multiple pods on the SAME node
# (e.g. one writer, several readers on that node)

静态 vs 动态供应

静态供应需管理员预创建 PV——对 NFS 尚可,但规模化时痛苦。动态供应让 PVC 通过 StorageClass 的 provisioner 触发按需卷创建。现代集群几乎总用动态供应;静态供应保留给共享/遗留存储。

kubernetes
# STATIC: admin pre-creates PVs; PVCs bind to them.
#   Good for: pre-existing NFS exports, manual capacity planning.

# DYNAMIC: PVC requests storage; StorageClass provisions a PV
#   automatically (AWS EBS, GCE PD, Ceph, local-path, etc.)

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: dynamic-claim
spec:
  storageClassName: ebs-sc      # triggers dynamic provisioning
  accessModes: ["ReadWriteOnce"]
  resources:
    requests:
      storage: 20Gi

# no PV exists -> provisioner creates one -> binds to PVC
# kubectl get pvc dynamic-claim -> Bound
# kubectl get pv -> shows the dynamically-created PV
15

StorageClass

StorageClass 清单

StorageClass 描述动态供应存储的一种'风味':provisioner(CSI 驱动)、parameters(磁盘类型、加密、fsType)和策略。PVC 通过 spec.storageClassName 引用它。一个集群通常有几种类(快速 SSD、大容量 HDD、NFS…)。

kubernetes
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  fsType: ext4
  encrypted: "true"
reclaimPolicy: Delete            # Retain | Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
mountOptions:
  - noatime
# kubectl get storageclass

默认 StorageClass

恰好一个 StorageClass 可作为默认(is-default-class: true 注解)。省略 storageClassName 的 PVC 自动使用它——对不在乎后端的用户很方便。用 kubectl get sc 查看哪个类被标记为 (default)。

kubernetes
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: standard
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

# a PVC with no storageClassName uses the default
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: auto
spec:
  accessModes: ["ReadWriteOnce"]
  resources:
    requests:
      storage: 5Gi
# (no storageClassName set -> uses 'standard')

Provisioner

kubernetes.io/no-provisioner 表示仅静态绑定(无动态创建)。所有真正的动态供应都用 CSI 驱动——云厂商提供自己的(ebs.csi.aws.com 等),自托管选项(Longhorn、Rook/Ceph、local-path)覆盖裸金属。parameters 完全取决于 provisioner。

kubernetes
# built-in (no external driver): only static binding
provisioner: kubernetes.io/no-provisioner

# cloud CSI drivers (dynamic):
provisioner: ebs.csi.aws.com          # AWS EBS
provisioner: pd.csi.storage.gke.io    # GCE PD
provisioner: disk.csi.azure.com       # Azure Disk
provisioner: nfs.csi.k8s.io           # NFS

# popular self-hosted:
provisioner: driver.longhorn.io       # Longhorn
provisioner: rook-ceph.ceph.com       # Rook/Ceph
provisioner: rancher.io/local-path    # local-path (dev)

# parameters are provisioner-specific
# (e.g. AWS: type=gp3|iops=3000|encrypted=true)

卷绑定模式

Immediate 在 PVC 创建时即绑定——对分区磁盘有风险,因为 Pod 可能落在不同分区。WaitForFirstConsumer 延迟绑定直到有 Pod 实际消费 PVC,从而卷落在正确分区。对分区云磁盘务必用 WaitForFirstConsumer。

kubernetes
spec:
  volumeBindingMode: WaitForFirstConsumer
  # ^ default for many CSI drivers
  # alternatives:
  # volumeBindingMode: Immediate

# Immediate: PVC binds/provisions as soon as created
#   risk: volume created in zone A, pod scheduled in zone B
#   -> multi-attach / cross-zone latency issues

# WaitForFirstConsumer: delays binding until a pod using the PVC
#   is scheduled. The PV is then created in the pod's zone.
#   REQUIRED for topology-constrained backends (EBS, etc.)

# topology constraints come from the CSI driver via
# AllowedTopologies

每个 StorageClass 的回收策略

StorageClass.reclaimPolicy 设置其动态供应的每个 PV 的策略。Delete(默认)在 PVC 删除时销毁卷——高效但对生产数据危险。要保留数据,在删除 PVC 前将 PV 切换为 Retain,或从一开始就用 Retain 类。

kubernetes
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-temp
provisioner: ebs.csi.aws.com
reclaimPolicy: Delete            # default for dynamic volumes
# reclaimPolicy: Retain          # keep data after PVC delete

# the StorageClass policy becomes the PV's policy
# when a PV is dynamically provisioned

# to preserve data, either:
# 1. use a Retain StorageClass
# 2. patch the dynamically-created PV to Retain before deleting PVC:
kubectl patch pv pvc-xxxx -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'

# then delete PVC safely; data survives

卷扩容

设置 allowVolumeExpansion: true 让用户通过编辑 spec.resources.requests.storage 扩容 PVC。CSI 驱动扩展底层卷,然后 kubelet 在下次挂载时扩展文件系统。不支持缩容。多数云 CSI 驱动支持在线扩容(无需卸载)。

kubernetes
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
provisioner: ebs.csi.aws.com
allowVolumeExpansion: true       # must be true to resize

# then resize by editing the PVC's requested size
kubectl patch pvc data-claim -p '{"spec":{"resources":{"requests":{"storage":"50Gi"}}}}'

# status.conditions shows Resizing / FileSystemResizePending
kubectl describe pvc data-claim

# requirements:
# - StorageClass.allowVolumeExpansion = true
# - driver supports online expansion (most CSI drivers do)
# - shrinking is NOT supported (only grow)
# - FilesystemResize happens after the PV is expanded
16

Helm

Helm 安装与发布

Helm 将 Kubernetes 清单打包为'chart'并以'release'管理。install 创建发布;upgrade 应用变更;upgrade --install 是幂等的。发布以 Secret/ConfigMap 跟踪在 namespace 中——这就是回滚工作的原理。

kubernetes
# add and update a chart repo
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

# search for charts
helm search repo nginx
helm search hub wordpress   # searches Artifact Hub

# install a chart (creates a release)
helm install my-nginx bitnami/nginx --namespace web --create-namespace

# upgrade an existing release
helm upgrade my-nginx bitnami/nginx --set replicaCount=3

# upgrade + install in one idempotent command
helm upgrade --install my-nginx bitnami/nginx -f values.yaml

# uninstall
helm uninstall my-nginx -n web

# list releases
helm list -n web
helm list --all-namespaces

Chart 结构

chart 是模板化 YAML 加默认值的目录。Chart.yaml 持有元数据;values.yaml 持有默认值;templates/ 持有用这些值渲染的 Go 模板。helm create 脚手架一个可用 chart。helm lint 在发布前捕获模式/模板错误。

kubernetes
my-chart/
├── Chart.yaml          # chart metadata (name, version, apiVersion)
├── values.yaml         # default values (overridable)
├── charts/             # chart dependencies (subcharts)
├── templates/          # Go-templated YAML
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── _helpers.tpl    # named templates (partials)
│   └── NOTES.txt       # post-install notes
├── templates.yaml      # (optional) CRDs to install before templates
└── README.md

# create a new chart skeleton
helm create my-chart

# lint a chart
helm lint my-chart

# package into a .tgz
helm package my-chart

值与覆盖

values.yaml 持有 chart 默认值。用 --set(标量)或 -f(整个文件)覆盖。helm show values 列出 chart 接受的每个 key。helm template 在不触碰集群的情况下渲染清单——对 diff 发布实际应用的内容至关重要。

kubernetes
# values.yaml (chart defaults)
image:
  repository: nginx
  tag: "1.25"
replicaCount: 2
service:
  type: ClusterIP
  port: 80

# override on the command line
helm upgrade --install web my-chart \
  --set replicaCount=5 \
  --set image.tag=1.26 \
  --set service.type=LoadBalancer

# override from a file
helm upgrade --install web my-chart -f prod-values.yaml

# see all values a chart supports
helm show values bitnami/nginx

# rendered output (debug, no install)
helm template web my-chart -f prod-values.yaml

模板与内置对象

模板使用 Go 模板语法加 Sprig 函数。.Release.Name 使每次安装唯一;.Values 暴露 chart 值;.Chart 取自 Chart.yaml。default 函数提供回退。通过 .Release.Name 的渲染安全命名让一个 chart 可在同 namespace 运行多个发布。

kubernetes
# built-in template objects:
#   .Values         chart values (after overrides)
#   .Release        release metadata (Name, Namespace, Service, Revision, IsInstall, IsUpgrade)
#   .Chart          Chart.yaml contents
#   .Files          files in the chart
#   .Capabilities   cluster capabilities (KubeVersion, APIVersions)
#   .Template       current template info

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-app
  labels:
    app.kubernetes.io/instance: {{ .Release.Name }}
    app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
  replicas: {{ .Values.replicaCount | default 1 }}
  selector:
    matchLabels:
      app: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}

Helm 仓库

Helm 3 同时支持经典 HTTP chart 仓库和 OCI 注册表(helm push/pull oci://…)。OCI 是现代、对签名友好的路径。helm repo update 刷新索引;升级前务必运行它以获取最新 chart 版本。Artifact Hub(helm search hub)索引公共 chart。

kubernetes
# add a chart repository
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add jetstack https://charts.jetstack.io

# list configured repos
helm repo list

# update repo indexes
helm repo update

# remove a repo
helm repo remove bitnami

# push to OCI registry (Helm 3+)
helm registry login registry.example.com
helm package my-chart
helm push my-chart-0.1.0.tgz oci://registry.example.com/charts

# pull an OCI chart
helm pull oci://registry.example.com/charts/my-chart --version 0.1.0

回滚与历史

每次 install/upgrade 创建一个以 Secret 存储的编号版本。helm rollback 立即切回之前的版本——这是 Helm 相对纯 kubectl apply 的杀手锏。helm get values 显示实际部署的内容,对调试漂移状态极有价值。

kubernetes
# view release history
helm history my-nginx -n web

# rollback to a previous revision
helm rollback my-nginx 1 -n web

# get rendered manifests of a deployed release
helm get manifest my-nginx -n web

# get the values used at install/upgrade
helm get values my-nginx -n web
helm get values my-nginx -n web --all   # incl. chart defaults

# get all info (hooks, manifest, values, notes)
helm get all my-nginx -n web

# wait for resources to be ready on install/upgrade
helm upgrade --install my-nginx bitnami/nginx --wait --timeout 5m
17

NetworkPolicy

NetworkPolicy 清单

NetworkPolicy 是 Pod 的防火墙规则。空 podSelector 选择 namespace 内所有 Pod;空规则列表拒绝该类型所有流量。NetworkPolicy 是叠加的——若有任何策略允许,Pod 即被允许。需要支持的 CNI;纯 flannel 会忽略它们。

kubernetes
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: prod
spec:
  podSelector: {}             # selects ALL pods in the namespace
  policyTypes:
    - Ingress
    - Egress
  # no ingress/egress rules => deny all traffic of that type
# effect: pods in 'prod' can't send or receive ANY traffic
# until another policy explicitly allows it

# REQUIRES a CNI that supports NetworkPolicy
# (Calico, Cilium, Weave, kube-router; NOT flannel alone)

Ingress 规则

Ingress 规则允许流量进入所选 Pod。from 条目之间为 OR;ports 之间为 OR。podSelector 匹配同 namespace 的 Pod;namespaceSelector 匹配整个 namespace(用自动添加的 kubernetes.io/metadata.name 标签)。在一个条目中组合两者为 AND。

kubernetes
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-web
  namespace: prod
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:               # pods in same namespace
            matchLabels:
              app: gateway
        - namespaceSelector:         # whole other namespace
            matchLabels:
              kubernetes.io/metadata.name: monitoring
        - ipBlock:                   # external CIDR
            cidr: 10.0.0.0/8
      ports:
        - protocol: TCP
          port: 8080

Egress 规则

Egress 规则控制所选 Pod 能向谁通信。常见陷阱:默认拒绝 egress 会破坏 DNS 解析,Pod 无法访问 kube-dns。在拒绝其他一切之前,务必先允许 UDP/TCP 53 到 kube-system namespace。ipBlock.except 划出例外。

kubernetes
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-egress-dns
  namespace: prod
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector: {}     # any namespace (kube-dns)
      ports:
        - protocol: UDP
          port: 53
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0
            except:
              - 10.0.0.0/8          # allow internet, deny internal
      ports:
        - protocol: TCP
          port: 443

# WARNING: egress deny-all blocks DNS and breaks pods.
# Always allow kube-dns first.

选择器与 Namespace 选择

裸 podSelector 匹配策略所在 namespace 的 Pod。namespaceSelector 匹配整个 namespace。在一个条目中同时指定 podSelector 和 namespaceSelector 为 AND(命名空间 Y 中标签 X 的 Pod)——作为分开条目则为 OR。ipBlock 匹配外部 IP。

kubernetes
spec:
  podSelector:                       # selects pods in THIS namespace
    matchLabels:
      app: web
  ingress:
    - from:
        # SAME namespace, matching pods
        - podSelector:
            matchLabels:
              app: gateway

        # DIFFERENT namespace (whole namespace)
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: monitoring

        # BOTH: pods in another namespace with specific labels
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: backend
          podSelector:
            matchLabels:
              app: api

        # external IP range
        - ipBlock:
            cidr: 192.168.1.0/24

默认策略(拒绝/允许全部)

默认拒绝策略(空规则)锁定 namespace,使只有显式允许列表能开洞。应用 deny-all ingress + deny-all egress 作为基线,然后添加有针对性的允许策略。空 ingress: [{}] 条目允许所有 ingress——opt-out 的逃生舱。

kubernetes
# --- DEFAULT DENY INGRESS (in a namespace) ---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: prod
spec:
  podSelector: {}
  policyTypes: [Ingress]
---
# --- DEFAULT DENY EGRESS ---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
  namespace: prod
spec:
  podSelector: {}
  policyTypes: [Egress]
---
# --- ALLOW ALL INGRESS (whitelist opt-out) ---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-ingress
  namespace: prod
spec:
  podSelector: {}
  policyTypes: [Ingress]
  ingress:
    - {}      # allow from anywhere

策略类型与默认行为

NetworkPolicy 是叠加的——一旦任何策略选中 Pod,该流量类型对 Pod 变为默认拒绝,除非显式规则允许。完全没有策略时一切开放。列出匹配 Pod 标签的策略可查看管辖其流量的策略。

kubernetes
spec:
  policyTypes:
    - Ingress
    - Egress
  # if omitted, defaults are inferred:
  #   - Ingress is always present (a policy always affects ingress)
  #   - Egress is implied if any egress rule exists

# key behaviors:
# - policies are ADDITIVE: a pod is allowed if ANY matching
#   policy permits the traffic
# - if NO policy selects a pod => all traffic allowed (default open)
# - if at least one policy selects a pod => default deny for that type
#   unless an explicit rule allows it

# inspect effective policies for a pod
kubectl get networkpolicy -n prod -l app=web
18

RBAC

Role(命名空间作用域)

Role 授予单个 namespace 内命名空间资源的权限。rules 列出 apiGroups、resources 和 verbs。pods/log 是子资源;pods/exec 需要 create 动词(因为 exec 创建子资源)。用 '*' 通配任何值。

kubernetes
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: dev
rules:
  - apiGroups: [""]
    resources: ["pods", "pods/log"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["pods/exec"]
    verbs: ["create"]
# a Role grants permissions WITHIN one namespace
# verbs: get, list, watch, create, update, patch, delete, deletecollection, "*"
# apiGroups: "" (core), "apps", "batch", "rbac.authorization.k8s.io", ...

RoleBinding

RoleBinding 将 Role(或 ClusterRole,限定到一个 namespace)授予主体:User、Group 或 ServiceAccount。绑定位于权限应用的 namespace。roleRef 不可变——要更改引用的 Role,需删除并重建绑定。

kubernetes
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: dev
subjects:
  - kind: User
    name: alice
    apiGroup: rbac.authorization.k8s.io
  - kind: ServiceAccount
    name: my-sa
    namespace: dev
  - kind: Group
    name: dev-team
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io
# binds the Role to users, groups, or service accounts
# RoleBinding can also reference a ClusterRole (scoped to its namespace)

ClusterRole 与 ClusterRoleBinding

ClusterRole 授予集群作用域资源(Node、namespace、PV)的权限——Role 无法触及这些。ClusterRole 也可通过 RoleBinding 在任何 namespace 绑定以复用(定义一次,绑定多次)。ClusterRoleBinding 集群范围授予 ClusterRole。

kubernetes
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: node-reader
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: read-nodes
subjects:
  - kind: ServiceAccount
    name: monitor
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: node-reader
  apiGroup: rbac.authorization.k8s.io
# ClusterRole grants cluster-scoped resources (nodes, PVs, namespaces)
# or can be reused across namespaces via a RoleBinding

动词、资源与 API 组

apiGroups 对资源分组——core 是 ''(空字符串);apps 含 Deployment/StatefulSet;batch 含 Job/CronJob。子资源(pods/log、pods/exec、pods/portforward)是独立权限。resourceNames 将规则限定到特定实例。nonResourceURLs 覆盖 /healthz、/metrics 等。

kubernetes
rules:
  - apiGroups: [""]                        # core API group
    resources: ["pods", "services", "configmaps", "secrets"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["apps"]
    resources: ["deployments", "replicasets", "statefulsets"]
    verbs: ["*"]
  - apiGroups: ["batch"]
    resources: ["jobs", "cronjobs"]
    verbs: ["create", "delete", "get"]
  - apiGroups: [""]
    resources: ["pods/log", "pods/exec", "pods/portforward"]
    verbs: ["get", "create"]
  - nonResourceURLs: ["/healthz", "/healthz/*"]   # non-resource URLs
    verbs: ["get"]

# resourceNames: restrict to specific instances
  - apiGroups: [""]
    resources: ["configmaps"]
    resourceNames: ["my-config"]
    verbs: ["get"]

ServiceAccount

ServiceAccount 是 Pod 的身份。通过 serviceAccountName 分配;token 自动挂载到 /var/run/secrets/kubernetes.io/serviceaccount。自 1.24 起,SA 不再有永久 token Secret——用 kubectl create token 获取短期限时 token。automountServiceAccountToken: false 选择退出。

kubernetes
# create a service account
kubectl create serviceaccount my-sa -n dev

# assign a RoleBinding (see RoleBinding example)
# mount the SA in a pod
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  serviceAccountName: my-sa
  automountServiceAccountToken: false   # opt out of token mount
  containers:
    - name: app
      image: myapp:1.0

# short-lived tokens (1.24+) - no permanent secret
kubectl create token my-sa -n dev --duration=1h

# list SAs
kubectl get sa -n dev

kubectl auth can-i

kubectl auth can-i 检查当前(或被模拟)用户的 RBAC 权限——调试 'forbidden' 错误的关键。--list 显示每个允许的动词/资源。--as 模拟用户/SA 进行测试。内置角色(view、edit、admin、cluster-admin)覆盖常见需求。

kubernetes
# check if you can do something
kubectl auth can-i create pods -n dev
kubectl auth can-i delete deployments -n prod

# check on behalf of another user/SA
kubectl auth can-i list secrets --as=system:serviceaccount:dev:my-sa -n dev

# check all allowed verbs on a resource
kubectl auth can-i --list --as=alice -n dev

# whoami (1.25+)
kubectl auth whoami

# reconcile: detect over-privileged bindings
kubectl get rolebindings,clusterrolebindings --all-namespaces -o wide

# common built-in cluster roles:
#   view, edit, admin, cluster-admin
19

探针(Liveness/Readiness)

Liveness 探针

Liveness 探针告诉 kubelet 何时重启容器。若连续失败 failureThreshold 次,kubelet 杀死容器并应用重启策略。用于从死锁或不可恢复状态中恢复——而非检查依赖(那是 readiness)。

kubernetes
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
    - name: app
      image: myapp:1.0
      livenessProbe:
        httpGet:
          path: /healthz
          port: 8080
        initialDelaySeconds: 15
        periodSeconds: 10
        timeoutSeconds: 2
        failureThreshold: 3
        successThreshold: 1
# if the probe fails failureThreshold times in a row,
# kubelet kills and restarts the container (per restartPolicy)

Readiness 探针

Readiness 探针控制 Pod 是否从 Service 接收流量。失败的 readiness 探针将 Pod IP 从端点移除——但不会重启它。用于预热(就绪前不路由)以及在短暂故障或优雅关闭期间排空流量。

kubernetes
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
    - name: app
      image: myapp:1.0
      readinessProbe:
        httpGet:
          path: /ready
          port: 8080
        initialDelaySeconds: 5
        periodSeconds: 5
        failureThreshold: 3
# a failing readiness probe REMOVES the pod from service endpoints,
# but does NOT restart the container.
# use to drain traffic during deploys, warm-up, or transient outages.

Startup 探针

Startup 探针(1.18+)用于慢启动应用(Java、遗留服务器)。它运行期间,liveness 和 readiness 被禁用——所以慢启动不会被 liveness 杀死。一旦 startup 成功,liveness/readiness 激活。为启动用长 failureThreshold × periodSeconds 窗口。

kubernetes
apiVersion: v1
kind: Pod
metadata:
  name: slow-app
spec:
  containers:
    - name: app
      image: myapp:1.0
      startupProbe:
        httpGet:
          path: /startup
          port: 8080
        failureThreshold: 30
        periodSeconds: 10      # up to 300s to start
      livenessProbe:
        httpGet:
          path: /healthz
          port: 8080
        periodSeconds: 10
# while the startup probe runs, liveness/readiness are disabled.
# once startup succeeds, liveness/readiness take over.

探针处理器

三种处理器类型:httpGet(成功 = HTTP 2xx/3xx)、tcpSocket(成功 = TCP 连接)、exec(成功 = 退出 0)。gRPC 探针(1.27+ GA)是 gRPC 服务的干净选项。优先 httpGet——它让应用发出'健康但忙'(503)信号而不重启。exec 脆弱(镜像中需要 shell/二进制)。

kubernetes
# three handler types:

# 1. HTTP GET (most common) - success = 200-399
livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
    httpHeaders:
      - name: X-Custom
        value: probe
    scheme: HTTP

# 2. TCP socket - success = port open
livenessProbe:
  tcpSocket:
    port: 3306

# 3. Exec - success = exit code 0
livenessProbe:
  exec:
    command:
      - /bin/sh
      - -c
      - "pg_isready -h localhost"

# gRPC (1.24+, alpha -> GA): use grpc probe
livenessProbe:
  grpc:
    port: 9090
    service: my.package.Health

探针参数

initialDelaySeconds 延迟首次探针——但 startup 探针是处理慢启动的更干净方式。periodSeconds 是频率;failureThreshold × periodSeconds 是 Pod 可不健康多久才行动。收紧这些以快速故障转移,放宽以容忍波动。terminationGracePeriodSeconds 限制关闭时间。

kubernetes
livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 15   # wait before first probe (after start)
  periodSeconds: 10         # probe every 10s
  timeoutSeconds: 2         # max time per probe
  successThreshold: 1       # consecutive successes to mark OK
  failureThreshold: 3       # consecutive failures to mark failed
  terminationGracePeriodSeconds: 30  # (liveness) grace before SIGKILL

# tuning tips:
# - set initialDelaySeconds > typical startup time
# - OR use a startup probe instead (cleaner)
# - shorter period = faster reaction, more load
# - higher failureThreshold = more tolerant of blips

探针失败行为

Liveness 失败会原位杀死+重启容器(不重新调度)。Readiness 失败只是将 Pod 从 Service 移除——不重启。Startup 失败行为类似 liveness。抖动的 liveness 常来自依赖慢下游服务的探针——保持健康检查本地且廉价。

kubernetes
# --- LIVENESS FAIL ---
#   container killed -> restarted (per restartPolicy: Always/OnFailure)
#   pod stays on the same node (NOT rescheduled)
#   CrashLoopBackOff if it keeps failing

# --- READINESS FAIL ---
#   pod stays running, but is REMOVED from Service endpoints
#   no traffic until it succeeds again
#   NOT restarted by kubelet

# --- STARTUP FAIL ---
#   container killed and restarted (like liveness)
#   liveness/readiness never activate
#   after failureThreshold × periodSeconds, pod is stuck restarting

# check probe results:
kubectl describe pod app | grep -A5 "Last State"
kubectl get pod app -o jsonpath='{.status.containerStatuses[*].state}'

# common cause of flapping: liveness probe hitting a slow dependency
20

资源与 kubectl 进阶

Requests 与 Limits

requests 是调度器预留的(只有节点有剩余 requests 时才调度 Pod)——设为稳态需求。limits 是硬上限:CPU 被限流,内存被 OOMKilled。cpu 以核为单位(500m = 0.5),memory 以字节(Mi/Gi)。生产中务必两者都设。

kubernetes
spec:
  containers:
    - name: app
      image: myapp:1.0
      resources:
        requests:           # what the scheduler guarantees (reservation)
          cpu: 250m          # 250 millicores = 0.25 core
          memory: 256Mi      # 256 mebibytes
          ephemeral-storage: 1Gi
        limits:             # hard ceiling (enforced)
          cpu: "1"           # 1 core
          memory: 512Mi
          ephemeral-storage: 2Gi

# cpu limit: throttled (cfs quota)
# memory limit: OOMKilled if exceeded
# ephemeral-storage limit: evicted if exceeded
# request only (no limit): best-effort burst

LimitRange 默认值

LimitRange 为未指定的 Pod 应用默认 requests/limits——当 ResourceQuota 要求 requests 时至关重要。max/min 约束单个容器能多大/多小。maxLimitRequestRatio 限制容器能在 request 之上突发多少,防止吵闹邻居。

kubernetes
apiVersion: v1
kind: LimitRange
metadata:
  name: defaults
  namespace: prod
spec:
  limits:
    - type: Container
      default:               # applied as LIMITS when not set
        cpu: 500m
        memory: 512Mi
      defaultRequest:        # applied as REQUESTS when not set
        cpu: 100m
        memory: 128Mi
      max:                   # max allowed LIMITS
        cpu: "4"
        memory: 8Gi
      min:                   # min allowed REQUESTS
        cpu: 50m
        memory: 64Mi
      maxLimitRequestRatio:  # limit/request ratio cap (burst cap)
        cpu: "4"

# a pod with no resources gets default/defaultRequest applied
# a pod with limit=4cpu, request=50m would breach maxLimitRequestRatio

水平 Pod 自动扩缩器

HPA 基于指标(通过 metrics-server 的 CPU/内存,或通过 Prometheus Adapter 的自定义/外部指标)扩缩副本。behavior(v2)调整激进程度:stabilizationWindowSeconds 防止抖动,policies 限制每分钟速率。扩容通常快速/激进;缩容刻意缓慢。

kubernetes
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  minReplicas: 3
  maxReplicas: 50
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization          # avg across pods
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80
  behavior:                          # (v2) scale up/down tuning
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Percent
          value: 50                  # max 50% down per minute
          periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
        - type: Percent
          value: 100
          periodSeconds: 60

# requires metrics-server for CPU/memory
kubectl get hpa web -w

Pod Disruption Budget

PodDisruptionBudget 限制一组 Pod 中可被自愿驱逐的数量——在节点 drain 和 cluster-autoscaler 操作期间保护可用性。使用 minAvailable 或 maxUnavailable(不可同时用)。它不防止非自愿中断(硬件故障)——只有副本能做到。

kubernetes
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web-pdb
  namespace: prod
spec:
  minAvailable: 2            # at least 2 pods always available
  # OR
  # maxUnavailable: 1        # at most 1 down at a time
  selector:
    matchLabels:
      app: web
# PDB protects against VOLUNTARY disruptions:
#   - kubectl drain (node maintenance)
#   - cluster autoscaler evictions
#   - kubectl delete pod (controller-managed)
# It does NOT prevent INVOLUNTARY disruptions (node failure, kernel panic).

# check PDB status
kubectl get pdb -n prod
kubectl describe pdb web-pdb -n prod

污点、容忍与亲和性

污点排斥 Pod;容忍让特定 Pod 忽略污点——用于专用节点(GPU、ingress、控制平面)。nodeAffinity 偏好/要求某些节点。podAntiAffinity 将副本分散到拓扑域(主机、分区)以实现 HA。用同 key+effect 后跟短横线移除污点。

kubernetes
# taint a node
kubectl taint nodes node-1 dedicated=gpu:NoSchedule

# tolerate the taint so a pod can schedule there
spec:
  tolerations:
    - key: dedicated
      operator: Equal
      value: gpu
      effect: NoSchedule

# prefer specific nodes
spec:
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 100
          preference:
            matchExpressions:
              - key: disktype
                operator: In
                values: [ssd]
    podAntiAffinity:               # spread replicas across nodes
      requiredDuringSchedulingIgnoredDuringExecution:
        - topologyKey: kubernetes.io/hostname
          labelSelector:
            matchLabels:
              app: web

# remove a taint
kubectl taint nodes node-1 dedicated=gpu:NoSchedule-

kubectl 进阶(patch/wait/top/debug)

patch 支持 JSON、strategic-merge 和 merge 类型。wait 阻塞直到条件满足——适合脚本。top 显示实时 CPU/内存(需 metrics-server)。kubectl debug 向运行中 Pod 附加临时容器(对 distroless 镜像很有用)或在节点上开 shell。

kubernetes
# JSON patch (precise field ops)
kubectl patch deployment web --type json -p \
  '[{"op":"replace","path":"/spec/replicas","value":3}]'

# strategic merge patch (default for k8s objects)
kubectl patch svc web -p '{"spec":{"type":"NodePort"}}'

# wait for a condition
kubectl wait --for=condition=Ready pod/web --timeout=60s
kubectl wait --for=delete pod/web --timeout=30s

# resource usage (needs metrics-server)
kubectl top nodes
kubectl top pods -n prod
kubectl top pod web --containers

# ephemeral debug container (1.25+)
kubectl debug -it web --image=busybox --target=web
# debug a node
kubectl debug node/node-1 -it --image=ubuntu

# run a one-off pod
kubectl run tmp --rm -it --image=alpine -- sh

# explain a field
kubectl explain pod.spec.containers.resources

这篇内容对您有帮助吗?

学习路径

从零开始学习

通过结构化课程从头学习这个语言。