跳到主要内容

配置管理

本章介绍 Kubernetes 中的配置管理机制,包括 ConfigMap、Secret、ResourceQuota 和 LimitRange。合理的配置管理是实现应用与配置解耦、保障敏感数据安全的关键。

ConfigMap

ConfigMap 用于存储非敏感的配置数据,以键值对形式组织。它将环境特定的配置与容器镜像解耦,使应用更易于移植。

为什么需要 ConfigMap?

在传统部署中,配置通常有以下几种方式:

方式问题
硬编码在代码中修改配置需要重新编译
打包在镜像中不同环境需要不同镜像
环境变量管理复杂,难以维护
外部配置中心增加架构复杂度

ConfigMap 提供了一种 Kubernetes 原生的配置管理方式:

  • 配置与镜像分离,同一镜像可用于不同环境
  • 配置可动态更新(部分场景)
  • 通过 Namespace 隔离不同环境配置

注意:ConfigMap 不适合存储大量数据,单个 ConfigMap 不能超过 1 MiB。超过此限制应考虑使用卷挂载或外部存储服务。

创建 ConfigMap

从命令行创建

# 从字面值创建
kubectl create configmap app-config \
--from-literal=LOG_LEVEL=info \
--from-literal=MAX_CONNECTIONS=100

# 从文件创建
kubectl create configmap app-config \
--from-file=config.properties

# 从环境文件创建
kubectl create configmap app-env \
--from-env-file=env.properties

# 从目录创建(目录下所有文件)
kubectl create configmap app-config \
--from-file=./config/

YAML 定义

apiVersion: v1
kind: ConfigMap
metadata:
name: game-config
# 可选:设置不可变
# immutable: true
data:
# 简单键值对
player_initial_lives: "3"
ui_properties_file_name: "user-interface.properties"

# 文件类键(多行值)
game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
difficulty.level=hard

user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true

键名规则

  • 只能包含字母、数字、-_.
  • 不能以 . 开头(会被视为隐藏文件)

在 Pod 中使用 ConfigMap

ConfigMap 有四种使用方式:

方式一:环境变量

单个值引用

apiVersion: v1
kind: Pod
metadata:
name: env-single-pod
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "echo $LOG_LEVEL && sleep 3600"]
env:
- name: LOG_LEVEL # 环境变量名
valueFrom:
configMapKeyRef:
name: app-config # ConfigMap 名称
key: LOG_LEVEL # 键名

全部键值对导入

apiVersion: v1
kind: Pod
metadata:
name: env-all-pod
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "env && sleep 3600"]
envFrom:
- configMapRef:
name: app-config
# 可选:添加前缀
# prefix: APP_

注意:环境变量名称受限,不符合规则的键会被跳过,但 Pod 仍可启动。

方式二:命令行参数

apiVersion: v1
kind: Pod
metadata:
name: cmd-args-pod
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c"]
args:
- "echo Log Level: $(LOG_LEVEL) && sleep 3600"
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL

方式三:卷挂载

apiVersion: v1
kind: Pod
metadata:
name: volume-pod
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "cat /etc/config/game.properties && sleep 3600"]
volumeMounts:
- name: config
mountPath: /etc/config
readOnly: true
volumes:
- name: config
configMap:
name: game-config
# 可选:指定特定键
# items:
# - key: game.properties
# path: game.properties

挂载行为

  • 不指定 items:每个键都成为 mountPath 下的文件
  • 指定 items:只挂载指定的键

挂载示例对比

# 挂载所有键
volumes:
- name: config
configMap:
name: game-config
# 结果:/etc/config/ 下有 4 个文件

# 只挂载指定键
volumes:
- name: config
configMap:
name: game-config
items:
- key: game.properties
path: game.properties
# 结果:/etc/config/ 下只有 game.properties 文件

方式四:在容器代码中读取

应用通过 Kubernetes API 直接读取 ConfigMap,可以订阅更新通知。这种方式适合需要动态感知配置变化的场景。

