6月5日 22:29

Docker 容器配置怎么管理?环境变量、挂载和配置中心怎么选

Docker 容器的配置管理不是把配置写死在镜像里——那样每次改配置都得重新构建。正确做法是配置与镜像分离,容器启动时注入配置,运行时能动态更新。这篇讲清楚 Docker 环境下四种配置管理方式的适用场景和实现方法。

环境变量:最简单的配置注入

适合少量、扁平的配置项(数据库地址、端口、开关):

yaml
# docker-compose.yml services: app: image: myapp:latest environment: - DB_HOST=postgres - DB_PORT=5432 - LOG_LEVEL=info - FEATURE_FLAG=true

或者用 .env 文件:

bash
# .env DB_HOST=postgres DB_PORT=5432 LOG_LEVEL=info
yaml
services: app: env_file: .env

优势:简单、Docker 原生支持、docker-compose 直接读取 局限:只有字符串值、不能表示嵌套结构、修改需要重启容器

敏感信息别放环境变量

环境变量会被 docker inspect 暴露,也会出现在进程列表里。密码、密钥等用 Docker Secret 或文件挂载:

bash
# Docker Swarm Secret echo "my_password" | docker secret create db_password -
yaml
services: app: secrets: - db_password secrets: db_password: external: true

配置文件挂载:复杂配置的首选

当配置是结构化的(YAML、JSON、TOML),用 Volume 挂载比环境变量更合适:

yaml
services: app: image: myapp:latest volumes: - ./config/app.yml:/app/config/app.yml:ro - ./config/nginx.conf:/etc/nginx/conf.d/default.conf:ro

:ro 表示只读挂载——容器不能修改配置文件,只能读取。防止容器内进程意外修改配置。

只挂载需要的文件,别挂载整个目录

yaml
# 好:只挂载需要的文件 volumes: - ./config/app.yml:/app/config/app.yml:ro # 差:挂载整个目录,可能暴露无关文件 volumes: - ./config:/app/config:ro

配置热更新:不重启容器更新配置

挂载的文件修改后,容器内立即可见——但应用是否自动重新加载取决于应用本身:

  • Nginxdocker exec nginx nginx -s reload
  • Spring Boot:配合 Spring Cloud Config 自动刷新
  • Node.js:用 chokidar 监听文件变化

如果应用不支持热加载,可以配合 inotifywait 检测文件变化后发送信号:

bash
#!/bin/bash inotifywait -m -e modify /app/config/app.yml | while read event; do kill -SIGHUP 1 # 发送 HUP 信号给主进程 done

配置中心:分布式系统的统一配置

多服务、多实例的场景,配置文件挂载管理成本太高——改一个配置要同步到所有机器。配置中心解决的就是这个问题。

Consul + Consul-Template

yaml
# docker-compose.yml services: consul: image: consul:1.15 ports: - "8500:8500" command: agent -dev -client=0.0.0.0 app: image: myapp:latest volumes: - ./templates:/templates command: > consul-template -consul-addr=consul:8500 -template="/templates/app.ctmpl:/app/config/app.yml:docker restart app"

consul-template 监听 Consul KV 变化,自动重新生成配置文件并触发容器重启。

Etcd + Confd

和 Consul-Template 类似的模式,Etcd 做存储,Confd 做模板渲染:

bash
# 写入配置 etcdctl set /myapp/db_host "postgres.prod" # confd 读取 etcd 并渲染模板 confd -onetime -backend etcd -node http://etcd:2379

Spring Cloud Config Server

Java 生态的标准方案:

yaml
services: config-server: image: springcloud/configserver ports: - "8888:8888" environment: - SPRING_CLOUD_CONFIG_SERVER_GIT_URI=https://github.com/org/config-repo app: image: my-spring-app environment: - SPRING_CLOUD_CONFIG_URI=http://config-server:8888

配置存在 Git 仓库里,有版本历史。应用启动时从 Config Server 拉取配置,配合 /actuator/refresh 端点实现热更新。

Kubernetes ConfigMap 和 Secret

如果跑在 K8s 上,环境变量和文件挂载都由 ConfigMap/Secret 管理:

yaml
# ConfigMap apiVersion: v1 kind: ConfigMap metadata: name: app-config data: DB_HOST: postgres app.yml: | server: port: 8080 logging: level: info --- # Pod 使用 ConfigMap apiVersion: v1 kind: Pod spec: containers: - name: app envFrom: - configMapRef: name: app-config volumeMounts: - name: config mountPath: /app/config volumes: - name: config configMap: name: app-config

Secret 和 ConfigMap 用法一样,但值是 base64 编码的,且访问可以加 RBAC 控制:

bash
kubectl create secret generic db-credentials \ --from-literal=username=admin \ --from-literal=password=s3cret

ConfigMap/Secret 更新后 Pod 不会自动重启——需要手动 kubectl rollout restart 或用 Reloader 之类的工具自动触发。

选择决策

场景推荐方案原因
单容器、少量配置环境变量 + .env最简单
单容器、复杂配置Volume 挂载配置文件支持结构化配置
多容器、同一台主机docker-compose + 挂载compose 管理方便
多主机、多服务Consul/Etcd 配置中心统一管理、动态更新
Kubernetes 环境ConfigMap + SecretK8s 原生方案
敏感信息Docker Secret / K8s Secret不暴露在环境变量里

原则:配置与代码分离,敏感信息加密,变更可追溯。能用简单的就不用复杂的——别为了用 Consul 而用 Consul。

标签:Docker