构建镜像¶
在深入了解 Airflow 镜像的构建方式之前,让我们首先解释一下为什么您可能需要构建自定义容器镜像,并展示一些您可以执行此操作的典型方法。
镜像扩展的快速入门场景¶
您想要构建自己的镜像的最常见场景是添加新的 apt
包、添加新的 PyPI
依赖项(单独添加或通过 requirements.txt 添加)以及将 DAG 嵌入到镜像中。
下面是这些场景的 Dockerfile 示例,您可以进一步阅读,了解可能涉及扩展或自定义镜像的更复杂的情况。您将在下面找到有关更复杂场景的更多信息,但如果您的目标是使用新的提供程序、包等快速扩展 Airflow 镜像,那么这里有一个快速入门指南。
添加新的 apt
包¶
以下示例将 vim
添加到 Airflow 镜像。当通过 apt
添加包时,您应该在运行 apt
命令时切换到 root
用户,但不要忘记在安装完成后切换回 airflow
用户。
docs/docker-stack/docker-examples/extending/add-apt-packages/Dockerfile
FROM apache/airflow:2.10.4
USER root
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
vim \
&& apt-get autoremove -yqq --purge \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
USER airflow
单独添加新的 PyPI
包¶
以下示例将 PyPI 中的 lxml
python 包添加到镜像。当通过 pip
添加包时,您需要使用 airflow
用户而不是 root
。尝试以 root
身份安装 pip
包将失败,并显示相应的错误消息。
注意
在下面的示例中,我们还添加了要安装的 apache-airflow 包 - 与您使用的镜像版本相同的版本。这不是绝对必要的,但始终安装与您正在使用的 apache-airflow 版本相同的版本是一个好习惯。这样,您可以确保您使用的版本与您正在扩展的版本相同。在某些情况下,当您的新包具有冲突的依赖项时,pip
可能会决定为您降级或升级 apache-airflow,因此显式添加它是一个好习惯 - 这样,如果您的需求存在冲突,您将收到包含冲突信息的错误消息,而不是意外地降级或升级 airflow。如果您升级了 airflow 基础镜像,您还应该更新版本以匹配新的 airflow 版本。
注意
创建自定义镜像意味着您还需要维护一定程度的自动化,因为当您要安装的包或 Airflow 升级时,您需要重新创建镜像。请不要忘记保留这些脚本。另请记住,在运行纯 Python 任务时,您可以使用 Python Virtualenv 函数,该函数将在运行时动态地获取和安装 python 依赖项。使用 Airflow 2.8.0,Virtualenvs 也可以缓存。
docs/docker-stack/docker-examples/extending/add-pypi-packages/Dockerfile
FROM apache/airflow:2.10.4
RUN pip install --no-cache-dir "apache-airflow==${AIRFLOW_VERSION}" lxml
从 requirements.txt 添加包¶
以下示例从 PyPI 的 requirements.txt
文件中添加了一些 python 包到镜像。请注意,与添加单个包类似,您需要使用 airflow
用户而不是 root
。尝试以 root
身份安装 pip
包将失败,并显示相应的错误消息。
注意
在下面的示例中,我们还添加了要安装的 apache-airflow 包 - 与您使用的镜像版本相同的版本。这不是绝对必要的,但始终安装与您正在使用的 apache-airflow 版本相同的版本是一个好习惯。这样,您可以确保您使用的版本与您正在扩展的版本相同。在某些情况下,当您的新包具有冲突的依赖项时,pip
可能会决定为您降级或升级 apache-airflow,因此显式添加它是一个好习惯 - 这样,如果您的需求存在冲突,您将收到包含冲突信息的错误消息,而不是意外地降级或升级 airflow。如果您升级了 airflow 基础镜像,您还应该更新版本以匹配新的 airflow 版本。
docs/docker-stack/docker-examples/extending/add-requirement-packages/Dockerfile
FROM apache/airflow:2.10.4
COPY requirements.txt /
RUN pip install --no-cache-dir "apache-airflow==${AIRFLOW_VERSION}" -r /requirements.txt
docs/docker-stack/docker-examples/extending/add-requirement-packages/requirements.txt
lxml
beautifulsoup4
嵌入 DAG¶
以下示例将 test_dag.py
添加到镜像中的 /opt/airflow/dags
文件夹中。
docs/docker-stack/docker-examples/extending/embedding-dags/Dockerfile
FROM apache/airflow:2.10.4
COPY --chown=airflow:root test_dag.py /opt/airflow/dags
import datetime
import pendulum
from airflow.models.dag import DAG
from airflow.operators.empty import EmptyOperator
now = pendulum.now(tz="UTC")
now_to_the_hour = (now - datetime.timedelta(0, 0, 0, 0, 0, 3)).replace(minute=0, second=0, microsecond=0)
START_DATE = now_to_the_hour
DAG_NAME = "test_dag_v1"
dag = DAG(
DAG_NAME,
schedule="*/10 * * * *",
default_args={"depends_on_past": True},
start_date=pendulum.datetime(2021, 1, 1, tz="UTC"),
catchup=False,
)
run_this_1 = EmptyOperator(task_id="run_this_1", dag=dag)
run_this_2 = EmptyOperator(task_id="run_this_2", dag=dag)
run_this_2.set_upstream(run_this_1)
run_this_3 = EmptyOperator(task_id="run_this_3", dag=dag)
run_this_3.set_upstream(run_this_2)
使用环境变量添加 Airflow 配置¶
以下示例将 airflow 配置添加到镜像。$AIRFLOW_HOME
目录中的 airflow.cfg
文件包含 Airflow 的配置。您可以通过使用此格式为那些 Airflow 配置设置环境变量中的选项:AIRFLOW__{SECTION}__{KEY}
(请注意双下划线)。
docs/docker-stack/docker-examples/extending/add-airflow-configuration/Dockerfile
FROM apache/airflow:2.10.4
ENV AIRFLOW__CORE__LOAD_EXAMPLES=True
ENV AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=my_conn_string
扩展与自定义镜像¶
您可能想快速了解您是需要扩展还是自定义 Apache Airflow 的现有镜像。本章为您提供了这些问题的简短答案。
以下是两种方法的比较
扩展 |
自定义 |
|
---|---|---|
使用熟悉的镜像构建“FROM”模式 |
是 |
否 |
仅需要关于镜像的基本知识 |
是 |
否 |
构建速度快 |
是 |
否 |
生成针对大小进行了高度优化的镜像 |
否 |
是 |
可以从自定义 airflow 源(分支)构建 |
否 |
是 |
可以在气隙系统上构建 |
否 |
是 |
TL;DR;如果您需要构建自定义镜像,则从“扩展”开始更容易。但是,如果您的依赖项需要编译步骤,或者当您需要从安全审查过的包构建镜像时,切换到“自定义”镜像可以提供更加优化的镜像。例如,如果我们比较通过“扩展”和“自定义”构建的等效镜像,它们的最终大小分别为 1.1GB 和 874MB - 自定义镜像的大小提高了 20%。
注意
您还可以将两者结合起来 - 在一个中自定义和扩展镜像。您可以先使用 customization
方法(例如由您的管理员团队)构建优化的基础镜像,其中包含所有需要大量编译的依赖项,您可以将其发布到您的注册表中,并让其他用户使用 FROM
extend
您的镜像并添加他们自己的轻量级依赖项。这很好地反映了典型的“普通”用户将扩展镜像,而“高级用户”将自定义镜像的分割。
Airflow Summit 2020 的 Production Docker Image 演讲提供了有关生产镜像的上下文、架构和自定义/扩展方法的更多详细信息。
为什么要自定义镜像?¶
Apache Airflow 社区发布 Docker 镜像,这些镜像是指向 Apache Airflow 的 参考 镜像
。但是,Airflow 有超过 60 个社区管理的提供程序(可通过 extras 安装),并且并非每个人都使用某些默认安装的 extras/提供程序,有时需要其他 extras/提供程序,有时(实际上非常频繁)您需要添加自己的自定义依赖项、包,甚至自定义提供程序。
在 Kubernetes 和 Docker 术语中,这意味着您需要另一个具有您特定要求的镜像。这就是为什么您应该学习如何构建自己的 Docker(或更准确地说是 Container)镜像的原因。您可能很想使用 参考 镜像
并在启动容器时动态安装新包,但由于多种原因,这是一个坏主意 - 从构建的脆弱性开始,到安装这些包所需的额外时间结束 - 这必须在每个容器启动时发生。在生产中处理新依赖项和要求的唯一可行方法是构建和使用您自己的镜像。您应该仅在“爱好者”和“快速入门”场景中动态安装依赖项,当您想要快速迭代以尝试各种方法,然后再用自己的镜像替换它时。
构建镜像入门¶
注意
在特性和向后兼容性方面,Dockerfile
并不严格遵循 Apache Airflow 的 SemVer 方法。虽然 Airflow 代码严格遵循它,但 Dockerfile
实际上是一种使用标准容器方法方便地打包 Airflow 的方式,有时在构建过程或镜像的入口点上会发生一些变化,需要进行细微的调整。有关更改和所需调整的详细信息,请参阅 Changelog。
您会遇到几种最典型的场景,这里提供一个快速指南,说明如何快速实现您的目标。为了理解细节,您可以进一步阅读,但对于使用典型工具的简单情况,这里有一些简单的例子。
在最简单的情况下,构建镜像包括以下步骤
创建您自己的
Dockerfile
(命名为Dockerfile
),在其中添加
您的镜像应该基于什么信息(例如
FROM: apache/airflow:2.10.4-python3.8
)应在您的镜像中执行的其他步骤(通常以
RUN <命令>
的形式)
构建您的镜像。这可以使用
docker
CLI 工具完成,下面的例子假设使用docker
。还有其他工具如kaniko
或podman
允许您构建镜像,但docker
是目前最流行的和对开发者友好的工具。构建镜像的典型方法如下(my-image:0.0.1
是您的镜像包含版本的自定义标签)。如果您使用某种注册表来使用镜像,通常会以registry/image-name
的形式命名。镜像的名称必须为部署镜像的部署方法配置。例如,可以在 在 Docker 中运行 Airflow 或 Apache Airflow 的 Helm Chart 中设置为镜像名称。
docker build . -f Dockerfile --pull --tag my-image:0.0.1
[可选] 测试镜像。Airflow 包含允许您测试镜像的工具。但是,此步骤需要本地检出或提取的 Airflow 源代码。如果您碰巧有源代码,可以通过运行此命令(在 airflow 根文件夹中)来测试镜像。输出将告诉您镜像是否 “可以投入使用”。
./scripts/ci/tools/verify_docker_image.sh PROD my-image:0.0.1
一旦您在本地构建了镜像,通常有几种选项使其可用于您的部署
对于
docker-compose
部署,如果您已经构建了镜像,并希望在需要时继续使用docker build
手动构建镜像,您可以编辑 docker-compose.yaml 并将 “apache/airflow:<version>” 镜像替换为您刚构建的镜像my-image:0.0.1
- 它将从您本地的 Docker Engine 缓存中使用。您也可以简单地设置AIRFLOW_IMAGE_NAME
变量以指向您的镜像,docker-compose
将自动使用它,而无需修改文件。同样,对于
docker-compose
部署,您可以将镜像构建委托给 docker-compose。为此,请打开您的docker-compose.yaml
文件,并搜索短语 “In order to add custom dependencies”。按照这些说明注释 “image” 行并取消注释 “build” 行。这是一个标准的 docker-compose 功能,您可以在 Docker Compose 构建参考 中阅读有关它的信息。运行docker-compose build
来构建镜像。与前面的情况类似,镜像存储在 Docker 引擎缓存中,Docker Compose 将从那里使用它。docker-compose build
命令使用您可以在底层手动运行的相同的docker build
命令。对于一些 - 针对开发的 - Kubernetes 部署,您可以将镜像直接加载到 Kubernetes 集群。诸如
kind
或minikube
之类的集群具有专用的load
方法,用于将镜像加载到集群。最后但并非最不重要的一点 - 您可以将镜像推送到远程注册表,这是存储和公开镜像的最常见方式,也是发布镜像的最便携方式。Docker-Compose 和 Kubernetes 都可以利用通过注册表公开的镜像。
扩展镜像¶
如果您只需要添加一些不需要编译的依赖项,则扩展镜像最容易。Linux 的编译框架(所谓的 build-essential
)非常大,对于生产镜像,大小是一个非常重要的优化因素,因此我们的生产镜像不包含 build-essential
。如果您需要像 gcc 或 g++ 或 make/cmake 等编译器 - 这些在镜像中找不到,建议您遵循 “自定义” 路线。
如何扩展镜像 - 这是您最熟悉的事情 - 只需使用 Dockerfile 的 FROM
指令构建一个新镜像,并添加您需要的任何内容。然后您可以使用 apt
添加您的 Debian 依赖项,或使用 pip install
添加 PyPI 依赖项,或任何其他您需要的内容。
基础镜像¶
有两种类型的镜像您可以从中扩展您的镜像
常规 Airflow 镜像,包含最常见的额外组件和提供程序,以及适用于 AMD64 平台的所有受支持的后端数据库客户端和适用于 ARM64 平台的 Postgres。
Slim Airflow 镜像,这是一个最小的镜像,包含为 AMD64 平台安装的所有受支持的后端数据库客户端和为 ARM64 平台安装的 Postgres,但不包含任何额外组件或提供程序,除了 4 个默认提供程序。
注意
Slim 镜像中的数据库客户端和数据库提供程序 Slim 镜像为了您的方便预装了数据库客户端,但是,包含的默认提供程序不包括任何数据库提供程序。您仍然需要手动安装您需要的任何数据库提供程序
注意
Slim 镜像与常规镜像的区别。
与常规镜像(~500 MB vs ~1.1GB)相比,Slim 镜像很小,您可能需要添加更多软件包和提供程序才能使其在您的案例中可用(但如果您只使用一小部分提供程序,它可能是一个很好的起点)。
Slim 镜像的依赖项版本可能与预安装提供程序时使用的版本不同,这仅仅是因为核心 Airflow 对自身版本的限制较少。当您安装某些提供程序时,如果提供程序对相同的依赖项有不同的限制,则它们可能需要降级某些依赖项。
镜像的命名约定
镜像 |
Python |
标准镜像 |
Slim 镜像 |
---|---|---|---|
最新默认 |
3.8 |
apache/airflow:latest |
apache/airflow:slim-latest |
默认 |
3.8 |
apache/airflow:X.Y.Z |
apache/airflow:slim-X.Y.Z |
最新 |
3.8,3.9,3.10,3.11 |
apache/airflow:latest-pythonN.M |
apache/airflow:slim-latest-pythonN.M |
特定 |
3.8,3.9,3.10,3.11 |
apache/airflow:X.Y.Z-pythonN.M |
apache/airflow:slim-X.Y.Z-pythonN.M |
“latest” 镜像始终是可用的最新发布的稳定版本。
基础镜像的重要注意事项¶
您应该注意以下几点
airflow 的生产镜像使用 “airflow” 用户,因此如果您想以
root
用户身份添加某些工具,则需要使用 Dockerfile 的USER
指令切换到该用户,并在完成后切换回airflow
用户。您还应该记住遵循 Dockerfiles 的最佳实践,以确保您的镜像精简且体积小。您可以使用常规的
pip install
命令(以及自 Airflow 2.9 中的 Dockerfile 开始,也可以使用uv pip install
- 实验性)来安装 PyPI 包。应该使用常规的install
命令,但是您应该记住在命令中添加apache-airflow==${AIRFLOW_VERSION}
,以避免意外升级或降级 Apache Airflow 的版本。根据具体情况,您也可以使用约束文件。从 Airflow 2.9.0 中可用的 Dockerfile 开始,用于构建镜像的约束文件位于${HOME}/constraints.txt.
中。Apache Airflow 中的 PyPI 依赖项安装在 “airflow” 用户的
~/.local
virtualenv 中,因此 PIP 包会安装到~/.local
文件夹,就像运行 PIP 时指定了--user
标志一样。这样做的效果是,当您使用--system-site-packages
标志创建 virtualenv 时,创建的 virtualenv 将自动安装所有与本地 airflow 安装相同的软件包。另请注意,在pip
中使用--no-cache-dir
或在uv
中使用--no-cache
是一个好主意,可以帮助您缩小镜像大小。如果您的 apt 或 PyPI 依赖项需要一些
build-essential
或其他需要编译 python 依赖项的软件包,那么您的最佳选择是遵循“自定义镜像”路线,因为您可以以这种方式构建高度优化(大小)的镜像。但是,这需要您使用作为 Apache Airflow 源代码一部分发布的 Dockerfile(也可以在 Dockerfile 中找到)。您还可以通过使用 Airflow 的 COPY 指令简单地将您的 DAG 嵌入到镜像中。生产镜像中的 DAG 位于
/opt/airflow/dags
文件夹中。您可以在不需要任何 Airflow 源代码的情况下构建镜像。您只需将
Dockerfile
和任何引用的文件(例如 DAG 文件)放在一个单独的目录中,并运行命令docker build . --pull --tag my-image:my-tag
(其中my-image
是您想要命名的名称,my-tag
是您想要标记镜像的标签)。如果您的扩展镜像的方式需要创建可写目录,您必须记住在 RUN 命令中添加
umask 0002
步骤。为了适应我们使用任意用户运行镜像的方法,这是必要的。这样的用户将始终使用GID=0
运行 - 入口点将阻止非 root GID。您可以在入口点的 任意 docker 用户 文档中了解更多信息。umask 0002
在您进入镜像时设置为默认值,因此您在运行时默认创建的任何目录都将具有GID=0
并且是组可写的。
扩展镜像的示例¶
设置自己的 Airflow 提供程序包的示例¶
Airflow 提供程序 与核心 Airflow 独立发布,有时您可能只想升级特定的提供程序以修复某些问题或使用该提供程序版本中可用的功能。这是一个关于如何执行此操作的示例
docs/docker-stack/docker-examples/extending/custom-providers/Dockerfile
FROM apache/airflow:2.10.4
RUN pip install "apache-airflow==${AIRFLOW_VERSION}" --no-cache-dir apache-airflow-providers-docker==2.5.1
添加 Airflow 提供程序包和 apt
包的示例¶
以下示例添加了 apache-spark
airflow-providers,它需要 java
和 PyPI 中的 python 包。
docs/docker-stack/docker-examples/extending/add-providers/Dockerfile
FROM apache/airflow:2.10.4
USER root
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
openjdk-17-jre-headless \
&& apt-get autoremove -yqq --purge \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
USER airflow
ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
RUN pip install --no-cache-dir "apache-airflow==${AIRFLOW_VERSION}" apache-airflow-providers-apache-spark==2.1.3
添加 apt
包的示例¶
以下示例将 vim
添加到 airflow 镜像中。
docs/docker-stack/docker-examples/extending/add-apt-packages/Dockerfile
FROM apache/airflow:2.10.4
USER root
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
vim \
&& apt-get autoremove -yqq --purge \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
USER airflow
添加 PyPI
包的示例¶
以下示例将 PyPI 中的 lxml
python 包添加到镜像中。
docs/docker-stack/docker-examples/extending/add-pypi-packages/Dockerfile
FROM apache/airflow:2.10.4
RUN pip install --no-cache-dir "apache-airflow==${AIRFLOW_VERSION}" lxml
添加带有约束的 PyPI
包的示例¶
以下示例将 PyPI 中的 lxml
python 包添加到镜像中,并使用安装 airflow 时使用的约束。这允许您使用已知已使用给定 Airflow 版本测试过的软件包版本。如果您不想使用 Airflow 版本之后发布的潜在较新版本,也可以使用它。
docs/docker-stack/docker-examples/extending/add-pypi-packages-constraints/Dockerfile
FROM apache/airflow:2.10.4
RUN pip install --no-cache-dir "apache-airflow==${AIRFLOW_VERSION}" lxml --constraint "${HOME}/constraints.txt"
使用 uv 添加 PyPI
包的示例¶
以下示例使用 uv
将 PyPI 中的 lxml
python 包添加到镜像中。这是一个实验性功能,因为 uv
是 Python 生态系统中一个非常快但也很新的工具。
docs/docker-stack/docker-examples/extending/add-pypi-packages-uv/Dockerfile
FROM apache/airflow:2.10.4
# The `uv` tools is Rust packaging tool that is much faster than `pip` and other installer
# Support for uv as installation tool is experimental
RUN uv pip install --no-cache "apache-airflow==${AIRFLOW_VERSION}" lxml
从 requirements.txt 添加软件包的示例¶
以下示例从 PyPI 的 requirements.txt
文件中添加了一些 python 包到镜像。请注意,与添加单个包类似,您需要使用 airflow
用户而不是 root
。尝试以 root
身份安装 pip
包将失败,并显示相应的错误消息。
注意
在下面的示例中,我们还添加了要安装的 apache-airflow 包 - 与您使用的镜像版本相同的版本。这不是绝对必要的,但始终安装与您正在使用的 apache-airflow 版本相同的版本是一个好习惯。这样,您可以确保您使用的版本与您正在扩展的版本相同。在某些情况下,当您的新包具有冲突的依赖项时,pip
可能会决定为您降级或升级 apache-airflow,因此显式添加它是一个好习惯 - 这样,如果您的需求存在冲突,您将收到包含冲突信息的错误消息,而不是意外地降级或升级 airflow。如果您升级了 airflow 基础镜像,您还应该更新版本以匹配新的 airflow 版本。
docs/docker-stack/docker-examples/extending/add-requirement-packages/Dockerfile
FROM apache/airflow:2.10.4
COPY requirements.txt /
RUN pip install --no-cache-dir "apache-airflow==${AIRFLOW_VERSION}" -r /requirements.txt
docs/docker-stack/docker-examples/extending/add-requirement-packages/requirements.txt
lxml
beautifulsoup4
需要可写目录时的示例¶
以下示例添加了一个新目录,该目录应对于运行容器的任何任意用户都是可写的。
docs/docker-stack/docker-examples/extending/writable-directory/Dockerfile
FROM apache/airflow:2.10.4
RUN umask 0002; \
mkdir -p ~/writeable-directory
添加需要编译的软件包时的示例¶
以下示例添加了 mpi4py
包,该包需要 build-essential
和 mpi 编译器
。
docs/docker-stack/docker-examples/extending/add-build-essential-extend/Dockerfile
FROM apache/airflow:2.10.4
USER root
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential libopenmpi-dev \
&& apt-get autoremove -yqq --purge \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
USER airflow
RUN pip install --no-cache-dir "apache-airflow==${AIRFLOW_VERSION}" "mpi4py==3.1.6"
构建时此镜像的大小约为 1.1 GB。正如您将进一步看到的,如果您使用“自定义”而不是“扩展”镜像,则可以使镜像大小减少 20%。
当您想要嵌入 DAG 时示例¶
以下示例将 test_dag.py
添加到镜像中的 /opt/airflow/dags
文件夹中。
docs/docker-stack/docker-examples/extending/embedding-dags/Dockerfile
FROM apache/airflow:2.10.4
COPY --chown=airflow:root test_dag.py /opt/airflow/dags
import datetime
import pendulum
from airflow.models.dag import DAG
from airflow.operators.empty import EmptyOperator
now = pendulum.now(tz="UTC")
now_to_the_hour = (now - datetime.timedelta(0, 0, 0, 0, 0, 3)).replace(minute=0, second=0, microsecond=0)
START_DATE = now_to_the_hour
DAG_NAME = "test_dag_v1"
dag = DAG(
DAG_NAME,
schedule="*/10 * * * *",
default_args={"depends_on_past": True},
start_date=pendulum.datetime(2021, 1, 1, tz="UTC"),
catchup=False,
)
run_this_1 = EmptyOperator(task_id="run_this_1", dag=dag)
run_this_2 = EmptyOperator(task_id="run_this_2", dag=dag)
run_this_2.set_upstream(run_this_1)
run_this_3 = EmptyOperator(task_id="run_this_3", dag=dag)
run_this_3.set_upstream(run_this_2)
使用环境变量更改 airflow 配置的示例¶
以下示例将 airflow 配置更改添加到 airflow 镜像中。
docs/docker-stack/docker-examples/extending/add-airflow-configuration/Dockerfile
FROM apache/airflow:2.10.4
ENV AIRFLOW__CORE__LOAD_EXAMPLES=True
ENV AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=my_conn_string
自定义镜像¶
警告
在 Airflow 2.8.0 中发布的 Dockerfile 中,镜像基于 Debian Bookworm
镜像作为基础镜像。
注意
您通常可以使用 Airflow 发布的最新 Dockerfile
来构建以前的 Airflow 版本。但是请注意,Dockerfile 和入口点脚本中存在细微的变化,这些变化可能会使其行为略有不同,具体取决于您使用的 Dockerfile 版本。有关每个已发布版本的 Docker 镜像中更改了哪些内容的详细信息,请参阅 变更日志。
构建自定义 docker 镜像的先决条件
您需要启用 Buildkit 来构建镜像。这可以通过将
DOCKER_BUILDKIT=1
设置为环境变量或安装 buildx 插件 并运行docker buildx build
命令来完成。Docker Desktop 默认启用Buildkit
。您需要安装新的 Docker 来处理 Dockerfile 的
1.4
语法。已知 Docker 版本23.0.0
及以上版本可以正常工作。
在尝试自定义镜像之前,您需要下载灵活且可自定义的 Dockerfile
。您可以从 发布的源代码 中提取官方发布的 Dockerfile 版本。您还可以方便地从 GitHub 下载最新发布的版本。您可以将其保存在任何目录中 - 无需存在任何其他文件。如果您希望使用自己的文件(例如 pip
的自定义配置或您自己的 requirements
或自定义依赖项),则需要使用 DOCKER_CONTEXT_FILES
构建参数,并将文件放置在参数指向的目录中(有关详细信息,请参阅 使用 docker 上下文文件)。
自定义镜像是一种优化方式,可以将您自己的依赖项添加到镜像中 - 更适合准备高度优化(大小)的生产镜像,尤其是在您有需要在安装之前编译的依赖项(例如 mpi4py
)时。
它还允许“高级用户”所需的更复杂用法 - 例如使用 Airflow 的 fork 版本,或从经过安全审查的来源构建镜像。
此方法的最大优点是,即使您需要最终镜像中不需要的一些编译时依赖项,它也会生成优化的镜像。
缺点是构建镜像需要更长的时间,并且需要您使用作为 Apache Airflow 源代码一部分发布的 Dockerfile。
缺点是使用 --build-arg
构建 Docker 镜像的模式对于此类镜像的开发人员来说不太熟悉。但是,它对于“高级用户”来说是众所周知的。这就是为什么自定义流程更适合那些更熟悉并具有更多自定义要求的用户。
镜像的构建时间通常也比等效的“扩展”镜像长得多,因为与其扩展已经来自基础镜像的层,它会重建在镜像构建早期阶段添加额外依赖项所需的层。
自定义镜像时,您可以选择多种安装 Airflow 的方式
从 PyPI 版本(默认)
从自定义安装源 - 使用额外的/替换原始 apt 或 PyPI 存储库
从本地源。这主要在开发期间使用。
从 GitHub Airflow 存储库(或分支)的标签或分支,或特定提交。当您为自定义版本的 Airflow 构建镜像,并且您不想将自定义 Airflow 版本发布到 PyPI 时,这特别有用。
从本地存储的 Airflow、Airflow 提供程序和其他依赖项的二进制包。如果您想在高度安全的环境中构建 Airflow,其中所有此类包都必须由您的安全团队审查并存储在您的私有工件注册表中,这将特别有用。 这也允许在气隙环境中构建 airflow 镜像。
旁注。在
气隙
环境中构建Airflow
听起来很有趣,不是吗?
您还可以在构建镜像时添加一系列自定义项
您用于 Airflow 的基本 python 镜像
要安装的 Airflow 版本
要为 Airflow 安装的额外组件(甚至删除一些默认的额外组件)
在构建 Airflow 时要使用的额外 apt/python 依赖项(DEV 依赖项)
将
requirements.txt
文件添加到docker-context-files
目录以添加额外的需求要为 Airflow 的运行时版本安装的额外 apt/python 依赖项(RUNTIME 依赖项)
如果需要在构建或准备 Airflow 运行时期间设置的其他命令和变量
选择安装 Airflow 时要使用的约束文件
最后一点需要额外解释。Airflow 使用约束来确保它可以被可预测地安装,即使发布了 Airflow 的一些新版本的依赖项(甚至是我们的依赖项的依赖项!)。 docker 镜像和随附的脚本通常会根据安装的 Airflow 版本和 Python 版本自动确定要使用的正确约束版本。例如,从 PyPI 安装的 Airflow 2.0.2 版本使用来自 constraints-2.0.2
标签的约束)。但是,在某些情况下(例如从 GitHub 安装 airflow 时),您必须手动指定使用的约束版本,否则它将默认为最新版本的约束,这可能与您使用的 Airflow 版本不兼容。
您还可以下载任何版本的 Airflow 约束,并使用您自己的一组约束进行调整,并在您自己的约束中手动设置您自己的依赖项版本,并使用您手动准备的约束版本。
您可以在从 PyPI 安装中阅读更多关于约束的信息
请注意,如果您将 requirements.txt
放在 docker-context-files
文件夹中,它将用于安装此处声明的所有需求。建议该文件包含使用 ==
版本说明符指定的依赖项版本,以实现一组稳定的需求,而无需考虑是否有人发布了较新版本。但是,您必须确保更新这些要求并重建镜像,以解决最新的安全修复程序。
使用 docker-context-files¶
在自定义镜像时,您可以选择使 Airflow 安装自定义二进制文件或为 docker-context-files
中的 pip 提供自定义配置。为了启用它,您需要在构建镜像时添加 --build-arg DOCKER_CONTEXT_FILES=docker-context-files
构建参数。您可以传递 docker 上下文的任何子目录,它在构建期间将始终映射到 /docker-context-files
。
您可以将 docker-context-files
用于以下目的
您可以放置
requirements.txt
并在docker-context-file
文件夹中添加您要安装的任何pip
包。这些需求将在构建期间自动安装。
注意
在下面的示例中,我们还添加了要安装的 apache-airflow 包 - 与您使用的镜像版本相同的版本。这不是绝对必要的,但始终安装与您正在使用的 apache-airflow 版本相同的版本是一个好习惯。这样,您可以确保您使用的版本与您正在扩展的版本相同。在某些情况下,当您的新包具有冲突的依赖项时,pip
可能会决定为您降级或升级 apache-airflow,因此显式添加它是一个好习惯 - 这样,如果您的需求存在冲突,您将收到包含冲突信息的错误消息,而不是意外地降级或升级 airflow。如果您升级了 airflow 基础镜像,您还应该更新版本以匹配新的 airflow 版本。
docs/docker-stack/docker-examples/customizing/own-requirements.sh
mkdir -p docker-context-files
cat <<EOF >./docker-context-files/requirements.txt
beautifulsoup4==4.10.0
apache-airflow==2.9.0.dev0
EOF
export DOCKER_BUILDKIT=1
docker build . \
--build-arg DOCKER_CONTEXT_FILES=./docker-context-files \
--tag "my-beautifulsoup4-airflow:0.0.1"
docker run -it my-beautifulsoup4-airflow:0.0.1 python -c 'import bs4; import sys; sys.exit(0)' && \
echo "Success! Beautifulsoup4 installed" && echo
您可以将
pip.conf
(和旧版.piprc
)放在docker-context-files
文件夹中,它们将用于所有pip
命令(例如,您可以配置自己的源或身份验证机制)
docs/docker-stack/docker-examples/customizing/custom-pip.sh
mkdir -p docker-context-files
cat <<EOF >./docker-context-files/pip.conf
[global]
verbose = 2
EOF
export DOCKER_BUILDKIT=1
docker build . \
--build-arg DOCKER_CONTEXT_FILES=./docker-context-files \
--tag "my-custom-pip-verbose-airflow:0.0.1"
您可以放置您下载的
.whl
包,并将INSTALL_PACKAGES_FROM_CONTEXT
设置为true
来安装它们。如果您在受限安全环境中构建镜像,这将非常有用(有关详细信息,请参阅:在安全受限环境中构建镜像)
docs/docker-stack/docker-examples/restricted/restricted_environments.sh
mkdir -p docker-context-files
export AIRFLOW_VERSION="2.5.3"
rm docker-context-files/*.whl docker-context-files/*.tar.gz docker-context-files/*.txt || true
curl -Lo "docker-context-files/constraints-3.8.txt" \
"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-3.8.txt"
echo
echo "Make sure you use the right python version here (should be same as in constraints)!"
echo
python --version
pip download --dest docker-context-files \
--constraint docker-context-files/constraints-3.8.txt \
"apache-airflow[async,celery,elasticsearch,kubernetes,postgres,redis,ssh,statsd,virtualenv]==${AIRFLOW_VERSION}"
注意
如果您想将 requirements.txt
放在主目录中而不创建专用文件夹,您还可以传递 --build-arg DOCKER_CONTEXT_FILES=.
。但是,最佳实践是将您复制到镜像上下文的任何文件都保留在子文件夹中。这使得更容易将主机上使用的内容与 Docker 上下文中传递的内容分开。当然,默认情况下,当您运行 docker build .
时,整个文件夹都可用作“Docker 构建上下文”并发送到 docker 引擎,但 DOCKER_CONTEXT_FILES
始终复制到镜像的 build
段,因此复制所有本地文件夹可能会不必要地增加构建镜像所需的时间,并且您的缓存会在每次本地文件夹中的任何文件更改时失效。
警告
重大更改!从 Airflow 2.3.0 开始,您需要指定附加标志:--build-arg DOCKER_CONTEXT_Files=docker-context-files
才能使用放置在 docker-context-files
中的文件。以前不需要该开关。不幸的是,需要此更改才能将 Dockerfile
作为独立的 Dockerfile 而无需任何额外文件。从 Airflow 2.3.0 开始,与 Airflow 一起发布的 Dockerfile
不需要任何额外的文件夹或文件,可以从任何文件夹复制和使用。以前,您需要将 Airflow 源代码与 Dockerfile 一起复制,因为需要一些脚本才能使其工作。使用 Airflow 2.3.0,我们正在使用 Buildkit
功能,使我们能够将 Dockerfile
变成一个完全独立的文件,可以“按原样”使用。
镜像自定义示例¶
从 PyPI 包构建¶
这是从源代码构建自定义镜像的基本方法。
以下示例构建了 3.8
版本中的生产镜像,其中包含最新的 PyPI 发布版 Airflow、默认的 Airflow 额外组件和依赖项。最新的 PyPI 发布版 Airflow 约束会自动使用。
docs/docker-stack/docker-examples/customizing/stable-airflow.sh
export DOCKER_BUILDKIT=1
docker build . \
--tag "my-stable-airflow:0.0.1"
以下示例构建了 3.8
版本中的生产镜像,其中包含来自 2.3.0
Airflow 包的默认额外组件。2.3.0
约束会自动使用。
docs/docker-stack/docker-examples/customizing/pypi-selected-version.sh
export AIRFLOW_VERSION=2.3.4
export DOCKER_BUILDKIT=1
docker build . \
--build-arg PYTHON_BASE_IMAGE="python:3.8-slim-bookworm" \
--build-arg AIRFLOW_VERSION="${AIRFLOW_VERSION}" \
--tag "my-pypi-selected-version:0.0.1"
以下示例构建了 3.8
版本中的生产镜像,其中包含来自 2.3.0
PyPI 包的其他 airflow 额外组件(mssql,hdfs
)和其他依赖项(oauth2client
)。
docs/docker-stack/docker-examples/customizing/pypi-extras-and-deps.sh
export AIRFLOW_VERSION=2.3.4
export DOCKER_BUILDKIT=1
docker build . \
--pull \
--build-arg PYTHON_BASE_IMAGE="python:3.8-slim-bookworm" \
--build-arg AIRFLOW_VERSION="${AIRFLOW_VERSION}" \
--build-arg ADDITIONAL_AIRFLOW_EXTRAS="mssql,hdfs" \
--build-arg ADDITIONAL_PYTHON_DEPS="oauth2client" \
--tag "my-pypi-extras-and-deps:0.0.1"
以下示例添加了 mpi4py
包,该包需要 build-essential
和 mpi 编译器
。
docs/docker-stack/docker-examples/customizing/add-build-essential-custom.sh
export AIRFLOW_VERSION=2.8.2
export DOCKER_BUILDKIT=1
docker build . \
--pull \
--build-arg PYTHON_BASE_IMAGE="python:3.8-slim-bookworm" \
--build-arg AIRFLOW_VERSION="${AIRFLOW_VERSION}" \
--build-arg ADDITIONAL_PYTHON_DEPS="mpi4py==3.1.6" \
--build-arg ADDITIONAL_DEV_APT_DEPS="libopenmpi-dev" \
--build-arg ADDITIONAL_RUNTIME_APT_DEPS="openmpi-common" \
--tag "my-build-essential-image:0.0.1"
上面的镜像等效于上一章中的“扩展”镜像,但其大小仅为 874 MB。 与“扩展镜像”的 1.1 GB 相比,这减少了约 230 MB,因此通过使用“自定义”而不是扩展,您可以将镜像的大小提高约 20%。 如果您有更复杂的依赖项要构建,则节省的空间可能会增加。
构建优化的镜像¶
以下示例构建了 3.8
版本中的生产镜像,其中包含来自 PyPI 包的其他 airflow 额外组件,但它包括额外的 apt 开发和运行时依赖项。
开发依赖是指那些需要 build-essential
的依赖,并且通常需要重新编译一些 Python 依赖项,因此这些包可能需要一些额外的开发依赖项在重新编译期间存在。这些包在运行时不需要,所以我们只在“构建”时安装它们。它们不会安装在最终镜像中,从而产生更小的镜像。在这种情况下,pandas 需要重新编译,因此它也需要 gcc 和 g++ 作为开发 APT 依赖项。jre-headless
不需要重新编译,所以它可以作为运行时 APT 依赖项安装。
docs/docker-stack/docker-examples/customizing/pypi-dev-runtime-deps.sh
export AIRFLOW_VERSION=2.2.4
export DOCKER_BUILDKIT=1
docker build . \
--pull \
--build-arg PYTHON_BASE_IMAGE="python:3.8-slim-bookworm" \
--build-arg AIRFLOW_VERSION="${AIRFLOW_VERSION}" \
--build-arg ADDITIONAL_AIRFLOW_EXTRAS="jdbc" \
--build-arg ADDITIONAL_PYTHON_DEPS="pandas" \
--build-arg ADDITIONAL_DEV_APT_DEPS="gcc g++" \
--build-arg ADDITIONAL_RUNTIME_APT_DEPS="default-jre-headless" \
--tag "my-pypi-dev-runtime:0.0.1"
使用 UV 作为包安装器构建生产镜像¶
以下示例在默认设置下构建生产镜像,但使用 uv
构建镜像。这是一个实验性功能,因为 uv
是 Python 生态系统中一个非常快速但也很新的工具。
docs/docker-stack/docker-examples/customizing/use-uv.sh
export DOCKER_BUILDKIT=1
docker build . \
--build-arg AIRFLOW_USE_UV="true" \
--tag "my-custom-use-uv-airflow:0.0.1"
构建带有 MySQL 客户端的镜像¶
警告
默认情况下,从 Airflow 2.8.0 开始的 Airflow 镜像在“X86_64”和“ARM64”平台上都默认使用“MariaDB”客户端。但是,您也可以构建带有 MySQL 客户端的镜像。以下示例构建了具有“MySQL”客户端的默认 Python 版本的生产镜像。
docs/docker-stack/docker-examples/customizing/mysql-client.sh
export DOCKER_BUILDKIT=1
docker build . \
--build-arg INSTALL_MYSQL_CLIENT_TYPE="mysql" \
--tag "my-mysql-airflow:0.0.1"
从 GitHub 构建¶
此方法通常用于开发目的。但是,如果您有自己的 fork,您可以将其指向您 fork 的源代码版本,而无需将其发布到 PyPI。在您的存储库中有一个分支或标签,并在您指向安装的 URL 中使用该标签或分支就足够了。
对于 GitHub 构建,如果您想使用特定的约束,您需要手动传递约束引用,否则将使用默认的 constraints-main
。
以下示例构建了版本为 3.8
的生产镜像,其中包含来自最新 main 版本和约束的默认 extras,约束取自 GitHub 中 constraints-main 分支的最新版本。
docs/docker-stack/docker-examples/customizing/github-main.sh
export DOCKER_BUILDKIT=1
docker build . \
--pull \
--build-arg PYTHON_BASE_IMAGE="python:3.8-slim-bookworm" \
--build-arg AIRFLOW_INSTALLATION_METHOD="apache-airflow @ https://github.com/apache/airflow/archive/main.tar.gz" \
--build-arg AIRFLOW_CONSTRAINTS_REFERENCE="constraints-main" \
--tag "my-github-main:0.0.1"
以下示例构建了具有来自最新 v2-*-test
版本的默认 extras 的生产镜像,并且约束取自 GitHub 中 constraints-2-*
分支的最新版本(例如,v2-2-test
分支匹配 constraints-2-2
)。请注意,此命令可能会偶尔失败,因为只有在构建版本时“发布版本”约束和在构建 main 时“main”约束才能保证工作。
docs/docker-stack/docker-examples/customizing/github-v2-2-test.sh
export DOCKER_BUILDKIT=1
docker build . \
--pull \
--build-arg PYTHON_BASE_IMAGE="python:3.8-slim-bookworm" \
--build-arg AIRFLOW_INSTALLATION_METHOD="apache-airflow @ https://github.com/apache/airflow/archive/v2-2-test.tar.gz" \
--build-arg AIRFLOW_CONSTRAINTS_REFERENCE="constraints-2-2" \
--tag "my-github-v2-2:0.0.1"
您还可以指定另一个要从中构建的存储库。如果您还想使用不同的约束存储库源,则必须将其指定为额外的 CONSTRAINTS_GITHUB_REPOSITORY
构建参数。
以下示例使用 Airflow 的 potiuk/airflow
fork 构建生产镜像,并且约束也从该存储库下载。
docs/docker-stack/docker-examples/customizing/github-different-repository.sh
export DOCKER_BUILDKIT=1
docker build . \
--pull \
--build-arg PYTHON_BASE_IMAGE="python:3.8-slim-bookworm" \
--build-arg AIRFLOW_INSTALLATION_METHOD="apache-airflow @ https://github.com/potiuk/airflow/archive/main.tar.gz" \
--build-arg AIRFLOW_CONSTRAINTS_REFERENCE="constraints-main" \
--build-arg CONSTRAINTS_GITHUB_REPOSITORY="potiuk/airflow" \
--tag "github-different-repository-image:0.0.1"
使用自定义安装源¶
您可以自定义镜像的更多方面 - 例如在安装 apt 依赖项之前执行的额外命令,或者添加额外的源来从中安装您的依赖项。您可以在下面看到所有描述的参数,但这里有一个比较复杂的命令示例,用于根据此评论中的示例自定义镜像。
如果您需要使用自定义 PyPI 包索引,您还可以在构建镜像时添加一个 docker-context-files/pip.conf
文件来自定义镜像构建期间使用的 PYPI 源。此 pip.conf
不会提交到存储库(它被添加到 .gitignore
),也不会出现在最终的生产镜像中。它仅在镜像的构建部分添加和使用。因此,此 pip.conf
文件可以安全地包含您要使用的包索引列表、用于身份验证的用户名和密码。pip.conf
文件的更多详细信息可以在pip 配置中找到。
如果您之前使用过 .piprc
(某些旧版本的 pip
用它来进行自定义),您可以将其放入 docker-context-files/.piprc
文件中,它将自动复制到 airflow
用户的 HOME
目录中。
请注意,这些自定义项仅在 Airflow 镜像的 build
部分可用,并且它们不会出现在 final
镜像中。如果您希望扩展最终镜像并添加自定义 .piprc
和 pip.conf
,则应将它们添加到您用于扩展 Airflow 镜像的自定义 Dockerfile 中。
这些自定义项与 airflow 的安装方式无关。
注意
可以通过手动修改 Dockerfile(见下文)并注入所需的命令来实现类似的结果,但是通过 build-args 指定自定义项,您可以避免从未来的 Airflow Dockerfile 中同步更改的需要。这些自定义项应该适用于未来版本的 Airflow 官方 Dockerfile
,最多只需对参数名称进行最小的修改(如果有),因此使用 build 命令进行自定义可以使您的自定义镜像更具未来适应性。
以下 - 相当复杂的 - 示例显示了以下功能
添加 airflow extras (slack, odbc)
添加 PyPI 依赖项 (
azure-storage-blob, oauth2client, beautifulsoup4, dateparser, rocketchat_API,typeform
)在安装
apt
依赖项时添加自定义环境变量 - 包括 DEV 和 RUNTIME (ACCEPT_EULA=Y'
)添加自定义 curl 命令,用于添加密钥和配置安装
apt
依赖项(包括 DEV 和 RUNTIME)所需的其他 apt 源添加自定义
apt
依赖项,包括 DEV (msodbcsql17 unixodbc-dev g++
) 和 runtimemsodbcsql17 unixodbc git procps vim
docs/docker-stack/docker-examples/customizing/custom-sources.sh
export AIRFLOW_VERSION=2.2.4
export DOCKER_BUILDKIT=1
docker build . -f Dockerfile \
--pull \
--platform 'linux/amd64' \
--build-arg PYTHON_BASE_IMAGE="python:3.8-slim-bookworm" \
--build-arg AIRFLOW_VERSION="${AIRFLOW_VERSION}" \
--build-arg ADDITIONAL_AIRFLOW_EXTRAS="slack,odbc" \
--build-arg ADDITIONAL_PYTHON_DEPS=" \
azure-storage-blob<12.9.0 \
oauth2client \
beautifulsoup4 \
dateparser \
rocketchat_API \
typeform" \
--build-arg ADDITIONAL_DEV_APT_COMMAND="curl https://packages.microsoft.com/keys/microsoft.asc | \
apt-key add --no-tty - && \
curl https://packages.microsoft.com/config/debian/10/prod.list > /etc/apt/sources.list.d/mssql-release.list" \
--build-arg ADDITIONAL_DEV_APT_ENV="ACCEPT_EULA=Y" \
--build-arg ADDITIONAL_DEV_APT_DEPS="msodbcsql17 unixodbc-dev g++" \
--build-arg ADDITIONAL_RUNTIME_APT_COMMAND="curl https://packages.microsoft.com/keys/microsoft.asc | \
apt-key add --no-tty - && \
curl https://packages.microsoft.com/config/debian/10/prod.list > /etc/apt/sources.list.d/mssql-release.list" \
--build-arg ADDITIONAL_RUNTIME_APT_ENV="ACCEPT_EULA=Y" \
--build-arg ADDITIONAL_RUNTIME_APT_DEPS="msodbcsql17 unixodbc git procps vim" \
--tag "my-custom-sources-image:0.0.1"
在安全受限的环境中构建镜像¶
您还可以确保您的镜像仅使用本地约束文件和本地下载的 wheel 文件构建。这在企业环境中通常很有用,在这些环境中,二进制文件由安全团队验证和审查。这也是构建镜像最复杂的方式。您应该是在构建和使用 Dockerfile 方面的专家,并且如果您想遵循这条路线,则必须具有特定的安全需求。
下面的构建使用来自本地 docker-context-files
的包和约束构建生产镜像,而不是从 PyPI 或 GitHub 安装。它还禁用 MySQL 客户端安装,因为它使用的是外部安装方法。
请注意,作为先决条件 - 您需要下载 wheel 文件。在下面的示例中,我们首先在本地下载这样的约束文件,然后使用 pip download
来获取所需的 .whl
文件,但在最可能的情况下,这些 wheel 文件应该从 .whl 文件的内部存储库复制。请注意,AIRFLOW_VERSION_SPECIFICATION
仅用于参考,正确版本的 apache airflow .whl
文件是下载的 .whl
文件的一部分。
请注意,“pip download”仅在 Linux 主机上有效,因为某些软件包需要从源代码编译,并且您不能提供 --platform
开关来安装它们。它们还需要使用与目标镜像相同的 python 版本下载。
pip download
可能会在单独的环境中发生。这些文件可以提交到单独的二进制存储库,并由安全团队审查/验证,然后用于在需要时在气隙系统上构建 Airflow 镜像。
准备约束文件和 wheel 文件的示例。请注意,mysql
依赖项已被删除,因为 mysqlclient
是从 Oracle 的 apt
存储库安装的,如果您想添加它,您需要从您的存储库提供此库,如果您想在“气隙”系统中构建 Airflow 镜像。
docs/docker-stack/docker-examples/restricted/restricted_environments.sh
mkdir -p docker-context-files
export AIRFLOW_VERSION="2.5.3"
rm docker-context-files/*.whl docker-context-files/*.tar.gz docker-context-files/*.txt || true
curl -Lo "docker-context-files/constraints-3.8.txt" \
"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-3.8.txt"
echo
echo "Make sure you use the right python version here (should be same as in constraints)!"
echo
python --version
pip download --dest docker-context-files \
--constraint docker-context-files/constraints-3.8.txt \
"apache-airflow[async,celery,elasticsearch,kubernetes,postgres,redis,ssh,statsd,virtualenv]==${AIRFLOW_VERSION}"
完成此步骤后,你的 docker-context-files
文件夹将包含从安装 Airflow 所需的所有软件包。
这些下载的软件包和约束文件可以在您尝试安装镜像之前由您的安全团队进行预先审查。您还可以将这些下载的二进制软件包存储在您的私有工件仓库中,这样您可以在一台机器上下载软件包,仅提交新软件包进行安全审查,并在软件包通过审查后才使用它们。
在一个独立的(气隙)系统中,所有 PyPI 包都可以复制到 docker-context-files
中,您可以在此处使用传递这些构建参数下载的软件包来构建镜像
INSTALL_PACKAGES_FROM_CONTEXT="true"
- 使用docker-context-files
中存在的软件包AIRFLOW_PRE_CACHED_PIP_PACKAGES="false"
- 在构建镜像时不从 PyPI 预缓存软件包AIRFLOW_CONSTRAINTS_LOCATION=/docker-context-files/YOUR_CONSTRAINT_FILE.txt
- 指定已下载的约束文件(可选)如果您不想从 Oracle 存储库安装
MySQL
客户端,请设置INSTALL_MYSQL_CLIENT="false"
。(可选)如果您不想从 Microsoft 存储库安装
MsSQL
客户端,请设置INSTALL_MSSQL_CLIENT="false"
。(可选)如果您不想从 Postgres 存储库安装
Postgres
客户端,请设置INSTALL_POSTGRES_CLIENT="false"
。
请注意,我们用于从本地软件包安装 Python 软件包的解决方案,仅解决了“气隙” Python 安装的问题。Docker 镜像还会下载 apt
依赖项和 node-modules
。这些类型的依赖项更可能通过透明代理在您的“气隙”系统中可用,并且它应该自动连接到您的私有注册表。但是,将来该解决方案可能会应用于这两个安装步骤。
您还可以使用上一章中描述的技术,使 docker build
使用您的私有 apt 源或私有 PyPI 存储库(通过 .pypirc
),这些资源是可以进行安全审查的。
如果您满足所有条件,您可以通过运行类似于下面的命令在气隙系统上构建镜像
docs/docker-stack/docker-examples/restricted/restricted_environments.sh
export DOCKER_BUILDKIT=1
docker build . \
--pull \
--build-arg PYTHON_BASE_IMAGE="python:3.8-slim-bookworm" \
--build-arg AIRFLOW_INSTALLATION_METHOD="apache-airflow" \
--build-arg AIRFLOW_VERSION="${AIRFLOW_VERSION}" \
--build-arg INSTALL_MYSQL_CLIENT="false" \
--build-arg INSTALL_MSSQL_CLIENT="false" \
--build-arg INSTALL_POSTGRES_CLIENT="true" \
--build-arg AIRFLOW_PRE_CACHED_PIP_PACKAGES="false" \
--build-arg DOCKER_CONTEXT_FILES="docker-context-files" \
--build-arg INSTALL_PACKAGES_FROM_CONTEXT="true" \
--build-arg AIRFLOW_CONSTRAINTS_LOCATION="/docker-context-files/constraints-3.8.txt" \
--tag airflow-my-restricted-environment:0.0.1
修改 Dockerfile¶
如果您不想手动修改 Dockerfile
,构建参数方法是一种方便的方法。我们的方法足够灵活,可以适应大多数开箱即用的需求和自定义。当您使用它时,您无需担心每次发布新版本的 Airflow 时都需要调整镜像。但是,如果您的需求非常具体并且想要构建非常定制的镜像,有时这是不够的。在这种情况下,您可以根据需要手动修改 Dockerfile
并将其存储在您 fork 的存储库中。但是,您必须确保在每次发布新版本的 Airflow 时重新基于您的更改,因为我们可能会在未来修改 Dockerfile 构建的方法,并且您可能需要解决冲突并重新基于您的更改。
在修改 Dockerfile
时,需要记住以下几点
我们正在使用广泛推荐的
.dockerignore
模式,其中默认情况下忽略所有内容,仅通过排除(!)添加所需文件夹。这可以使 docker 上下文保持较小,因为 Airflow 的源代码中会生成许多二进制工件,如果将它们添加到上下文中,则构建镜像的时间将大大增加。如果您想添加任何新的文件夹以便在镜像中可用,则必须在此处添加它们,并以!
开头# Ignore everything ** # Allow only these directories !airflow ...
docker-context-files
文件夹会自动添加到镜像的上下文中,因此如果您想添加单个文件、二进制文件、需求文件等,您可以将它们添加到此处。docker-context-files
被复制到镜像构建部分的/docker-context-files
文件夹中,因此它不会出现在最终镜像中 - 如果您只想在build
部分中使用这些文件,这会使最终镜像更小。如果您想将文件放入最终镜像(在主镜像部分),则必须使用 COPY 命令手动从该目录复制任何文件。