ConfigMap 更新机制

卷挂载的 ConfigMap 会自动更新

当 ConfigMap 更新时,kubelet 会在定期同步时检测并更新挂载的文件。更新延迟取决于:

  • kubelet 同步周期(默认 1 分钟)
  • 缓存传播延迟

环境变量不会自动更新:使用 ConfigMap 作为环境变量的 Pod 需要重启才能获取新值。

缓存类型

通过 KubeletConfigurationconfigMapAndSecretChangeDetectionStrategy 配置:

类型说明
Watch(默认)监听变化,更新较快
TTL基于时间缓存,有延迟
Get直接请求 API Server,无缓存

子路径挂载不会更新:使用 subPath 挂载的 ConfigMap 不会自动更新。

不可变 ConfigMap

Kubernetes 1.21+ 稳定支持不可变 ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
name: immutable-config
data:
LOG_LEVEL: info
immutable: true # 关键配置

优点

  • 防止意外修改,提高安全性
  • 减少 kubelet 对 API Server 的监听负载
  • 大规模集群性能优化

限制:一旦设置为不可变,无法修改或恢复。只能删除后重新创建。

Secret

Secret 用于存储敏感数据,如密码、令牌、密钥等。与 ConfigMap 类似,但专门为敏感数据设计。

Secret 安全注意事项

默认情况下,Secret 存储不安全

  • Secret 在 etcd 中以明文存储
  • 有 API 访问权限的人可以读取 Secret
  • 有 etcd 访问权限的人可以读取 Secret
  • 在命名空间中有创建 Pod 权限的人可以读取该命名空间的所有 Secret

安全使用 Secret 的步骤

  1. 为 Secret 启用静态加密
  2. 启用 RBAC 规则限制 Secret 访问
  3. 限制 Secret 只能被特定命名空间访问
  4. 考虑使用外部密钥管理系统

Secret 类型

类型用途
Opaque通用类型(默认)
kubernetes.io/tlsTLS 证书
kubernetes.io/dockerconfigjsonDocker 仓库凭证
kubernetes.io/basic-authHTTP 基本认证
kubernetes.io/ssh-authSSH 认证
kubernetes.io/service-account-tokenServiceAccount 令牌
bootstrap.kubernetes.io/token节点引导令牌

创建 Secret

从命令行创建

# 从字面值创建
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password=S3cr3t!

# 从文件创建
kubectl create secret generic db-credentials \
--from-file=username=./username.txt \
--from-file=password=./password.txt

# 创建 TLS Secret
kubectl create secret tls my-tls \
--cert=./cert.pem \
--key=./key.pem

# 创建 Docker 仓库凭证
kubectl create secret docker-registry my-registry \
--docker-server=https://index.docker.io/v1/ \
--docker-username=myuser \
--docker-password=mypassword \
--docker-email=[email protected]

YAML 定义

apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
# 方式一:使用 data 字段(需要 base64 编码)
data:
username: YWRtaW4= # echo -n "admin" | base64
password: UzNjcjN0IQ== # echo -n "S3cr3t!" | base64
---
# 方式二:使用 stringData 字段(明文,自动编码)
apiVersion: v1
kind: Secret
metadata:
name: my-secret-string
type: Opaque
stringData:
username: admin
password: S3cr3t!

编码与加密的区别

Base64 编码不是加密,只是格式转换。Secret 的安全性来自访问控制和存储加密,而非 base64 编码。

在 Pod 中使用 Secret

作为环境变量

apiVersion: v1
kind: Pod
metadata:
name: secret-env-pod
spec:
containers:
- name: app
image: my-app
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password

作为卷挂载

apiVersion: v1
kind: Pod
metadata:
name: secret-volume-pod
spec:
containers:
- name: app
image: my-app
volumeMounts:
- name: credentials
mountPath: /etc/credentials
readOnly: true
volumes:
- name: credentials
secret:
secretName: db-credentials
# 可选:设置文件权限
# defaultMode: 0400
# 可选:指定特定键
# items:
# - key: username
# path: username

