入门
kubectl 基础
kubectl 是 Kubernetes 的命令行工具。get 列出资源,create 创建新资源,expose 创建 Service,scale 修改副本数。describe 提供资源的详细信息。
# 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 可去掉列名。
# 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 环境变量组合多个文件来管理多个集群。
# 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-configexplain 与 API 资源
api-resources 列出集群支持的资源;explain 显示任意资源的 OpenAPI 模式——在终端内编写 YAML 时非常实用。使用 --recursive 可转储完整的嵌套结构。
# 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/v1Dry Run 与生成 YAML
--dry-run=client -o yaml 是从命令式命令生成清单的标准方法。--dry-run=server 会与真实 apiserver 校验(准入 webhook、模 式)但不持久化。非常适合引导声明式 YAML。
# 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 在从业者中近乎通用——配合补全使用体验最佳。
# 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' >> ~/.bashrcPod
Pod 清单
Pod 是最小可部署单元,持有一个或多个共享网络和存储的容器。同一 Pod 内的容器总是共同调度到同一节点。很少直接创建 Pod——应使用 Deployment 或 Job。
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 读取主容器写入的日志。
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 表示容器反复退出。检查重启次数和事件来诊断。
# 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 将事件与资源规格打包,便于快速分诊。
# 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=nginxexec 与端口转发
exec 在容器内运行命令;-it 为 shell 分配 TTY。port-forward 将本地端口隧道到 Pod/Service 而不对外暴露——从笔记本调试数据库或 Web UI 的必备手段。
# 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。
# 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=30sDeployment
Deployment 清单
Deployment 管理 ReplicaSet,并提供声明式滚动更新和回滚。spec.selector 必须匹配 spec.template.metadata.labels。template 定义要推出的 Pod 规格。
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——用于应用不能同时运行两个版本时(如单卷写入者)。
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(已弃用)或注解跟踪变更原因。
# 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(缩容稳定化)。
# 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 做临时修复。
# 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.yamlDeployment 状态
Deployment 拥有 ReplicaSet;只有一个处于活跃状态(replicas>0)。旧 ReplicaSet 缩到 0 以备回滚。pod-template-hash 标签为每个 Pod 标记版本。检查 status.conditions 看 Available、Progressing、ReplicaFailure 信号。
# 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}'Service
Service 类型
Service 提供稳定的 IP/DNS,在一组 Pod 间负载均衡。ClusterIP 是默认(仅集群内)。NodePort 和 LoadBalancer 对外暴露。ExternalName 是 DNS 别名,非代理。
# 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.comClusterIP Service
ClusterIP 在集群内提供稳定的虚拟 IP 和 DNS 名。selector 匹配 Pod 标签;kube-proxy 编程 iptables/IPVS 在端点间负载均衡。通过 <svc>.<ns>.svc.cluster.local 或直接 <svc> 解析。
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 VIPNodePort Service
NodePort 在每个节点上开放相同的静态端口(30000-32767)。访问任意 node:nodePort 的流量都会到达某个 Pod(kube-proxy 可能重定向到其他节点上的 Pod)。在无法配置云 LB 时有用;配合外部 LB 实现 HA。
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。
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/hostnameHeadless Service
Headless Service(clusterIP: None)没有 VIP——DNS 直接返回 Pod IP。StatefulSet 必需它,以便每个 Pod 拥有稳定 DNS 名(pod-0.svc、pod-1.svc)。也用于想自行发现所有后端的客户端。
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.localEndpoints 与 EndpointSlices
Endpoints/EndpointSlices 列出真正接收流量的 Pod IP——只有 Ready 的 Pod 才会出现。如果 Service 没有端点,说明 Pod 未匹配 selector 或未 Ready。EndpointSlices(v1)对大型 Service 扩展性更好,是默认选择。
# 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)ConfigMap
创建 ConfigMap
ConfigMap 以键值对存储非敏感配置。--from-literal 用于内联值,--from-file 嵌入整个文件(文件名成为 key)。用于将配置与镜像解耦而无需重新构建。
# 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.propertiesConfigMap 清单
data 存储字符串值(每个 key 在挂载时成为环境变量或文件)。多行字符串使用 YAML 块标量(|)。binaryData 接受 base64 二进制数据。每个 ConfigMap 总大小限制为 1 MiB。
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 的环境变量。
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 且不会更新。
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 传播配置更新的最干净方式。
# 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 流量(规模化时的重大可扩展性收益)。生产中常用于与镜像版本绑定的应用配置。
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)Secret
创建 Secret
Secret 以 base64 编码存储敏感数据(默认未加密静止存储——生产环境应启用 encryption at rest)。generic/Opaque 用于任意数据,docker-registry 用于镜像拉取,tls 用于 Ingress TLS。切勿将 Secret YAML 提交到 git。
# 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.pemSecret 清单
data 值必须 base64 编码(echo -n 'value' | base64)。stringData 是接受明文的便捷方式,apply 时合并到 data。type Opaque 是默认;专用类型(kubernetes.io/tls、kubernetes.io/dockerconfigjson)会校验 key。
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 及容器内任何进程可见——高度敏感数据建议改用卷挂载。
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 不同。
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 nodeImagePullSecret
imagePullSecrets 在拉取镜像时向私有仓库认证。附加到 ServiceAccount 会自动应用于使用该 SA 的每个 Pod——这是推荐模式。docker-registry secret 类型自动生成正确的 .dockerconfigjson 负载。
# 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 被校验并被正确的控制器消费。
# 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: passNamespace
创建 Namespace
Namespace 为多团队或多环境(dev/stage/prod)划分集群。资源名在同一 namespace 内必须唯一。某些资源(Node、PV、StorageClass)是集群作用域,不属于 namespace。
# 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=devResourceQuota
ResourceQuota 限定 namespace 内的资源总用量——CPU/内存 requests/limits 总量、对象计数(Pod、PVC、Service、Deployment)。多租户集群必备,防止一个团队饿死其他团队。设置配额后未显式设 requests 的 Pod 会被拒绝。
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 namespaceLimitRange
LimitRange 设置单资源的默认值和边界:为未指定的 Pod 提供默认 requests/limits,并用 min/max 约束极端值。与 ResourceQuota 配对——没有默认 requests,配额会拒绝所有忘记设置的 Pod。
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 可强制完成,但可能泄漏外部资源。
# 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。
# 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 的简写——对集群全局可见性至关重要。
# 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标签与选择器
标签语法
标签是用于识别和分组资源的键值对。key 可有可选前缀(DNS 子域名,如 app.kubernetes.io/)。标签用于查询/过滤,而注解用于任意非标识性元数据。
# 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 支持两者。
# 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、工单、描述、工具提示)。节点常被标记拓扑或硬件提示来驱动调度。
# 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。
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 块。
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 跟踪所有权。
# 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.ReplicaSet
ReplicaSet 清单
ReplicaSet 维护一组匹配选择器的稳定副本 Pod——在 Pod 被删除或失败时重建它们。几乎总是用 Deployment 代替,它包装 ReplicaSet 并增加滚动更新和回滚。
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 nginxReplicaSet 工作原理
ReplicaSet 控制器用选择器调和期望与实际 Pod 数。每个 Pod 有指向 RS 的 ownerReference——这就是 kubectl get pod 显 示 'Owned by ReplicaSet/nginx' 的原因。扩缩容只是改变期望数。
# 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=5ReplicaSet vs ReplicationController
ReplicationController(原始 v1 原语)仅支持等式选择器,已弃用。ReplicaSet(apps/v1)增加集合选择器。实践中应使用 Deployment——它替你管理 ReplicaSet 并提供滚动更新/回滚。
# 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。
# 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,这可能导致意外行为。
# 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 不再拥有它。用于调试特定实例或在清理前提取日志。
# 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 itStatefulSet
StatefulSet 清单
StatefulSet 为 Pod 提供稳定标识(名、主机名、存储)和有序的部署/扩缩。需要 headless serviceName。volumeClaimTemplates 为每个 Pod 创建专用 PVC——所以即使 pod-0 被重新调度,它也会重新挂载同一卷。
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 被调度到别处但保留名称并重新挂载卷——对依赖稳定成员关系的集群数据库至关重要。
# 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。
# 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)更快。
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 慢。
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 templateHeadless Service 关联
spec.serviceName 引用的 headless service(clusterIP: None)是使稳定每 Pod DNS 工作的关键。没有它 StatefulSet 不会创建 Pod。客户端解析 service 名获得轮询,或 pod-0.svc 固定到主节点。别忘了创建 Service。
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 nameDaemonSet
DaemonSet 清单
DaemonSet 在每个(匹配调度约束的)节点上运行恰好一个 Pod。适合节点级代理:日志采集、监控、存储、CNI、Ingress 控制器。新节点自动获得 Pod;删除节点时其 Pod 被垃圾回收。
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 也可在被污染的控制平面节点上运行代理。
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)。
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。
# 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 | PreferNoScheduleDaemonSet 使用场景
DaemonSet 是节点级基础设施的标准部署形态。它们常需要特权访问(hostNetwork、hostPID、hostPath)来完成工作——有意识地授予且仅授予受信任镜像。切勿用 DaemonSet 部署应水平扩展的应用工作负载。
# 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/containersDaemonSet 状态
DESIRED 等于匹配调度约束的节点数;CURRENT/READY 显示存在并通过就绪检查的 Pod 数。-o wide 是查看每个 Pod 落在哪个节点的最简单方式。DaemonSet 像 Deployment 一样支持 rollout history/undo。
# 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-abcdeJob 与 CronJob
Job 清单
Job 运行 Pod 直到指定数量成功完成(completions)。restartPolicy 必须是 Never 或 OnFailure(不是 Always——那是长期运行工作负载)。backoffLimit 限制重试;activeDeadlineSeconds 限制总运行时间。
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/piJob 完成数与并行度
completions = 满足 Job 所需的成功 Pod 数;parallelism = 同时运行多少。Indexed Job 为每个 Pod 分配序号(环境变量 JOB_COMPLETION_INDEX)——适合每个 Pod 处理一个分片的分批处理。NonIndexed(默认) 只需任意 N 次成功。
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+)让你对特定退出码快速失败或忽略自愿驱逐。
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 换算。
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 jobsCronJob 挂起与历史
suspend: true 暂停 CronJob 而不删除——在事件期间很方便。历史限制保持 Job 列表可管理(默认 3 成功 / 1 失败)。kubectl create job --from=cronjob/X 立即运行模板,适合手动触发或回填错过的运行。
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=backupCronJob 计划与边界情况
标准 5 字段 cron。当 day-of-month 和 day-of-week 同时被限制时,cron 在任一匹配时触发(OR 语义)——经典陷阱。若 CronJob 的计划时间错过超过 startingDeadlineSeconds,该运行会被跳过而非回填。
# 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 mathIngress
Ingress 清单
Ingress 将集群外的 HTTP/HTTPS 路由暴露给 Service,由 Ingress 控制器(nginx、traefik、ALB…)管理。ingressClassName 选择哪个控制器处理它。每条规则将 host + path 映射到 service+port 后端。
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 证书。
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-prodIngress 规则与默认后端
defaultBackend 处理不匹配任何规则的流量(无 host 或未匹配的 path)。多条规则让一个 Ingress 路由多个虚拟主机。每条规则可有 多个 path 后端——单个 Ingress 可前端整个应用的路由拓扑。
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 使用它。
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 会绑定到单一控制器。
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、基本认证、配置片段。它们是控制器特定的——迁移到另一控制器意味着重写它们。
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 } }存储卷(PV/PVC)
PersistentVolume 清单
PersistentVolume(PV)是集群作用域的存储,由管理员预置或由 StorageClass 动态供应。accessModes 描述如何挂载。reclaimPolicy 控制 PVC 释放后存储的处理方式。
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-xxxxPersistentVolumeClaim 清单
PersistentVolumeClaim(PVC)是 namespace 作用域的存储请求。控制器将它绑定到匹配的 PV(accessModes、足够容量、相同 StorageClass)。若有默认 StorageClass,storageClassName 留空会触发动态供应。
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。
# 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 才能重新绑定。
# 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 错误。
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 触发按需卷创建。现代集群几乎总用动态供应;静态供应保留给共享/遗留存储。
# 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 PVStorageClass
StorageClass 清单
StorageClass 描述动态供应存储的一种'风味':provisioner(CSI 驱动)、parameters(磁盘类型、加密、fsType)和策略。PVC 通过 spec.storageClassName 引用它。一个集群通常有几种类(快速 SSD、大容量 HDD、NFS…)。
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)。
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。
# 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。
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 类。
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 驱动支持在线扩容(无需卸载)。
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 expandedHelm
Helm 安装与发布
Helm 将 Kubernetes 清单打包为'chart'并以'release'管理。install 创建发布;upgrade 应用变更;upgrade --install 是幂等的。发布以 Secret/ConfigMap 跟踪在 namespace 中——这就是回滚工作的原理。
# 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-namespacesChart 结构
chart 是模板化 YAML 加默认值的目录。Chart.yaml 持有元数据;values.yaml 持有默认值;templates/ 持有用这些值渲染的 Go 模板。helm create 脚手架一个可用 chart。helm lint 在发布前捕获模式/模板错误。
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 发布实际应用的内容至关重要。
# 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 运行多个发布。
# 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。
# 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 显示实际部署的内容,对调试漂移状态极有价值。
# 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 5mNetworkPolicy
NetworkPolicy 清单
NetworkPolicy 是 Pod 的防火墙规则。空 podSelector 选择 namespace 内所有 Pod;空规则列表拒绝该类型所有流量。NetworkPolicy 是叠加的——若有任何策略允许,Pod 即被允许。需要支持的 CNI;纯 flannel 会忽略它 们。
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。
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: 8080Egress 规则
Egress 规则控制所选 Pod 能向谁通信。常见陷阱:默认拒绝 egress 会破坏 DNS 解析,Pod 无法访问 kube-dns。在拒绝其他一切之前,务必先允许 UDP/TCP 53 到 kube-system namespace。ipBlock.except 划出例外。
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。
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 的逃生舱。
# --- 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 标签的策略可查看管辖其流量的策略。
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=webRBAC
Role(命名空间作用域)
Role 授予单个 namespace 内命名空间资源的权限。rules 列出 apiGroups、resources 和 verbs。pods/log 是子资源;pods/exec 需要 create 动词(因为 exec 创建子资源)。用 '*' 通配任何值。
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,需删除并重建绑定。
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。
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 等。
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 选择退出。
# 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 devkubectl auth can-i
kubectl auth can-i 检查当前(或被模拟)用户的 RBAC 权限——调试 'forbidden' 错误的关键。--list 显示每个允许的动词/资源。--as 模拟用户/SA 进行测试。内置角色(view、edit、admin、cluster-admin)覆盖常见需求。
# 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探针(Liveness/Readiness)
Liveness 探针
Liveness 探针告诉 kubelet 何时重启容器。若连续失败 failureThreshold 次,kubelet 杀死容器并应用重启策略。用于从死锁或不可恢复状态中恢复——而非检查依赖(那是 readiness)。
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 从端点移除——但不会重启它。用于预热(就绪前不路由)以及在短暂故障或优雅关闭期间排空流量。
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 窗口。
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/二进制)。
# 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 限制关闭时间。
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 常来自依赖慢下游服务的探针——保持健康检查本地且廉价。
# --- 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资源与 kubectl 进阶
Requests 与 Limits
requests 是调度器预留的(只有节点有剩余 requests 时才调度 Pod)——设为稳态需求。limits 是硬上限:CPU 被限流,内存被 OOMKilled。cpu 以核为单位(500m = 0.5),memory 以字节(Mi/Gi)。生产中务必两者都设。
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 burstLimitRange 默认值
LimitRange 为未指定的 Pod 应用默认 requests/limits——当 ResourceQuota 要求 requests 时至关重要。max/min 约束单个容器能多大/多小。maxLimitRequestRatio 限制容器能在 request 之上突发多少,防止吵闹邻居。
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 限制每分钟速率。扩容通常快速/激进;缩容刻意缓慢。
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 -wPod Disruption Budget
PodDisruptionBudget 限制一组 Pod 中可被自愿驱逐的数量——在节点 drain 和 cluster-autoscaler 操作期间保护可用性。使用 minAvailable 或 maxUnavailable(不可同时用)。它不防止非自愿中断(硬件故障)——只有副本能做到。
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 后跟短横线移除污点。
# 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。
# 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相关 Kubernetes 代码片段
Copy-paste ready code for common tasks.
Pod Manifest
Define a standalone Pod with a container, env, and probe.
Deployment & Rollout
Manage a replicated, rolling-updated workload.
Service Types
Expose Pods via ClusterIP, NodePort, and LoadBalancer services.
ConfigMap & Secret
Inject configuration and sensitive data into containers.
Ingress Routing
Route external HTTP traffic to services by host and path.
Labels & Selectors
Tag resources and query them with selectors.
kubectl Basics
Common kubectl commands for everyday operations.
Namespaces
Partition a cluster into isolated virtual clusters.
这篇内容对您有帮助吗?