Airflow 从私有 Google 容器仓库中拉取 Docker 镜像

6

我正在使用https://github.com/puckel/docker-airflow镜像运行Airflow。我必须添加pip install docker以使其支持DockerOperator。

一切似乎都很好,但我无法弄清楚如何从私有的Google Docker容器存储库中拉取映像。

我尝试在管理员部分添加连接,类型为Google Cloud Connection,并进行以下操作,运行docker operator。

    t2 = DockerOperator(
            task_id='docker_command',
            image='eu.gcr.io/project/image',
            api_version='2.3',
            auto_remove=True,
            command="/bin/sleep 30",
            docker_url="unix://var/run/docker.sock",
            network_mode="bridge",
            docker_conn_id="google_con"
    )

但总是出现错误...

[2019-11-05 14:12:51,162] {{taskinstance.py:1047}} 错误 - 没有提供Docker注册表URL

我还尝试了docker_conf_option

    t2 = DockerOperator(
            task_id='docker_command',
            image='eu.gcr.io/project/image',
            api_version='2.3',
            auto_remove=True,
            command="/bin/sleep 30",
            docker_url="unix://var/run/docker.sock",
            network_mode="bridge",
            dockercfg_path="/usr/local/airflow/config.json",

    )

我得到了以下错误:
[2019-11-06 13:59:40,522] {{docker_operator.py:194}} INFO - 正在从镜像eu.gcr.io/project/image启动docker容器 [2019-11-06 13:59:40,524] {{taskinstance.py:1047}} ERROR - ('Connection aborted.', FileNotFoundError(2, '没有这个文件或目录'))
我也尝试仅使用dockercfg_path="config.json",但出现相同的错误。
我无法使用Bash Operator尝试进行docker登录,因为它无法识别docker命令...
我错过了什么?
第一行:docker: 命令未找到
t3 = BashOperator(
                task_id='print_hello',
                bash_command='docker login -u _json_key - p /usr/local/airflow/config.json eu.gcr.io'
        )

你是否启用了Google容器注册表API,以便推送和拉取镜像?如果您计划拉取和推送Docker镜像,请确保将存储管理员角色附加到服务帐户。您可以在Google Cloud Platform文档中查看GCR的权限和角色。 - redhatvicky
请尝试在composer的PyPI部分安装docker-py==1.10.6。 - redhatvicky
快速解决方法是使用gcloud sdk来验证docker。类似于gcloud auth configure-docker -q && docker pull $(IMAGE_NAME),这应该可以工作。 - redhatvicky
您也可以按照以下步骤来破解此问题:
  1. 将当前部署配置导出到文件 kubectl get deployment airflow-worker -o yaml --export > airflow-worker-config.yaml
  2. 编辑 airflow-worker-config.yaml(示例链接)以挂载 docker.sock 和 docker,并授予 airflow-worker 特权访问以运行 docker 命令
  3. 应用部署设置 kubectl apply -f airflow-worker-config.yaml 来源:https://groups.google.com/forum/?hl=zh-CN#!topic/cloud-composer-discuss/pSPKFS7AOj0
- redhatvicky
5个回答

8

airflow.hooks.docker_hook.DockerHook 正在使用没有配置连接的 docker_default 连接。

在第一次尝试中,您将 google_con 设置为 docker_conn_id,而抛出的错误显示主机(即注册表名称)未配置。

以下是需要进行的一些更改:

  • DockerOperator 中传递的 image 参数应设置为不带注册表名称前缀的镜像标签。
DockerOperator(api_version='1.21',
    # docker_url='tcp://localhost:2375', #Set your docker URL
    command='/bin/ls',
    image='image',
    network_mode='bridge',
    task_id='docker_op_tester',
    docker_conn_id='google_con',
    dag=dag,
    # added this to map to host path in MacOS
    host_tmp_dir='/tmp', 
    tmp_dir='/tmp',
    )
  • 提供注册表名称、用户名和密码,用于在您的google_con连接中验证底层的DockerHook与Docker进行身份验证。

你可以从服务账户密钥获取长期有效的身份验证凭据。对于用户名,请使用_json_key,并在密码字段中粘贴json密钥文件的内容。

