GitHub Actions构建Docker镜像部署AWS ECS报exec format error
问题现象
使用Docker构建应用部署至AWS ECS集群,Docker镜像通过GitHub Actions完成构建后推送至AWS ECR,镜像部署到ECS集群时抛出如下错误:
standard_init_linux.go:228: exec user process caused: exec format error
故障截图参考:
相关配置
Dockerfile内容
FROM python:3.9.11-slim ENV PYTHONUNBUFFERED=1 ARG APP_USER=app RUN groupadd -r ${APP_USER} && useradd --no-log-init -r -m -g ${APP_USER} ${APP_USER} RUN set -ex \ && RUN_DEPS=" \ libpcre3 \ mime-support \ libmagic1 \ default-libmysqlclient-dev \ inkscape \ libcurl4-nss-dev libssl-dev \ " \ && seq 1 8 | xargs -I{} mkdir -p /usr/share/man/man{} \ && apt-get update && apt-get install -y --no-install-recommends $RUN_DEPS \ && python -m pip install --upgrade pip \ && rm -rf /var/lib/apt/lists/* \ && mkdir -p /home/${APP_USER}/.config/inkscape \ && chown -R ${APP_USER} /home/${APP_USER}/.config/inkscape \ # Create directories && mkdir /app/ \ && mkdir /config/ \ && mkdir /scripts/ \ && mkdir -p /static_cdn/static_root/ \ && chown -R ${APP_USER} /static_cdn/ COPY ./requirements/requirements.txt / RUN set -ex \ && BUILD_DEPS=" \ build-essential \ libpcre3-dev \ libpq-dev \ " \ && apt-get update && apt-get install -y --no-install-recommends $BUILD_DEPS \ && pip install -r requirements.txt \ && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $BUILD_DEPS \ && rm -rf /var/lib/apt/lists/* COPY ./src /app/ COPY pytest.ini / COPY ./scripts/ /scripts/ COPY ./configs/ /configs/ COPY library_data /library_data WORKDIR /app/ EXPOSE 8000 ENV UWSGI_WSGI_FILE=app/wsgi.py ENV UWSGI_HTTP=:8000 UWSGI_MASTER=1 UWSGI_HTTP_AUTO_CHUNKED=1 UWSGI_HTTP_KEEPALIVE=1 UWSGI_LAZY_APPS=1 UWSGI_WSGI_ENV_BEHAVIOR=holy ENV UWSGI_WORKERS=2 UWSGI_THREADS=4 ENV UWSGI_STATIC_MAP="/static/=/static_cdn/static_root/" UWSGI_STATIC_EXPIRES_URI="/static/.*\.[a-f0-9]{12,}\.(css|js|png|jpg|jpeg|gif|ico|woff|ttf|otf|svg|scss|map|txt) 315360000" # Change to a non-root user USER ${APP_USER}:${APP_USER} ENTRYPOINT ["/scripts/docker/entrypoint.sh"]
entrypoint.sh内容
#!/bin/sh #set -e safeRunCommand() { cmnd="$*" echo cmnd="$cmnd" eval "$cmnd" ret_code=$? if [ $ret_code != 0 ]; then printf "Error : [code: %d] when executing command: '$cmnd'\n" $ret_code exit $ret_code else echo "Command run successfully: $cmnd" fi } runDjangoCollectStatic() { echo "Collecting static files" cmnd="python manage.py collectstatic --noinput" safeRunCommand "$cmnd" echo "Done: Collecting static files" } runDjangoMigrate() { echo "Migrating database" safeRunCommand "python manage.py migrate --noinput" echo "Done: Migrating database" } runDjangoCheckDeploy() { echo "Checking Django deployment" safeRunCommand "python manage.py check --deploy" echo "Done: Checking Django deployment" } if [ "x$DEPLOYMENT_MODE" = 'xproduction' ]; then echo "Running in production mode..." runDjangoCheckDeploy runDjangoCollectStatic runDjangoMigrate fi if [ "x$DJANGO_MANAGE_COLLECTSTATIC" = 'xon' ] && [ ! "x$DEPLOYMENT_MODE" = 'xproduction' ]; then runDjangoCollectStatic fi if [ "x$DJANGO_MANAGE_MIGRATE" = 'xon' ] && [ ! "x$DEPLOYMENT_MODE" = 'xproduction' ]; then runDjangoMigrate fi # Accept other commands exec "$@"
异常补充信息
- 相同代码在本地构建镜像推送至ECR后,部署运行无任何异常
- 拉取GitHub Actions构建并推送至ECR的镜像在本地运行时,会出现如下平台不匹配警告,但镜像可在本地正常运行:
docker pull ecr/image docker run -it ecr/image bash WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested app@fc0e09fc9094:/app$
- 当前ECS集群使用的EC2实例为m6g系列(搭载Graviton处理器),在服务容器中执行
uname -m命令返回结果为aarch64 - GitHub Actions构建的镜像内执行
uname -m命令返回结果为x86_64
故障根因
exec format error是典型的CPU架构不匹配错误:
- GitHub Actions默认使用x86_64架构的运行器,未指定构建平台时默认输出
linux/amd64架构镜像,和Graviton实例的ARM64(aarch64)架构不兼容 - 本地ARM架构设备运行该镜像不报错,是因为本地Docker默认开启了QEMU跨架构模拟,可以转译执行x86二进制,ECS的EC2实例默认未开启该模拟,直接运行异架构镜像就会启动失败
- 本地构建的镜像可以正常部署,说明本地构建时自动匹配了对应部署的架构,和CI构建输出的架构存在差异
解决方案
方案1:构建ARM64架构镜像(推荐,性能最优)
修改GitHub Actions的镜像构建流程,指定输出ARM64架构镜像适配Graviton实例:
- 如果使用官方
docker/build-push-action构建镜像,添加platforms: linux/arm64配置即可,示例片段:
- name: Build and push to ECR uses: docker/build-push-action@v5 with: context: . push: true tags: ${{ steps.meta.outputs.tags }} # 指定构建ARM64架构镜像适配Graviton platforms: linux/arm64
- 如果直接使用docker命令构建,添加
--platform linux/arm64参数:
docker build --platform linux/arm64 -t <your-ecr-image-uri> .
方案2:构建多架构镜像(兼容多环境)
如果后续需要同时支持x86和ARM架构的ECS实例,可以配置构建多架构镜像,推送时会同时上传两种架构的镜像层,Docker拉取时会自动匹配节点架构,配置示例:
- name: Build and push multi-arch image uses: docker/build-push-action@v5 with: context: . push: true tags: ${{ steps.meta.outputs.tags }} # 同时构建x86、ARM两种架构镜像 platforms: linux/amd64,linux/arm64
方案3:更换ECS实例架构
如果不想修改CI流程,可以将ECS集群的EC2实例更换为x86_64架构类型(如m5、c5系列),匹配现有CI构建的amd64镜像。但Graviton实例性价比更高,该方案仅作为临时备选。
内容的提问来源于stack exchange,提问作者Anuj TBE
相关产品推荐
相关产品推荐

