一、CMDENTRYPOINT 为什么总让人混淆

这两个指令都和容器启动有关,但职责并不一样:

  • CMD 更像默认参数或默认启动命令
  • ENTRYPOINT 更像容器真正的主程序入口

如果只记一句话:

  • CMD 容易被运行时参数覆盖
  • ENTRYPOINT 默认不会被普通运行参数直接覆盖

二、如何理解 ENTRYPOINT

例如下面这个 Dockerfile:

FROM registry.cn-hangzhou.aliyuncs.com/abroad_images/centos:7
RUN useradd dot
ENV envir=test version=1.0
ENTRYPOINT echo "envir:$envir version:$version"

启动容器时:

docker run --rm centos:entrypoint

就会直接执行 ENTRYPOINT 指定的命令。

如果你想临时替换它,则需要显式使用:

docker run --rm --entrypoint=ls centos:entrypoint /tmp

这说明 ENTRYPOINT 的控制级别更高。

三、CMDENTRYPOINT 的区别怎么记最稳

可以直接按启动行为来记:

3.1 CMD 可以被覆盖

例如:

docker run --rm centos:env-cmd echo "cover..."

这里传入的新命令会把原有 CMD 覆盖掉。

3.2 ENTRYPOINT 默认不会被后置参数直接替换

例如:

docker run --rm centos:entrypoint cannot cover...

后面的参数通常会被当成 ENTRYPOINT 的附加参数处理,而不是完全替换入口命令。

因此,经验上可以这样选:

  • 想给用户留出更灵活的启动覆盖空间,用 CMD
  • 想固定主启动程序,用 ENTRYPOINT

四、ARG 为什么适合做动态构建

很多镜像在构建时并不希望把所有内容写死,例如基础镜像、用户名、目录名等都可能随环境变化。这个时候就适合使用 ARG

示例:

ARG BASE_IMAGE
FROM $BASE_IMAGE

LABEL maintainer="dot" version="demo"

ARG USERNAME
ARG DIR="defaultValue"

RUN useradd -m $USERNAME -u 1001 && mkdir $DIR

构建时传参:

docker build \
  --build-arg BASE_IMAGE=registry.cn-hangzhou.aliyuncs.com/abroad_images/centos:7 \
  --build-arg USERNAME=test_arg \
  -t test:arg .

这类做法的好处是:

  • Dockerfile 复用性更高
  • 不同环境可以共用同一份构建逻辑
  • 更适合流水线和自动化构建场景

五、为什么会需要制作 ARM 镜像

随着 ARM 服务器、Mac 芯片和多架构部署场景变多,镜像只支持 amd64 已经不够用了。这个时候就需要借助 docker buildx 构建 ARM 或多平台镜像。

其核心思路是:

  • 创建支持多平台的构建器
  • 安装必要的 binfmt 支持
  • buildx 指定目标平台构建

六、国外环境下的 buildx 基本流程

6.1 创建并查看构建器

docker builder ls
docker buildx create --name mybuilder --use --platform linux/amd64,linux/arm64 --driver docker-container
docker builder ls | grep mybuilder
docker buildx inspect --bootstrap

6.2 安装多架构支持

docker run --privileged --rm tonistiigi/binfmt --install all

安装完成后,再次查看构建器,通常就能看到 linux/arm64 等平台支持已经可用。

6.3 构建 ARM 镜像

FROM centos:7
COPY files /mnt/files
docker buildx build --platform linux/arm64 \
  -t registry.cn-hangzhou.aliyuncs.com/abroad_images/buildx:v2 \
  --push -f ./Dockerfile .

如果只想本地加载镜像,可以考虑 --load

七、国内环境下的多架构构建要注意什么

国内环境的主要差异通常在两个地方:

  • 需要替换 buildkitbinfmt 镜像源
  • 基础镜像本身必须支持目标架构

例如:

docker buildx create \
  --name mybuilder \
  --driver-opt image=registry.cn-hangzhou.aliyuncs.com/abroad_images/buildkit:buildx-stable-1 \
  --use \
  --platform linux/amd64,linux/arm64 \
  --driver docker-container

docker run --privileged --rm registry.cn-hangzhou.aliyuncs.com/abroad_images/binfmt:latest --install all

同时,基础镜像也要确认能在 arm64 下运行。例如:

docker pull --platform=linux/arm64 centos:7

如果基础镜像本身不支持 ARM,那么后面的构建链路也走不通。

八、多架构构建最容易踩的坑有哪些

根据原始笔记,最典型的几个坑是:

8.1 拷贝二进制文件时架构不匹配

如果你用 COPY 拷贝的是已经编译好的二进制文件,那么它本身也必须能在目标架构运行。否则镜像能构建出来,容器也可能跑不起来。

8.2 在 amd64 主机直接运行 arm64 镜像

这种情况下经常会看到平台不匹配的警告。构建成功,不代表当前主机就一定能原生运行该镜像。

8.3 只关注构建命令,忽略基础镜像支持

很多多架构构建失败,本质上不是 buildx 命令错了,而是基础镜像压根没适配目标平台。

九、什么时候该用这些进阶能力

可以把本篇内容对应到三个典型场景:

  • 需要灵活启动参数时,用 CMD
  • 需要固定主入口时,用 ENTRYPOINT
  • 需要复用构建逻辑时,用 ARG
  • 需要适配多平台交付时,用 buildx

把这几项能力掌握之后,你的 Dockerfile 就不再只是“能构建”,而是开始具备面向复杂场景交付的能力。