docker-compose,容器启动后运行脚本?
Posted
技术标签:
【中文标题】docker-compose,容器启动后运行脚本?【英文标题】:docker-compose, run a script after container has started? 【发布时间】:2018-05-16 21:05:38 【问题描述】:我通过 docker-compose 通过 Rancher 提供了一项服务。我遇到的问题是我需要在容器部署后设置密码。
rancher secret 的工作方式是,我设置我的 secret,rancher 将在我的容器上安装一个卷,其中包含一个包含我的 secret 的文件。我希望能够执行一个脚本来获取该秘密,并将其设置为我的配置文件中的密码。
我不相信我有办法通过 Dockerfile 获取该秘密,因为我不希望秘密存在于 git 中,所以我只能通过 docker-compose 来实现。
有人知道这是否可行吗?
【问题讨论】:
当然,这是一种相当正常的设置机密的方式。只需将相关的 shell 脚本添加为(或添加到)您的 CMD 或 ENTRYPOINT。 要访问秘密而不暴露在 Dockerfile 中,您可以使用 .env 文件和 docker-compose :docs.docker.com/compose/environment-variables 【参考方案1】:您也可以使用卷来执行此操作:
services:
example:
image: <whatever>
volume: ./init.sh:/init.sh
entrypoint: sh -c "/init.sh"
请注意,这会将init.sh
挂载到容器,不复制它(如果这很重要,通常不会)。基本上容器内的进程可以修改init.sh
,它会修改文件,因为它存在于您的实际计算机中。
【讨论】:
【参考方案2】:这是我在容器启动后调用脚本而不覆盖入口点的方式。
在我的示例中,我使用它来初始化本地 MongoDB 的副本集
services:
mongo:
image: mongo:4.2.8
hostname: mongo
container_name: mongodb
entrypoint: ["/usr/bin/mongod","--bind_ip_all","--replSet","rs0"]
ports:
- 27017:27017
mongosetup:
image: mongo:4.2.8
depends_on:
- mongo
restart: "no"
entrypoint: [ "bash", "-c", "sleep 10 && mongo --host mongo:27017 --eval 'rs.initiate()'"]
在第一部分,我只是启动我的服务 (mongo)
第二个服务使用“bash”入口点和restart: no
重要
我还在服务和设置服务之间使用depends_on
来管理启动顺序。
【讨论】:
幸运的是,我正在尝试对 mongo 做同样的事情,并在这个线程中偶然发现了这个答案。谢谢!【参考方案3】:诀窍是在调用原始命令之前覆盖 compose COMMAND 以执行您需要的任何初始化操作。
-
在您的映像中添加一个脚本,该脚本将执行您想要的初始化工作,例如设置密码、更改内部配置文件等。我们称之为
init.sh
。您将其添加到您的图像中。
Dockerfile:
FROM: sourceimage:tag
COPY init.sh /usr/local/bin/
ENTRYPOINT []
以上内容覆盖了sourceimage
中定义的任何入口点。这是为了让这个例子更简单。确保您从sourceimage
了解 ENTRYPOINT 在 Dockerfile 中的作用,并在 docker-compose.yml 文件的 command:
中调用它。
docker-compose.yml:
services:
myservice:
image: something:tag
...
command: sh -c "/usr/local/bin/init.sh && exec myexecutable"
在调用主命令之前使用exec
很重要。这会将命令安装为第一个进程 (PID1),这将使其接收 STOP、KILL(键盘上的 Ctrl-C)或 HUP 等信号。
【讨论】:
执行这个会导致/usr/local/bin/docker-entrypoint.sh: line 172: /usr/local/bin/init.sh: No such file or directory
另外,删除命令的第一部分会导致错误exec: not found
@BurhanAli 我已经更新了答案以明确调用“shell -c”。此外,ENTRYPOINT
/CMD
(Dockerfile) 和 entrypoint:
/command:
(docker compose) 有许多不同的组合,它们可以相互覆盖。为了使这个答案简洁,我重置了 ENTRYPOINT 以便它不会覆盖command
。
@MurtazaHaji。在您的情况下,该行将是 command: sh -c "/usr/local/bin/init.sh && exec redid-server --deamonize yes
@aderchox 没错,command
会覆盖图片中的CMD
指令。但是,通过ENTRYPOINT
和CMD
组合得到最终的启动动作。因此,如果ENTRYPOINT
是例如["echo"]
,您可以将CMD
设置为"hello"
,这将打印“hello”。我相信这在历史上是为了便于指定不同的论点。 ENTRYPOINT
包含主可执行文件,CMD
包含传递给可执行文件的参数。您还可以将ENTRYPOINT
设置为一个空数组,以便CMD
或command
包含完整的启动操作行,就像我们上面所做的那样。【参考方案4】:
docker-compose 指定如何启动容器,而不是如何修改现有的正在运行的容器。
Rancher documentation 提到,对于秘密的默认用法,您可以在 docker-compose.yml
的秘密数组中按名称引用秘密。
目标文件名将与密钥名称相同。 默认情况下,目标文件名将创建为用户 ID 和组 ID 0,文件模式为 0444。 在 secrets 部分将 external 设置为 true 将确保它知道 secret 已经创建。
基本
docker-compose.yml
示例:
version: '2'
services:
web:
image: sdelements/lets-chat
stdin_open: true
secrets:
- name-of-secret
labels:
io.rancher.container.pull_image: always
secrets:
name-of-secret:
external: true
如“How to Update a Single Running docker-compose Container”中所示,更新容器将涉及“构建、终止和启动”序列。
docker-compose up -d --no-deps --build <service_name>
【讨论】:
以上是关于docker-compose,容器启动后运行脚本?的主要内容,如果未能解决你的问题,请参考以下文章