Kubernetes

K8s 环境变量 全维度详解

·17 分钟阅读·6790 字
📋 目录

K8s 环境变量 全维度详解

1. 基础认知

1.1. 核心作用

环境变量是向容器注入配置、元数据、标识信息的标准方式,容器内所有进程均可读取,解耦镜像与运行配置,实现镜像一次构建、多环境运行。

1.2. 生效范围

  • 定义在 spec.containers[].env / envFrom容器级别配置;
  • 同 Pod 不同容器可配置不同环境变量,互不干扰;
  • 环境变量在容器启动时一次性注入,运行期间默认不会动态更新

1.3. 两大配置方式

  1. env:逐条定义单个环境变量,灵活精准;
  2. envFrom:批量导入 ConfigMap / Secret 中所有键值,适合大批量配置。

2. 环境变量五大来源(分类+示例)

K8s 环境变量共分为 5 种来源,从简单到高阶依次说明,包含完整 YAML、语法规则、使用场景。

2.1. 直接字面量(value)

最基础用法,硬编码键值对,静态固定值。

2.1.1. 语法

env:
- name: 变量名  # 容器内读取的变量名,大小写敏感
  value: 变量值  # 纯字符串,数字/布尔也写为字符串

2.1.2. 完整示例

apiVersion: v1
kind: Pod
metadata:
  name: env-value-demo
spec:
  containers:
  - name: app
    image: busybox
    command: ["sh", "-c", "echo $APP_NAME $APP_ENV"]
    env:
    - name: APP_NAME
      value: "order-service"
    - name: APP_ENV
      value: "production"

2.1.3. 特点

  • 优点:简单直观;
  • 缺点:配置硬编码,改值需要重建 Pod,不适合敏感配置、大量配置

2.2. 引用 Pod/节点元数据(fieldRef)

从 K8s 资源对象中动态提取元数据注入环境变量,比如 Pod 名称、IP、命名空间、节点名等。
底层依赖 valueFrom.fieldRef

2.2.1. 常用字段(生产高频)

fieldPath说明
metadata.namePod 名称
metadata.namespacePod 所在命名空间
metadata.uidPod 唯一ID
status.podIPPod 内网IP
status.hostIP宿主机节点IP
spec.nodeName节点名称

2.2.2. 示例

containers:
- name: app
  image: busybox
  command: ["sh", "-c", "echo PodName: $POD_NAME, PodIP: $POD_IP"]
  env:
  - name: POD_NAME
    valueFrom:
      fieldRef:
        fieldPath: metadata.name
  - name: POD_IP
    valueFrom:
      fieldRef:
        fieldPath: status.podIP
  - name: NAMESPACE
    valueFrom:
      fieldRef:
        fieldPath: metadata.namespace

2.2.3. 适用场景

  • 应用日志打印 Pod 标识、IP、节点信息,方便排查;
  • 服务自注册时上报自身实例信息。

2.3. 引用容器资源配置(resourceFieldRef)

动态注入当前容器的 CPU/内存 requests、limits 配置,底层 valueFrom.resourceFieldRef

2.3.1. 支持资源

  • limits.cpu / requests.cpu
  • limits.memory / requests.memory
  • 高阶:hugepages-2Mi 大页内存等

2.3.2. 示例

containers:
- name: app
  image: busybox
  resources:
    requests:
      cpu: 200m
      memory: 256Mi
    limits:
      cpu: 500m
      memory: 512Mi
  command: ["sh", "-c", "echo CPU_LIMIT: $CPU_LIMIT, MEM_REQ: $MEM_REQ"]
  env:
  - name: CPU_LIMIT
    valueFrom:
      resourceFieldRef:
        containerName: app  # 当前容器名,多容器Pod必须指定
        resource: limits.cpu
  - name: MEM_REQ
    valueFrom:
      resourceFieldRef:
        containerName: app
        resource: requests.memory

2.3.3. 特点

  • 单位保留 K8s 原生单位(m、Mi、Gi);
  • 适合应用动态感知自身资源配额,做内部限流、堆内存自适应(如 Java JVM 参数)。

2.4. 引用 ConfigMap 配置

ConfigMap 中的单个 Key 映射为环境变量,区分「单键引用」和「全量导入」。

