在AWS云上使用amazon-mwaa-docker-images搭建MWAA的V3.x本地测试环境实践和故障排查

近期MWAA推出了3.x版本(首个支持版本为 v3.0.6,于 2025 年 10 月发布),实际上Apache Airflow 从 2.x 升级到 3.x 是一次非常重大的底层重构。截至 2026 年 4 月,Airflow 3 已经步入 3.2.x 版本的稳定迭代期。

  • Airflow 2.x 架构所有的 Worker 节点和任务实例 (Task Instances) 都直接连接到后端的元数据库(如 PostgreSQL/MySQL)。前端 UI 和后端强绑定,基于老旧的 Flask-AppBuilder 构建。界面响应慢,且许多 UI 交互需要完整的页面刷新。

  • Airflow 3.x 架构取消了 Worker/任务对数据库的直接访问。所有的任务、Worker 和自定义 Operator 必须通过基于 FastAPI 构建的 内部任务执行 API (Task Execution API) 与控制平面通信。并且彻底抛弃了 Flask 界面,重写为基于 React 的单页应用 (SPA)**,后端 API 全部迁移至 FastAPI(全新的 REST API v2)。

此外,为了配合执行环境的解耦,Airflow 3 引入了独立的 Task SDK。在 Airflow 3 中,序列化、反序列化逻辑以及任务级异常处理被下放到了 Task SDK 中。这意味着可以在一个更轻量、依赖更少的 Python 环境中定义和执行任务,大大降低了依赖冲突的概率

对于版本特性和迁移说明可以参考

需要注意的是mwaa并非完全支持v3特性,例如mwaa中集成iam认证,因此暂时无法弃用Flask AppBuilder

Although we are launching most of the Airflow 3 features on Amazon MWAA in this release, some features are not supported at this time:

  • Replace Flask AppBuilder (AIP-79) – Full replacement capabilities
  • Edge Executor and task isolations (AIP-69) – Remote execution capabilities
  • Multi-language support (AIP-72) – Support for languages other than Python

根据官方的issue,aws-mwaa-local-runner后期似乎不再支持3.x版本的mwaa-local-runner环境,所以需要迁移到amazon-mwaa-docker-images。

image

简单来说amazon-mwaa-docker-images是新一代的、更灵活的基础镜像库,而 aws-mwaa-local-runner 是较早期的、开箱即用的本地测试工具。

  • aws-mwaa-local-runner是最早发布的本地运行工具。它的设计目标是一键式体验,让开发者能快速在本地拉起一个和 MWAA 环境高度相似的 Airflow。包含了一个 CLI 脚本 (mwaa-local-env),自动处理 Docker 镜像构建、容器启动、环境变量加载等。仅仅是为了在本地测试一下 DAG 代码、简单的 Python 依赖(requirements.txt)或插件。

  • amazon-mwaa-docker-images是 AWS 近期推出的更现代化的仓库。镜像与 AWS 在云端实际运行的环境(Fargate 容器)几乎完全一致。它提供了不同层级的镜像,例如:standard: 生产标准版。dev: 包含调试工具(如文本编辑器、更详细的日志等)。explorer: 不自动启动 Airflow,方便你进去“探索”文件系统。

本文主要涉及如何在本地搭建mwaa v3的测试环境

编译镜像

amazon-mwaa-docker-images 项目提供 7 种镜像类型,基于相同的 base 镜像构建,适用于不同场景:

镜像类型 Dockerfile 用途
base Dockerfile.base 基础镜像,包含所有核心组件
standard Dockerfile 生产环境标准镜像
dev Dockerfile-dev 开发调试镜像
explorer Dockerfile-explorer 交互式探索镜像
explorer-dev Dockerfile-explorer-dev 带开发工具的探索镜像
explorer-privileged Dockerfile-explorer-privileged root 权限的探索镜像
explorer-privileged-dev Dockerfile-explorer-privileged-dev root 权限 + 开发工具

./build.sh docker可以直接构建所有镜像类型,可以根据需要选择。这里只构建标准镜像

需要生产部署?
├─ 是 → Standard
└─ 否 → 需要自动运行 Airflow?
    ├─ 是 → Dev(如果需要编辑文件)
    └─ 否 → 需要 root 权限?
        ├─ 是 → Explorer-Privileged-Dev
        └─ 否 → Explorer-Dev

