所以我在这个问题上停留了很长时间。
我知道我们应该这样编写代码,以便在任何时候都可以使项目开源,而不会影响机密性。
因此,我似乎理解不建议直接在Dockerfile或docker-compose.yml中定义环境变量,而应该在一个单独的文件(例如 .env)中定义所有这些变量。 strong>。
现在,我知道在处理docker-compose时可以使用docker-compose -f docker-compose.yml --env-file=.env up
。
我想知道以下两件事:
--env-file
)有人也可以评论以下内容(使用Dockerfile)
example_Dockerfile :
FROM python:latest
# many other steps in between
RUN printf 'key=21345' > config
ENTRYPOINT ["./boot.sh"]
构建和运行的步骤:
docker build -f example_Dockerfile -t my_container .
docker run --env-file=example.env my_container
我知道方法1是正确的,但我想知道是否可以完成类似方法2的操作(如下)。
example_Dockerfile :
FROM python:latest
# many other steps in between
RUN printf 'key=${KEY}' > config
ENTRYPOINT ["./boot.sh"]
example.env :
# many other environment variables
KEY = 21345
如果您还可以提供命令步骤来构建并运行此方法中的容器来做到这一点,那就太棒了。
这两种方法的主要区别在于,在方法2中,我在 .env 文件中定义了 KEY 变量,并希望以某种方式将其集成到 Dockerfile (就像在 docker-compose.yml 中一样使用${KEY}
),而在 Dockerfile 中没有提及该值>
如果有人可以通过举例说明上述两点,我将不胜感激。
非常感谢高级
。答案 0 :(得分:0)
此用例有两个方面:
docker build
期间,它们未打包在最终映像中。有关更多信息,请检查此link。
docker build --build-arg VAR_A=val_a -f Dockerfile .
FROM python:3.7-slim
ARG VAR_A
RUN echo $VAR_A
ENV
指令安全地打包它们 [Bonus Tip] -最好避免在Dockerfile中将latest
图像标签与FROM
指令一起使用,因为这会导致难以跟踪正在运行的图像版本回滚。
答案 1 :(得分:0)
我的一般经验是,最好使用环境变量进行设置(可以(或应该或必须)在运行时更改),但是比其他机制(如命令行参数或配置文件)更好。这包括诸如您依赖的其他服务的主机名之类的东西。典型的最小docker-compose.yml
设置可能类似于:
version: '3.8'
services:
app:
build: .
ports: ['8080:8080']
environment:
- REDIS_HOST=redis
- PUBLIC_URL=http://example.com/
redis:
image: redis:6.0
我倾向于最小化Dockerfile中的环境变量。您暗示问题中存在一些保密问题;拥有图像的任何人都可以docker inspect
或docker run --rm imagename env
并将其转储出去,而不管它们是如何添加的;构建时的.env
文件无济于事。在其他SO问题中,我看到了用于文件系统路径或端口的变量,但这些变量无需在运行时更改。
# Avoid setting filesystem paths or ports as environment variables:
ENV APP_DIR=/app
COPY . $APP_DIR
RUN chmod +x $APP_DIR/entrypoint.sh
ENV PORT=8080
EXPOSE $PORT
# It's fine to hard-code these values, and use relative paths:
WORKDIR /app
COPY . .
RUN chmod +x entrypoint.sh
EXPOSE 8080
# No matter what, the container will always be run as
docker run -v $PWD/data:/app/data -p 8080:8080 imagename
# and changing the build-time environment variables has no effect
从样式上讲,使Dockerfile尽可能简单(但没有更简单)会更好。如果您有带有固定键和固定值的配置文件,请不要尝试在Dockerfile中生成它。直接将其维护在磁盘上,如果对您而言有意义,则可以使用其他名称。
# Don't RUN echo ... > file; instead just
COPY config.docker.yaml ./config.yaml
另一面是不需要设置环境变量,因此您需要容忍一些未设置的事情。我发现有用的模式是猜测,如果一个程序直接运行,则是由开发人员手动配置的,如果它是在容器中运行,则诸如Compose或Kubernetes的自动化将提供环境变量。
# Check that $PUBLIC_URL is set
public_url = os.environ.get('PUBLIC_URL')
if public_url is None:
print('Please set $PUBLIC_URL environment variable')
os.exit(1)
# Get the Redis host, or assume a developer environment
redis_host = os.environ.get('REDIS_HOST', 'localhost')
我预先说过,与配置文件相比,我更喜欢直接使用环境变量。示例1和2的输出是相同的,因为配置文件在生成时是固定的。如果需要基于环境变量重新创建配置文件,则必须在容器启动时在入口点脚本中执行此操作。一个典型的示例可能使用GNU envsubst工具(不会在基于Alpine的映像上预安装)来重写它:
#!/bin/sh
# Rewrite the config file
envsubst < config.tmpl > config
# Switch over to the main container process
exec "$@"
# ENTRYPOINT _must_ be JSON-array syntax for this
ENTRYPOINT ["./entrypoint.sh"]
CMD ["./boot.sh"]
envsubst
替换了文件中的外壳样式$ENVIRONMENT_VARIABLE
引用,因此此处的config.tmpl
文件看起来像
key=$KEY