ECS Fargate 任务无法启动:"standard_init_linux.go:228: exec user process caused: exec format error" 即使是为 amd64 构建的

ECS Fargate task failing to start: "standard_init_linux.go:228: exec user process caused: exec format error" even when built for amd64

我的带有 Fargate 任务的 CDK 堆栈无法启动,任务直接停止并出现错误:

"standard_init_linux.go:228: exec user process caused: exec format error"

我知道这个错误通常是由于 Docker 图像不适合正确的 CPU 架构或一些格式错误的 shell 脚本,因此已采取措施解决这个问题。

我的 Docker 图像是一个 nodejs express 服务器,我在我的 MacOs M1 机器上构建了它。 我已经构建了镜像多架构(amd64 和 arm)以及 amd64。

我在另一个 AWS 账户中的 ALB 后面有一个手动创建的 Fargare 服务,它模拟了我试图用 CDK 做的事情。 我在另一个 AWS 账户 ECS 存储库中有相同的 Docker 图像,我的任务在那里工作。

因此我得出结论,它不是 Docker 图像本身,而是任务定义的东西。

有什么问题吗?

这是我的 CDK 堆栈:

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';

import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecr from 'aws-cdk-lib/aws-ecr';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ecsp from 'aws-cdk-lib/aws-ecs-patterns';

export class HelloEcsStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const serviceName = 'my-backend';
    const servicePort = 5432;

    const vpc = new ec2.Vpc(this, "MyVpc", {
      maxAzs: 2
    });

    const cluster = new ecs.Cluster(this, "BackendCluster", {
      vpc: vpc
    });    

    const load_balanced_fargate_service = new ecsp.ApplicationLoadBalancedFargateService(this, 'Backend', {
      cluster: cluster,
      taskImageOptions: {
        image: ecs.ContainerImage.fromEcrRepository(
          ecr.Repository.fromRepositoryName(this, id, 'backend-container-repo')
        ),
        containerPort: servicePort,
        environment: {
          // some key values our backend needs
        }
      },
      listenerPort: servicePort,
      publicLoadBalancer: true
    });

    load_balanced_fargate_service.targetGroup.configureHealthCheck({
      port: `${servicePort}`,
      path: '/api/health'
    });
  }
}

手册中我的任务定义 JSON 与 CDK 变体之间的唯一区别是:

手动:任务内存和CPU更大(2048/1024)

CDK:

"runtimePlatform": null,

手动:

"runtimePlatform": {
    "operatingSystemFamily": "LINUX",
    "cpuArchitecture": null
},

也有一些值CDK中的数组为空,而手动任务def中的值为null。不确定这是否重要。例子: 手册:“入口点”:空, CDK:“入口点”:[],

为了完整起见,这是我的 Docker图像文件:

# --------------> The build image
FROM node:latest AS build
WORKDIR /usr/src/app
COPY package*.json /usr/src/app/
RUN npm ci --only=production
 
# --------------> The production image
FROM node:lts-alpine
RUN apk add dumb-init
ENV NODE_ENV production
USER node
WORKDIR /usr/src/app
COPY --chown=node:node --from=build /usr/src/app/node_modules /usr/src/app/node_modules
COPY --chown=node:node . /usr/src/app

# Setup backend port (default can be overridden by --build-arg PORT <port value>)
ARG PORT=5432
ENV PORT=$PORT
EXPOSE $PORT

RUN echo 

CMD ["dumb-init", "node", "server.js"]

毕竟是图片

我的问题是我首先在本地构建了一个图像,但在部署时我使用了 shell 脚本。该脚本没有正确标记图像,因此实际推送的图像是旧图像(架构错误)。通过在本地清除我的 docker 图像和容器发现了这一点,并且在构建 运行 脚本时出现错误。

更正后的构建和部署脚本现在如下所示:

#!/bin/bash
if [ -z "" ]
then
  echo "Please provide all parameters"
  echo "usage: ./docker_deploy.sh <AWS account profile> <AWS region>"
  exit 1
fi

if [ -z "" ]
then
  echo "Please provide all parameters"
  echo "usage: ./docker_deploy.sh <AWS account profile> <AWS region>"
  exit 1
fi

PROFILE=""
REGION=""

export AWS_PROFILE=$PROFILE
export AWS_REGION=$REGION

REPO_NAME=your-repo
if aws ecr describe-repositories --repository-names ${REPO_NAME} >/dev/null ; then
    echo "ECR repository exists"
else
    echo "ECR repository doest not exist, creating..."
    aws ecr create-repository --repository-name ${REPO_NAME} >/dev/null
fi

REPO_URI=`aws ecr describe-repositories --repository-names ${REPO_NAME} | jq -r '.repositories[].repositoryUri | match( "([^/]*)" ).string'`



set -e # fail script on any individual command failing

aws ecr get-login-password --profile ${PROFILE} --region ${REGION} | docker login --username AWS --password-stdin ${REPO_URI}
docker build --platform=linux/amd64 -t ${REPO_NAME} .
docker tag ${REPO_NAME}:latest ${REPO_URI}/${REPO_NAME}:latest
docker push ${REPO_URI}/${REPO_NAME}:latest