配置与扩缩
Part 1:ConfigMap 与 Secret
概念引入
你的应用总需要一些"外部信息":数据库地址、API 密钥、日志级别......把它们硬编码在镜像里是个坏主意------换个环境就得重新打包。
ConfigMap 和 Secret 就是 K8s 的"配置管理中心":
- ConfigMap:存普通配置(数据库地址、日志级别)
- Secret:存敏感信息(密码、证书、API 密钥),内容 Base64 编码
#mermaid-svg-qUM7LX8UztcU3PKP{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qUM7LX8UztcU3PKP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qUM7LX8UztcU3PKP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qUM7LX8UztcU3PKP .error-icon{fill:#552222;}#mermaid-svg-qUM7LX8UztcU3PKP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qUM7LX8UztcU3PKP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qUM7LX8UztcU3PKP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qUM7LX8UztcU3PKP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qUM7LX8UztcU3PKP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qUM7LX8UztcU3PKP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qUM7LX8UztcU3PKP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qUM7LX8UztcU3PKP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qUM7LX8UztcU3PKP .marker.cross{stroke:#333333;}#mermaid-svg-qUM7LX8UztcU3PKP svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qUM7LX8UztcU3PKP p{margin:0;}#mermaid-svg-qUM7LX8UztcU3PKP .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-qUM7LX8UztcU3PKP .cluster-label text{fill:#333;}#mermaid-svg-qUM7LX8UztcU3PKP .cluster-label span{color:#333;}#mermaid-svg-qUM7LX8UztcU3PKP .cluster-label span p{background-color:transparent;}#mermaid-svg-qUM7LX8UztcU3PKP .label text,#mermaid-svg-qUM7LX8UztcU3PKP span{fill:#333;color:#333;}#mermaid-svg-qUM7LX8UztcU3PKP .node rect,#mermaid-svg-qUM7LX8UztcU3PKP .node circle,#mermaid-svg-qUM7LX8UztcU3PKP .node ellipse,#mermaid-svg-qUM7LX8UztcU3PKP .node polygon,#mermaid-svg-qUM7LX8UztcU3PKP .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-qUM7LX8UztcU3PKP .rough-node .label text,#mermaid-svg-qUM7LX8UztcU3PKP .node .label text,#mermaid-svg-qUM7LX8UztcU3PKP .image-shape .label,#mermaid-svg-qUM7LX8UztcU3PKP .icon-shape .label{text-anchor:middle;}#mermaid-svg-qUM7LX8UztcU3PKP .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-qUM7LX8UztcU3PKP .rough-node .label,#mermaid-svg-qUM7LX8UztcU3PKP .node .label,#mermaid-svg-qUM7LX8UztcU3PKP .image-shape .label,#mermaid-svg-qUM7LX8UztcU3PKP .icon-shape .label{text-align:center;}#mermaid-svg-qUM7LX8UztcU3PKP .node.clickable{cursor:pointer;}#mermaid-svg-qUM7LX8UztcU3PKP .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-qUM7LX8UztcU3PKP .arrowheadPath{fill:#333333;}#mermaid-svg-qUM7LX8UztcU3PKP .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-qUM7LX8UztcU3PKP .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-qUM7LX8UztcU3PKP .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qUM7LX8UztcU3PKP .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-qUM7LX8UztcU3PKP .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qUM7LX8UztcU3PKP .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-qUM7LX8UztcU3PKP .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-qUM7LX8UztcU3PKP .cluster text{fill:#333;}#mermaid-svg-qUM7LX8UztcU3PKP .cluster span{color:#333;}#mermaid-svg-qUM7LX8UztcU3PKP div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-qUM7LX8UztcU3PKP .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-qUM7LX8UztcU3PKP rect.text{fill:none;stroke-width:0;}#mermaid-svg-qUM7LX8UztcU3PKP .icon-shape,#mermaid-svg-qUM7LX8UztcU3PKP .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qUM7LX8UztcU3PKP .icon-shape p,#mermaid-svg-qUM7LX8UztcU3PKP .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-qUM7LX8UztcU3PKP .icon-shape .label rect,#mermaid-svg-qUM7LX8UztcU3PKP .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qUM7LX8UztcU3PKP .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-qUM7LX8UztcU3PKP .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-qUM7LX8UztcU3PKP :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 读取配置
ConfigMap
普通配置
Pod
Secret
敏感信息
你的应用
原理讲解
两种注入方式
ConfigMap/Secret 的内容可以通过两种方式注入到 Pod:
| 方式 | 怎么用 | 特点 |
|---|---|---|
| 环境变量 | 变成容器里的环境变量 | 简单,但更新需重启 Pod |
| 文件挂载 | 变成容器里的文件 | 灵活,更新自动同步 |
#mermaid-svg-qMru3KRiTwN9npGz{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qMru3KRiTwN9npGz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qMru3KRiTwN9npGz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qMru3KRiTwN9npGz .error-icon{fill:#552222;}#mermaid-svg-qMru3KRiTwN9npGz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qMru3KRiTwN9npGz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qMru3KRiTwN9npGz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qMru3KRiTwN9npGz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qMru3KRiTwN9npGz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qMru3KRiTwN9npGz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qMru3KRiTwN9npGz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qMru3KRiTwN9npGz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qMru3KRiTwN9npGz .marker.cross{stroke:#333333;}#mermaid-svg-qMru3KRiTwN9npGz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qMru3KRiTwN9npGz p{margin:0;}#mermaid-svg-qMru3KRiTwN9npGz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-qMru3KRiTwN9npGz .cluster-label text{fill:#333;}#mermaid-svg-qMru3KRiTwN9npGz .cluster-label span{color:#333;}#mermaid-svg-qMru3KRiTwN9npGz .cluster-label span p{background-color:transparent;}#mermaid-svg-qMru3KRiTwN9npGz .label text,#mermaid-svg-qMru3KRiTwN9npGz span{fill:#333;color:#333;}#mermaid-svg-qMru3KRiTwN9npGz .node rect,#mermaid-svg-qMru3KRiTwN9npGz .node circle,#mermaid-svg-qMru3KRiTwN9npGz .node ellipse,#mermaid-svg-qMru3KRiTwN9npGz .node polygon,#mermaid-svg-qMru3KRiTwN9npGz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-qMru3KRiTwN9npGz .rough-node .label text,#mermaid-svg-qMru3KRiTwN9npGz .node .label text,#mermaid-svg-qMru3KRiTwN9npGz .image-shape .label,#mermaid-svg-qMru3KRiTwN9npGz .icon-shape .label{text-anchor:middle;}#mermaid-svg-qMru3KRiTwN9npGz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-qMru3KRiTwN9npGz .rough-node .label,#mermaid-svg-qMru3KRiTwN9npGz .node .label,#mermaid-svg-qMru3KRiTwN9npGz .image-shape .label,#mermaid-svg-qMru3KRiTwN9npGz .icon-shape .label{text-align:center;}#mermaid-svg-qMru3KRiTwN9npGz .node.clickable{cursor:pointer;}#mermaid-svg-qMru3KRiTwN9npGz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-qMru3KRiTwN9npGz .arrowheadPath{fill:#333333;}#mermaid-svg-qMru3KRiTwN9npGz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-qMru3KRiTwN9npGz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-qMru3KRiTwN9npGz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qMru3KRiTwN9npGz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-qMru3KRiTwN9npGz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qMru3KRiTwN9npGz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-qMru3KRiTwN9npGz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-qMru3KRiTwN9npGz .cluster text{fill:#333;}#mermaid-svg-qMru3KRiTwN9npGz .cluster span{color:#333;}#mermaid-svg-qMru3KRiTwN9npGz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-qMru3KRiTwN9npGz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-qMru3KRiTwN9npGz rect.text{fill:none;stroke-width:0;}#mermaid-svg-qMru3KRiTwN9npGz .icon-shape,#mermaid-svg-qMru3KRiTwN9npGz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qMru3KRiTwN9npGz .icon-shape p,#mermaid-svg-qMru3KRiTwN9npGz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-qMru3KRiTwN9npGz .icon-shape .label rect,#mermaid-svg-qMru3KRiTwN9npGz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qMru3KRiTwN9npGz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-qMru3KRiTwN9npGz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-qMru3KRiTwN9npGz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ConfigMap
环境变量方式
DATABASE_URL=mysql://...
文件挂载方式
/etc/config/app.conf
Pod
ConfigMap 创建方式
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DATABASE_URL: "mysql://db:3306/myapp"
LOG_LEVEL: "info"
app.conf: |
server.port=8080
server.context-path=/api
Secret 创建方式
yaml
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
data:
# 值需要 Base64 编码
# echo -n "mypassword" | base64
DB_PASSWORD: bXlwYXNzd29yZA==
⚠️ Secret 的"安全"只是 Base64 编码(不是加密)。真正的安全需要配合 RBAC 和加密方案。
动手实验
步骤 1:创建 ConfigMap
bash
cat > app-config.yaml << 'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: "info"
APP_COLOR: "blue"
EOF
kubectl apply -f app-config.yaml
步骤 2:用环境变量注入
bash
cat > config-env-pod.yaml << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: config-env-pod
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "echo LOG_LEVEL=$LOG_LEVEL APP_COLOR=$APP_COLOR && sleep 3600"]
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
- name: APP_COLOR
valueFrom:
configMapKeyRef:
name: app-config
key: APP_COLOR
EOF
kubectl apply -f config-env-pod.yaml
步骤 3:验证环境变量
bash
kubectl logs config-env-pod
预期输出:
text
LOG_LEVEL=info APP_COLOR=blue
步骤 4:用文件挂载注入
bash
cat > config-vol-pod.yaml << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: config-vol-pod
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "ls /etc/config/ && cat /etc/config/LOG_LEVEL && sleep 3600"]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-config
EOF
kubectl apply -f config-vol-pod.yaml
步骤 5:验证文件挂载
bash
kubectl logs config-vol-pod
每个 ConfigMap 的 key 变成了 /etc/config/ 下的一个文件,文件内容就是 value。
步骤 6:创建 Secret
bash
# 用命令行创建(自动 Base64 编码)
kubectl create secret generic app-secret \
--from-literal=DB_PASSWORD=supersecret \
--from-literal=API_KEY=abc123
# 查看
kubectl get secret app-secret -o yaml
步骤 7:清理
bash
kubectl delete pod config-env-pod config-vol-pod
kubectl delete configmap app-config
kubectl delete secret app-secret
rm -f app-config.yaml config-env-pod.yaml config-vol-pod.yaml
Part 2:扩缩容与发布
概念引入
你的电商网站白天流量大需要 10 个 Pod,半夜没什么人只要 2 个就够了。每次手动 kubectl scale 太累了。
HPA(Horizontal Pod Autoscaler) 就是你的"自动调度员"------它监控 CPU/内存使用率,自动增减 Pod 数量。
#mermaid-svg-Pel3G7GBOWPiFwPK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Pel3G7GBOWPiFwPK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Pel3G7GBOWPiFwPK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Pel3G7GBOWPiFwPK .error-icon{fill:#552222;}#mermaid-svg-Pel3G7GBOWPiFwPK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Pel3G7GBOWPiFwPK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Pel3G7GBOWPiFwPK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Pel3G7GBOWPiFwPK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Pel3G7GBOWPiFwPK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Pel3G7GBOWPiFwPK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Pel3G7GBOWPiFwPK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Pel3G7GBOWPiFwPK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Pel3G7GBOWPiFwPK .marker.cross{stroke:#333333;}#mermaid-svg-Pel3G7GBOWPiFwPK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Pel3G7GBOWPiFwPK p{margin:0;}#mermaid-svg-Pel3G7GBOWPiFwPK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Pel3G7GBOWPiFwPK .cluster-label text{fill:#333;}#mermaid-svg-Pel3G7GBOWPiFwPK .cluster-label span{color:#333;}#mermaid-svg-Pel3G7GBOWPiFwPK .cluster-label span p{background-color:transparent;}#mermaid-svg-Pel3G7GBOWPiFwPK .label text,#mermaid-svg-Pel3G7GBOWPiFwPK span{fill:#333;color:#333;}#mermaid-svg-Pel3G7GBOWPiFwPK .node rect,#mermaid-svg-Pel3G7GBOWPiFwPK .node circle,#mermaid-svg-Pel3G7GBOWPiFwPK .node ellipse,#mermaid-svg-Pel3G7GBOWPiFwPK .node polygon,#mermaid-svg-Pel3G7GBOWPiFwPK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Pel3G7GBOWPiFwPK .rough-node .label text,#mermaid-svg-Pel3G7GBOWPiFwPK .node .label text,#mermaid-svg-Pel3G7GBOWPiFwPK .image-shape .label,#mermaid-svg-Pel3G7GBOWPiFwPK .icon-shape .label{text-anchor:middle;}#mermaid-svg-Pel3G7GBOWPiFwPK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Pel3G7GBOWPiFwPK .rough-node .label,#mermaid-svg-Pel3G7GBOWPiFwPK .node .label,#mermaid-svg-Pel3G7GBOWPiFwPK .image-shape .label,#mermaid-svg-Pel3G7GBOWPiFwPK .icon-shape .label{text-align:center;}#mermaid-svg-Pel3G7GBOWPiFwPK .node.clickable{cursor:pointer;}#mermaid-svg-Pel3G7GBOWPiFwPK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Pel3G7GBOWPiFwPK .arrowheadPath{fill:#333333;}#mermaid-svg-Pel3G7GBOWPiFwPK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Pel3G7GBOWPiFwPK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Pel3G7GBOWPiFwPK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Pel3G7GBOWPiFwPK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Pel3G7GBOWPiFwPK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Pel3G7GBOWPiFwPK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Pel3G7GBOWPiFwPK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Pel3G7GBOWPiFwPK .cluster text{fill:#333;}#mermaid-svg-Pel3G7GBOWPiFwPK .cluster span{color:#333;}#mermaid-svg-Pel3G7GBOWPiFwPK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Pel3G7GBOWPiFwPK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Pel3G7GBOWPiFwPK rect.text{fill:none;stroke-width:0;}#mermaid-svg-Pel3G7GBOWPiFwPK .icon-shape,#mermaid-svg-Pel3G7GBOWPiFwPK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Pel3G7GBOWPiFwPK .icon-shape p,#mermaid-svg-Pel3G7GBOWPiFwPK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Pel3G7GBOWPiFwPK .icon-shape .label rect,#mermaid-svg-Pel3G7GBOWPiFwPK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Pel3G7GBOWPiFwPK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Pel3G7GBOWPiFwPK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Pel3G7GBOWPiFwPK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} CPU > 70%
CPU < 30%
Metrics Server
监控指标
HPA
自动调度员
扩容 + Pod
缩容 - Pod
Deployment
原理讲解
HPA 的工作流程
#mermaid-svg-I4fwQASRASLpwMPF{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-I4fwQASRASLpwMPF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-I4fwQASRASLpwMPF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-I4fwQASRASLpwMPF .error-icon{fill:#552222;}#mermaid-svg-I4fwQASRASLpwMPF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-I4fwQASRASLpwMPF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-I4fwQASRASLpwMPF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-I4fwQASRASLpwMPF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-I4fwQASRASLpwMPF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-I4fwQASRASLpwMPF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-I4fwQASRASLpwMPF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-I4fwQASRASLpwMPF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-I4fwQASRASLpwMPF .marker.cross{stroke:#333333;}#mermaid-svg-I4fwQASRASLpwMPF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-I4fwQASRASLpwMPF p{margin:0;}#mermaid-svg-I4fwQASRASLpwMPF .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-I4fwQASRASLpwMPF .cluster-label text{fill:#333;}#mermaid-svg-I4fwQASRASLpwMPF .cluster-label span{color:#333;}#mermaid-svg-I4fwQASRASLpwMPF .cluster-label span p{background-color:transparent;}#mermaid-svg-I4fwQASRASLpwMPF .label text,#mermaid-svg-I4fwQASRASLpwMPF span{fill:#333;color:#333;}#mermaid-svg-I4fwQASRASLpwMPF .node rect,#mermaid-svg-I4fwQASRASLpwMPF .node circle,#mermaid-svg-I4fwQASRASLpwMPF .node ellipse,#mermaid-svg-I4fwQASRASLpwMPF .node polygon,#mermaid-svg-I4fwQASRASLpwMPF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-I4fwQASRASLpwMPF .rough-node .label text,#mermaid-svg-I4fwQASRASLpwMPF .node .label text,#mermaid-svg-I4fwQASRASLpwMPF .image-shape .label,#mermaid-svg-I4fwQASRASLpwMPF .icon-shape .label{text-anchor:middle;}#mermaid-svg-I4fwQASRASLpwMPF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-I4fwQASRASLpwMPF .rough-node .label,#mermaid-svg-I4fwQASRASLpwMPF .node .label,#mermaid-svg-I4fwQASRASLpwMPF .image-shape .label,#mermaid-svg-I4fwQASRASLpwMPF .icon-shape .label{text-align:center;}#mermaid-svg-I4fwQASRASLpwMPF .node.clickable{cursor:pointer;}#mermaid-svg-I4fwQASRASLpwMPF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-I4fwQASRASLpwMPF .arrowheadPath{fill:#333333;}#mermaid-svg-I4fwQASRASLpwMPF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-I4fwQASRASLpwMPF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-I4fwQASRASLpwMPF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-I4fwQASRASLpwMPF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-I4fwQASRASLpwMPF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-I4fwQASRASLpwMPF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-I4fwQASRASLpwMPF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-I4fwQASRASLpwMPF .cluster text{fill:#333;}#mermaid-svg-I4fwQASRASLpwMPF .cluster span{color:#333;}#mermaid-svg-I4fwQASRASLpwMPF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-I4fwQASRASLpwMPF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-I4fwQASRASLpwMPF rect.text{fill:none;stroke-width:0;}#mermaid-svg-I4fwQASRASLpwMPF .icon-shape,#mermaid-svg-I4fwQASRASLpwMPF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-I4fwQASRASLpwMPF .icon-shape p,#mermaid-svg-I4fwQASRASLpwMPF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-I4fwQASRASLpwMPF .icon-shape .label rect,#mermaid-svg-I4fwQASRASLpwMPF .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-I4fwQASRASLpwMPF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-I4fwQASRASLpwMPF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-I4fwQASRASLpwMPF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 高于目标
低于目标
在范围内
每隔 15 秒查询指标
当前 CPU 使用率
计算需要几个 Pod
计算可以减少几个
什么都不做
调整 Deployment replicas
HPA 的关键参数
| 参数 | 含义 | 示例 |
|---|---|---|
| minReplicas | 最少几个 Pod | 2 |
| maxReplicas | 最多几个 Pod | 10 |
| targetCPUUtilization | 目标 CPU 使用率 | 70% |
发布策略概览
除了自动扩缩容,你还需要了解常见的发布策略:
| 策略 | 原理 | 风险 |
|---|---|---|
| 滚动更新 | 逐个替换旧 Pod | 低(默认策略) |
| 蓝绿部署 | 新旧两套环境,切换流量 | 资源翻倍 |
| 金丝雀发布 | 先放少量流量到新版本 | 需要额外工具 |
💡 K8s 的 Deployment 原生支持滚动更新。蓝绿和金丝雀需要 Istio/Argo Rollouts 等工具。
动手实验
前提:安装 Metrics Server
Kind 集群默认没有 Metrics Server,需要先安装:
bash
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# Kind 集群使用自签证书,Metrics Server 默认会因 TLS 验证失败(x509 错误)
# --kubelet-insecure-tls 跳过 TLS 验证,仅适用于本地开发和测试环境
kubectl patch deployment metrics-server -n kube-system --type='json' \
-p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}]'
⚠️ 开发/测试限定 :
--kubelet-insecure-tls会跳过 kubelet 的 TLS 证书验证,仅用于本地 Kind/Minikube 等开发环境 。生产集群中应配置 kubelet-csr-approver 来自动签发 kubelet 证书,实现安全的 TLS 通信。本文基于 Metrics Server v0.7.x 验证,最新安装方式请参考 Metrics Server 官方文档。
等待 Metrics Server 就绪:
bash
kubectl wait --for=condition=ready pod -l k8s-app=metrics-server -n kube-system --timeout=60s
步骤 1:创建 Deployment
bash
cat > php-apache.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
replicas: 1
selector:
matchLabels:
app: php-apache
template:
metadata:
labels:
app: php-apache
spec:
containers:
- name: php-apache
image: registry.k8s.io/hpa-example
resources:
requests:
cpu: 200m
limits:
cpu: 500m
ports:
- containerPort: 80
EOF
kubectl apply -f php-apache.yaml
步骤 2:创建 HPA
bash
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
步骤 3:查看 HPA
bash
kubectl get hpa
预期输出:
text
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
php-apache Deployment/php-apache 0%/50% 1 10 1
步骤 4:模拟压力
在另一个终端生成流量:
bash
kubectl run load-gen --image=busybox --rm -it -- /bin/sh
# 进入 shell 后执行:
while true; do wget -q -O- http://php-apache; done
回到第一个终端观察:
bash
kubectl get hpa -w
你会看到 CPU 使用率上升,HPA 自动扩容 Pod 数量。按 Ctrl+C 退出。
步骤 5:停止压力测试
关闭 load-gen 终端(或按 Ctrl+C 然后 exit)。
等待 1-2 分钟后:
bash
kubectl get hpa
HPA 会自动缩容回最小值。
步骤 6:清理
bash
kubectl delete hpa php-apache
kubectl delete -f php-apache.yaml
rm php-apache.yaml
自检问题
- ConfigMap 和 Secret 的区别是什么?
查看答案 ConfigMap 存普通配置,明文存储。Secret 存敏感信息,Base64 编码(不是加密)。两者注入 Pod 的方式相同。
- 环境变量和文件挂载各有什么优缺点?
查看答案 环境变量:简单直接,但更新 ConfigMap 后 Pod 需要重启才能生效。文件挂载:更灵活,ConfigMap 更新后文件会自动同步到容器内,不需要重启。
- HPA 扩容后什么时候会缩容?
查看答案 HPA 使用缩容稳定窗口(默认 5 分钟):在这 5 分钟内,HPA 取所有推荐副本数的**最大值**来决定缩容目标,而不是简单地看"CPU 是否持续低于阈值"。这样可以避免因短暂的指标波动导致过度缩容。
- 滚动更新和蓝绿部署的区别?
查看答案 滚动更新逐个替换 Pod,期间新旧版本共存,不需要额外资源。蓝绿部署维护两套完整环境,通过切换流量实现零停机,但需要双倍资源。
下一步
配置和扩缩都搞定了。接下来了解 K8s 怎么管理持久化数据:
→ 05. 存储基础
📚 本文来自 K8s Guide ------ 开源免费的 Kubernetes 中文学习指南
- 🗺️ 初学者轨道 + 面试轨道,从零基础到拿 Offer 一站式覆盖
- 🧪 每篇文章配套 Kind 实验脚本,本地一键运行
- 🔗 本文源码:docs/beginner/07-configmap-secret.md / docs/beginner/08-scaling-rollout.md
⭐ 如果对你有帮助,欢迎 Star! github.com/callmebg/k8s-guide