Google连接docker

这是运行我的任务的日志:

[2019-11-16 20:20:46,874] {base_task_runner.py:110} INFO - Job 443: Subtask docker_op_tester [2019-11-16 20:20:46,874] {dagbag.py:88} INFO - Filling up the DagBag from /Users/r7/OSS/airflow/airflow/example_dags/example_docker_operator.py
[2019-11-16 20:20:47,054] {base_task_runner.py:110} INFO - Job 443: Subtask docker_op_tester [2019-11-16 20:20:47,054] {cli.py:592} INFO - Running <TaskInstance: docker_sample.docker_op_tester 2019-11-14T00:00:00+00:00 [running]> on host 1.0.0.127.in-addr.arpa
[2019-11-16 20:20:47,074] {logging_mixin.py:89} INFO - [2019-11-16 20:20:47,074] {local_task_job.py:120} WARNING - Time since last heartbeat(0.01 s) < heartrate(5.0 s), sleeping for 4.989537 s
[2019-11-16 20:20:47,088] {logging_mixin.py:89} INFO - [2019-11-16 20:20:47,088] {base_hook.py:89} INFO - Using connection to: id: google_con. Host: gcr.io/<redacted-project-id>, Port: None, Schema: , Login: _json_key, Password: XXXXXXXX, extra: {}
[2019-11-16 20:20:48,404] {docker_operator.py:209} INFO - Starting docker container from image alpine
[2019-11-16 20:20:52,066] {logging_mixin.py:89} INFO - [2019-11-16 20:20:52,066] {local_task_job.py:99} INFO - Task exited with return code 0

当我尝试将JSON密钥的内容粘贴到密码框中时,我遇到了MySQL数据库错误:“无法创建记录。 (_mysql_exceptions.DataError) (1406,“行1处的'password'列数据过长”)”。您也遇到了这个问题吗? - Evan Kaeding
没有,我没有遇到过这个问题。你在哪个版本的Airflow上遇到了这个问题? - Oluwafemi Sule
好的呼叫。从Airflow 1.10.6开始,密码长度被限制为500个字符,对于Google JSON密钥文件来说太长了。在版本1.10.7中,密码长度增加到了5,000个字符。源在这里 - Evan Kaeding

3

我知道这个问题是关于GCR的,但值得注意的是其他容器注册表可能期望以不同的格式提供配置。

例如,Gitlab希望您将完全限定的镜像名称传递给DAG,并仅在连接中放置Gitlab容器注册表主机名:

DockerOperator(
    task_id='docker_command',
    image='registry.gitlab.com/group/project/image:tag',
    api_version='auto',
    docker_conn_id='gitlab_registry',
)

设置你的 gitlab_registry 连接如下:

docker://gitlab+deploy-token-1234:ABDCtoken1234@registry.gitlab.com

1
我们如何从我们的GitLab账户访问部署令牌。 - Mobin Al Hassan
1
请参考完整信息 https://docs.gitlab.com/ee/user/packages/container_registry/ 并且你可以通过 https://gitlab.com/<your_group>/<your_project>/-/settings/repository 创建部署令牌。希望能对你有所帮助 @mobinalhassan - imsheth
1
@imsheth,我不知道如何创建连接...你能解释一下吗?我遇到了太长时间的问题。 - Mobin Al Hassan
@mobinalhassan在https://dev59.com/dbfna4cB1Zd3GeqPq1ZO#67372027下面发布了一个答案,希望这可以帮到你。 - imsheth
1
@mobinalhassan,关于Docker化的Airflow,在Airflow 1.10.x和Airflow 2.0.x上的主要问题是权限问题。我花了将近两个多月的时间,但仍无法解决——因为Docker化的Airflow的基础镜像既不是Ubuntu也不是Alpine,为了节省时间,我最终放弃了Docker化的Airflow,转而使用非Docker化的Airflow来使其正常工作。 - imsheth
显示剩余6条评论

1

