docker entrypoint入口文件详解

在编写Dockerfile的时候,包含一个entrypoint配置,该配置的作用是在容器启动之前做一些初始化配置,或者一些自定义的配置等。通常是一个脚本,然后在脚本里配置相关预定义项。这篇文档就详细说一说entrypoint入口文件的编写技巧。

下面以mysql官方镜像中的entrypoint文件docker-entrypoint.sh为例,文件地址为:

docker-entrypoint.sh

set -e

你写的每个脚本都应该在文件开头加上set -e, 这句语句告诉bash如果任何语句的执行结果不是true则应该退出. 这样的好处是防止错误像滚雪球般变大导致一个致命的错误, 而这些错误本应该在之前就被处理掉. 如果要增加可读性, 可以使用set -o errexit, 它的作用与set -e相同

set -o pipefail

设计用途同上, 就是希望在执行错误之后立即退出, 不要再向下执行了. 而 -o pipefail 的作用域是管道, 也就是说在 Linux 脚本中的管道, 如果前面的命令执行出了问题, 应该立即退出

shopt -s nullglob

在使用 Linux 中的通配符时 * ?等 如果没有匹配到任何文件, 不会报 No such file or directory 而是将命令后面的参数去掉执行

if [ "${1:0:1}" = '-' ]; then...

这是一个判断语句, 在官方文件中, 上一行已经给出了注释: if command starts with an option, prepend mysqld

这个判断语句是 ${1:0:1} 意思是判断 $1(调用该脚本的第一个参数), 偏移量0(不偏移), 取一个字符(取字符串的长度)

如果判断出来调用这个脚本后面所跟的参数第一个字符是-中横线的话, 就认为后面的所有字符串都是 mysqld 的启动参数

上面的这个操作类似于 Python 的字符串切片

set -- mysqld "$@"

在上面判断完第一个参数是-开头之后, 紧接着就执行了 set -- mysqld "$@" 这个命令. 使用了 set -- 的用法. set --会将他后面所有以空格区分的字符串, 按顺序分别存储到$1, $2, $3 变量中, 其中新的$@为set --后面的全部内容

举例来说: bash docker-entrypoint.sh -f xxx.conf

在这种情况下, set -- mysqld "$@" 中的 $@ 的值为 -f xxx.conf

当执行完 set -- mysqld "$@" 这条命令后:

  • $1=mysqld
  • $2=-f
  • $3=xxx.conf
  • $@=mysqld -f xxx.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=

exec gosu mysql "$BASH_SOURCE" "$@"

这里的 gosu 命令, 是 Linux 中 sudo 命令的轻量级”替代品”

gosu 是一个 golang 语言开发的工具, 用来取代 shell 中的 sudo 命令. su 和 sudo 命令有一些缺陷, 主要是会引起不确定的 TTY, 对信号量的转发也存在问题. 如果仅仅为了使用特定的用户运行程序, 使用 su 或 sudo 显得太重了, 为此 gosu 应运而生.

