从零到专业的 Kubernetes:100 个示例,涵盖 kubectl、清单文件、Helm 与 GitOps
Kubernetes 在一组机器组成的集群中运行容器。它会重启失败的容器,把容器分布到各个节点上,无停机地发布新版本,并随负载进行扩缩容。本文通过 100 个示例,带你从第一个 Pod 走到面向生产的配置。你将学习 kubectl 与上下文、Pod、Deployment 与滚动更新、Service 与 Ingress、ConfigMap 与 Secret、持久化存储、Job 与 CronJob、StatefulSet 与 DaemonSet、自动扩缩容、资源请求与探针、调度、RBAC 与 Pod 安全、Helm 与 Kustomize、可观测性与调试,以及 GitOps 与备份。需要坦诚说明:准备本文所用的计算机上没有安装 Kubernetes 集群,也没有安装 kubectl,因此这 100 个示例都没有在这里实际运行。清单文件遵循当前的 Kubernetes API 编写,但在依赖它们之前,请你自己在测试集群中逐一应用。
需要准备的东西
带内置 Kubernetes 的 Docker Desktop,或用于本地练习集群的 kind 或 minikube,并安装 kubectl 和 Helm。具备容器基础知识会有帮助,本系列中的 Docker 文章是很好的起点。部分示例使用 Azure Kubernetes Service 等云厂商和 ingress controller。请使用 shop.example.com 之类的占位主机名,以及 <strong-password> 之类的占位密码,切勿在清单或命令中粘贴真实凭据。
如何使用示例
bash 示例使用 kubectl、Helm 和 Kustomize。YAML 示例保存为 .yaml 文件,并用 kubectl apply -f 应用正文中给出的文件名。Python 示例使用官方的 Kubernetes Python 客户端。
知识点 1: Kubernetes 入门
Kubernetes 是一个控制循环。你用 YAML 描述期望的状态,集群会持续工作,直到实际状态与之相符。学习集群的组成部分、kubectl 客户端、上下文和命名空间。
控制平面与节点
控制平面保存期望的状态并做出决策,工作节点运行你的容器。你通过 API 服务器与集群通信,kubectl 是发送请求的标准客户端。
上下文与命名空间
上下文记录了你的命令使用哪个集群、用户和命名空间。在做任何修改之前,先用 kubectl config current-context 检查,以免在错误的集群中删除资源。
清单文件与声明式变更
清单文件包含 apiVersion、kind、metadata 和 spec。kubectl apply 会把你的文件与集群进行比较,只修改有差异的部分,这使变更可以重复执行,并且便于在 Git 中审查。
示意图
示例 1: 检查客户端与集群
确认 kubectl 能与集群通信。
kubectl version --client
kubectl cluster-info
kubectl get nodes -o wide
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 2: 用 kind 创建练习集群
在你的电脑上运行的本地集群,用于学习。
kind create cluster --name learn
kubectl config current-context
kubectl get nodes
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 3: 切换上下文
选择命令作用的集群。
kubectl config get-contexts
kubectl config use-context kind-learn
kubectl config view --minify --output "jsonpath={.current-context}"
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 4: 创建命名空间
在一个集群内隔离团队和应用。
kubectl create namespace shop
kubectl config set-context --current --namespace=shop
kubectl get pods
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 5: 阅读清单文件
每个对象都有的四个顶层字段。
apiVersion: v1
kind: Namespace
metadata:
name: shop
labels:
team: platform
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 6: 应用清单文件
用 kubectl apply 进行声明式变更。
kubectl apply -f namespace.yaml
kubectl get namespace shop --show-labels
kubectl describe namespace shop
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
知识点 2: Pod:最小的单元
Pod 是共享网络地址和存储的一个或多个容器。大多数 Pod 只运行一个容器,但 Pod 也可以包含必须与主应用一同运行的辅助容器。
什么是 Pod
Pod 中的所有容器共享同一个 IP 地址,并可以通过 localhost 互相访问。Pod 是临时的:某个 Pod 消失后,集群会用新的名称和地址创建一个新的,因此不要依赖 Pod 的地址。
初始化容器与边车容器
初始化容器会在主容器启动前运行至完成,适合用来等待数据库就绪。边车容器与主容器并行运行,用于日志、代理或文件同步,并与主容器共享卷。
日志、事件与 exec
kubectl logs 显示输出,kubectl describe 显示事件,例如镜像拉取错误和调度失败,kubectl exec 则打开一个 shell。大多数启动故障都能在 describe 中找到解释,所以应先阅读它。
示例 7: 快速运行一个 Pod
命令式的做法,仅用于快速测试。
kubectl run hello --image=nginx:1.27 --port=80
kubectl get pod hello -o wide
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 8: 声明式的 Pod
你部署的最小单元。
apiVersion: v1
kind: Pod
metadata:
name: web
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 9: 阅读日志和事件
查明 Pod 发生了什么。
kubectl logs web
kubectl logs web --previous
kubectl get events --sort-by=.lastTimestamp
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 10: 在 Pod 内运行命令
从内部进行调试。
kubectl exec -it web -- sh
kubectl exec web -- nginx -v
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 11: 端口转发到 Pod
为了测试,从你的电脑访问 Pod。
kubectl port-forward pod/web 8080:80
curl http://localhost:8080
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 12: 两个容器共享卷
边车(sidecar)模式。
apiVersion: v1
kind: Pod
metadata:
name: sidecar-demo
spec:
volumes:
- name: logs
emptyDir: {}
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "while true; do date >> /logs/app.log; sleep 5; done"]
volumeMounts:
- name: logs
mountPath: /logs
- name: log-reader
image: busybox:1.36
command: ["sh", "-c", "tail -F /logs/app.log"]
volumeMounts:
- name: logs
mountPath: /logs
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 13: 初始化容器等待
在应用启动前执行准备步骤。
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
initContainers:
- name: wait-for-db
image: busybox:1.36
command: ["sh", "-c", "until nslookup db; do sleep 2; done"]
containers:
- name: app
image: nginx:1.27
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 14: 删除测试用的 Pod
清理不再需要的对象。
kubectl delete pod hello web sidecar-demo init-demo --ignore-not-found
kubectl get pods
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
知识点 3: Deployment 与滚动更新
你很少直接创建 Pod。Deployment 管理一个 ReplicaSet,由它保持指定数量的 Pod 运行,并执行滚动更新,使新版本逐步替换旧版本。
副本数与选择器
replicas 字段设置你想要的 Pod 数量。选择器必须与 Pod 的标签匹配,这样 Deployment 才知道它拥有哪些 Pod。不匹配会在创建时被拒绝。
滚动更新策略
maxSurge 设置更新期间允许多出的 Pod 数量,maxUnavailable 设置允许缺失的 Pod 数量。将 maxUnavailable 设为 0,可以在发布期间保持全部容量。
发布历史与回滚
每次变更都会创建新的 ReplicaSet 和修订号。kubectl rollout undo 会回到上一个版本,kubectl rollout history 则列出各个修订版本,方便你选择特定的一个。
示例 15: Deployment 保持副本运行
由系统为你管理滚动更新。
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 16: 创建并观察 Deployment
查看发布状态。
kubectl apply -f deployment.yaml
kubectl rollout status deployment/web
kubectl get deploy,rs,pods -l app=web
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 17: 手动扩缩容
修改副本数量。
kubectl scale deployment web --replicas=5
kubectl get pods -l app=web -o wide
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 18: 发布新镜像
更新应用版本。
kubectl set image deployment/web web=nginx:1.27.2
kubectl rollout status deployment/web
kubectl rollout history deployment/web
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 19: 回滚有问题的发布
撤销出错的发布。
kubectl rollout undo deployment/web
kubectl rollout undo deployment/web --to-revision=1
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 20: 控制滚动更新
maxSurge 与 maxUnavailable。
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 21: 暂停和恢复发布
把多个变更合并在一起。
kubectl rollout pause deployment/web
kubectl set resources deployment/web -c web --limits=memory=256Mi
kubectl rollout resume deployment/web
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 22: 就绪探针
应用就绪之前不接收流量。
containers:
- name: web
image: nginx:1.27
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 3
periodSeconds: 5
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
知识点 4: Service 与网络
Pod 会不断出现和消失,因此客户端需要稳定的名称和地址。Service 通过标签选择 Pod,并提供一个虚拟 IP 和一个不变的 DNS 名称。
Service 的类型
ClusterIP 只能在集群内部访问。NodePort 在每个节点上开放一个端口。LoadBalancer 向云厂商申请外部负载均衡器。选择能满足需求的最小类型。
DNS 与端点
每个 Service 都有一个 DNS 名称,例如 web-svc.shop.svc.cluster.local,在同一命名空间内可以使用短名称。kubectl get endpoints 显示 Service 背后的 Pod 地址,这是 Service 无响应时首先应检查的内容。
无头 Service
将 clusterIP 设为 None 后,DNS 会返回各个 Pod 的地址,而不是一个虚拟 IP。数据库和集群化系统借此让客户端与特定成员通信。
示例 23: ClusterIP Service
集群内部的稳定地址。
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: ClusterIP
selector:
app: web
ports:
- port: 80
targetPort: 80
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 24: 用 kubectl 暴露服务
快速创建 Service 的方法。
kubectl expose deployment web --port=80 --target-port=80 --name=web-svc
kubectl get svc web-svc
kubectl get endpoints web-svc
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 25: 从临时 Pod 调用 Service
测试集群内的 DNS。
kubectl run tmp-client --rm -it --image=busybox:1.36 --restart=Never -- wget -qO- http://web-svc
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 26: NodePort Service
在每个节点上开放一个端口。
apiVersion: v1
kind: Service
metadata:
name: web-nodeport
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 80
nodePort: 30080
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 27: LoadBalancer Service
云厂商的负载均衡器,用于公网访问。
apiVersion: v1
kind: Service
metadata:
name: web-public
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "false"
spec:
type: LoadBalancer
selector:
app: web
ports:
- port: 80
targetPort: 80
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 28: 查找外部地址
读取云平台分配的地址。
kubectl get svc web-public -o jsonpath="{.status.loadBalancer.ingress[0].ip}"
kubectl get svc web-public -w
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 29: 命名端口
使用端口名,便于安全地修改端口号。
apiVersion: v1
kind: Service
metadata:
name: api
spec:
selector:
app: api
ports:
- name: http
port: 8000
targetPort: http
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 30: 无头 Service
获取各个 Pod 的地址。
apiVersion: v1
kind: Service
metadata:
name: db-headless
spec:
clusterIP: None
selector:
app: db
ports:
- port: 5432
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
知识点 5: 用 ConfigMap 与 Secret 管理配置
把配置放在镜像之外。ConfigMap 保存普通设置,Secret 保存敏感值。两者都可以在 Pod 中变成环境变量或文件,因此无需重新构建镜像即可修改设置。
ConfigMap
ConfigMap 保存键值对或整个文件。使用 envFrom 可以把每个键加载为环境变量;当应用读取文件时,则把 ConfigMap 挂载为目录。
Secret
Secret 保存经过 base64 编码的值。base64 只是编码,并不是加密,因此应在集群中启用静态加密,用 RBAC 限制谁能读取 Secret,并尽可能将其挂载为文件。
重新加载变更
环境变量只在启动时读取,因此修改了 ConfigMap 后需要新的发布。挂载的文件会在延迟后更新,但应用必须重新读取它们。修改配置时,应同时规划如何重新加载。
示例 31: 用字面值创建 ConfigMap
保存非机密的配置。
kubectl create configmap app-config --from-literal=LOG_LEVEL=info --from-literal=FEATURE_X=on
kubectl get configmap app-config -o yaml
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 32: ConfigMap 清单
用 YAML 编写配置。
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: info
FEATURE_X: "on"
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 33: ConfigMap 作为环境变量
用 envFrom 加载所有键。
containers:
- name: api
image: sample-api:1.4.2
envFrom:
- configMapRef:
name: app-config
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 34: 把 ConfigMap 挂载为文件
容器内的配置文件。
containers:
- name: web
image: nginx:1.27
volumeMounts:
- name: site-config
mountPath: /etc/nginx/conf.d
readOnly: true
volumes:
- name: site-config
configMap:
name: nginx-conf
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 35: 创建 Secret
保存密码,不写入文件。
kubectl create secret generic db-secret --from-literal=DB_PASSWORD='<strong-password>'
kubectl get secret db-secret -o jsonpath="{.type}"
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 36: Secret 清单
stringData 允许直接写明文。
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
stringData:
DB_PASSWORD: <strong-password>
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 37: 读取 Secret 的值
检查解码后的值,并注意保密。
kubectl get secret db-secret -o jsonpath="{.data.DB_PASSWORD}" | base64 --decode; echo
# Do not print secrets in shared logs or screenshots.
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 38: 把 Secret 挂载为文件
只读的凭据文件。
containers:
- name: api
image: sample-api:1.4.2
volumeMounts:
- name: db-creds
mountPath: /var/run/secrets/db
readOnly: true
volumes:
- name: db-creds
secret:
secretName: db-secret
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
知识点 6: 持久化存储
容器重启后会丢失其文件。PersistentVolumeClaim 申请一种比 Pod 生命周期更长的存储,StorageClass 则告诉集群如何创建这种存储。
PV、PVC 与 StorageClass
PersistentVolume 是实际的存储,PersistentVolumeClaim 是对它的申请,StorageClass 定义按需创建卷的方式。大多数集群都提供默认的 StorageClass,因此申请通常只需指定大小。
访问模式
ReadWriteOnce 一次只能在一个节点上挂载卷,适合大多数数据库。ReadWriteMany 允许多个节点写入,但只有部分存储类型支持。应选择存储本身支持的模式。
回收策略
Delete 会在删除申请时同时删除存储,Retain 则保留数据以便手动恢复。对于必须在误删后仍然保留的数据,使用 Retain,并且无论如何都应备份重要数据。
示例 39: PersistentVolumeClaim
向集群申请存储。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 40: 使用 claim 的 Pod
Pod 重启后数据依然保留。
apiVersion: v1
kind: Pod
metadata:
name: writer
spec:
containers:
- name: writer
image: busybox:1.36
command: ["sh", "-c", "echo hello >> /data/out.txt; sleep 3600"]
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: data-pvc
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 41: 检查已绑定的存储
查看 claim 和卷的状态。
kubectl get pvc data-pvc
kubectl get pv
kubectl describe pvc data-pvc
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 42: 选择 StorageClass
选择磁盘类型。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: fast-pvc
spec:
storageClassName: managed-premium
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 43: 列出 StorageClass
找到默认类。
kubectl get storageclass
kubectl get storageclass -o custom-columns=NAME:.metadata.name,DEFAULT:.metadata.annotations."storageclass\.kubernetes\.io/is-default-class"
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 44: 扩容 claim
在支持的存储类上增加容量。
kubectl patch pvc data-pvc -p '{"spec":{"resources":{"requests":{"storage":"2Gi"}}}}'
kubectl get pvc data-pvc
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 45: 回收策略
删除 claim 后仍保留数据。
apiVersion: v1
kind: PersistentVolume
metadata:
name: archive-pv
spec:
capacity:
storage: 5Gi
accessModes: ["ReadWriteOnce"]
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /srv/archive
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 46: 限制临时存储
防止临时文件无限增长。
containers:
- name: worker
image: busybox:1.36
resources:
limits:
ephemeral-storage: 1Gi
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
知识点 7: Ingress 与流量路由
Ingress 把集群外部的 HTTP 和 HTTPS 路由暴露给 Service。它按主机名和路径进行路由,并终止 TLS,因此一个公网地址就能服务多个应用。
Ingress 与控制器
Ingress 资源本身不会做任何事情。ingress-nginx 等 ingress controller 会读取 Ingress 对象并配置代理。每个集群安装一个控制器,并为每个 Ingress 设置 ingressClassName。
TLS 证书
tls 部分指向一个保存证书和私钥的 Secret。cert-manager 可以自动申请并续期证书,因此你不必手动处理过期问题。
路径与主机路由
规则会匹配主机名和路径前缀,最具体的路径优先。因此 /api 可以指向 API,而 / 指向网站。路由应保持简单,以便路由表易于审查。
示例 47: 按主机名的 Ingress
把 HTTP 路由到 Service。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
spec:
ingressClassName: nginx
rules:
- host: shop.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 48: 带 TLS 的 Ingress
使用存于 Secret 中的证书提供 HTTPS。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-tls
spec:
ingressClassName: nginx
tls:
- hosts: [shop.example.com]
secretName: shop-tls
rules:
- host: shop.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 49: 安装 ingress controller
用 Helm 安装控制器。
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress ingress-nginx/ingress-nginx --namespace ingress --create-namespace
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 50: 按路径路由
把 /api 和 / 发送到不同的 Service。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop-routes
spec:
ingressClassName: nginx
rules:
- host: shop.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api
port:
number: 8000
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 51: 上传场景的 Ingress 注解
为某个站点提高上传大小上限和超时时间。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: upload-ingress
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "20m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
spec:
ingressClassName: nginx
rules:
- host: upload.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: uploader
port:
number: 80
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 52: cert-manager 的 ClusterIssuer
自动向 Let's Encrypt 申请证书。
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: [email protected]
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
ingressClassName: nginx
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 53: 从 Ingress 申请证书
使用注解让 TLS 由系统自动管理。
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts: [shop.example.com]
secretName: shop-tls
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 54: API 的 NetworkPolicy
只允许 Web 层访问 API。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow-web
spec:
podSelector:
matchLabels:
app: api
policyTypes: [Ingress]
ingress:
- from:
- podSelector:
matchLabels:
app: web
ports:
- port: 8000
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
知识点 8: Job 与 CronJob
并非所有工作负载都会永久运行。Job 会运行任务直至成功,CronJob 则按计划启动 Job,就像在集群内部运行的 cron 表。
Job 与完成数
Job 会不断创建 Pod,直到所要求的完成数成功。backoffLimit 限制重试次数。Job 不允许 Always,因此应使用 Never 或 OnFailure 作为 restartPolicy。
并行工作
parallelism 设置同时运行的 Pod 数量,completions 设置所需的成功次数。这种模式用多个工作进程处理一批任务。
CronJob 与历史记录
CronJob 的计划使用 cron 语法。concurrencyPolicy 设为 Forbid 可以防止运行重叠,历史记录上限则会删除旧的 Job,使集群保持整洁。
示例 55: Job 运行到完成
一次性任务,例如数据库迁移。
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
spec:
backoffLimit: 2
template:
spec:
restartPolicy: Never
containers:
- name: migrate
image: sample-api:1.4.2
command: ["python", "manage.py", "migrate"]
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 56: 运行 Job 并等待
等任务完成后再读取日志。
kubectl apply -f job.yaml
kubectl wait --for=condition=complete job/db-migrate --timeout=120s
kubectl logs job/db-migrate
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 57: 并行 Job
用多个工作进程处理大量任务。
apiVersion: batch/v1
kind: Job
metadata:
name: thumbnails
spec:
completions: 10
parallelism: 3
template:
spec:
restartPolicy: OnFailure
containers:
- name: worker
image: thumbnailer:2.0
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 58: 按计划运行的 CronJob
每天凌晨 02:00 生成报告。
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-report
spec:
schedule: "0 2 * * *"
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: report
image: reporter:1.1
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 59: 检查并触发 CronJob
查看历史运行,并手动启动一次。
kubectl get cronjob nightly-report
kubectl get jobs --sort-by=.metadata.creationTimestamp
kubectl create job --from=cronjob/nightly-report manual-report-1
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 60: Job 历史保留上限
避免已完成的 Job 不断堆积。
spec:
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 5
startingDeadlineSeconds: 300
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
知识点 9: StatefulSet 与 DaemonSet
某些工作负载需要稳定的身份,或者每个节点只运行一个 Pod。StatefulSet 为 Pod 提供有序的名称和各自的存储;DaemonSet 则在每个符合条件的节点上运行一份 Pod。
StatefulSet 的身份
Pod 被命名为 name-0、name-1 等,每个 Pod 都保留由 volumeClaimTemplates 创建的自己的 claim。Pod 重启后名称不变,适合数据库和消息代理。
有序操作
默认情况下,StatefulSet 会按顺序启动和停止 Pod。分区更新允许你先修改编号最大的 Pod,从而对有状态系统进行可控的金丝雀发布。
DaemonSet
DaemonSet 在每个节点上保留一个 Pod,适合日志收集器、监控代理和网络插件。可以使用 nodeSelector 或 tolerations 将其限制在特定节点上。
示例 61: StatefulSet
为数据库提供稳定的名称和存储。
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
spec:
serviceName: redis
replicas: 3
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
volumeMounts:
- name: data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 62: 检查 StatefulSet
带序号的名称,每个 Pod 一个 claim。
kubectl get statefulset redis
kubectl get pods -l app=redis
kubectl get pvc
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 63: DaemonSet
每个节点运行一个 Pod,适合代理程序。
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-agent
spec:
selector:
matchLabels:
app: node-agent
template:
metadata:
labels:
app: node-agent
spec:
containers:
- name: agent
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 64: 在带标签的节点上运行 DaemonSet
用 nodeSelector 选择节点。
spec:
template:
spec:
nodeSelector:
workload: edge
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 65: StatefulSet 的 partition
先只更新一部分 Pod。
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 2
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 66: 谨慎地扩缩 StatefulSet
缩容后检查 claim。
kubectl get statefulset redis -o jsonpath="{.spec.replicas}"; echo
kubectl scale statefulset redis --replicas=2
kubectl get pvc -l app=redis
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
知识点 10: 自动扩缩容
负载会随着时间变化。自动扩缩容在需求高时增加 Pod,需求降低时减少 Pod,这样你只为实际使用付费,用户也能获得快速响应。
Horizontal Pod Autoscaler
HPA 会把某个指标(例如平均 CPU 使用率)与目标值比较,并调整副本数。由于使用率是相对于请求值计算的,因此需要 metrics server,并且 Pod 必须设置 CPU 请求。
扩缩容行为
behavior 字段控制 HPA 扩容和缩容的速度。缩容时的稳定窗口可以防止短暂峰值之后出现快速的来回波动。
事件驱动的扩缩容
KEDA 根据队列长度或消息延迟等外部信号进行扩缩,并且在没有任务时可以缩减到零。适用于消费队列的 worker。
示例 67: 实时资源使用
kubectl top 需要 metrics server。
kubectl top nodes
kubectl top pods -l app=web
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 68: 按 CPU 自动扩缩
平均负载高时增加 Pod。
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 69: 从命令行创建 HPA
自动扩缩并观察其响应。
kubectl autoscale deployment web --min=2 --max=10 --cpu-percent=70
kubectl get hpa web -w
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 70: 按内存自动扩缩
使用多个指标。
spec:
metrics:
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 75
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 71: 限制 HPA 缩容速度
用稳定窗口避免频繁波动。
spec:
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 60
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 72: 事件驱动的扩缩
用 KEDA 根据队列长度扩缩 worker。
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: worker-scaler
spec:
scaleTargetRef:
name: worker
minReplicaCount: 0
maxReplicaCount: 20
triggers:
- type: rabbitmq
metadata:
queueName: orders
mode: QueueLength
value: "50"
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
知识点 11: 资源、探针与调度
告诉 Kubernetes 每个容器需要多少 CPU 和内存,以及如何判断它是否健康。调度器使用 requests 放置 Pod,探针则决定何时重启容器或停止向其发送流量。
requests 与 limits
request 是调度器为容器预留的资源量,limit 则是它最多可以使用的量。超过 limit 的内存会导致容器被终止,超过的 CPU 会被限流。两者都应根据实际测量的用量来设置。
探针
存活探针会重启卡住的容器。就绪探针在容器尚未就绪时将其从 Service 端点中移除。启动探针会为启动较慢的应用推迟其他探针的执行。
分散与中断
拓扑分布约束把副本放在不同的节点或可用区上。PodDisruptionBudget 限制像排空节点这类主动操作一次可以删除的 Pod 数量。
示例 73: requests 与 limits
调度器和内核如何使用它们。
containers:
- name: api
image: sample-api:1.4.2
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: "1"
memory: 512Mi
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 74: 存活探针
重启卡住的容器。
livenessProbe:
httpGet:
path: /healthz
port: 8000
initialDelaySeconds: 10
periodSeconds: 15
failureThreshold: 3
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 75: 启动探针
给启动较慢的应用留出时间。
startupProbe:
httpGet:
path: /healthz
port: 8000
failureThreshold: 30
periodSeconds: 10
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 76: PodDisruptionBudget
维护期间保证足够的副本可用。
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: web
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 77: 把副本分散到多个节点
避免所有副本都在同一台机器上。
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: web
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 78: PriorityClass
集群满载时仍优先调度重要的 Pod。
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: business-critical
value: 100000
globalDefault: false
description: "Keep these Pods running when the cluster is full."
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
知识点 12: 安全:RBAC 与 Pod 安全
最小权限原则同时适用于人和应用。RBAC 决定谁能做什么,Pod 安全设置则限制容器在节点上能做什么。
ServiceAccount、Role 与绑定
ServiceAccount 是 Pod 的身份。Role 列出在一个命名空间内对资源允许的动词,RoleBinding 把它关联起来。只授予应用所需的动词,并避免为应用授予 cluster-admin。
检查访问权限
kubectl auth can-i 可以测试某项权限,也可以指定另一个用户或 ServiceAccount 进行测试。把它放在审查步骤中运行,使错误在部署之前而不是事故之后暴露出来。
Pod 安全
命名空间标签可以强制执行 Pod 安全标准,例如 restricted,它会阻止以 root 运行的容器和权限提升。应结合 securityContext 使用,删除 capability,并将根文件系统设为只读。
示例 79: ServiceAccount
Pod 的身份,并关闭令牌自动挂载。
apiVersion: v1
kind: ServiceAccount
metadata:
name: api-sa
automountServiceAccountToken: false
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 80: 最小权限的 Role
只允许读取某个命名空间的 ConfigMap。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: read-config
namespace: shop
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 81: RoleBinding
把 Role 绑定到 ServiceAccount。
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: api-read-config
namespace: shop
subjects:
- kind: ServiceAccount
name: api-sa
namespace: shop
roleRef:
kind: Role
name: read-config
apiGroup: rbac.authorization.k8s.io
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 82: 用 auth can-i 检查权限
部署前验证 RBAC。
kubectl auth can-i list configmaps --as=system:serviceaccount:shop:api-sa -n shop
kubectl auth can-i delete pods --as=system:serviceaccount:shop:api-sa -n shop
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 83: Pod 安全标准
在命名空间上强制执行 restricted 级别。
kubectl label namespace shop pod-security.kubernetes.io/enforce=restricted
kubectl label namespace shop pod-security.kubernetes.io/warn=restricted
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 84: 加固的安全上下文
非 root、只读、不添加额外能力。
securityContext:
runAsNonRoot: true
runAsUser: 10001
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
知识点 13: Helm 与 Kustomize
真实的应用有很多清单文件,也有多个环境。Helm 把它们打包成带有 values 的 chart,Kustomize 则保留一个 base,并为每个环境应用小型覆盖层。
Helm chart 与 release
chart 是带有默认值的模板包,release 是一次安装的实例。使用 helm 进行安装、升级和回滚,并使用 --atomic,使失败的升级自动回退。
各环境的 values
每个环境保留一个 values 文件,并用 -f 传入。安装前用 helm template 检查渲染结果,这样你就准确知道哪些内容会进入集群。
Kustomize 覆盖层
Kustomize 把 base 与覆盖层组合起来,无需模板即可修改副本数、镜像或标签。kubectl apply -k 应用结果,kubectl diff 可以先显示变化。
示例 85: 用 Helm 安装应用
使用仓库中的 chart。
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm install shop-cache bitnami/redis --namespace shop --set architecture=standalone
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 86: 渲染并检查 chart
预览 YAML,并在服务端验证。
helm template shop-web ./chart --values values-prod.yaml > rendered.yaml
kubectl apply --dry-run=server -f rendered.yaml
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 87: Helm 的 values 文件
某一环境的配置。
replicaCount: 3
image:
repository: registry.example.com/team/web
tag: "1.4.2"
resources:
limits:
memory: 512Mi
ingress:
enabled: true
host: shop.example.com
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 88: 用 Helm 升级与回滚
原子升级,失败时自动撤销。
helm upgrade shop-web ./chart -n shop -f values-prod.yaml --atomic --wait
helm history shop-web -n shop
helm rollback shop-web 1 -n shop
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 89: Kustomize 覆盖层
无需模板即可实现环境差异。
# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
replicas:
- name: web
count: 5
images:
- name: web
newTag: "1.4.2"
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 90: 应用 Kustomize 覆盖层
先查看 diff,再应用。
kubectl kustomize overlays/prod | kubectl diff -f -
kubectl apply -k overlays/prod
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
知识点 14: 可观测性与调试
当 Pod 行为异常时,答案就在它的状态、事件、日志和指标中。冷静、有序的排查流程能很快找到大多数故障,而同样的信号也会被用于仪表盘和告警。
状态、事件与 describe
kubectl get pod 显示阶段和重启次数。kubectl describe 列出事件,例如 ImagePullBackOff、CrashLoopBackOff 或 FailedScheduling,并解释 Pod 为何停滞。
跨 Pod 查看日志
使用 kubectl logs -l 按标签选择 Pod,并加上 --prefix,就能看出每一行是哪个 Pod 写的。要读取已崩溃并重启的容器的日志,使用 --previous。
临时调试容器
kubectl debug 会把一个临时容器挂接到正在运行的 Pod 上,因此你可以使用应用镜像中没有的工具,而无需重启应用。
示例 91: 多个 Pod 的日志
按标签选择 Pod。
kubectl logs -l app=web --all-containers --prefix --tail=20
kubectl logs -l app=web -f --max-log-requests=10
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 92: Pod 为什么无法启动
阅读 describe 输出和容器状态。
kubectl describe pod web-6d4cf56db6-abcde
kubectl get pod web-6d4cf56db6-abcde -o jsonpath="{.status.containerStatuses[0].state}"
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 93: 临时调试容器
不重启正在运行的 Pod 即可调试。
kubectl debug -it web-6d4cf56db6-abcde --image=busybox:1.36 --target=web -- sh
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 94: 事件与节点压力
发现容量和驱逐问题。
kubectl get events -A --sort-by=.lastTimestamp | tail -20
kubectl describe node worker-1 | grep -A5 "Conditions"
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
知识点 15: 生产运维与 GitOps
生产意味着可重复的发布、安全的维护和恢复能力。GitOps 使集群与 Git 仓库保持一致,备份则保护那些无法重建的对象和数据。
GitOps
Argo CD 这类 GitOps 工具会监视仓库,并把其中的清单应用到集群。每一项变更都经过拉取请求,selfHeal 会撤销偏离 Git 的手动修改。
无停机维护
kubectl drain 会在升级节点之前把 Pod 迁移走,PodDisruptionBudget 则保证有足够的副本持续运行。节点准备就绪后,运行 kubectl uncordon。
备份与恢复
Velero 把集群对象和持久卷备份到对象存储。从未恢复过的备份并不可靠,因此应在单独的集群中测试恢复。
示例 95: 用 Argo CD 实现 GitOps
让集群与 Git 仓库保持同步。
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: shop
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/example/shop-deploy
targetRevision: main
path: overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: shop
syncPolicy:
automated:
prune: true
selfHeal: true
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 96: 生产环境的 Deployment
探针、资源限制和安全发布结合在一起。
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
labels:
app: api
spec:
replicas: 3
revisionHistoryLimit: 5
selector:
matchLabels:
app: api
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: registry.example.com/team/api:1.4.2
ports:
- containerPort: 8000
resources:
requests: {cpu: 250m, memory: 256Mi}
limits: {memory: 512Mi}
readinessProbe:
httpGet: {path: /ready, port: 8000}
livenessProbe:
httpGet: {path: /healthz, port: 8000}
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 97: 用 Velero 备份
把集群对象和卷保存到存储中。
velero install --provider azure --plugins velero/velero-plugin-for-microsoft-azure:v1.10.0 --bucket k8s-backups
velero backup create shop-daily --include-namespaces shop
velero backup describe shop-daily
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 98: 排空并恢复调度节点
维护时让 Pod 不中断服务。
kubectl cordon worker-1
kubectl drain worker-1 --ignore-daemonsets --delete-emptydir-data
kubectl uncordon worker-1
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 99: 用 Python 检查副本数
使用官方的 Kubernetes 客户端。
from kubernetes import client, config
config.load_kube_config()
apps = client.AppsV1Api()
for d in apps.list_namespaced_deployment("shop").items:
ready = d.status.ready_replicas or 0
print(d.metadata.name, f"{ready}/{d.spec.replicas}")
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
示例 100: 发布检查清单脚本
任一检查失败时阻止发布。
#!/usr/bin/env bash
set -euo pipefail
NS="$1"
kubectl -n "$NS" rollout status deployment --timeout=180s
kubectl -n "$NS" get pdb
kubectl -n "$NS" auth can-i --list --as=system:serviceaccount:"$NS":default | grep -q "\*" && { echo "default account has wildcard rights"; exit 1; }
kubectl -n "$NS" get pods -o jsonpath="{range .items[*]}{.metadata.name}{' runAsRoot='}{.spec.securityContext.runAsNonRoot}{'\n'}{end}"
echo "release checks passed for namespace $NS"
*此示例未在本机运行,因为准备本文的计算机没有安装 Kubernetes 集群或 kubectl。*
实验:部署、暴露并发布一个小型 Web 应用
在一个练习集群中把本文串起来:带探针和资源限制的 Deployment、Service、Ingress、ConfigMap 与 Secret、带回滚的滚动更新,以及发布检查。
1. 用 kind 创建练习集群,然后创建名为 shop 的命名空间并将其设为默认。
2. 应用一个包含三个副本、资源 requests 与 limits、就绪探针和存活探针的 Deployment。
3. 添加一个 ClusterIP 类型的 Service,检查其端点,然后从临时 Pod 中调用它。
4. 为设置创建 ConfigMap,为占位密码创建 Secret,并把两者都挂载到 Pod 中。
5. 发布新的镜像版本,观察发布过程,然后用 kubectl rollout undo 撤销。
6. 为 shop.example.com 添加 Ingress,然后用 NetworkPolicy 限制对 API 的访问。
7. 对该命名空间运行第 100 个示例中的发布检查清单,如果任何检查失败就停止。
下一步
完成实验后,请在沙盒订阅中的托管集群上练习,为你自己的应用学习 Helm chart,并设置 GitOps,使每项变更都在 Git 中经过审查。把示例保存在仓库中,并在每次升级集群时重新运行,因为 Kubernetes 的 API 会随版本变化。
总结
Kubernetes 让你的容器持续运行,把它们分布到各个节点上,无停机地更新,并根据需求进行扩缩容。你学习了 kubectl 与上下文、Pod、Deployment 与回滚、Service 与 Ingress、配置与机密、存储、Job 与 CronJob、StatefulSet 与 DaemonSet、自动扩缩容、资源请求与探针、RBAC 与 Pod 安全、Helm 与 Kustomize、调试,以及面向生产的 GitOps 和备份。