在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 环境中定义和执行任务,大大降低了依赖冲突的概率
对于版本特性和迁移说明可以参考
- https://aws.amazon.com/cn/blogs/big-data/introducing-apache-airflow-3-on-amazon-mwaa-new-features-and-capabilities/
- https://aws.amazon.com/cn/blogs/big-data/best-practices-for-migrating-from-apache-airflow-2-x-to-apache-airflow-3-x-on-amazon-mwaa/
需要注意的是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:
根据官方的issue,aws-mwaa-local-runner后期似乎不再支持3.x版本的mwaa-local-runner环境,所以需要迁移到amazon-mwaa-docker-images。

简单来说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
查看容器结构

调度器日志

worker日志

webserver日志

web界面

示例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()
任务日志

配置页面

故障排查
环境变量未定义导致 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

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

浙公网安备 33010602011771号