gosu 直接借用了 libcontainer 在容器中启动应用程序的原理, 使用 /etc/passwd 处理应用程序. gosu 首先找出指定的用户或用户组, 然后切换到该用户或用户组. 接下来, 使用 exec 启动应用程序. 到此为止, gosu 完成了它的工作, 不会参与到应用程序后面的声明周期中. 使用这种方式避免了 gosu 处理 TTY 和转发信号量的问题, 把这两个工作直接交给了应用程序去完成

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • docker entrypoint入口文件详解

    在编写Dockerfile的时候,包含一个entrypoint配置,该配置的作用是在容器启动之前做一些初始化配置,或者一些自定义的配置等.通常是一个脚本,然后在脚本里配置相关预定义项.这篇文档就详细说一说entrypoint入口文件的编写技巧. 下面以mysql官方镜像中的entrypoint文件docker-entrypoint.sh为例,文件地址为: docker-entrypoint.sh set -e 你写的每个脚本都应该在文件开头加上set -e, 这句语句告诉bash如果任何语句的执

  • docker中的run/cmd/entrypoint的区别详解

    Dockerfile中run.cmd和entrypoint都能够用于执行命令,下面是三者的主要用途: run命令执行命令并创建新的镜像层,通常用于安装软件包 cmd命令设置容器启动后默认执行的命令及其参数,但CMD设置的命令能够被docker run命令后面的命令行参数替换 entrypoint配置容器启动时的执行命令,不会被忽略,一定会被执行,即使运行 docker run时指定了其他命令. Shell格式和Exec格式运行命令 我们可以用下面两种格式指定run.cmd和entrypoint要

  • Docker Compose 网络设置详解

    基本概念 默认情况下,Compose会为我们的应用创建一个网络,服务的每个容器都会加入该网络中.这样,容器就可被该网络中的其他容器访问,不仅如此,该容器还能以服务名称作为hostname被其他容器访问. 默认情况下,应用程序的网络名称基于Compose的工程名称,而项目名称基于docker-compose.yml所在目录的名称.如需修改工程名称,可使用--project-name标识或COMPOSE_PORJECT_NAME环境变量. 举个例子,假如一个应用程序在名为myapp的目录中,并且do

  • docker+gitlab+gitlab-runner部署详解

    环境 服务端:centos7 客户端:window 在centos7上部署docker+gitlab+gitlab-runner,win10利用ssh连接,开发人员只需提交代码,就可以进行项目文件上传,打包镜像,发布运行测试 一.centos7上安装docker和docker-compose 安装docker: 1.Docker 要求 CentOS 系统的内核版本高于 3.10 ,查看本页面的前提条件来验证你的CentOS 版本是否支持 Docker . 通过uname -r命令查看你当前的内核

  • Spring Cloud中使用jib进行docker部署的步骤详解

    Jib介绍 Jib 是 Google 开发的可以直接构建 Java 应用的 Docker 和 OCI 镜像的类库,以 Maven 和 Gradle 插件形式提供. 通过 Jib,Java 开发者可以使用他们熟悉的 Java 工具来构建容器.Jib 是一个快速而简单的容器镜像构建工具,它负责处理将应用程序打包到容器镜像中所需的所有步骤.它不需要你编写 Dockerfile 或安装 Docker,而且可以直接集成到 Maven 和 Gradle中 -- 只需要将插件添加到构建中,就可以立即将 Jav

  • SpringBoot+docker环境变量配置详解

    项目中遇到springBoot+docker需要配置不同环境变量的问题,做个简单的总结: 1.开发环境ide中启动项目 可以通过ide的环境变量参数配置,启动之后使用哪个配置,比如 这样就使用application-test.yml中的配置 2.通过gradle打包 可以通过-P参数来指定打包后的jar使用哪种环境来运行,比如 gradlew -Pprod bootWar 打包之后运行会使用prod中的配置:我的项目是jhipster生成出来的,现在需要添加test的环境配置,需求修改下项目的g

  • Docker compose 编排工具详解

    Docker Compose Docker Compose是一个定义及运行多个Docker容器的工具,通过 Compose,无需用shell脚本来启动容器,而使用 YAML 文件来配置应用程序需要的所有服务,然后使用命令,根据 YAML 的文件配置创建并启动所有服务,非常适合于多个容器进行开发的场景. Compose非常适合开发,测试和登台环境以及CI工作流程. YAML YAML是一个可读性高,用来表达数据序列化的格式 相关命令及格式 version:指定此yml文件基于的compase的版本

  • docker网络配置过程详解介绍

    目录 Linux内核实现名称空间的创建 操作Network Namespace 创建veth pair 实现Network Namespace间通信 四种网络模式配置 容器的常用操作 自定义docker0桥的网络属性信息 Linux内核实现名称空间的创建 ip netns命令 可以借助ip netns命令来完成对 Network Namespace 的各种操作.ip netns命令来自于iproute安装包,一般系统会默认安装,如果没有的话,请自行安装. 注意:ip netns命令修改网络配置时

  • Docker Swarm入门实例详解

    Swarm 在 Docker 1.12 版本之前属于一个独立的项目,在 Docker 1.12 版本发布之后,该项目合并到了 Docker 中,成为 Docker 的一个子命令.目前,Swarm 是 Docker 社区提供的唯一一个原生支持 Docker 集群管理的工具.它可以把多个 Docker 主机组成的系统转换为单一的虚拟 Docker 主机,使得容器可以组成跨主机的子网网络. 1. Swarm 认识 Swarm 是目前 Docker 官方唯一指定(绑定)的集群管理工具.Docker 1.

  • Linux下修改jar、zip等文件内的文件详解

    Linux下修改jar.zip等文件内的文件详解 看到很多同事在Linux环境下修改jar包内的文本文件或zip中的文本文件时,经常是先把jar包或zip包下载下来,然后修改,再上传.其实Linux针对此类文件提供了相应的操作功能. 平时修改Linxu文件时使用vi或vim命令来修改.其实修改jar包或zip可以同样使用此命令. 对文件执行vi或vim. vim xxx.jar 执行之后,会显示jar包或zip包中的文件. 通过以下命令根据文件名字查找文件: /index.ftl 比如上面的命令

随机推荐