exteon/docker-recipes

一个库,用于聚合多个Dockerfile的多阶段文件,并添加可重用模板

3.0.0 2022-07-09 18:54 UTC

This package is auto-updated.

Last update: 2024-09-16 02:11:25 UTC


README

允许合并 Dockerfiledocker-compose.yml 脚本的库,增加了docker脚本的模块化和可重用性

概念

模板

docker-recipes 的上下文中,模板是 Dockerfile 的一个片段,使用相同的语法,用于拼接最终 Dockerfile

一个模板可以需要多个其他模板。

Dockerfile

使用 docker-recipes,源 Dockerfile 是一个常规的 Dockerfile,增加了包含任何数量模板的语法。

docker-compose.yml

docker-recipes 提供了一种机制,可以将多个 docker-compose.yml 合并到一个目标 docker-compose.yml 中。同时,在 docker-compose.yml 中引用的模板 Dockerfile 将被管理,以便指向生成的合并 docker-compose.yml 中的生成 Dockerfile

AppEnv的

很多时候,一个应用程序可以在多个运行环境中运行。例如,它可以有一个 live 环境,具有最小的占用空间,以及一个 dev 环境,其中在容器中添加了多个调试工具(例如 xdebug)。

从 v3.0 开始,docker-recipes 提供了一种机制,可以指定 Dockerfile 模板以及 docker-compose 文件的 app-env。每个 Dockerfile 和 docker-compose 文件都与一个 app-env 相关联,基于目录结构确定(更多详细信息请参见 定位器)。

在编译 Dockerfile 和 docker-compose 文件时,可以提供一个 app-env 栈作为数组

  • 然后根据提供的 app-env 的顺序查找 Dockerfile(索引 0 优先)。
  • docker-compose 文件按照提供的 app-env 的逆序堆叠和合并(索引 0 在顶部)。

Dockerfile 组成和语法

Dockerfile 和模板中,要求另一个模板的语法是

#TEMPLATE[ template-name ]

-或-

#TEMPLATE[ app-env/template-name ]

