- name
- kubernetes-patterns
- description
- Kubernetes 工作负载模式、资源管理、RBAC、probes、autoscaling、ConfigMap/Secret 处理,以及面向生产级部署的 kubectl 调试。
- metadata
- {"origin":"ECC"}
# Kubernetes Patterns
面向可靠部署、管理和调试工作负载的生产级 Kubernetes 模式。
## 何时激活
- 编写 Kubernetes manifests(Deployments、Services、Ingress、Jobs)
- 配置 resource requests/limits、liveness/readiness probes
- 搭建 RBAC、namespaces 或 ServiceAccounts
- 在 K8s 中管理配置和 secrets
- 调试 CrashLoopBackOff、OOMKilled、pending pods 或 image pull errors
- 配置 HPA(Horizontal Pod Autoscaler)或 PodDisruptionBudgets
- 审查 K8s YAML 的安全或正确性
## 何时使用
> 同上方 **何时激活**。此别名满足仓库 skill-format 约定。任何编写、审查或调试 Kubernetes YAML 和工作负载时都可使用此技能。
## 工作方式
此技能提供**可复制粘贴的生产级 YAML 模式**和按任务组织的 **kubectl 调试命令**:
1. **Deployment 模板** — 完整配置的生产 `Deployment`,含 security context、rolling update 策略、三种 probe 类型、resource limits,以及从 ConfigMap/Secret 注入环境变量。
2. **Probes** — startup vs liveness vs readiness 的决策表,含正确的 `failureThreshold × periodSeconds` 数学。
3. **Services & Ingress** — ClusterIP、LoadBalancer 和带 cert-manager annotations 的 TLS Ingress 模式。
4. **ConfigMaps & Secrets** — `envFrom`、file-mount 和 external secrets 指引。
5. **资源管理** — 按工作负载类型(web API、JVM、worker、sidecar)的 requests vs limits 经验规则。
6. **RBAC** — 最小权限 ServiceAccount → Role → RoleBinding 链。
7. **HPA & PDB** — Autoscaling 和 node-drain 安全配置。
8. **Jobs & CronJobs** — 带正确 `restartPolicy` 的一次性和定时工作负载模式。
9. **kubectl cheatsheet** — logs、exec、rollback、port-forward、dry-run 和常见错误诊断命令。
10. **反模式与 checklist** — 不要做什么,以及安全/可靠性/可观测性 checklist。
## 示例
完整可运行示例见下方 sections。快速参考:
| 任务 | 跳转到 |
|------|---------|
| 完整生产 Deployment YAML | [Core Workload Patterns](#core-workload-patterns) |
| Probe 配置 | [Probes](#probes--liveness-readiness-startup) |
| RBAC 最小权限设置 | [RBAC](#rbac--roles-and-serviceaccounts) |
| 调试 CrashLoopBackOff | [kubectl Debugging Cheatsheet](#kubectl-debugging-cheatsheet) |
| Autoscaling | [HPA](#horizontal-pod-autoscaler-hpa) |
---
## Core Workload Patterns
### Deployment — 生产模板
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: my-namespace
labels:
app: my-app
version: "1.0.0"
spec:
replicas: 3
selector:
matchLabels:
app: my-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 更新期间允许 1 个额外 pod
maxUnavailable: 0 # 绝不低于期望数量
template:
metadata:
labels:
app: my-app
version: "1.0.0"
spec:
# pod 级 security context
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001
# 优雅关闭
terminationGracePeriodSeconds: 30
containers:
- name: my-app
image: ghcr.io/org/my-app:1.0.0 # 绝不用 :latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
protocol: TCP
# requests 和 limits 都必须配置
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
# 容器 security context
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
# Probes(见下方 Probes section)
startupProbe:
httpGet:
path: /health
port: 8080
failureThreshold: 30
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 0
periodSeconds: 30
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 2
# 从 ConfigMap 和 Secret 注入环境变量
envFrom:
- configMapRef:
name: my-app-config
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-app-secrets
key: db-password
# readOnlyRootFilesystem: true 时可写的 tmp 目录
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
```
---
## Probes — Liveness, Readiness, Startup
理解每种 probe 何时使用很关键:
| Probe | 失败动作 | 用于 |
|-------|---------------|---------|
| `startupProbe` | 启动慢则杀掉容器 | 慢启动应用(JVM、Python) |
| `livenessProbe` | 重启容器 | 死锁 / 卡住进程检测 |
| `readinessProbe` | 从 Service endpoints 移除 | 临时不可用(DB 重连) |
```yaml
# 正确模式:startupProbe 覆盖慢启动,
# 然后 liveness/readiness 接管
startupProbe:
httpGet:
path: /health
port: 8080
failureThreshold: 30 # 30 * 5s = 最长 150s 启动时间
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8080
periodSeconds: 30
failureThreshold: 3 # 3 * 30s = 90s 后重启
readinessProbe:
httpGet:
path: /ready # 独立 endpoint:检查 DB、cache 等
port: 8080
periodSeconds: 10
failureThreshold: 2
```
```yaml
# 错误:没有 startupProbe 却用 initialDelaySeconds
# 如果应用要 60s 启动,应设 startupProbe
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 60 # 差:任意等待,有竞态
```
---
## Services and Ingress
### Service 类型
```yaml
# ClusterIP(默认)— 仅内部
apiVersion: v1
kind: Service
metadata:
name: my-app
namespace: my-namespace
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
protocol: TCP
type: ClusterIP
```
```yaml
# LoadBalancer — 外部流量(云厂商)
spec:
type: LoadBalancer
ports:
- port: 443
targetPort: 8080
```
### 带 TLS 的 Ingress
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
namespace: my-namespace
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.example.com
secretName: my-app-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
```
---
## ConfigMaps and Secrets
### ConfigMap — 非敏感配置
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-app-config
namespace: my-namespace
data:
LOG_LEVEL: "info"
APP_ENV: "production"
MAX_CONNECTIONS: "100"
# 复杂配置挂载为文件
app.yaml: |
server:
port: 8080
timeout: 30s
```
```yaml
# 把 ConfigMap 挂载为文件
volumes:
- name: config
configMap:
name: my-app-config
items:
- key: app.yaml
path: app.yaml
volumeMounts:
- name: config
mountPath: /etc/app
readOnly: true
```
### Secrets — 敏感数据
```bash
# 从字面量创建 secret(CLI,然后存到 Vault/SOPS)
kubectl create secret generic my-app-secrets \
--from-literal=db-password='s3cr3t' \
--namespace=my-namespace \
--dry-run=client -o yaml | kubectl apply -f -
```
```yaml
apiVersion: v1
kind: Secret
metadata:
name: my-app-secrets
namespace: my-namespace
type: Opaque
# 值是 base64 编码(不是加密——要真正加密用 Sealed Secrets 或 ESO)
data:
db-password: czNjcjN0 # base64 of 's3cr3t'
```
> **重要:** 原始 Kubernetes Secrets 只是 base64 编码,除非集群配置了加密,否则不是静态加密。生产环境用 [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) 或 [External Secrets Operator](https://external-secrets.io)。
---
## Resource Requests and Limits
```yaml
resources:
requests: # 调度器用它放置 pod
cpu: "100m" # 100 millicores = 0.1 CPU
memory: "128Mi"
limits: # 超过此值容器被 kill/throttle
cpu: "500m"
memory: "256Mi"
```
**经验规则:**
| 工作负载类型 | CPU Request | Memory Request | 备注 |
|---------------|-------------|----------------|-------|
| Web API | 100–250m | 128–256Mi | limits 设为 requests 的 2-4 倍 |
| Worker/consumer | 250–500m | 256–512Mi | memory limit = request 以保证可预测 |
| JVM 应用 | 500m–1 | 512Mi–2Gi | 在 `-Xmx` 之上留 JVM overhead |
| Sidecar | 10–50m | 32–64Mi | 保持最小 |
```yaml
# 错误:没有 requests 或 limits——调度不可预测,OOM 驱逐
containers:
- name: app
image: myapp:latest
# 缺少 resources: {} —— 生产环境很危险
# 错误:有 limits 无 requests——requests 默认等于 limits,过度预留容量
resources:
limits:
cpu: "2"
memory: "1Gi"
# 缺少 requests——会默认等于 limits
```
---
## RBAC — Roles and ServiceAccounts
### 最小权限原则
**两种模式,取决于应用是否调用 Kubernetes API:**
#### 模式 A — 应用不需要 Kubernetes API(大多数应用)
在 ServiceAccount 上禁用 token 自动挂载。不需要 Role/RoleBinding。
```yaml
# 禁用 token 的 ServiceAccount——最安全的默认
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: my-namespace
automountServiceAccountToken: false # 不向 pods 注入 K8s API token
```
```yaml
# 在 Deployment 中引用——无 token、无 API 访问
spec:
template:
spec:
serviceAccountName: my-app-sa
automountServiceAccountToken: false # 双保险:pod 级也设
```
#### 模式 B — 应用需要 Kubernetes API(operators、controllers、config watchers)
启用 token,并只授予实际需要的权限。
```yaml
# 1. ServiceAccount——为此 SA 启用 token
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: my-namespace
automountServiceAccountToken: true # 需要 token:应用调用 K8s API
```
```yaml
# 2. Role——只授予应用所需(namespace 作用域)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: my-app-role
namespace: my-namespace
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"] # 只读,特定资源
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["my-app-secrets"] # 按名称限制到特定 secret
verbs: ["get"]
```
```yaml
# 3. 把 Role 绑定到 ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-app-rolebinding
namespace: my-namespace
subjects:
- kind: ServiceAccount
name: my-app-sa
namespace: my-namespace
roleRef:
kind: Role
apiGroup: rbac.authorization.k8s.io
name: my-app-role
```
```yaml
# 4. 在 Deployment 中引用 SA
spec:
template:
spec:
serviceAccountName: my-app-sa
# automountServiceAccountToken 默认从 SA 为 true——token 会注入
```
---
## Horizontal Pod Autoscaler (HPA)
```yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
namespace: my-namespace
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2 # HA 至少 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # 平均 CPU > 70% 时扩容
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
```
> HPA 要求所有容器都设置 `resources.requests`——它按 `current / request` 计算 utilization。
---
## PodDisruptionBudget (PDB)
防止 node drain 或滚动更新期间过多 pod 同时下线:
```yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
namespace: my-namespace
spec:
minAvailable: 2 # 或用 maxUnavailable: 1
selector:
matchLabels:
app: my-app
```
---
## Namespaces and Multi-Tenancy
```bash
# 创建带 resource quotas 的 namespace
kubectl create namespace my-namespace
# 应用 ResourceQuota 限制 namespace 消耗
kubectl apply -f - <<EOF
apiVersion: v1
kind: ResourceQuota
metadata:
name: my-namespace-quota
namespace: my-namespace
spec:
hard:
requests.cpu: "4"
requests.memory: 4Gi
limits.cpu: "8"
limits.memory: 8Gi
pods: "20"
EOF
```
---
## Jobs and CronJobs
```yaml
# 一次性 Job(DB migration、数据处理)
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
namespace: my-namespace
spec:
backoffLimit: 3 # 失败最多重试 3 次
ttlSecondsAfterFinished: 3600 # 1h 后自动删除
template:
spec:
restartPolicy: OnFailure # Jobs 用 Never 或 OnFailure,不用 Always
containers:
- name: migrate
image: ghcr.io/org/my-app:1.0.0
command: ["python", "manage.py", "migrate"]
resources:
requests:
cpu: "100m"
memory: "256Mi"
```
```yaml
# CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
name: cleanup-job
namespace: my-namespace
spec:
schedule: "0 2 * * *" # 每天凌晨 2 点
concurrencyPolicy: Forbid # 上一个仍在跑就不启动新的
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: cleanup
image: ghcr.io/org/cleanup:1.0.0
resources:
requests:
cpu: "50m"
memory: "64Mi"
```
---
## kubectl Debugging Cheatsheet
```bash
# --- Pod 状态和日志 ---
kubectl get pods -n my-namespace
kubectl get pods -n my-namespace -o wide # 显示 node 分配
kubectl describe pod <pod-name> -n my-namespace # events 和状态详情
kubectl logs <pod-name> -n my-namespace # 当前日志
kubectl logs <pod-name> -n my-namespace --previous # 崩溃容器的日志
kubectl logs <pod-name> -n my-namespace -c <container> # 多容器 pod
# --- 进入运行中容器 ---
kubectl exec -it <pod-name> -n my-namespace -- sh
kubectl exec -it <pod-name> -n my-namespace -- bash
# --- 查看资源使用 ---
kubectl top pods -n my-namespace
kubectl top nodes
# --- Deployment 操作 ---
kubectl rollout status deployment/my-app -n my-namespace
kubectl rollout history deployment/my-app -n my-namespace
Auf GitHub ansehen