安装方式
命令行安装
在项目根目录执行以下命令,完成 Skill 安装。
npx bzskills add affaan-m/everything-claude-code --skill kubernetes-patterns Kubernetes工作负载模式、资源管理、RBAC、探针、自动扩缩、ConfigMap/Secret处理,以及面向生产级部署的kubectl调试。
25
下载量
命令行安装
在项目根目录执行以下命令,完成 Skill 安装。
npx bzskills add affaan-m/everything-claude-code --skill kubernetes-patterns name: kubernetes-patterns
description: Kubernetes工作负载模式、资源管理、RBAC、探针、自动扩缩、ConfigMap/Secret处理,以及面向生产级部署的kubectl调试。
metadata:
origin: ECC用于可靠部署、管理和调试工作负载的生产级 Kubernetes 模式。
与上面的 何时激活 相同。此别名满足仓库技能格式约定。在编写、审查或调试 Kubernetes YAML 和工作负载时,随时使用此技能。
此技能提供可直接复制粘贴的生产级 YAML 模式和 kubectl 调试命令,按任务组织:
failureThreshold × periodSeconds 计算。envFrom、文件挂载和外部密钥指导。restartPolicy。请参阅下面的章节获取完整的可运行示例。快速参考:
| 任务 | 跳转到 |
|---|---|
| 完整的生产级 Deployment YAML | 核心工作负载模式 |
| 探针配置 | 探针 |
| RBAC 最小权限设置 | RBAC |
| 调试 CrashLoopBackOff | kubectl 调试速查表 |
| 自动缩放 | HPA |
---
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 级别的安全上下文
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
# 资源请求和限制都需要
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
# 容器安全上下文
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
# 探针(见下方探针部分)
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: {}
---
理解何时使用每种探针至关重要:
| 探针 | 失败时的操作 | 用途 |
|---|---|---|
startupProbe | 如果启动慢则终止容器 | 启动缓慢的应用(JVM、Python) |
livenessProbe | 重启容器 | 检测死锁/挂起进程 |
readinessProbe | 从 Service 端点移除 | 临时不可用(数据库重连) |
# 正确模式: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 # 单独的端点:检查数据库、缓存等
port: 8080
periodSeconds: 10
failureThreshold: 2
# 错误:不带 startupProbe 使用 initialDelaySeconds
# 如果应用需要 60 秒启动,应改用 startupProbe
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 60 # 不好:任意等待,存在竞态条件
---
# 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
# LoadBalancer — 外部流量(云提供商)
spec:
type: LoadBalancer
ports:
- port: 443
targetPort: 8080
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
---
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
# 将 ConfigMap 作为文件挂载
volumes:
- name: config
configMap:
name: my-app-config
items:
- key: app.yaml
path: app.yaml
volumeMounts:
- name: config
mountPath: /etc/app
readOnly: true
# 从字面值创建 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 -
apiVersion: v1
kind: Secret
metadata:
name: my-app-secrets
namespace: my-namespace
type: Opaque
# 值为 base64 编码(未加密——对于真正的加密请使用 Sealed Secrets 或 ESO)
data:
db-password: czNjcjN0 # 's3cr3t' 的 base64
重要: 原生 Kubernetes Secret 仅经过 base64 编码,除非集群配置了静态加密,否则不会加密存储。对于生产环境,使用 Sealed Secrets 或 External Secrets Operator。
---
resources:
requests: # 调度器根据此值放置 Pod
cpu: "100m" # 100 毫核 = 0.1 CPU
memory: "128Mi"
limits: # 超过此值时容器会被终止/限流
cpu: "500m"
memory: "256Mi"
经验法则:
| 工作负载类型 | CPU 请求 | 内存请求 | 说明 |
|---|---|---|---|
| Web API | 100–250m | 128–256Mi | 限制设为请求的 2-4 倍 |
| Worker/消费者 | 250–500m | 256–512Mi | 为可预测性,内存限制等于请求 |
| JVM 应用 | 500m–1 | 512Mi–2Gi | 为 JVM 开销在 -Xmx 之上留出空间 |
| Sidecar | 10–50m | 32–64Mi | 保持最小 |
# 错误:没有设置请求或限制 —— 不可预测的调度,OOM 驱逐
containers:
- name: app
image: myapp:latest
# 缺少 resources: {} —— 生产环境中很危险
# 错误:有限制但没有请求 —— 请求默认等于限制,过度预留容量
resources:
limits:
cpu: "2"
memory: "1Gi"
# 缺少 requests —— 将默认使用限制值
---
两种模式,取决于应用是否调用 Kubernetes API:
#### 模式 A — 应用不需要 Kubernetes API(大多数应用)
在 ServiceAccount 上禁用令牌自动挂载。不需要 Role/RoleBinding。
# 禁用令牌的 ServiceAccount —— 最安全默认值
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: my-namespace
automountServiceAccountToken: false # 不会向 Pod 注入 K8s API 令牌
# 在 Deployment 中引用 —— 无令牌,无 API 访问
spec:
template:
spec:
serviceAccountName: my-app-sa
automountServiceAccountToken: false # 双重保险:也在 Pod 级别设置
#### 模式 B — 应用确实需要 Kubernetes API(operator、controller、配置监视器)
启用令牌并仅授予实际需要的权限。
# 1. ServiceAccount —— 为此 SA 启用令牌
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: my-namespace
automountServiceAccountToken: true # 需要令牌:应用调用 K8s API
# 2. Role —— 仅授予应用需要的权限(命名空间作用域)
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"]
# 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
# 4. 在 Deployment 中引用 SA
spec:
template:
spec:
serviceAccountName: my-app-sa
# automountServiceAccountToken 默认为 SA 中的 true —— 令牌被注入
---
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 # 高可用至少 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—— 它计算利用率为当前值 / 请求值。
---
防止在节点排空或滚动更新期间过多 Pod 下线:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
namespace: my-namespace
spec:
minAvailable: 2 # 或者使用 maxUnavailable: 1
selector:
matchLabels:
app: my-app
---
# 创建带资源配额的命名空间
kubectl create namespace my-namespace
# 应用 ResourceQuota 限制命名空间消耗
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
---
# 一次性 Job(数据库迁移、数据处理)
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
namespace: my-namespace
spec:
backoffLimit: 3 # 失败时最多重试 3 次
ttlSecondsAfterFinished: 3600 # 1 小时后自动删除
template:
spec:
restartPolicy: OnFailure # Job 使用 Never(不是 Always)
containers:
- name: migrate
image: ghcr.io/org/my-app:1.0.0
command: ["python", "manage.py", "migrate"]
resources:
requests:
cpu: "100m"
memory: "256Mi"
# 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"
---
# --- Pod 状态和日志 ---
kubectl get pods -n my-namespace
kubectl get pods -n my-namespace -o wide # 显示节点分配
kubectl describe pod <pod-name> -n my-namespace # 事件和状态详情
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
kubectl rollout undo deployment/my-app -n my-namespace # 回滚
kubectl rollout undo deployment/my-app --to-revision=2 -n my-namespace
# --- 手动缩放 ---
kubectl scale deployment my-app --replicas=5 -n my-namespace
# --- 检查事件(集群范围的问题) ---
kubectl get events -n my-namespace --sort-by='.lastTimestamp'
# --- 端口转发用于本地调试 ---
kubectl port-forward pod/<pod-name> 8080:8080 -n my-namespace
kubectl port-forward svc/my-app 8080:80 -n my-namespace
# --- 通过 Dry-run 验证 YAML ---
kubectl apply -f deployment.yaml --dry-run=client
kubectl apply -f deployment.yaml --dry-run=server # 针对实时集群验证
# CrashLoopBackOff:容器不断崩溃
kubectl logs <pod-name> --previous -n my-namespace # 检查崩溃日志
kubectl describe pod <pod-name> -n my-namespace # 检查退出码和 OOMKilled
# ImagePullBackOff:无法拉取镜像
kubectl describe pod <pod-name> -n my-namespace # 检查 Events 部分
# 原因:镜像标签错误,缺少 imagePullSecret,私有仓库
# Pending pod:未调度
kubectl describe pod <pod-name> -n my-namespace
# 原因:资源不足,没有匹配的节点选择器,污点/容忍不匹配
# OOMKilled:内存不足
# 增加内存限制,检查内存泄漏
kubectl describe pod <pod-name> -n my-namespace | grep -A5 "Last State"
---
# 错误:使用 :latest 标签 —— 不可确定的部署
image: myapp:latest
# 正确:固定到特定的不可变标签(SHA 或 semver)
image: ghcr.io/org/myapp:1.4.2
# 或
image: ghcr.io/org/myapp@sha256:abc123...
# ---
# 错误:以 root 身份运行
securityContext: {} # 默认 root
# 正确:非 root 并指定 UID
securityContext:
runAsNonRoot: true
runAsUser: 1001
# ---
# 错误:没有资源限制 —— 一个 Pod 可能饿死整个节点
containers:
- name: app
image: myapp:1.0.0
# 未定义资源
# 正确:始终设置请求和限制
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
# ---
# 错误:在 ConfigMap 中存储明文密钥
apiVersion: v1
kind: ConfigMap
data:
DB_PASSWORD: "mysecretpassword" # 绝对不要 —— 应使用 Secret 或外部密钥管理器
# ---
# 错误:为应用 ServiceAccount 使用 ClusterAdmin
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
roleRef:
kind: ClusterRole
name: cluster-admin # 为应用授予 God 模式
# ---
# 错误:PDB 中 minAvailable: 0 —— 违背目的
spec:
minAvailable: 0
# ---
# 错误:Job 中使用 restartPolicy: Always(导致无限重启循环)
spec:
restartPolicy: Always # Job 应使用 OnFailure 或 Never
---
runAsNonRoot: true,设置 runAsUser)readOnlyRootFilesystem: true,配合 emptyDir 用于可写路径allowPrivilegeEscalation: falsecapabilities.drop: [ALL])defaultautomountServiceAccountToken: falseRole,除非需要否则不用 ClusterRole)minReplicas: 2+RollingUpdate 策略,maxUnavailable: 0/health(liveness)和 /ready(readiness)端点app、version、environment---
docker-patterns — 多阶段 Dockerfile 和镜像安全deployment-patterns — CI/CD 流水线、回滚策略、健康检查端点security-review — 更广泛的安全加固上下文git-workflow — 与 Kubernetes 的 GitOps 集成 (ArgoCD / Flux 模式)