如何向Docker容器传递环境变量
技术背景
在使用Docker容器时,常常需要为容器设置环境变量,以满足不同的配置需求。例如,设置数据库连接信息、API密钥等。环境变量的传递可以让容器在不同的环境中灵活运行,避免硬编码配置信息。
实现步骤
使用 -e
或 --env
标志
可以使用 -e
(--env
的别名)标志将环境变量传递给容器。例如:
具体示例:
1 2 3 4 5 6 7 8 9
| sudo docker run -d -t -i -e REDIS_NAMESPACE='staging' \ -e POSTGRES_ENV_POSTGRES_PASSWORD='foo' \ -e POSTGRES_ENV_POSTGRES_USER='bar' \ -e POSTGRES_ENV_DB_NAME='mysite_staging' \ -e POSTGRES_PORT_5432_TCP_ADDR='docker-db-1.hidden.us-east-1.rds.amazonaws.com' \ -e SITE_URL='staging.mysite.com' \ -p 80:80 \ --link redis:redis \ --name container_name dockerhub_id/image_name
|
如果不想在命令行中显示环境变量的值,可以直接使用 -e
引用当前环境中的变量:
1
| sudo PASSWORD='foo' docker run [...] -e PASSWORD [...]
|
使用 --env-file
标志
当有许多环境变量,尤其是需要保密的变量时,可以使用 --env-file
:
1
| docker run --env-file ./env.list ubuntu bash
|
--env-file
标志接受一个文件名作为参数,要求每行格式为 VAR=VAL
。
在 docker-compose.yml
中传递环境变量
如果使用 docker-compose
,可以在 docker-compose.yml
文件中传递环境变量。例如,将本地环境变量 NODE_DB_CONNECT
传递给容器并重命名为 HAPI_DB_CONNECT
:
1 2 3 4 5 6 7
| hapi_server: container_name: hapi_server image: node_image environment: - HAPI_DB_CONNECT=${NODE_DB_CONNECT} expose: - "3000"
|
继承环境变量
在 docker-compose.yml
和 Dockerfile
中可以继承环境变量。示例如下:
docker-compose.yml:
1 2 3 4 5 6 7 8 9
| version: '3.1' services: my-service: build: context: . args: - RAILS_ENV=${RAILS_ENV:-production} environment: - RAILS_ENV=${RAILS_ENV:-production}
|
Dockerfile:
1 2 3 4 5 6
| FROM ruby:2.3.4
ARG RAILS_ENV=production ENV RAILS_ENV $RAILS_ENV
RUN if [ "$RAILS_ENV" = "production" ] ; then echo "production env"; else echo "non-production env: $RAILS_ENV"; fi
|
核心代码
使用 -e
传递多个环境变量
1
| sudo docker run -d -t -i -e NAMESPACE='staging' -e PASSWORD='foo' busybox sh
|
使用 --env-file
传递环境变量
1
| docker run --env-file ./my_env ubuntu bash
|
在 docker-compose.yml
中传递环境变量
1 2 3 4 5 6 7
| hapi_server: container_name: hapi_server image: node_image environment: - HAPI_DB_CONNECT=${NODE_DB_CONNECT} expose: - "3000"
|
最佳实践
- 使用
--env-file
:当有大量环境变量或敏感信息时,使用 --env-file
可以更好地组织和管理环境变量。 - 使用
docker-compose
:对于复杂的应用,使用 docker-compose
可以更方便地管理多个容器的环境变量。 - 避免硬编码:尽量避免在容器内硬编码环境变量,而是通过传递环境变量的方式进行配置。
常见问题
docker run
中引号问题
docker run
子命令不接受格式为有效BASH脚本的 env
文件,会将引号视为环境变量值的一部分。可以使用以下解决方案:
- 创建
Dockerfile
:
1 2 3 4 5 6 7
| FROM python:3.10-slim-buster WORKDIR /some-name COPY . /some-name/ RUN apt-get -y update \ && apt-get -y upgrade \ [...] ENTRYPOINT bash entrypoint.bash
|
- 创建
env
文件(.env
):
1 2 3 4 5
| #!/bin/bash
SOME_ENV_VAR_A="some value a" SOME_ENV_VAR_B="some value b" SOME_ENV_VAR_C="some value c"
|
- 创建
ENTRYPOINT
的BASH脚本文件(entrypoint.bash
):
1 2 3 4
| #!/bin/bash
set -a;source <(echo -n "$ENV_VARS");set +a python main.py
|
- 使用
run
子命令注入环境变量:
1
| docker run -it --name "some-ctn-name" --env ENV_VARS="$(cat ./.env)" "some-img-name:Dockerfile"
|
--env
标志错误
如果遇到 unknown flag: --env
错误,可以使用等号 --env=key=value
。
--env-file
位置问题
--env-file
应放在 docker run
命令中选项部分,而不是放在命令末尾。例如:
1 2 3 4
| docker run -it --rm -p 8080:80 imagename --env-file ./env.list
docker run --env-file ./env.list -it --rm -p 8080:80 imagename
|