在Mac OSX上构建的Docker镜像无法在AWS EC2实例上运行

15

使用M1处理器的Mac OSX上构建的图像,部署到EC2实例上。但是在运行脚本时出现以下错误:

standard_init_linux.go:219: exec user process caused: exec format error

在Stackoverflow的其他地方,这被解释为操作系统体系结构不匹配。确实,在EC2实例上运行"uname -m"显示它是x86_64,“docker image inspect”显示容器具有arm64体系结构。

这里是我不理解的地方。我的Mac上运行"uname -m"也显示为x86_64。那么容器是如何继承不同的体系结构的呢?

更重要的是,我该如何在自己的Mac上构建一个可以在EC2上运行的图像?

Docker文件简单地是

FROM python
WORKDIR /
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY src /src

目前,src文件包含一些简单的Python脚本,可以通过以下方式执行:

docker run container/name python test.py

在我的Mac上运行良好,但在AWS上执行时出现了以上错误。

5个回答

22

好的,这里是正在发生的事情。我的 Mac 电脑有新的 M1 芯片,并且我正在运行 Docker Desktop 的技术预览版本。在芯片下面,它具有 arm64 架构,但是通过 iTerm 和 VSCode 进行询问时,它声称是 x86_64,因此我发布问题时感到困惑。这可能是因为这两个应用程序在后台静默地通过英特尔模拟器运行,这就是 uname 命令响应的原因。

然而,由于处理器实际上是 arm64,这是我从 Docker 中拉取 Python 映像时的基础架构 (我尝试了许多不同风格和版本的 Python,结果都相同)。

为了强制使用 amd64 AWS 兼容映像,我将 Dockerfile 的第一行更改为:

FROM --platform=linux/x86-64 python

当在 Mac 上运行来自此映像的容器时,会出现警告:

WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested

但这只是一个警告,脚本会运行 (可能通过重新定向到英特尔模拟器)。现在,这些脚本在 EC2 实例上运行时没有问题 (或警告)。


我得记住这个 - 这在未来肯定会越来越普遍,好答案! - Maurice
2
您还可以使用 buildx 强制构建不同平台的镜像 https://www.docker.com/blog/multi-platform-docker-builds/ - Software Engineer

2
我不确定为什么会出现这个错误,但如果您愿意且不介意您的代码和图像是公开的,有一种不错的方法可以解决它。我猜这只是家庭事务,所以可能不会太糟糕。
以下是步骤:
1. 将您的代码放在github上。 2. 配置hub.docker.com上的存储库以及从github配置自动构建。 3. ssh登录您的ec2实例并直接从docker hub拉取您的镜像。
另一种方法是先执行第一步,然后使用ssh登录到您的ec2并在该机器上克隆repo。然后您可以在真实的Linux机器上直接构建它(您的osx机器不运行Linux,这与docker不匹配)。如果您在服务器上构建它,则应该能够在那里无问题地运行它。

这是测试一条路径,以便将客户工作转移到Docker上,因此公共图像并不是一个选项。其中一些图像将被容器化并发送到一组服务器,因此在每个服务器上构建图像对于这种情况并不起作用。尽管如此,了解来自github的自动构建非常有趣,可能会出现在其他地方。因此,非常感谢您引起我的注意。 - petercoles
你也可以使用私有仓库,不必公开。如果使用多个服务器,这是您希望遵循的标准模式。这是所有选项中最简单的方法。您甚至可以通过更受限制的注册表(如亚马逊自己的ECR)运行。最终,如果您为服务器群使用此功能,还应该使用Kubernetes - 这很难,但这是让所有内容协同工作并支持服务器群集的最简单方式。 - Software Engineer

1
尝试在容器中运行 CMD ["lscpu"] 或类似的命令,比较架构。另外一件事:在构建时可能会拉取 Python 映像的 arm 架构,并尝试在 x86_64(EC2)上运行它。

docker image inspect | grep Architecture 也可以提供这些信息,而无需将代码注入到镜像中。不过你说得对,问题确实是关于使用错误架构拉取镜像的,你的回答激发了我深入挖掘并找到了根本原因。 - petercoles

1
您可以通过在“设置/ DockerEngine”中添加"default-platform": "linux/amd64"到JSON配置的"builder"部分来配置Docker Desktop for Mac默认构建AMD映像。

0
除了上面分享的内容外,你还可以使用Buildx构建多架构镜像。
基本上,最近的Docker版本配备了一个CLI命令叫做buildx。您可以在Mac和Windows上的Docker桌面版上使用buildx命令来构建多架构镜像,使用清单文件将它们链接在一起,并使用单个命令将它们全部推送到注册表中。
以下是我成功使用的方法:
创建一个新的构建器,以便访问新的多架构特性。
docker buildx create --name mybuilder --use

使用buildx构建Dockerfile,传递要构建的架构列表:

 docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t username/demo:latest --push .
 => pushing layers                                                             2.7s
 => pushing manifest for docker.io/username/demo:latest                       2.2

其中,username 是有效的 Docker 用户名。

注意: --platform 标志告知 buildx 为 AMD 64 位、Arm 64 位和 Armv7 架构生成 Linux 映像。
--push 标志生成多架构清单并将所有映像推送到 Docker Hub。

要检查映像,请使用以下命令

docker buildx imagetools inspect username/demo:latest

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