背景
有同事反馈在集群内的 Pod 一直处于 CrashLoopBackOff 状态,我们检查日志后发现以下错误信息:
➜ kubectl logs -f [PODNAME]
exec /bin/sh: exec format error
这个是 Linux 中的一个常见错误,一般来说是因为镜像所运行的架构与宿主机的架构不兼容所导致的。
我们可以执行 docker 命令
➜ docker image inspect [REPOSITORY]:[TAG]
在输出中,可以快速找到当前镜像的架构信息,例如:
...
"Architecture": "arm64",
"Os": "linux",
...
因云平台节点可能有不同的架构,所以需要保证应用程序能够在不同的环境上运行。
解决办法
针对容器镜像需要在不通架构上运行,常见两种方式:
- 在镜像名称上标识出镜像所运行依赖架构的名称,在调用镜像时根据镜像名称进行选择,比如demo_arm64:v1、demo_amd64:v1。保证其应用能够正常运行。
- 构建多架构镜像。
多架构镜像
我们会发现在Docker Hub 上官方提供的镜像能够同时支持不同的处理器架构。
这是因为 Docker 提供了 Docker Manifest 来解决跨平台镜像构建的问题,它是一种用于描述不同 CPU 架构、操作系统和操作系统版本的多平台 Docker 镜像的格式。我们可以将不同平台的镜像打包成一个 Image Manifests,并将其上传到 Docker Registry 上。
Manifest list 为不同的架构指向不同的镜像,这样当在特定的架构上使用镜像时,Docker 会快速检测与当前平台兼容的镜像版本,并且自动从镜像仓库中下载相应的镜像。
这种方式使得在不同的架构上运行 Docker 容器时更加的方便和灵活,而且多架构镜像本身也是遵循 Build Once, Deploy Anywhere 的原则。
Manifest
manifest list 是一个 JSON 数组,数组当中应用了不同平台镜像的 Manifest。所以,推送多平台镜像时,我们需要先分别推送不同平台的镜像层;然后创建 manifest list , 再引用平台镜像的 Manifest,最后把 manifest list 上传到 Registry 服务。而拉取镜像时,客户端应当设置 HTTP 的请求头字段 Accept 值为 applica