2.4.1. 前置:创建 ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: default
data:
  db.host: 10.0.0.10
  db.port: 3306
  log.level: info

2.4.2. 方式1:单独引用某个 Key

精准选取指定配置项,推荐精细化使用。

spec:
  containers:
  - name: app
    image: busybox
    env:
    # 引用 configMap 单个键
    - name: DB_HOST
      valueFrom:
        configMapKeyRef:
          name: app-config  # ConfigMap 名称
          key: db.host      # ConfigMap 内的 key
    - name: DB_PORT
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: db.port

2.4.3. 方式2:批量导入所有键

一次性把 ConfigMap 所有 key=value 转为环境变量,适合配置项较多场景。

spec:
  containers:
  - name: app
    image: busybox
    # 批量导入
    envFrom:
    - configMapRef:
        name: app-config

容器内变量名 = ConfigMap 的 key,示例中变量名为 db.host


2.5. 引用 Secret 密钥

用法和 ConfigMap 完全一致,专门存放密码、密钥、令牌等敏感数据。
Secret 数据底层会 Base64 编码,K8s 注入容器时自动解码,容器内明文读取。

2.5.1. 前置:创建 Secret

apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque
data:
  db.username: YWRtaW4=  # base64 编码:admin
  db.password: MTIzNDU2  # base64 编码:123456

2.5.2. 方式1:单键引用

containers:
- name: app
  image: busybox
  env:
  - name: DB_USER
    valueFrom:
      secretKeyRef:
        name: app-secret
        key: db.username
  - name: DB_PWD
    valueFrom:
      secretKeyRef:
        name: app-secret
        key: db.password

2.5.3. 方式2:批量导入(envFrom)

containers:
- name: app
  image: busybox
  envFrom:
  - secretRef:
      name: app-secret

3. 关键高级特性

3.1. 可选引用(optional)

默认情况下:如果引用的 ConfigMap/Secret 不存在、或指定 Key 缺失,Pod 会启动失败
通过 optional: true 设置为可选,缺失时不报错、该变量不注入。

3.1.1. 示例(可选引用)

env:
- name: EXT_CONFIG
  valueFrom:
    configMapKeyRef:
      name: not-exist-cm
      key: ext.key
      optional: true  # 配置不存在也正常启动

3.2. 环境变量相互引用 / 变量嵌套

K8s 支持后定义的变量引用前面已定义的变量,实现拼接、组合。

规则:按 YAML 书写顺序解析,只能向前引用,不能向后。

3.2.1. 示例:变量拼接

env:
- name: DB_HOST
  value: "10.0.0.10"
- name: DB_PORT
  value: "3306"
# 引用上面两个变量拼接连接串
- name: DB_URL
  value: "mysql://$(DB_HOST):$(DB_PORT)"

3.3. 变量名规范

  1. 变量名由字母、数字、下划线组成,不能以数字开头;
  2. 不建议使用 .- 等特殊字符(部分编程语言不兼容);
  3. 系统预留变量(如 PATHHOME)谨慎覆盖。

3.4. 环境变量更新机制(重点坑点)

  1. 静态注入特性
    env / envFrom 方式注入的变量,仅在容器启动时加载一次
  • 修改 ConfigMap / Secret → 已运行的 Pod 环境变量不会自动更新
  • 必须重建 Pod 或滚动更新 Deployment 才能生效。
  1. 补充:ConfigMap/Secret 挂载为文件时
    volume 方式挂载的配置文件,K8s 会定时热更新(默认几秒~一分钟),和环境变量行为不同。

4. 配置优先级(变量冲突覆盖规则)

当多个来源定义同名环境变量时,遵循固定优先级(从高到低):

  1. env 字面量(value)
  2. env 各类 valueFrom(fieldRef / configMapKeyRef / secretKeyRef)
  3. envFrom 批量导入(configMapRef / secretRef)

总结:逐条 env 优先级 > 批量 envFrom;前面定义的变量会被后面同名变量覆盖。

示例:同名变量冲突

env:
# 优先级低
- name: APP_ENV
  value: "test"
# 优先级高,覆盖上面的值
- name: APP_ENV
  valueFrom:
    configMapKeyRef:
      name: app-config
      key: env

5. env 与 envFrom 选型 & 最佳实践

5.1. 选型建议

场景推荐方案
少量固定配置、简单标识env + value 字面量
注入 Pod/节点元数据env + fieldRef
注入资源配额env + resourceFieldRef
少量配置项、需要精细化管控env + configMapKeyRef / secretKeyRef
大量配置项、整体导入envFrom + configMapRef / secretRef
敏感密码、令牌必须使用 Secret,禁止明文 value

5.2. 生产规范

  1. 禁止明文存放敏感信息账号、密码、密钥、Token 一律存入 Secret,不用 value 硬编码。
  2. 区分环境
    开发/测试/生产使用不同 ConfigMap/Secret,通过名称区分,不修改 Pod 模板。
  3. 优先单键引用,少用 envFrom 全量导入
    全量导入会把所有 Key 都注入容器,容易泄露多余配置,权限最小化原则推荐按需引用 Key。
  4. 配合 optional 做容错非核心配置开启 optional: true,避免因配置缺失导致 Pod 大面积启动失败。
  5. 动态配置场景补充
    如需配置热更新(不重启 Pod):
  • 方案1:ConfigMap/Secret 挂载为 Volume,应用监听文件变化;
  • 方案2:对接 Nacos/Apollo 等配置中心。

6. 常见问题 & 排障

问题1:Pod 启动失败,提示 configmap/secret not found

原因:引用的 ConfigMap/Secret 不存在,或 Key 名称写错。
解决:

  1. 检查资源是否存在:kubectl get configmap/secret
  2. 核对 namekey 拼写
  3. 非核心配置添加 optional: true

问题2:修改 ConfigMap 后,容器内环境变量不变

原因:环境变量启动时一次性注入,不支持热更新
解决:重建 Pod / 触发 Deployment 滚动更新。

问题3:Secret 密码在容器内读取乱码/为空

原因:Secret 的 data 字段必须是 Base64 编码字符串
解决:

# 快速生成 base64 编码
echo -n "你的密码" | base64

问题4:变量引用不生效($(XXX) 原样输出)

原因:容器启动命令不是 shell 环境,无法解析变量语法。
解决:使用 shell 包装命令:

command: ["sh", "-c", "echo $(DB_HOST)"]

7. 综合完整示例(整合所有用法)

apiVersion: v1
kind: Pod
metadata:
  name: env-all-demo
spec:
  containers:
  - name: app
    image: busybox
    command: ["sh", "-c", "echo 所有环境变量; env"]
    resources:
      requests:
        cpu: 100m
        memory: 128Mi
    # 1. 逐条环境变量
    env:
    # 字面量
    - name: APP_NAME
      value: "payment"
    # Pod 元数据
    - name: POD_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP
    # 资源配置
    - name: MEM_LIMIT
      valueFrom:
        resourceFieldRef:
          containerName: app
          resource: limits.memory
    # 引用 ConfigMap 单键
    - name: LOG_LEVEL
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: log.level
          optional: true
    # 引用 Secret 单键
    - name: DB_PASS
      valueFrom:
        secretKeyRef:
          name: app-secret
          key: db.password
    # 变量拼接
    - name: FULL_URL
      value: "service-$(APP_NAME).svc.cluster.local"
  # 2. 批量导入(全量 ConfigMap + Secret)
  envFrom:
  - configMapRef:
      name: app-config
  - secretRef:
      name: app-secret

8. 高频面试题

  1. K8s 环境变量有哪几种来源?
    答:字面量、Pod/节点元数据(fieldRef)、资源配额(resourceFieldRef)、ConfigMap、Secret。
  2. 修改 ConfigMap 后,Pod 内环境变量为什么不更新?
    答:环境变量在容器启动时一次性注入,运行期不会热更新;需重建 Pod 生效。挂载为文件形式会自动更新。
  3. **引用不存在的 ConfigMap/Secret 会发生什么?如何容错?**答:默认 Pod 启动失败;添加 optional: true 可实现容错,配置缺失时变量不注入、Pod 正常启动。
  4. env 和 envFrom 区别、优先级?
    答:env 逐条定义,envFrom 批量导入;env 优先级高于 envFrom,同名变量会被覆盖。
  5. Secret 存密码,容器内是明文吗?安全吗?
    答:Secret 底层 Base64 编码(非加密),注入容器后自动解码为明文;适合集群内基础保密,高敏感数据建议搭配外部密钥管理服务。

关联文档