docker-compose 支持 init 容器吗?

Zha*_* Yi 46 docker docker-compose

init container这是 Kubernetes 中的一个很棒的功能,我想知道 docker-compose 是否支持它?它允许我在启动主应用程序之前运行一些命令。

我遇到了这个 PR https://github.com/docker/compose-cli/issues/1499,其中提到支持 init 容器。但我在他们的参考文献中找不到相关文档。

Zei*_*tor 66

这对我来说是一个发现,但是,是的,现在可以在docker-compose1.29 版本中使用 init 容器,正如您在问题中链接的 PR 中可以看到的那样。

与此同时,当我写下这些行时,似乎该功能还没有进入文档

您可以定义对其他容器的依赖关系,条件基本上是“当其他容器成功完成其工作时”。这为定义运行任何类型脚本的容器留出了空间,并在启动其他依赖容器之前完成这些容器的退出。

为了说明这一点,我制作了一个非常常见的场景的示例:启动数据库容器,确保数据库已启动并在启动应用程序容器之前初始化其数据。

注意:初始化数据库(至少就官方 mysql 镜像而言)不需要 init 容器,因此这个示例更多的是一个说明,而不是一个坚如磐石的典型工作流程。

完整的示例可在公共 github 存储库中找到,因此我将仅展示此答案中的要点。

让我们从撰写文件开始

---
x-common-env: &cenv
    MYSQL_ROOT_PASSWORD: totopipobingo

services:
    db:
        image: mysql:8.0
        command: --default-authentication-plugin=mysql_native_password
        environment:
            <<: *cenv
    init-db:
        image: mysql:8.0
        command: /initproject.sh
        environment:
            <<: *cenv
        volumes:
            - ./initproject.sh:/initproject.sh
        depends_on:
            db:
                condition: service_started
    my_app:
        build:
            context: ./php
        environment:
            <<: *cenv
        volumes:
            - ./index.php:/var/www/html/index.php
        ports:
            - 9999:80
        depends_on:
            init-db:
                condition: service_completed_successfully
Run Code Online (Sandbox Code Playgroud)

你可以看到我定义了3个服务:

  • 最先启动的数据库
  • 仅在数据库启动后启动的 init 容器。这个只运行一个脚本(见下文),一旦一切都初始化,该脚本就会退出
  • 应用程序容器仅在 init 容器成功完成其工作后才会启动。

initproject.sh容器运行的脚本对于db-init此演示来说非常基本,只需每 2 秒重试一次连接到数据库,直到成功或达到 50 次尝试的限制,然后创建一个数据库/表并插入一些数据:

#! /usr/bin/env bash

# Test we can access the db container allowing for start
for i in {1..50}; do mysql -u root -p${MYSQL_ROOT_PASSWORD} -h db -e "show databases" && s=0 && break || s=$? && sleep 2; done
if [ ! $s -eq 0 ]; then exit $s; fi

# Init some stuff in db before leaving the floor to the application
mysql -u root -p${MYSQL_ROOT_PASSWORD} -h db -e "create database my_app"
mysql -u root -p${MYSQL_ROOT_PASSWORD} -h db -e "create table my_app.test (id int unsigned not null auto_increment primary key, myval varchar(255) not null)"
mysql -u root -p${MYSQL_ROOT_PASSWORD} -h db -e "insert into my_app.test (myval) values ('toto'), ('pipo'), ('bingo')"
Run Code Online (Sandbox Code Playgroud)

应用程序容器的 Dockerfile 很简单(为 php 添加 mysqli 驱动程序),可以在示例存储库以及 php 脚本中找到,以通过http://localhost:9999在浏览器中调用来测试 init 是否成功。

有趣的部分是观察使用 启动服务时发生了什么docker-compose up -d

这种功能的唯一限制可能是您的想象力;)感谢您让我发现了这一点。

  • 很好的答案。让我能够规避 https://github.com/docker/compose/issues/3140 中描述的限制,现在我有了一个可靠的解决方案,可以在生成依赖于它的容器之前等待 Postgres DB 准备好。 (2认同)