HarmonyOS开发者限时福利来啦!最高10w+现金激励等你拿~ 了解详情
写点什么

Docker 的 ENTRYPOINT 和 CMD 参数探秘

  • 2019-10-10
  • 本文字数:2785 字

    阅读完需:约 9 分钟

Docker 的 ENTRYPOINT 和 CMD 参数探秘

在开始创建 Docker 容器的过程中,您可能会发现自己面临一个十分困惑的问题:Dockerfile 是应包含一条 ENTRYPOINT 说明、一条 CMD 说明,还是两者? 在本博文中,我将详细讨论这两者的差异,解释如何在您可能遇到的不同使用案例中用好它们。

一般原则

如果说今天您可以学到一个经验 ,那就是要遵循以下一般原则:


ENTRYPOINT + CMD = 默认容器命令参数


但须满足下列条件:


  1. 必须都可在运行时上单独覆盖;

  2. 任何一个或两者都可为空;并且

  3. 其中的加号 (+) 是指 ENTRYPOINT 与 CMD 在阵列环境中分别串联。

Chamber 简介

为便于说明 ENTRYPOINT 的优势,我们推出了 Chamber,这是一种开源实用工具,可以使用在 AWS Systems Manager Parameter Store 中找到的值来填充容器环境。一种典型的调用是 chamber exec production – program,该函数会获取键前缀为 /production 的所有 Parameter Store 值,将键中的斜线转换为下划线,然后使用返回的键和值填充环境。例如,如果找到键 /production/mysql/password,则 Chamber 会将 MYSQL_PASSWORD 环境变量设置为其中的安全值。

简单示例

下面我们来看一个示例。假设 Dockerfile 代码段含有 ENTRYPOINT 和 CMD 并且这两个参数都指定为阵列:


ENTRYPOINT ["/bin/chamber", "exec", "production", "--"]CMD ["/bin/service", "-d"]
复制代码


将这两个参数组合起来,则容器的默认参数将为 ["/bin/chamber", “exec”, “production”, “–”, “/bin/service”, “-d”]。


此列表大致相当于壳命令 /bin/chamber exec production – /bin/service -d。(实际上,这涉及了壳的主要作用:它们提取提示屏幕上以空格分隔的“命令”,最终将这些命令转换为参数整列,以便发送到 exec 系统调用。)

参数始终为阵列

需要注意的是,在 Dockerfile 中,ENTRYPOINT 和 CMD 始终将转换为阵列 — 即使您声明它们为字符串。(但为避免歧义,我始终建议将它们声明为阵列。)


假设我们声明一个用于启动 Web 服务器的 CMD 如下:


CMD /usr/bin/httpd -DFOREGROUND
复制代码


Docker 会自动将 CMD 转换为阵列,如下所示:


["/bin/sh", "-c", "/usr/bin/httpd -DFOREGROUND"]
复制代码


这同样适用于 ENTRYPOINT 参数。


因此,当我们声明 ENTRYPOINT 和 CMD 时,ENTRYPOINT 将是一个列表,这两个参数将组合成为一个默认的参数列表 — 即使我们声明 CMD 为字符串。


请看下面的示例。如果我们声明如下:


ENTRYPOINT ["/bin/chamber", "exec", "production", "--"]CMD "/bin/service -d"
复制代码


默认的参数列表将为 ["/bin/chamber", “exec”, “production”, “–”, “/bin/sh”, “-c”, “/bin/service -d”]。


注意:ENTRYPOINT 和 CMD 不能同时为字符串值。 它们可以都是阵列值,或者 ENTRYPOINT 为一个阵列值而 CMD 为一个字符串值;但如果 ENTRYPOINT 为一个字符串值,则 CMD 将被忽略。这是将参数字符串转换为阵列后无法避免的不幸后果。这也是我始终建议尽可能指定阵列的原因之一。

CMD 仅为默认值

指定 Dockerfile 中的 CMD 仅会创建一个默认值:如果我们将无选项的参数提交到 docker run,则它们将被 CMD 的值覆盖。


为方便演示,假设我们拥有如下的 Dockerfile,并从它创建了一个叫做 myservice 的映像:


ENTRYPOINT ["/bin/chamber", "exec", "production", "--"]CMD ["/bin/service", "-d"]
复制代码


如果我们调用 docker run myservice,则将创建包含下列参数的容器:


["/bin/chamber", "exec", "production", "--", "/bin/service", "-d"]
复制代码


如果我们改为调用 docker run myservice /bin/debug,则将创建包含下列参数的容器:


["/bin/chamber", "exec", "production", "--", "/bin/debug"]
复制代码


请注意 CMD 将被完全替换 — 不能在其开头或结尾处添加任何字符。

ENTRYPOINT 也可覆盖

我可以轻松覆盖在 Dockerfile 中声明的 ENTRYPOINT。为此我们将指定 docker run 的 --entrypoint 选项参数。


如前面一样,假设我们拥有如下的 Dockerfile,并从它创建了一个叫做 myservice 的映像:


ENTRYPOINT ["/bin/chamber", "exec", "production", "--"]CMD ["/bin/service", "-d"]
复制代码


然后让我们通过运行如下命令来修改 ENTRYPOINT:


docker run --entrypoint /bin/logwrap myservice
复制代码


根据我们的一般原则,将会构建如下参数列表:


["/bin/logwrap", "/bin/service", "-d"]
复制代码

同时覆盖 ENTRYPOINT 和 CMD

我们能否同时覆盖 ENTRYPOINT 和 CMD? 当然可以:


docker run --entrypoint /bin/logwrap myservice /bin/service -e
复制代码


对应的参数列表如下 — 到这时应该不会发生任何意外了:


["/bin/logwrap", "/bin/service", "-e"]
复制代码

我们何时应该使用 ENTRYPOINT? CMD 呢?

假设我们为某个项目构建自己的 Dockerfile。我们已经了解了 ENTRYPOINT 和 CMD 如何结合起来构建容器的默认参数列表的原理。但现在我们需要知道如何选择:何时建议使用 ENTRYPOINT,何时又建议使用 CMD?


您所做的选择基本上属于一种艺术,它严重依赖您的使用案例。但我的经验是,ENTRYPOINT 几乎适合我遇到的所有案例。可以考虑下列使用案例:


封套


一些映像包含所谓的“封套”,将原有的程序进行装饰或者进行其他准备,以便于在容器化环境中应用。例如,假设您的服务设计为从文件读取配置,而非从环境变量读取。则在这种情况下,您可以包含一个将利用环境变量生成配置文件的封套脚本,然后在最后调用 exec /path/to/app 以启动应用程序。


声明指向封套的 ENTRYPOINT 就是确保封套始终运行的一个极佳方法,而不论将何参数发送到 docker run。


单用途映像


如果您的映像仅用于执行一个操作( 例如运行 Web 服务器),则使用 ENTRYPOINT 来指定服务器二进制代码和任何强制参数的路径。一个典型示例是 nginx 映像,它的唯一用途是运行 nginx Web 服务器。这使它本身拥有一个天然的命令行调用:docker run nginx。然后您可以顺理成章地在命令行后添加程序命令,例如 docker run nginx -c /test.conf,就好比您在运行无 Docker 的 nginx。


多模式映像


支持多种“模式”的映像在 docker run



上使用第一个参数来指定映射到模式的谓语(例如 shell、migrate 或 debug),也十分常见。对于此类使用案例,我建议 ENTRYPOINT 的设置应指向一个将解释动作参数并根据其值执行相关操作的脚本,例如:


ENTRYPOINT ["/bin/parse_container_args"]
复制代码


这些参数将在调用时通过 ARGV[1…n] 或 2 等发送到入口点。

小结

Docker 拥有极其强大与灵活的映像构建功能,但在确定如何构建容器的默认运行时参数方面可能极具挑战。但愿本文可以帮助您更加清楚参数-汇编机制,以及如何在您的环境中发挥它们的最佳作用。


作者介绍:


Michael Fischer


Michael Fischer 是 AWS 专业服务部门的一名高级开发运营架构师。他专长于大型系统架构、容器设计和队列管理、云编排与自动化以及无服务器部署。他生活在加利福尼亚州奥克兰,喜欢潜水和击鼓。


本文转载自 AWS 技术博客。


原文链接:


https://amazonaws-china.com/cn/blogs/china/demystifying-entrypoint-cmd-docker/


2019-10-10 10:181178
用户头像

发布了 1848 篇内容, 共 113.8 次阅读, 收获喜欢 78 次。

关注

评论

发布
暂无评论
发现更多内容

关于Java Chassis 3的契约优先(API First)开发

华为云开发者联盟

华为云 华为云开发者联盟 企业号2024年5月PK榜 Java Chassis 3

基于需求文档、设计文档、测试用例的测试答疑助手

测吧(北京)科技有限公司

测试

纬湃科技第一季度以稳健业绩开启2024财年

财见

LLM 大模型学习必知必会系列(一):大模型基础知识篇

汀丶人工智能

prompt 工程 检索增强技术RAG LLM大模型

一文了解基于ITIL的运维管理体系框架

嘉为蓝鲸

ITSM ITIL 运维管理

基于需求文档、设计文档、测试用例的测试答疑助手

测试人

人工智能 软件测试 测试开发

嘉为蓝鲸WeOps渠道沙龙:携手业界精英共探数字化运维新篇章

嘉为蓝鲸

weops IT 运维

LLM 大模型学习必知必会系列(二):提示词工程-Prompt Engineering 以及实战闯关

汀丶人工智能

Prompt工程

Mybatis传参parameterType方法汇总记录

百度搜索:蓝易云

Java sql 云计算 运维 mybatis

Go-Zero自定义goctl实战:定制化模板,加速你的微服务开发效率(四)

王中阳Go

Go golang 微服务 Go进阶 gozero

Hologres RoaringBitmap在Lazada选品平台的最佳实践

阿里云大数据AI技术

大数据 阿里云 hologres

淘宝商品详情API接口:实时更新商品信息与数据

技术冰糖葫芦

API 编排 API 文档 API】 API 策略 pinduoduo API

LED无线显示屏的特色与优势

Dylan

性能 加密 信息 无线 LED显示屏

【GaussDB(for MySQL)】 Big IN查询优化

华为云开发者联盟

数据库 华为云 华为云开发者联盟 华为云GaussDB(for MySQL) 企业号2024年5月PK榜

一图带你解锁数字化运维的建设思路

嘉为蓝鲸

数字化运维 IT 运维

嘉为蓝鲸受邀出席 2024 GOPS 全球运维大会 · 深圳站

嘉为蓝鲸

数字化运维 Ops GOPS大会

HBase Meta 元信息表修复实践

vivo互联网技术

HBase HBase meta表 HBase meta表修复

Docker 的 ENTRYPOINT 和 CMD 参数探秘_语言 & 开发_亚马逊云科技 (Amazon Web Services)_InfoQ精选文章