在@Tamlyn的回答之后,我们还可以跳过从airflow创建连接(docker_conn_id)并按照以下步骤使用gitlab

  1. 在您的开发机器上:
  • https://gitlab.com/yourgroup/yourproject/-/settings/repository(在此处创建令牌并获取登录详细信息)
  • docker login registry.gitlab.com(在要从机器登录到docker以将图像推送到docker的机器上输入gitlab凭据时)
  • docker build -t registry.gitlab.com/yourgroup/yourproject . && docker push registry.gitlab.com/yourgroup/yourproject(构建并推送到您的项目存储库的容器注册表)
  1. 在您的airflow机器上:
  • https://gitlab.com/yourgroup/yourproject/-/settings/repository(您可以使用上述创建的令牌进行登录)
  • docker login registry.gitlab.com(从机器登录到docker以从docker中拉取镜像,这样可以跳过创建docker注册表连接的需要-在提示时输入您的gitlab凭据=这会生成~/.docker/config.json,这是必需的来自docker文档的参考
  1. 在您的DAG中:
dag = DAG(
    "dag_id",
    default_args = default_args,
    schedule_interval = "15 1 * * *"
)

docker_trigger = DockerOperator(
    task_id = "task_id",
    api_version = "auto",
    network_mode = "bridge",
    image = "registry.gitlab.com/yourgroup/yourproject",
    auto_remove = True, # use if required
    force_pull = True, # use if required
    xcom_all = True, # use if required
    # tty = True, # turning this on screws up the log rendering
    # command = "", # use if required
    environment = { # use if required
        "envvar1": "envvar1value",
        "envvar2": "envvar2value",
    },
    dag = dag,
)

这适用于已安装airflowUbuntu 20.04.2 LTS实例(经过测试验证)。

我相信我已经成功地使用DigitalOcean的容器注册表解决了这个问题。不过,有一个快速问题,当您使用DockerOperator拉取镜像时,它是否会将镜像存储在Airflow机器上?还是会将其删除?似乎auto_remove标志仅适用于容器。 - dyao
auto_remove 是用于垃圾回收的,我相信。force_pull 每次都会尝试拉取新的镜像,如果有可用的话。 - imsheth

1
根据最近的 Cloud Composer 文档,建议使用 KubernetesPodOperator 替代,示例如下:

documentation

from airflow.contrib.operators.kubernetes_pod_operator import KubernetesPodOperator

KubernetesPodOperator(
    task_id='docker_op_tester',
    name='docker_op_tester',
    dag=dag,
    namespace="default",
    image="eu.gcr.io/project/image",
    cmds=["ls"]
    )

0
您需要在工作站上安装Cloud SDK,其中包括gcloud命令行工具。
安装完Cloud SDK和Docker版本18.03或更高版本后,根据其文档从容器注册表中提取,请使用以下命令:
docker pull [HOSTNAME]/[PROJECT-ID]/[IMAGE]:[TAG] 

或者

docker pull [HOSTNAME]/[PROJECT-ID]/[IMAGE]@[IMAGE_DIGEST]

说明:

  • [HOSTNAME] 在控制台的位置下列出。它是四个选项之一:gcr.io、us.gcr.io、eu.gcr.io 或 asia.gcr.io。
  • [PROJECT-ID] 是您的 Google Cloud 平台控制台项目 ID。
  • [IMAGE] 是容器注册表中图像的名称。
  • [TAG] 是应用于图像的标记。在注册表中,标记对于图像是唯一的。
  • [IMAGE_DIGEST] 是图像内容的 sha256 哈希值。在控制台中,单击特定图像以查看其元数据。摘要列为图像摘要。

获取特定图像的拉取命令:

  1. 单击图像名称以转到特定注册表。
  2. 在注册表中,选中要拉取的图像版本旁边的框。
  3. 单击页面顶部的 SHOW PULL COMMAND。
  4. 复制拉取命令,该命令使用标记或摘要标识图像。

*还要检查您是否从注册表获得了推送和拉取权限

**配置 Docker 使用 gcloud 作为凭据助手,或者使用另一种身份验证方法。要使用 gcloud 作为凭据助手,请运行以下命令:

gcloud auth configure-docker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接