进入amazon-mwaa-docker-images/images/airflow/3.0.6执行构建命令创建base镜像。需要注意的是要明确指定BUILDARCH

  • base是所有镜像的共同基础包含完整的环境和依赖
$ docker build   --build-arg BUILDARCH=amd64   -f ./Dockerfiles/Dockerfile.base   -t amazon-mwaa-docker-images/airflow:3.0.6-base ./

然后构建标准镜像

$ docker build --build-arg BUILDARCH=amd64   -f ./Dockerfiles/Dockerfile   -t amazon-mwaa-docker-images/airflow:3.0.6 ./

配置环境

创建配置文件

# cd amazon-mwaa-docker-images-main/images/airflow/3.0.6
# cat .env 
FERNET_KEY='{"FernetKey": "fake-key-nNge+lks3RBeGVrnZ1Dq5GjKerbZKmb7dXNnsNsGy3E="}'
AWS_ACCESS_KEY_ID=local
AWS_SECRET_ACCESS_KEY=local
AWS_SESSION_TOKEN=
REGION=us-west-2

# 日志配置(禁用 CloudWatch,使用本地文件日志)
MWAA__LOGGING__AIRFLOW_DAGPROCESSOR_LOG_LEVEL=INFO
MWAA__LOGGING__AIRFLOW_DAGPROCESSOR_LOGS_ENABLED=false
MWAA__LOGGING__AIRFLOW_DAGPROCESSOR_LOG_GROUP_ARN=
MWAA__LOGGING__AIRFLOW_SCHEDULER_LOG_LEVEL=INFO
MWAA__LOGGING__AIRFLOW_SCHEDULER_LOGS_ENABLED=false
MWAA__LOGGING__AIRFLOW_SCHEDULER_LOG_GROUP_ARN=
MWAA__LOGGING__AIRFLOW_TASK_LOG_LEVEL=INFO
MWAA__LOGGING__AIRFLOW_TASK_LOGS_ENABLED=false
MWAA__LOGGING__AIRFLOW_TASK_LOG_GROUP_ARN=
MWAA__LOGGING__AIRFLOW_TRIGGERER_LOG_LEVEL=INFO
MWAA__LOGGING__AIRFLOW_TRIGGERER_LOGS_ENABLED=false
MWAA__LOGGING__AIRFLOW_TRIGGERER_LOG_GROUP_ARN=
MWAA__LOGGING__AIRFLOW_WEBSERVER_LOG_LEVEL=INFO
MWAA__LOGGING__AIRFLOW_WEBSERVER_LOGS_ENABLED=false
MWAA__LOGGING__AIRFLOW_WEBSERVER_LOG_GROUP_ARN=
MWAA__LOGGING__AIRFLOW_WORKER_LOG_LEVEL=INFO
MWAA__LOGGING__AIRFLOW_WORKER_LOGS_ENABLED=false
MWAA__LOGGING__AIRFLOW_WORKER_LOG_GROUP_ARN=

# 核心配置
MWAA__CORE__API_SERVER_URL=http://mwaa-306-webserver:8080
MWAA__CORE__REQUIREMENTS_PATH=/usr/local/airflow/requirements/requirements.txt
MWAA__CORE__STARTUP_SCRIPT_PATH=/usr/local/airflow/startup/startup.sh
MWAA__CORE__TASK_MONITORING_ENABLED=false
MWAA__CORE__TERMINATE_IF_IDLE=false
MWAA__CORE__MWAA_SIGNAL_HANDLING_ENABLED=false
MWAA__HEALTH_MONITORING_ENABLE_REVAMPED_HEALTHCHECK=true
MWAA__CORE__KMS_KEY_ARN=

# 自定义配置(可选
# 允许在 Web UI 查看配置
MWAA__CORE__CUSTOM_AIRFLOW_CONFIGS={"webserver": {"expose_config": true}}

创建 requirements.txt(可选)

cat > requirements/requirements.txt << 'EOF'
# apache-airflow-providers-amazon==8.0.0
# pandas==2.0.3
EOF

创建 startup.sh(可选)

cat > startup/startup.sh << 'EOF'
#!/bin/bash
# 在这里添加你的启动脚本
echo "Running custom startup script..."
EOF
chmod +x startup/startup.sh

修改镜像为我们构建的标准镜像

