Dockerfile 的 ENTRYPOINT 通常是一个脚本文件, 用来启动和关闭 Docker 中的应用。 接下来就以 Linux 下常用的 Jexus 服务器为例, 来说明如何正确的启动和关闭 Docker 应用。

Docker 应用启动

根据 Jexus 的文档, Jexus 服务器启动只需要使用命令 /usr/jexus/jws start 即可, 所以启动非常简单, 只要定义一个函数来调用 /usr/jexus/jws start 即可:

# a function to start jexus server
function start_jws {
  /usr/jexus/jws start
}

调用完 jws start 之后, 用 ps a 命令查看, 可以看到如下进程:

# ps
  PID TTY          TIME CMD
    1 pts/0    00:00:00 bash
   36 pts/0    00:00:00 JwsMain
   43 pts/0    00:00:00 jwss
   95 pts/0    00:00:00 ps

只要有 JwsMainjwss 两个进程在运行, 则表示 Jexus 服务器正在运行。

等待应用关闭

由于 Docker 是单进程的, 如果 Jexus 服务关闭了, Docker 进程也应该退出, 所以需要一个函数来判断 Jexus 服务器的运行。

JwsMainjwss 两个命令位于 /usr/jexus 目录下, 只要这两个进程在运行, 就表示 Jexus 还在运行。 如果没有了这两个进程, 则表示 Jexus 已经退出。 所以判断 Jexus 运行的标志就是位于 /usr/jexus 目录下的进程是否存在, 这个可以使用 pgrep 来判断:

# pgrep -f "/usr/jexus"
36
43

接下来编写一个 wait_for_exit 函数, 每隔一秒钟检查一下是否有位于 /usr/jexus 目录下的进程存在, 如果没有, 则退出, 代码如下:

# a function that spins, stopping every 1s to check if any jexus
# processes are running. the loop terminates when no running jexus 
# processesa are found.
function wait_for_exit {
  while pgrep -f "/usr/jexus" > /dev/null; do
    /bin/sleep 1
  done
  echo "All jexus process have stopped."
}

处理应用关闭

Jexus 的关闭也很容易, 只要调用 /usr/jexus/jws stop , 如下所示:

# a function to stop jexus server
function stop_jws {
  /usr/jexus/jws stop
}

关键是如何做到让 Docker 停止时自动调用这个 stop_jws 函数。 因此需要向主进程发送一个信号通知, 当主进程停止时, 调用 stop_jws 函数。

先定义一个 signal_trap 函数, 调用 stop_jws 函数来关闭 Jexus 服务器:

# a function that is called whenever a signal is caught requesting that
# the process be terminated. in most cases, this will come from Docker
# as this script will be running as PID 1.
function signal_trap {
  echo "A SIGTERM or SIGINT signal was caught; trying to shut down."
  stop_jws
}

向主进程发送一个信号通知, 让主进程知道终止时需要调用 signal_trap 函数来关闭 Jexus 服务器。

# trap termination signals and stop the server processes. this is
# necessary because Docker will send SIGTERM to the container's
# PID 1 when it tries to stop the container. since Bash doesn't
# pass this along, we have to handle it ourselves.
trap signal_trap SIGTERM SIGINT

调用 start_jws 启动 Jexus 服务器之后, 立即调用 wait_for_exit 等待:

# begin the server startup process.
start_jws
echo "Listening for termination signals..."
# loop until all jexus processes are finished.
wait_for_exit

上面写的比较零散, 点击这里查看最终的 bootstrap.sh 文件, 也可以轻松的修改成其它应用的启动脚本。

PS: 也可以直接下载我的 beginor/jexus-x64 镜像来使用。