使用 Docker 仓库凭证

apiVersion: v1
kind: Pod
metadata:
name: private-image-pod
spec:
imagePullSecrets:
- name: my-registry
containers:
- name: app
image: my-private-registry/my-app:v1

使用 TLS 证书

apiVersion: v1
kind: Pod
metadata:
name: tls-pod
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: tls
mountPath: /etc/nginx/ssl
readOnly: true
volumes:
- name: tls
secret:
secretName: my-tls

Secret 文件权限

volumes:
- name: credentials
secret:
secretName: db-credentials
defaultMode: 0400 # 只读权限
items:
- key: username
path: username
mode: 0444
- key: password
path: password
mode: 0400

隐藏文件

. 开头的键会创建隐藏文件:

apiVersion: v1
kind: Secret
metadata:
name: dotfile-secret
data:
.hidden-file: c2VjcmV0
---
# 挂载后文件路径:/etc/secret/.hidden-file
# 需要使用 ls -la 才能看到

不可变 Secret

与 ConfigMap 一样,Secret 也支持不可变:

apiVersion: v1
kind: Secret
metadata:
name: immutable-secret
type: Opaque
stringData:
api-key: secret-api-key
immutable: true

ConfigMap 与 Secret 对比

特性ConfigMapSecret
数据大小限制1 MiB1 MiB
数据格式明文Base64 编码
存储安全不加密可启用加密
用途非敏感配置敏感数据
更新通知支持支持

使用原则

  • 不敏感的配置数据 → ConfigMap
  • 敏感数据(密码、密钥、令牌)→ Secret
  • 不确定是否敏感 → 使用 Secret

ResourceQuota(资源配额)

ResourceQuota 用于限制命名空间的资源使用总量,是多人共享集群时的重要管理工具。

创建 ResourceQuota

apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: production
spec:
hard:
# 计算资源
requests.cpu: "10"
requests.memory: 20Gi
limits.cpu: "20"
limits.memory: 40Gi

# 存储资源
requests.storage: 100Gi
persistentvolumeclaims: "10"

# 对象数量
pods: "50"
services: "10"
secrets: "20"
configmaps: "20"
replicationcontrollers: "10"

# 特定资源
count/deployments.apps: "10"
count/statefulsets.apps: "5"

查看配额使用情况

# 查看配额
kubectl get resourcequota -n production

# 查看详情
kubectl describe resourcequota compute-quota -n production

存储配额

apiVersion: v1
kind: ResourceQuota
metadata:
name: storage-quota
spec:
hard:
# 存储总量
requests.storage: "100Gi"

# PVC 数量
persistentvolumeclaims: "10"

# 特定 StorageClass 的存储
requests.storage.storageclass.storage.k8s.io/fast-storage: "50Gi"
persistentvolumeclaims.storageclass.storage.k8s.io/fast-storage: "5"

资源配额作用域

apiVersion: v1
kind: ResourceQuota
metadata:
name: scoped-quota
spec:
hard:
pods: "10"
cpu: "5"
scopeSelector:
matchExpressions:
- scopeName: PriorityClass
operator: In
values:
- high-priority

支持的 Scope

Scope说明
Terminatingspec.activeDeadlineSeconds 的 Pod
NotTerminating没有 spec.activeDeadlineSeconds 的 Pod
NotBestEffort有资源请求的 Pod
PriorityClass特定优先级的 Pod

LimitRange(限制范围)

LimitRange 为 Pod 或容器设置默认资源限制,确保所有工作负载都有资源约束。

创建 LimitRange

apiVersion: v1
kind: LimitRange
metadata:
name: resource-limits
spec:
limits:
# 容器默认值
- type: Container
max:
cpu: "2"
memory: 2Gi
min:
cpu: 100m
memory: 128Mi
default: # 默认 limits
cpu: 500m
memory: 512Mi
defaultRequest: # 默认 requests
cpu: 200m
memory: 256Mi
maxLimitRequestRatio:
cpu: 5 # limit/request 最大比例

