docker entrypoint入口文件详解
在编写Dockerfile的时候,包含一个entrypoint配置,该配置的作用是在容器启动之前做一些初始化配置,或者一些自定义的配置等。通常是一个脚本,然后在脚本里配置相关预定义项。这篇文档就详细说一说entrypoint入口文件的编写技巧。
下面以mysql官方镜像中的entrypoint文件docker-entrypoint.sh为例,文件地址为:
docker-entrypoint.sh
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[@]}会把这个数组当做可执行程序来执行
mysql=(mysql--protocol=socket-uroot-hlocalhost--socket="${SOCKET}") echo${mysql[1]} --output:mysql echo${mysql[2]} --output:--protocol=socket echo${mysql[3]} --output:-uroot echo${mysql[4]} --output:-hlocalhost echo${mysql[@]} --output: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和转发信号量的问题,把这两个工作直接交给了应用程序去完成
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。