04-配置与扩缩

配置与扩缩


Part 1:ConfigMap 与 Secret

概念引入

你的应用总需要一些"外部信息":数据库地址、API 密钥、日志级别......把它们硬编码在镜像里是个坏主意------换个环境就得重新打包。

ConfigMapSecret 就是 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

自检问题

  1. ConfigMap 和 Secret 的区别是什么?

查看答案 ConfigMap 存普通配置,明文存储。Secret 存敏感信息,Base64 编码(不是加密)。两者注入 Pod 的方式相同。

  1. 环境变量和文件挂载各有什么优缺点?

查看答案 环境变量:简单直接,但更新 ConfigMap 后 Pod 需要重启才能生效。文件挂载:更灵活,ConfigMap 更新后文件会自动同步到容器内,不需要重启。

  1. HPA 扩容后什么时候会缩容?

查看答案 HPA 使用缩容稳定窗口(默认 5 分钟):在这 5 分钟内,HPA 取所有推荐副本数的**最大值**来决定缩容目标,而不是简单地看"CPU 是否持续低于阈值"。这样可以避免因短暂的指标波动导致过度缩容。

  1. 滚动更新和蓝绿部署的区别?

查看答案 滚动更新逐个替换 Pod,期间新旧版本共存,不需要额外资源。蓝绿部署维护两套完整环境,通过切换流量实现零停机,但需要双倍资源。

下一步

配置和扩缩都搞定了。接下来了解 K8s 怎么管理持久化数据:

05. 存储基础


📚 本文来自 K8s Guide ------ 开源免费的 Kubernetes 中文学习指南

如果对你有帮助,欢迎 Star! github.com/callmebg/k8s-guide

相关推荐
小二·2 小时前
云原生2026:Kubernetes + Wasm + Serverless 深度实战
云原生·kubernetes·wasm
海兰4 小时前
基于 ES|QL 的 Kubernetes 监控工具箱:使用 ES|QL 进行 Kubernetes 监控,从内存压力到错误日志
大数据·elasticsearch·kubernetes
沉迷学习 日益消瘦5 小时前
09-Helm 包管理
kubernetes
爱吃龙利鱼8 小时前
K8s 运维体系搭建:全组件监控与日志收集实战(victoria-metrics-k8s-stack 0.87.0)
运维·容器·kubernetes
欢醉8 小时前
踩了个大坑!K8s 挂载目录的日志,居然也在吃容器内存?
kubernetes·springcloud
沉迷学习 日益消瘦8 小时前
10-可观测性与排错
kubernetes
heimeiyingwang1 天前
【架构实战】云原生架构:容器化与Kubernetes落地之路
云原生·架构·kubernetes
张忠琳1 天前
【NVIDIA】k8s-device-plugin v0.19.3 NVIDIA k8s-device-plugin v0.19.3 核心插件模块深度分析之一
云原生·容器·架构·kubernetes·nvidia
运维大师1 天前
【K8S 运维实战】15-链路追踪Jaeger与OTel
运维·容器·kubernetes