也就是说,一个以注释开始的行,后面跟着一个单行注释井号,然后没有空格地跟着 TEMPLATE[。在方括号之间,提供模板名称,可能前面跟着 app-env 和一个斜杠。模板定位的机制请参见 定位器

该库的目的在于,对于每个源 Dockerfile,生成一个包含所有编译进来的模板的目标 Dockerfile

当一个模板被多次要求时(可能由多个不同的其他模板要求),它将被去重并只包含在编译的 Dockerfile 中一次;功能模板(可调用/可参数化)的概念尚未实现,但考虑在未来的版本中实现。

Dockerfile 模板/镜像中,例如,当你有一个 COPY 指令时,你需要模板目录的路径。为此,你需要使用 $TEMPLATE_DIR 变量,它将被编译成正确的路径,即

COPY $TEMPLATE_DIR/supervisord/supervisord.conf /etc/supervisord.conf

(参见此 示例模板)

docker-compose.yml 组成和语法

最终将生成一个 docker-compose.yml 文件,该文件是通过合并每个定位器返回的 docker-compose.yml 文件来生成的。没有特殊的语法,除非你需要引用最终运行 compose 的上下文的路径。这也被称为“项目路径”,并作为 $projectRoot 传递给 DockerComposeCompiler 构造函数(请参见 docker-compose 编译)。

要引用该目录,请在源代码中的 docker-compose.yml 文件中使用环境变量 ${PROJECT_DIR}

(参见此 示例)

定位器

镜像和模板通过名称引用。为了定位并将它们映射到源文件,使用一个或多个定位器。提供了一个标准定位器实现,包含类 StdDockerfileLocatorStdDockerComposeLocator,这些类接收一个根目录作为构造函数参数;每个根目录包含一系列模板和一系列镜像,在 StdDockerComposeLocator 的情况下,还包含零个或一个 docker-compose.yml 文件。

文件结构如下

<root_dir>
  ├ templates
  │  ├ template_name_1
  │  │  └ Dockerfile
  │  └ some_other_template
  │     └ Dockerfile
  ├ image_name_1
  │  └ Dockerfile
  ├ some_other_image
  │  └ Dockerfile
  └ docker-compose.yml

两个定位器之间的区别在于

  • StdDockerfileLocatorDockerfileCompiler 使用,并且只会处理镜像和模板
  • StdDockerComposeLocatorDockerComposeCompiler 使用,除了处理镜像和模板外,还会处理 docker-compose.yml 文件。

如果您需要不同的目录结构,可以创建自定义定位器,实现 DockerComposeLocatorDockerfileLocator 接口。

AppEnv 的目录结构

上述目录结构适用于默认的 '' (空白) app-env。对于使用多个 app-env,目录结构将如下所示

<root_dir>
  ├ common
  │  ├ templates
  │  │  ├ template_name_1
  │  │  │  └ Dockerfile
  │  │  └ some_other_template
  │  │     └ Dockerfile
  │  ├ image_name_1
  │  │ └ Dockerfile
  │  ├ some_other_image
  │  │  └ Dockerfile
  │  └ docker-compose.yml
  ├ live
  │  ├ templates
  │  │  └ template_name_1
  │  │     └ Dockerfile
  │  └ docker-compose.yml
  └ dev
     └ docker-compose.yml

然后当使用 ['live', 'common'] 作为实例的 app-env 链时,则

  • 当在未指定 app-env 的 #TEMPALTE[ ] 标签中引用时,或在 docker-compose 文件中引用时,模板和镜像将首先在 live 中查找,然后在 common 目录中查找
  • common/docker-compose.ymllive/docker-compose.yml 将按此顺序合并。

Dockerfile 编译

从模板编译镜像是通过 DockerfileCompiler 完成的,其实例化方式如下

/**
 * @param DockerfileLocator[] $locators
 * @param string $targetDir
 * @param string[] $appEnv
 */
public function __construct(
   array $locators,
   string $targetDir,
   array $appEnv = ['']
)

$targetDir 是编译后的镜像文件将要写入的目标目录。

要编译镜像,您使用

/** @var \Exteon\DockerRecipes\DockerfileCompiler $compiler */
$compiler->compile();

这将生成一个目标目录,对于上述示例源目录,将生成

<target_dir>
  ├ image_name_1
  │  └ Dockerfile
  └ some_other_image
     └ Dockerfile

因此,对于每个源镜像,都会从模板编译出目标镜像。

docker-compose 编译

使用 DockerComposeCompiler 编译 docker-compose 脚本,它从定位器的 docker-compose.yml 文件编译出镜像(与 DockerfileCompiler 相同)和一个 docker-compose.yml 文件。它的实例化方式如下

/**
 * @param DockerComposeLocator[] $locators
 * @param string $dockerfilesTargetDir
 * @param string $composeFileTargetPath
 * @param string $projectRoot
 * @param string[] $appEnv
 */
public function __construct(
    array $locators,
    string $dockerfilesTargetDir,
    string $composeFileTargetPath,
    string $projectRoot,
    array $appEnv = ['']
)

$dockerfilesTargetDir 是编译后的镜像的目标目录。有关更多信息,请参阅 Dockerfile 编译

$composeFileTargetPath 是要编译的 docker-compose.yml 文件的目标路径。

$projectRoot 是用于在 docker-compose.yml 文件中替换 ${PROJECT_DIR} 的目录的路径。

$appEnv 是用于组合文件的 app-env 堆栈顺序。

要编译图像/组合文件,您使用

/** @var \Exteon\DockerRecipes\DockerComposeCompiler $compiler */
$compiler->compile();

当从多个来源(提供多个 docker-compose.yml 的多个定位器)编译 docker-compose.yml 时,目标文件将使用以下算法从所有源文件合并:递归地,对于 yml 文件中的所有字符串键,值将被合并(如果为标量则被覆盖)。对于所有顺序数组,内容将被附加。

示例

毕竟“熟能生巧”,您可以查看example目录中的示例,了解如何使用模板编译一个包含Web服务器的CentOS8镜像,这些模板可以用于构建其他不同的镜像(例如supervisor-rhel8模板)。

要运行示例,只需在命令行中运行php example.php。生成的centos8-web镜像配方将位于example/target,而docker-compose文件位于example/docker-compose.yml。要构建和运行容器,请在example目录下运行composer up -d