一、CMD 和 ENTRYPOINT 为什么总让人混淆¶
这两个指令都和容器启动有关,但职责并不一样:
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 的控制级别更高。
三、CMD 和 ENTRYPOINT 的区别怎么记最稳¶
可以直接按启动行为来记:
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。
七、国内环境下的多架构构建要注意什么¶
国内环境的主要差异通常在两个地方:
- 需要替换
buildkit和binfmt镜像源 - 基础镜像本身必须支持目标架构
例如:
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 就不再只是“能构建”,而是开始具备面向复杂场景交付的能力。