配置管理
本章介绍 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 需要重启才能获取新值。
缓存类型:
通过 KubeletConfiguration 的 configMapAndSecretChangeDetectionStrategy 配置:
| 类型 | 说明 |
|---|---|
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 的步骤:
- 为 Secret 启用静态加密
- 启用 RBAC 规则限制 Secret 访问
- 限制 Secret 只能被特定命名空间访问
- 考虑使用外部密钥管理系统
Secret 类型
| 类型 | 用途 |
|---|---|
Opaque | 通用类型(默认) |
kubernetes.io/tls | TLS 证书 |
kubernetes.io/dockerconfigjson | Docker 仓库凭证 |
kubernetes.io/basic-auth | HTTP 基本认证 |
kubernetes.io/ssh-auth | SSH 认证 |
kubernetes.io/service-account-token | ServiceAccount 令牌 |
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 对比
| 特性 | ConfigMap | Secret |
|---|---|---|
| 数据大小限制 | 1 MiB | 1 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 | 说明 |
|---|---|
Terminating | 有 spec.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 没有指定资源时:
- 使用
defaultRequest作为 requests - 使用
default作为 limits - 如果 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 使用建议
- 分离配置和代码:配置变化时无需重新构建镜像
- 使用不可变 ConfigMap:大规模集群中减少 API Server 负载
- 合理组织配置:按应用或服务分组
- 避免大文件:单个 ConfigMap 不超过 1 MiB
Secret 使用建议
- 启用静态加密:在 etcd 中加密存储 Secret
- 使用 RBAC 限制访问:只授予必要的 Secret 访问权限
- 考虑外部密钥管理:Vault、AWS Secrets Manager 等
- 不要将 Secret 提交到 Git:使用 GitOps 时特别注意
- 使用不可变 Secret:防止意外修改
资源管理建议
- 为每个命名空间设置 ResourceQuota
- 配置合理的 LimitRange 默认值
- 监控资源使用情况:及时发现超额问题
- 设置告警:资源使用接近配额时告警
配置管理工具
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
练习
- 创建一个 ConfigMap 并在 Pod 中使用环境变量和卷挂载两种方式读取
- 创建 Secret 存储数据库凭证,并在应用中使用
- 配置 ResourceQuota 限制命名空间的资源使用
- 使用 LimitRange 为命名空间设置默认资源限制
- 创建不可变的 ConfigMap 和 Secret