docker-compose 是否支持初始化容器?

Does docker-compose support init container?

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

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

这对我来说是一个发现,但是是的,从 1.29 版开始,现在可以将初始化容器与 docker-compose 一起使用,如您在问题中链接的 PR 中所示。

与此同时,当我写下这些行时,似乎 this feature has not yet found its way to the documentation

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

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

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

complete example is available in a public github repo所以我只会在这个答案中展示重点。

让我们从撰写文件开始

---
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

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

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

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

#! /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')"

应用程序容器的 Dockerfile 很简单(为 php 添加 mysqli 驱动程序)并且可以在 example repo 和 php 中找到通过在浏览器中调用 http://localhost:9999 来测试 init 的脚本是否成功。

有趣的部分是观察使用 docker-compose up -d 启动服务时发生的情况。

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