Dockerfile中ENTRYPOINT 和 CMD的区别说明
在Docker的系统学习教程中我们了解到使用Dockerfile构建Docker镜像为一个规范的方式,根据Dockerfile可以了解镜像中安装的组件的详细内容。
Dockerfile一般由四部分组成:第一,构建的基础镜像;第二,镜像构建者的信息;第三,构建镜像过程中镜像层添加指令;第四,由该镜像启动容器时执行的程序。
本篇文章中涉及到的ENTRYPOINT和CMD属于Dockerfile中的最后一部分,这两个Dockerfile指令是用来告知Docker后台程序启动镜像时需要执行的程序,两者有细微的差别。
下面将从两者的异同以及两者联合使用的高级技巧方面对两个指令进行详解。
CMD指令
CMD指令指定容器启动时需要运行的程序。一般用最简单的方式启动一个容器时使用dockerrun会传递参数给docker指令
dockerrun-itimage/bin/bash
后面的/bin/bash其实是传递参数,告知容器启动时运行一个shell。这个过程可以用CMD指令等效的替换
CMD['/bin/bash']
因此在Dockerfile中存在这个CMD指令指定的命令时,启动容器就可以不进行参数传递。
dockerrun-itimage
执行效果一致。
[root@MiWiFi-R3L-srvtest]#dockerrun--nametest-ittest_image
[root@3a1bb0c9e35c/]#
如果dockerfile中已经指定了容器启动时运行的程序,同时在使用dockerrun启动容器时使用了命令行参数,那么dockerfile中的cmd指令将无效
dockerrun-itimage/bin/ps
发现启动容器后没有shell,只是打印出了当前容器中的进程状态,cmd指令效果被覆盖。
PIDTTYTIMECMD 1?00:00:00ps [root@MiWiFi-R3L-srvtest]#
此时可以看到cmd效果被覆盖。在一个dockerfile中只有最后一个cmd指令有效,因此一个dockerfile中只写一个cmd指令。
ENTRYPOINT指令
ENTRYPOINT指令效果与CMD非常的类似,比较容易混淆两者的功能。最大的区别在于使用的方式,ENTRYPOINT指定的命令需要与dockerrun启动容器进行搭配,将dockerrun指令后面跟的内容当做参数作为ENTRYPOINT指令指定的运行命令的参数,ENTRYPOINT指定的linux命令一般是不会被覆盖的。
以nginx镜像为例说明
首先构建一个nginx镜像,并且指定容器运行时执行的程序为nginx。
FROMcentos MAINTAINERallocator RUNyuminstall-ynginx RUNecho'helloworld'>/usr/share/nginx/html/index.html EXPOSE80 ENTRYPOINT["/usr/sbin/nginx"]
然后启动镜像
dockerrun--nametest-p5000:80-ittest_nginx-g"daemonoff"
后面两个是作为参数传递给nginx启动程序运行,此时nginx作为前台程序运行,是一个web服务器,可以根据外部绑定的端口,通过浏览器正常看到helloworld
两者联合使用技巧
已经明白了两者的区别,可以利用两者的特点构建一个含有默认启动运行程序的镜像,并且支持dockerrun启动时人为指定启动程序运行的参数。
举个例子。利用ENTRYPOINT指定启动时运行启动nginx程序,并给定默认的运行参数为显示帮助信息,dockerfile构建如下:
ENTRYPOINT["/usr/sbin/nginx"]
CMD["-h"]
当使用dockerrun--nametest-ittest_nginx不传递任何参数时,此时启动容器会使用cmd指令后的命令作为默认参数,打印nginx的帮助信息。此时cmd后的内容并不是一个完整的指令,而是参数,如果其内容是一个完整的指令,那么它将覆盖掉ENTRYPOINT中的内容。
如果使用dockerrun--nametest-ittest_nginx-g"daemonoff"启动时,此时给定的运行参数会覆盖掉CMD指令对应的内容,此时nginx将作为前台进程运行,作为一个web服务器使用,通过browser可以看到helloworld
补充知识:docker-entrypoint.sh入口文件编写技巧
在docker的官方Registry中(store.docker.com)流行的第三方应用在自己的页面中都提供了dockerfile的链接.而很多dockerfile的ENTRYPOINT命令都是这么写的["docker-entrypoint.sh"]
本篇文章就扫盲下docker-entrypoint.sh的特殊用法和设计逻辑
MySQL
set-e
你写的每个脚本都应该在文件开头加上set-e,这句语句告诉bash如果任何语句的执行结果不是true则应该退出.这样的好处是防止错误像滚雪球般变大导致一个致命的错误,而这些错误本应该在之前就被处理掉.如果要增加可读性,可以使用set-oerrexit,它的作用与set-e相同
set-opipefail
设计用途同上,就是希望在执行错误之后立即退出,不要再向下执行了.而-opipefail的作用域是管道,也就是说在Linux脚本中的管道,如果前面的命令执行出了问题,应该立即退出
shopt-snullglob
在使用Linux中的通配符时*?等如果没有匹配到任何文件,不会报Nosuchfileordirectory而是将命令后面的参数去掉执行
if[“${1:0:1}”=‘-‘];then…
这是一个判断语句,在官方文件中,上一行已经给出了注释:ifcommandstartswithanoption,prependmysqld
这个判断语句是${1:0:1}意思是判断$1(调用该脚本的第一个参数),偏移量0(不偏移),取一个字符(取字符串的长度)
如果判断出来调用这个脚本后面所跟的参数第一个字符是-中横线的话,就认为后面的所有字符串都是mysqld的启动参数
上面的这个操作类似于Python的字符串切片
set–mysqld“$@”
在上面判断完第一个参数是-开头之后,紧接着就执行了set--mysqld"$@"这个命令.使用了set--的用法.set—会将他后面所有以空格区分的字符串,按顺序分别存储到$1,$2,$3变量中,其中新的$@为set—后面的全部内容
举例来说:bashdocker-entrypoint.sh-fxxx.conf
在这种情况下,set--mysqld"$@"中的$@的值为-fxxx.conf
当执行完set--mysqld"$@"这条命令后:
$1=mysqld $2=-f $3=xxx.conf $@=mysqld-fxxx.conf
可以看到,当执行docker-entrypoint.sh脚本的时候后面加了-x形式的参数之后,$@的值发生的改变,在原有$@值的基础之上,在前面又预添加了mysqld命令
exec“$@”
几乎在每个docker-entrypoint.sh脚本的最后一行,执行的都是exec"$@"命令
这个命令的意义在于你已经为你的镜像预想到了应该有的调用情况,当实际使用镜像的人执行了你没有预料到的可执行命令时,将会走到脚本的这最后一行,去执行用户新的可执行命令
情况判断
上面直接说了脚本的最后一行,在之前的脚本中,需要充分的去考虑你自己的脚本可能会被调用的情况.还是拿MySQL官方的dockerfile来说,他判断以下情况:
开头是-,认为是参数的情况
开头是mysqld,且用户id为0(root用户)的情况
开头是mysqld的情况
判断完自己应用的所有调用形态之后,最后应该加上exec"$@"命令兜底
${mysql[@]}
Shell中的数组,直接执行${mysql[@]}会把这个数组当做可执行程序来执行
➜/tmpmysql=(mysql--protocol=socket-uroot-hlocalhost--socket="${SOCKET}") ➜/tmpecho${mysql[1]} mysql ➜/tmpecho${mysql[2]} --protocol=socket ➜/tmpecho${mysql[3]} -uroot ➜/tmpecho${mysql[4]} -hlocalhost ➜/tmpecho${mysql[@]} mysql--protocol=socket-uroot-hlocalhost--socket= execgosumysql“$BASH_SOURCE”“$@”
这里的gosu命令,是Linux中sudo命令的轻量级”替代品”
gosu是一个golang语言开发的工具,用来取代shell中的sudo命令.su和sudo命令有一些缺陷,主要是会引起不确定的TTY,对信号量的转发也存在问题.如果仅仅为了使用特定的用户运行程序,使用su或sudo显得太重了,为此gosu应运而生.
gosu直接借用了libcontainer在容器中启动应用程序的原理,使用/etc/passwd处理应用程序.gosu首先找出指定的用户或用户组,然后切换到该用户或用户组.接下来,使用exec启动应用程序.到此为止,gosu完成了它的工作,不会参与到应用程序后面的声明周期中.使用这种方式避免了gosu处理TTY和转发信号量的问题,把这两个工作直接交给了应用程序去完成
以上这篇Dockerfile中ENTRYPOINT和CMD的区别说明就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。