# 查看当前使用的镜像
grep "image:" docker-compose.yaml | head -5
sed -i 's|image: amazon-mwaa-docker-images/airflow:3.0.6|image: amazon-mwaa-docker-images/airflow:3.0.6-dev|g' docker-compose.yaml

启动环境

docker compose up -d

查看容器结构

image

调度器日志

image

worker日志

image

webserver日志

image

web界面

image

示例dag

# Python imports
from datetime import datetime, timedelta

# Airflow imports.
from airflow import DAG
from airflow.decorators import task

with DAG(
    dag_id="hello_world_dag",
    schedule=timedelta(minutes=1),
    dagrun_timeout=timedelta(minutes=5),
    start_date=datetime(2024, 1, 1),
    catchup=False,
    is_paused_upon_creation=True,
) as dag:

    @task(task_id="print_task")
    def hello_world() -> None:
        """print_task prints a Hello World message."""
        print("Hello, World!")

    hello_world()


if __name__ == "__main__":
    dag.cli()

任务日志

image

配置页面

image

故障排查

环境变量未定义导致 ValueError

错误信息:

ValueError: Unknown level: ''

Airflow 3.0 的 MWAA 日志配置要求所有日志级别变量必须显式设置,不能为空字符串。在 .env 文件中设置所有日志相关变量:

MWAA__LOGGING__AIRFLOW_SCHEDULER_LOG_LEVEL=INFO
MWAA__LOGGING__AIRFLOW_SCHEDULER_LOGS_ENABLED=false

JSON 格式环境变量导致 TypeError

错误信息:

TypeError: expected str, bytes or os.PathLike object, not dict

docker-compose.yaml 中直接使用 YAML 单引号包裹 JSON:

MWAA__CORE__CUSTOM_AIRFLOW_CONFIGS: \'{"webserver": {"expose_config": true}}\'

这种方式在 shell 层面被解析为 dict 对象而非字符串,导致 subprocess 创建环境变量时失败。不要在 docker-compose.yaml 中硬编码 JSON 值,改用 .env 文件并正确转义:

# .env 文件
MWAA__CORE__CUSTOM_AIRFLOW_CONFIGS='{"webserver": {"expose_config": true}}'

在 docker-compose.yaml 中引用:

environment:
  MWAA__CORE__CUSTOM_AIRFLOW_CONFIGS: ${MWAA__CORE__CUSTOM_AIRFLOW_CONFIGS}

Worker 无法连接到 API Server

错误信息如下,并且无法看到日志

ConnectError: [Errno 99] Cannot assign requested address

image

.env 中配置的 API Server URL 为:

MWAA__CORE__API_SERVER_URL=http://localhost:8080

需要明确指定apiserver的host地址

MWAA__CORE__API_SERVER_URL=http://mwaa-306-webserver:8080

CloudWatch 日志访问错误

错误信息:

Reading remote log from CloudWatch log_group: ...
An error occurred (UnrecognizedClientException): The security token included in the request is invalid.

明明已经禁用了日志上传MWAA__LOGGING__AIRFLOW_TASK_LOGS_ENABLED=false

配置项 作用 设置值
MWAA__LOGGING__AIRFLOW_TASK_LOGS_ENABLED 控制 MWAA 组件是否写入 CloudWatch false
MWAA__LOGGING__AIRFLOW_TASK_LOG_GROUP_ARN 控制 Airflow 任务日志从哪里读取 ARN 存在即触发读取

只要设置了 LOG_GROUP_ARN,Airflow 就认为任务日志存储在 CloudWatch,即使写入被禁用,仍然会尝试读取。使用本地假凭证(AWS_ACCESS_KEY_ID=local)导致认证失败。

清空所有 LOG_GROUP_ARN,完全使用本地文件日志:

MWAA__LOGGING__AIRFLOW_TASK_LOGS_ENABLED=false
MWAA__LOGGING__AIRFLOW_TASK_LOG_GROUP_ARN=

Config无法访问

尽管增加了如下配置,仍旧显示无法访问配置页面

MWAA__CORE__CUSTOM_AIRFLOW_CONFIGS={"webserver": {"expose_config": true}}

docker-compose中没有引用这个环境变量,修改为

AIRFLOW__WEBSERVER__EXPOSE_CONFIG: ${AIRFLOW__WEBSERVER__EXPOSE_CONFIG:-True}

参考资料

posted @ 2026-04-25 02:33  zhaojie10  阅读(7)  评论(0)    收藏  举报