【图文并茂】dockerfile构建镜像add和copy的区别,cmd和ENTRYPOINT 区别
ADD vs COPY 核心区别
| 场景 | 用什么 | 示例 |
|---|---|---|
| 复制本地文件到镜像 | COPY | COPY app.py /app/ |
| 复制并自动解压 tar 包 | ADD | ADD 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.gzCMD 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提供默认参数。这样既保证容器一定跑你想跑的程序,又允许运行时灵活调整参数。
几个易踩的坑
shell 格式 vs exec 格式:
CMD nginx -g "daemon off;"(shell 格式)会通过/bin/sh -c执行,收不到 SIGTERM 信号,容器停止会超时。生产环境用 exec 格式CMD ["nginx", "-g", "daemon off;"]。ENTRYPOINT 用 shell 格式会忽略 CMD:
ENTRYPOINT nginx这种写法会让 CMD 完全失效,因为 shell 格式会变成/bin/sh -c "nginx"。想覆盖 ENTRYPOINT:用
--entrypoint参数,如docker run --entrypoint bash myimage。基础镜像有 ENTRYPOINT 你想替换:在子 Dockerfile 里重新写
ENTRYPOINT,会覆盖父镜像的。
