【图文并茂】dockerfile构建镜像add和copy的区别,cmd和ENTRYPOINT 区别

ADD vs COPY 核心区别

场景用什么示例
复制本地文件到镜像COPYCOPY app.py /app/
复制并自动解压 tar 包ADDADD rootfs.tar.gz /
从 URL 下载文件RUN curl(推荐)RUN curl -o /x.sh https://...

为什么推荐 COPY:ADD 行为不透明——传 tar 它解压,传普通文件它不解压,传目录它复制目录,传 URL 它下载但不解压。容易踩坑。官方明确建议默认用 COPY。

dockerfile

# 推荐 COPY package.json /app/ COPY ./src /app/src # 仅当需要解压时用 ADD ADD rootfs.tar.xz / # 远程文件用 RUN curl 更可控(能校验、能重试) RUN curl -fsSL https://example.com/app.tar.gz -o /tmp/app.tar.gz \ && tar xzf /tmp/app.tar.gz -C /app \ && rm /tmp/app.tar.gz

CMD vs ENTRYPOINT 核心区别

一句话:CMD 可被docker run参数覆盖,ENTRYPOINT 不会被覆盖(参数追加到它后面)

三种写法 + 实际效果:

dockerfile

# 情况1:只用 CMD CMD ["nginx", "-g", "daemon off;"] # docker run myimage → 执行 nginx -g "daemon off;" # docker run myimage bash → 执行 bash(CMD 被整体替换!) # 情况2:只用 ENTRYPOINT ENTRYPOINT ["nginx", "-g", "daemon off;"] # docker run myimage → 执行 nginx -g "daemon off;" # docker run myimage -v → 执行 nginx -g "daemon off;" -v(参数追加) # 情况3:ENTRYPOINT + CMD 配合(最佳实践) ENTRYPOINT ["nginx"] CMD ["-g", "daemon off;"] # docker run myimage → 执行 nginx -g "daemon off;"(用 CMD 默认参数) # docker run myimage -t → 执行 nginx -t(CMD 参数被替换,程序不变)

最佳实践ENTRYPOINT固定主程序,CMD提供默认参数。这样既保证容器一定跑你想跑的程序,又允许运行时灵活调整参数。

几个易踩的坑

  1. shell 格式 vs exec 格式CMD nginx -g "daemon off;"(shell 格式)会通过/bin/sh -c执行,收不到 SIGTERM 信号,容器停止会超时。生产环境用 exec 格式CMD ["nginx", "-g", "daemon off;"]

  2. ENTRYPOINT 用 shell 格式会忽略 CMDENTRYPOINT nginx这种写法会让 CMD 完全失效,因为 shell 格式会变成/bin/sh -c "nginx"

  3. 想覆盖 ENTRYPOINT:用--entrypoint参数,如docker run --entrypoint bash myimage

  4. 基础镜像有 ENTRYPOINT 你想替换:在子 Dockerfile 里重新写ENTRYPOINT,会覆盖父镜像的。