Pod 级别限制

apiVersion: v1
kind: LimitRange
metadata:
name: pod-limits
spec:
limits:
- type: Pod
max:
cpu: "4"
memory: 4Gi

PVC 存储限制

apiVersion: v1
kind: LimitRange
metadata:
name: storage-limits
spec:
limits:
- type: PersistentVolumeClaim
max:
storage: 50Gi
min:
storage: 1Gi

默认行为

当 Pod 没有指定资源时:

  1. 使用 defaultRequest 作为 requests
  2. 使用 default 作为 limits
  3. 如果 Pod 指定了 limits 但没有 requests,requests 默认等于 limits
# Pod 没有指定资源
spec:
containers:
- name: app
image: nginx
# 没有资源配置

# 应用 LimitRange 后,相当于:
spec:
containers:
- name: app
image: nginx
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi

最佳实践

ConfigMap 使用建议

  1. 分离配置和代码:配置变化时无需重新构建镜像
  2. 使用不可变 ConfigMap:大规模集群中减少 API Server 负载
  3. 合理组织配置:按应用或服务分组
  4. 避免大文件:单个 ConfigMap 不超过 1 MiB

Secret 使用建议

  1. 启用静态加密:在 etcd 中加密存储 Secret
  2. 使用 RBAC 限制访问:只授予必要的 Secret 访问权限
  3. 考虑外部密钥管理:Vault、AWS Secrets Manager 等
  4. 不要将 Secret 提交到 Git:使用 GitOps 时特别注意
  5. 使用不可变 Secret:防止意外修改

资源管理建议

  1. 为每个命名空间设置 ResourceQuota
  2. 配置合理的 LimitRange 默认值
  3. 监控资源使用情况:及时发现超额问题
  4. 设置告警:资源使用接近配额时告警

配置管理工具

Kustomize

Kustomize 是 Kubernetes 原生的配置管理工具,无需模板引擎:

# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- deployment.yaml
- service.yaml

configMapGenerator:
- name: app-config
literals:
- LOG_LEVEL=info
files:
- config.properties

secretGenerator:
- name: db-credentials
literals:
- username=admin
- password=secret
type: Opaque

# 环境差异配置
images:
- name: my-app
newTag: v1.2.3

replicas:
- name: deployment
count: 3

目录结构

├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── production/
│ ├── kustomization.yaml
│ └── patches/
└── staging/
├── kustomization.yaml
└── patches/

Helm

Helm 是 Kubernetes 的包管理器,适合复杂应用:

# 安装 Helm
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# 添加仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

# 搜索 Chart
helm search repo nginx

# 安装 Chart
helm install my-nginx bitnami/nginx

# 自定义值安装
helm install my-nginx bitnami/nginx -f values.yaml

# 查看已安装的 Release
helm list

# 升级
helm upgrade my-nginx bitnami/nginx

# 回滚
helm rollback my-nginx 1

# 卸载
helm uninstall my-nginx

小结

本章我们学习了 Kubernetes 配置管理的核心概念:

  • ConfigMap:非敏感配置数据的存储和使用
  • Secret:敏感数据的安全存储
  • 不可变配置:提高安全性和性能
  • ResourceQuota:命名空间级别资源限制
  • LimitRange:默认资源配置
  • 配置工具:Kustomize 和 Helm

练习

  1. 创建一个 ConfigMap 并在 Pod 中使用环境变量和卷挂载两种方式读取
  2. 创建 Secret 存储数据库凭证,并在应用中使用
  3. 配置 ResourceQuota 限制命名空间的资源使用
  4. 使用 LimitRange 为命名空间设置默认资源限制
  5. 创建不可变的 ConfigMap 和 Secret

参考资源