【问题标题】:docker-compose, run a script after container has started?docker-compose,容器启动后运行脚本?
【发布时间】: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

标签: docker docker-compose dockerfile rancher


【解决方案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 以执行您需要的任何初始化操作。

    1. 在您的映像中添加一个脚本,该脚本将执行您想要的初始化工作,例如设置密码、更改内部配置文件等。我们称之为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>
    

    【讨论】:

      猜你喜欢
      • 2016-01-05
      • 1970-01-01
      • 2021-12-13
      • 2018-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多