docker-compose,在容器启动后运行脚本?

Blo*_*oze 20 docker dockerfile docker-compose rancher

我有一个服务,我通过牧场主通过docker-compose提出.我遇到的问题是我需要在部署容器后设置密码.

牧场主秘密工作的方式是,我设置我的秘密,牧场主将在我的容器上装载一个包含我的秘密的文件.我希望能够执行一个脚本来获取该秘密,并将其设置为我的配置文件中的密码.

我不相信我有办法通过Dockerfile获取秘密,因为我不想让秘密存在于git中,所以我只是想通过docker-compose来做这件事.

有谁知道这是否可能?

小智 28

这是我在容器启动后调用脚本而不覆盖入口点的方式。

在我的示例中,我使用它来初始化本地 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()'"]      
Run Code Online (Sandbox Code Playgroud)
  • 在第一部分,我只是启动我的服务 (mongo)
  • 第二个服务使用“bash”入口点和restart: no<= important

我还使用depends_on服务和设置服务之间的服务来管理启动顺序。

  • 这种方法看起来很有趣,但对我来说提出了一些问题。首先,为什么要使用“mongo”镜像作为“mongosetup”容器?任何图像都可以吗?或者它应该是“mongo”,这一点很重要吗?其次,你说设置 `restart: no` 很重要,但为什么呢?那么该设置不会被执行多次吗?最后,我看到“睡眠 10”?那是为了给mongo时间来初始化吗?使用“睡眠”似乎很棘手...... (3认同)

Ber*_*ard 12

诀窍是在调用原始命令之前,覆盖撰写COMMAND以执行所需的任何初始化操作。

  1. 在图像中添加一个脚本,该脚本将执行您想要的初始化工作,例如设置密码,更改内部配置文件等。我们称之为init.sh。您将其添加到您的图像。

Dockerfile:

FROM: sourceimage:tag
COPY init.sh /usr/local/bin/
Run Code Online (Sandbox Code Playgroud)
  1. 现在在您的docker compose文件中,只需在执行容器main操作之前调用该初始化脚本即可。

docker-compose.yml:

services:
  myservice:
    image: something:tag
    ...
    command: /usr/local/bin/init.sh && exec the_original_command_goes_here
Run Code Online (Sandbox Code Playgroud)

exec在调用main命令之前使用它很重要。这会将命令安装为第一个进程(PID1),这将使其接收停止或终止之类的信号。

  • 执行此操作将导致`/usr/local/bin/docker-entrypoint.sh:第172行:/usr/local/bin/init.sh:没有这样的文件或目录` (3认同)
  • @BurhanAli我已经更新了答案以明确调用“shell -c”。此外,`ENTRYPOINT`/`CMD` (Dockerfile) 和 `entrypoint:`/`command:`(docker compose) 有许多不同的组合,可以相互覆盖。为了保持这个答案简洁,我重置了 ENTRYPOINT,以便它不会覆盖“命令”。 (3认同)
  • @aderchox 这是正确的,“command”将覆盖图像中的“CMD”指令。然而,最终的启动动作是通过组合`ENTRYPOINT`和`CMD`来获得的。因此,如果`ENTRYPOINT`是例如`["echo"]`,您可以将`CMD`设置为`"hello"`,这将打印“hello”。我相信历史上这样做是为了允许轻松指定不同的参数。“ENTRYPOINT”包含主可执行文件,“CMD”包含传递给可执行文件的参数。您还可以将“ENTRYPOINT”设置为空数组,以便“CMD”或“command”包含完整的启动操作行,就像我们上面所做的那样。 (3认同)
  • 此外,删除命令的第一部分会导致错误 `exec: not found` (2认同)

Asa*_*han 5

您还可以使用卷来执行此操作:

services:
  example:
    image: <whatever>
    volume: ./init.sh:/init.sh
    entrypoint: sh -c "/init.sh"
Run Code Online (Sandbox Code Playgroud)

请注意,这将挂载init.sh到容器,而不是复制它(如果这很重要,通常不会)。基本上容器内的进程可以修改init.sh,它会修改文件,因为它存在于您的实际计算机中。


Von*_*onC 2

docker-compose 指定如何启动容器,而不是如何修改现有正在运行的容器。

Rancher文档提到,对于秘密的默认使用,您可以在docker-compose.yml.

目标文件名将与密钥名称相同。
默认情况下,目标文件名将创建为用户 ID 和组 ID 0,文件模式为 0444。
在机密部分将 external 设置为 true 将确保它知道机密已经创建。

基本示例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
Run Code Online (Sandbox Code Playgroud)

如“如何更新单个正在运行的 docker-compose 容器”中所示,更新容器将涉及“构建、终止和启动”序列。

docker-compose up -d --no-deps --build <service_name>
Run Code Online (Sandbox Code Playgroud)