【发布时间】:2015-08-10 05:21:03
【问题描述】:
我是 Docker 新手,不清楚如何从容器访问外部数据库。在连接字符串中硬编码是最好的方法吗?
# Dockerfile
ENV DATABASE_URL amazon:rds/connection?string
【问题讨论】:
标签: docker environment-variables dockerfile
我是 Docker 新手,不清楚如何从容器访问外部数据库。在连接字符串中硬编码是最好的方法吗?
# Dockerfile
ENV DATABASE_URL amazon:rds/connection?string
【问题讨论】:
标签: docker environment-variables dockerfile
您可以使用 -e 标志将环境变量传递给您的容器。
来自启动脚本的示例:
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
或者,如果您不希望在命令行上显示该值,ps 等将显示该值,-e 可以从当前环境中提取值,只要您提供它没有=:
sudo PASSWORD='foo' docker run [...] -e PASSWORD [...]
如果你有很多环境变量,特别是如果它们是保密的,你可以use an env-file:
$ docker run --env-file ./env.list ubuntu bash
--env-file 标志将文件名作为参数,并期望每一行都采用 VAR=VAL 格式,模仿传递给 --env 的参数。注释行只需要以#
为前缀
【讨论】:
export PASSWORD=foo,该变量将作为环境变量传递给docker run,使docker run -e PASSWORD工作。
-e 和Dockerfile 中的ENV 做同样的事情吗?
-e 值,否则不会引发错误,并且没有任何变量会有值!
【讨论】:
--env-file,当您使用--env 时,您的环境值将被引用/转义为您使用的任何shell 的标准语义,但是当使用--env-file 时,您将进入你的容器会有所不同。 docker run 命令只是读取文件,进行非常基本的解析并将值传递给容器,它并不等同于你的 shell 的行为方式。如果您要将一堆 --env 条目转换为 --env-file,请注意一个小问题。
如果您使用“docker-compose”作为启动容器的方法,实际上有一种有用的方法可以将服务器上定义的环境变量传递给 Docker 容器。
在您的 docker-compose.yml 文件中,假设您正在构建一个基本的 hapi-js 容器,代码如下所示:
hapi_server:
container_name: hapi_server
image: node_image
expose:
- "3000"
假设您的 docker 项目所在的本地服务器有一个名为“NODE_DB_CONNECT”的环境变量,您希望将其传递给您的 hapi-js 容器,并且您希望它的新名称为“HAPI_DB_CONNECT”。然后在docker-compose.yml 文件中,将本地环境变量传递给容器并重命名,如下所示:
hapi_server:
container_name: hapi_server
image: node_image
environment:
- HAPI_DB_CONNECT=${NODE_DB_CONNECT}
expose:
- "3000"
我希望这可以帮助您避免在容器中的任何文件中硬编码数据库连接字符串!
【讨论】:
使用-e 或--env 值设置环境变量(默认[])。
来自启动脚本的示例:
docker run -e myhost='localhost' -it busybox sh
如果您想从命令行使用多个环境,那么在每个环境变量之前使用 -e 标志。
例子:
sudo docker run -d -t -i -e NAMESPACE='staging' -e PASSWORD='foo' busybox sh
注意:确保将容器名称放在环境变量之后,而不是之前。
如果您需要设置许多变量,请使用--env-file 标志
例如,
$ docker run --env-file ./my_env ubuntu bash
如需任何其他帮助,请查看 Docker 帮助:
$ docker run --help
官方文档: https://docs.docker.com/compose/environment-variables/
【讨论】:
ubuntu bash?它适用于使用 ubuntu 作为基础镜像创建的镜像还是每个镜像?
bash 给你一个终端(虽然我认为你需要 -it 作为一个交互式终端)。
使用docker-compose,您可以继承 docker-compose.yml 中的环境变量以及随后由docker-compose 调用的任何 Dockerfile(s) 以构建映像。这在 Dockerfile RUN 命令应该执行特定于环境的命令时很有用。
(您的 shell 环境中已经存在 RAILS_ENV=development)
docker-compose.yml:
version: '3.1'
services:
my-service:
build:
#$RAILS_ENV is referencing the shell environment RAILS_ENV variable
#and passing it to the Dockerfile ARG RAILS_ENV
#the syntax below ensures that the RAILS_ENV arg will default to
#production if empty.
#note that is dockerfile: is not specified it assumes file name: Dockerfile
context: .
args:
- RAILS_ENV=${RAILS_ENV:-production}
environment:
- RAILS_ENV=${RAILS_ENV:-production}
Dockerfile:
FROM ruby:2.3.4
#give ARG RAILS_ENV a default value = production
ARG RAILS_ENV=production
#assign the $RAILS_ENV arg to the RAILS_ENV ENV so that it can be accessed
#by the subsequent RUN call within the container
ENV RAILS_ENV $RAILS_ENV
#the subsequent RUN call accesses the RAILS_ENV ENV variable within the container
RUN if [ "$RAILS_ENV" = "production" ] ; then echo "production env"; else echo "non-production env: $RAILS_ENV"; fi
这样,我就不需要在文件或docker-composebuild/up命令中指定环境变量:
docker-compose build
docker-compose up
【讨论】:
有一个很好的 hack 如何将主机环境变量通过管道传输到 docker 容器:
env > env_file && docker run --env-file env_file image_name
非常小心地使用这种技术,因为
env > env_file会将ALL 主机ENV 变量转储到env_file并使其在运行的容器中可访问。
【讨论】:
docker run --env-file =(env) image_name
我们还可以使用 -e 标志和 $ 来使用主机环境变量:
docker run -it -e MG_HOST=$MG_HOST \
-e MG_USER=$MG_USER \
-e MG_PASS=$MG_PASS \
-e MG_AUTH=$MG_AUTH \
-e MG_DB=$MG_DB \
-t image_tag_name_and_version
通过使用此方法,您可以使用您的给定名称自动设置环境变量。在我的情况下(MG_HOST,MG_USER)
如果您使用的是 python,您可以通过以下方式访问 docker 内的这些环境变量
import os
host = os.environ.get('MG_HOST')
username = os.environ.get('MG_USER')
password = os.environ.get('MG_PASS')
auth = os.environ.get('MG_AUTH')
database = os.environ.get('MG_DB')
【讨论】:
我遇到的问题是我将 --env-file 放在命令的末尾
docker run -it --rm -p 8080:80 imagename --env-file ./env.list
修复
docker run --env-file ./env.list -it --rm -p 8080:80 imagename
【讨论】:
另一种方法是使用/usr/bin/env的力量:
docker run ubuntu env DEBUG=1 path/to/script.sh
【讨论】:
对于 Amazon AWS ECS/ECR,您应该通过私有 S3 存储桶管理您的环境变量(尤其是机密)。请参阅博文 How to Manage Secrets for Amazon EC2 Container Service–Based Applications by Using Amazon S3 and Docker。
【讨论】:
如果你在本地有一个env.sh的环境变量,并且想在容器启动时设置它,你可以试试
COPY env.sh /env.sh
COPY <filename>.jar /<filename>.jar
ENTRYPOINT ["/bin/bash" , "-c", "source /env.sh && printenv && java -jar /<filename>.jar"]
此命令将使用 bash shell 启动容器(我想要一个 bash shell,因为 source 是一个 bash 命令),获取 env.sh 文件(设置环境变量)并执行 jar 文件。
env.sh 看起来像这样,
#!/bin/bash
export FOO="BAR"
export DB_NAME="DATABASE_NAME"
我添加了printenv 命令只是为了测试实际的源命令是否有效。当您确认源命令正常工作或环境变量将出现在您的 docker 日志中时,您可能应该将其删除。
【讨论】:
--env-file arg 指定给docker run 命令的选项。例如,如果您正在使用 Google 应用引擎部署应用程序,并且在容器内运行的应用程序需要在 docker 容器内设置环境变量,则您无法直接设置环境变量,因为您无法控制 @ 987654330@ 命令。在这种情况下,您可以有一个脚本,使用 KMS 解密 env 变量,并将它们添加到 env.sh 中,可用于设置 env 变量。
sh 中提供的POSIX .(点)命令,而不是source。 (source 与. 相同)
docker run --rm -it --env-file <(bash -c 'env | grep <your env data>')
是一种 grep 存储在 .env 中的数据并将它们传递给 Docker 的方法,而不会不安全地存储任何内容(因此您不能只查看 docker history 并获取密钥。
假设您的 .env 中有大量 AWS 内容,如下所示:
AWS_ACCESS_KEY: xxxxxxx
AWS_SECRET: xxxxxx
AWS_REGION: xxxxxx
使用docker run --rm -it --env-file <(bash -c 'env | grep AWS_') 运行 docker 将获取所有内容并将其安全传递,以便从容器内访问。
【讨论】:
使用 jq 将 env 转换为 JSON:
env_as_json=`jq -c -n env`
docker run -e HOST_ENV="$env_as_json" <image>
这需要 jq 版本 1.6 或更新版本
这将主机环境作为 json 推送,本质上就像在 Dockerfile 中一样:
ENV HOST_ENV (all env from the host as json)
【讨论】:
docker run -e HOST_ENV="$env_as_json" <image> ?在我的情况下,当作为 docker args 传递时,Docker 似乎没有解析变量或子 shell(${} 或 $())。例如:A=123 docker run --rm -it -e HE="$A" ubuntu 然后在该容器内:root@947c89c79397:/# echo $HE root@947c89c79397:/# .... HE 变量没有成功。
这是我解决它的方法
docker run --rm -ti -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e AWS_SECURITY_TOKEN amazon/aws-cli s3 ls
再举一个例子:
export VAR1=value1
export VAR2=value2
$ docker run --env VAR1 --env VAR2 ubuntu env | grep VAR
VAR1=value1
VAR2=value2
【讨论】: