Dockerfile 使用技巧

简介: 通常我们会在项目根目录编写 Dockerfile,它是描述镜像构建流程的配置文件。官方文档提供了详细语法说明,但实际使用中需要注意一些关键细节,尤其是 CMD 和 ENTRYPOINT 的区别。

本文翻译自我的英文博客,最新修订内容可随时参考:Dockerfile使用技巧

通常我们会在项目根目录编写 Dockerfile,它是描述镜像构建流程的配置文件。官方文档提供了详细语法说明,但实际使用中需要注意一些关键细节,尤其是 CMDENTRYPOINT 的区别。

一、Dockerfile 核心要点

  1. 多CMD指令
    若定义多个 CMD,仅有最后一个生效。建议将多个命令写入脚本文件(如 start.sh),通过 CMD ["./start.sh"] 执行。

  2. 容器启动机制
    Docker 容器不支持 systemd,其主进程即为应用进程。容器生命周期与主进程绑定,主进程退出则容器终止。

    • 错误示例:CMD service nginx startservice 会在后台运行,导致容器主进程立即退出)。
    • 正确示例:CMD ["nginx", "-g", "daemon off;"](让 Nginx 前台运行成为主进程)。
  3. 构建命令

    docker build -t my-image:1.0 .  # -t 指定镜像名和标签,. 表示构建上下文(通常为当前目录)
    

    构建上下文会打包目录内文件传递给 Docker 引擎,需避免包含无关文件(可通过 .dockerignore 过滤)。

二、CMD vs ENTRYPOINT:执行模式与区别

1. 执行模式(Exec vs Shell)

a. Exec 模式(推荐)

  • 格式CMD ["executable", "param1", "param2"]
  • 特点
    • 直接执行指定程序,不通过 Shell(如 /bin/sh)。
    • 环境变量需显式传递(如 ENTRYPOINT ["echo", "$HOME"] 不会解析 $HOME)。
    • 主进程为目标程序(PID 1),容器状态与程序生命周期一致。

b. Shell 模式

  • 格式CMD command param1 param2
  • 特点
    • 通过 /bin/sh -c 执行命令,主进程为 Shell(PID 1),目标程序为子进程(PID > 1)。
    • 自动解析环境变量(如 CMD echo $HOME 会输出 /root)。
    • 可能引发信号处理问题(如容器无法捕获程序的退出信号)。

2. CMD 指令

作用:定义容器默认执行的命令或参数,可被 docker run 命令覆盖。

语法形式

  1. Exec 模式(推荐)
    CMD ["python", "app.py"]  # 直接执行 Python 脚本
    
  2. Shell 模式
    CMD python app.py  # 等价于 CMD ["sh", "-c", "python app.py"]
    
  3. 为 ENTRYPOINT 提供默认参数
    ENTRYPOINT ["curl"]  
    CMD ["https://example.com"]  # 可通过 docker run my-image https://baidu.com 覆盖
    

覆盖规则

  • 执行 docker run my-image custom-command 时,CMD 会被 custom-command 替换。
  • 示例:
    CMD ["echo", "hello"]  # Dockerfile 中的默认命令
    
    docker run my-image ls  # 实际执行 ls(覆盖 CMD)
    

3. ENTRYPOINT 指令

作用:设置容器的固定入口命令,参数可通过 CMDdocker run 动态传递。

语法形式

  1. Exec 模式(推荐)
    ENTRYPOINT ["nginx", "-g", "daemon off;"]  # 前台运行 Nginx,主进程为 Nginx
    
  2. Shell 模式
    ENTRYPOINT nginx -g "daemon off;"  # 主进程为 sh,Nginx 为子进程
    

参数传递规则

  • Exec 模式docker run 的参数会追加到 ENTRYPOINT 之后。
    ENTRYPOINT ["curl", "-X"]  
    CMD ["GET"]
    
    docker run my-image POST https://example.com  # 实际执行 curl -X POST https://example.com
    
  • Shell 模式docker run 的参数会被忽略,仅执行 ENTRYPOINT 定义的命令。
    ENTRYPOINT curl https://example.com
    
    docker run my-image https://baidu.com  # 仍执行 curl https://example.com
    

强制覆盖 ENTRYPOINT

通过 --entrypoint 选项指定新的入口命令:

docker run --entrypoint ls my-image  # 忽略 Dockerfile 中的 ENTRYPOINT,执行 ls

三、组合使用 CMD 和 ENTRYPOINT

场景 配置示例 执行效果
固定命令 + 默认参数 ENTRYPOINT ["curl"]<br>CMD ["https://example.com"] docker run my-imagecurl https://example.com
docker run my-image https://baidu.comcurl https://baidu.com
禁止参数覆盖 ENTRYPOINT ["nginx", "-g", "daemon off;"] 无论 docker run 传递什么参数,始终运行 Nginx 前台模式
需要解析环境变量 ENTRYPOINT ["sh", "-c", "echo $ENV_VAR"] 正确输出环境变量值(如通过 docker run -e ENV_VAR=test my-image 传递)
复杂初始化脚本 ENTRYPOINT ["/app/init.sh"]<br>CMD ["main-process"] 先执行初始化脚本,再运行主进程(init.sh 需前台执行主进程)

四、最佳实践建议

  1. 优先使用 Exec 模式

    • 避免 Shell 模式的隐藏问题(如信号处理、性能损耗)。
    • 需要解析环境变量时,显式通过 sh -c 处理:
      ENTRYPOINT ["sh", "-c", "echo $HOME"]  # 正确解析 $HOME
      
  2. 明确职责分工

    • ENTRYPOINT:定义不可变的入口命令(如程序二进制文件)。
    • CMD:提供可覆盖的默认参数或备用命令。
  3. 主进程唯一性

    • 确保容器内只有一个主进程(如 Web 服务器、API 服务),避免多个阻塞进程导致容器异常退出。
  4. 构建上下文优化

    • 通过 .dockerignore 排除不必要的文件(如 node_modules、日志文件),减少构建时间和镜像体积。
      *.log  
      node_modules/
      
  5. 多阶段构建(减少镜像体积)

    FROM golang:1.20 AS builder  
    WORKDIR /app  
    COPY . .  
    RUN go build -o my-app  
    
    FROM alpine:3.17  
    COPY --from=builder /app/my-app /usr/bin/my-app  
    ENTRYPOINT ["my-app"]
    

五、常见问题与解决方案

问题 1:容器启动后立即退出

  • 原因:主进程执行完毕或崩溃。
  • 排查步骤
    1. 使用 docker run -it my-image sh 进入容器,手动执行主进程命令,查看错误日志。
    2. 确保主进程为前台运行(如去掉 daemon 参数)。

问题 2:环境变量未生效

  • 原因:使用 Exec 模式但未通过 Shell 解析。
  • 解决方案
    ENTRYPOINT ["sh", "-c", "echo $ENV_VAR && my-app"]  # 通过 Shell 解析环境变量
    

问题 3:无法通过 docker stop 优雅终止容器

  • 原因:主进程为 Shell 模式下的子进程,无法接收 SIGTERM 信号。
  • 解决方案:改用 Exec 模式,让主进程直接接收信号:
    ENTRYPOINT ["my-app"]  # 主进程为 my-app,可正确响应 docker stop
    

总结:选择策略

需求场景 推荐指令 示例
定义默认执行命令且可覆盖 CMD CMD ["python", "app.py"]
固定入口命令,参数可动态传递 ENTRYPOINT + CMD ENTRYPOINT ["curl"]<br>CMD ["https://example.com"]
需要解析环境变量 ENTRYPOINT + sh ENTRYPOINT ["sh", "-c", "echo $HOME && my-app"]
禁止任何参数覆盖 ENTRYPOINT ENTRYPOINT ["nginx", "-g", "daemon off;"]

通过合理组合 CMDENTRYPOINT,可以灵活控制容器的启动行为,同时保持镜像的可复用性和可扩展性。更多实战案例可参考博客:Dockerfile使用技巧

目录
相关文章
|
存储 安全 关系型数据库
AWS介绍
AWS介绍
748 0
|
10月前
|
SQL 数据可视化 BI
VeryReport和FastReport两款报表软件深度分析对比
VeryReport和FastReport两款报表软件深度分析对比
|
搜索推荐 Linux Shell
打造个性化的Linux命令提示符
【8月更文挑战第47天】在Linux的世界里,命令行是高效工作的利器。本文将引导你如何通过简单的配置,让你的命令提示符更加个性化和实用,从而提升你的工作效率和终端使用体验。我们将从基础的颜色设置开始,逐步深入到复杂的解析符号和脚本编写,最终实现一个既美观又功能丰富的命令提示符。无论你是初学者还是高级用户,都能在这里找到适合你的技巧。让我们一起探索,让命令行不再单调!
228 16
|
10月前
|
人工智能 自然语言处理 算法
DeepSeek vs ChatGPT:AI对决中的赢家是……人类吗?
DeepSeek VS ChatGPT:DeepSeek以开源黑马姿态崛起,凭借低成本、高性能的「DeepSeek-V3」和专为深度推理设计的「DeepSeek-R1」,成为中小开发者的首选。而ChatGPT则较贵。 然而,AI依赖也带来隐忧,长期使用可能导致记忆衰退和“脑雾”现象。为此,推荐Neuriva解决方案,专注力提升30%,记忆留存率提升2.1倍,助力人类在AI时代保持脑力巅峰。 DeepSeek赢在技术普惠,ChatGPT胜于生态构建,人类的关键在于平衡AI与脑力健康,实现“双核驱动”突破极限!
1077 7
|
10月前
|
前端开发 搜索推荐 数据挖掘
推三返一模式开发案例
推三返一模式是一种创新的营销策略,其核心是鼓励现有用户推荐新用户注册或购买,以实现用户基数的快速增长和品牌影响力的提升。以下是对推三返一模式开发的详细解析:
|
10月前
|
JSON 监控 API
虾皮(shopee)商品列表接口(虾皮API 系列)
虾皮(Shopee)是东南亚及台湾地区的知名电商平台,提供丰富的商品数据。通过其API接口,开发者可合法获取商品列表信息,包括商品ID、名称、价格等,支持按分类、关键词、价格范围等条件筛选。Python示例代码展示了如何使用API进行请求,并解析返回的JSON数据。应用场景涵盖市场调研、竞品分析、选品决策、价格监控及数据可视化,帮助电商从业者和分析师更好地理解市场动态,优化运营策略。
|
10月前
|
图形学
unity中Rigidbody添加力的几种方式
本篇就是添加力的几种方式,记录一下
|
10月前
|
存储 图形学 索引
unity 使物体跟随路径点自动移动位置
在Unity中,物体沿路径点自动移动的核心原理是通过预设路径点,控制物体依次移动。路径点可用空对象或三维向量数组定义,并按顺序存储。移动时,计算当前位置与下一个路径点的向量差以确定方向,使用`Vector3.MoveTowards`逐步靠近目标点。代码实现包括路径点设置、移动控制及插值计算,确保物体平滑移动和旋转。
|
12月前
|
JSON Shell Linux
dockerfile 用法全解析
Dockerfile指令简介:`FROM`基于Alpine镜像;`WORKDIR`设置工作目录;`COPY`复制文件;`ADD`支持URL;`RUN`运行命令;`CMD`容器启动时执行;`ENTRYPOINT`与`CMD`组合执行;`EXPOSE`声明端口;`VOLUME`映射文件;`ENV`设置环境变量;`ARG`构建参数;`LABEL`元数据;`ONBUILD`触发命令;`STOPSIGNAL`停止信号;`HEALTHCHECK`健康检查;`SHELL`默认Shell。Alpine仅5M,小巧高效。
269 4
dockerfile 用法全解析
|
Go Docker Python
docker的python与go镜像的制作
docker的python与go镜像的制作
210 1

热门文章

最新文章