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 &amp;&amp; exec redid-server --deamonize yes @aderchox 没错,command 会覆盖图片中的CMD 指令。但是,通过ENTRYPOINTCMD 组合得到最终的启动动作。因此,如果ENTRYPOINT 是例如["echo"],您可以将CMD 设置为"hello",这将打印“hello”。我相信这在历史上是为了便于指定不同的论点。 ENTRYPOINT 包含主可执行文件,CMD 包含传递给可执行文件的参数。您还可以将ENTRYPOINT 设置为一个空数组,以便CMDcommand 包含完整的启动操作行,就像我们上面所做的那样。【参考方案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,容器启动后运行脚本?的主要内容,如果未能解决你的问题,请参考以下文章

docker-compose教程(安装,使用, 快速入门)

docker及docker-compose于微服务的实践

无法从 docker-compose 启动 postgres docker 容器

Docker-Compose 安装

docker-compose命令在什么范围内运行

如何在系统启动时运行 docker-compose up -d?