如何防止Dockerfile中的脚本退出?

时间:2018-07-26 08:36:38

标签: java docker dockerfile

我的Dockerfile是:

FROM maven:3.3.9-jdk-8-alpine as build-env
COPY . /EscomledML
WORKDIR EscomledML
RUN mvn package

FROM openjdk:8-jdk-alpine
WORKDIR /EscomledML
ADD . /EscomledML
ADD ./lib EscomledML/lib
ADD ./config EscomledML/config
ADD ./config EscomledML/home/escomled/escomled_server/config
ADD ./MLScripts EscomledML/MLScripts
ADD target/escomled-machine-learning-0.0.1-SNAPSHOT-jar-with-dependencies.jar EscomledML/lib/escomled-machine-learning-0.0.1-SNAPSHOT-jar-with-dependencies.jar
EXPOSE 8085
RUN ["sh", "EscomledML/MLScripts/escomled_data_grid.sh"]
RUN ["sh", "EscomledML/MLScripts/escomled_dirwatcher.sh"]
RUN ["sh", "EscomledML/MLScripts/escomled_startmap.sh"]
RUN ["sh", "EscomledML/MLScripts/escomled_ml.sh"]

这些脚本基本上将依赖项jar添加到classpath并启动所需的类,例如。 “ java ${ARGS} -classpath "${CLASSPATH}" com.escomled.blackboard.main.DataGridServer”。

运行docker-compose up --build时,脚本没有任何输出。

docker ps -a返回

CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS                      PORTS                                        NAMES
ce690dbba3ab        escomled-ml                    "/bin/sh"                2 minutes ago       Exited (0) 2 minutes ago                                                 desktop_escomled-ml_1

3 个答案:

答案 0 :(得分:1)

  

如何防止Dockerfile中的脚本退出?

关于RUN,您不能/应该。

这不是应该的工作方式。 RUN用于构建图像的阶段。它应该完成任务,完成并继续下一个Dockerfile命令。

从文档中

  

RUN指令将在当前图像顶部的新层中执行所有命令,并提交结果。生成的提交图像将用于Dockerfile中的下一步。


启动容器时应运行的脚本可以通过ENTRYPOINTCMD声明的组合来设置。

答案 1 :(得分:1)

对于以下dockerfile:

FROM ubuntu:18.04

RUN echo a
CMD ["bash","-c","echo b && echo c; while true; do sleep 5; echo sleep; done"];

运行以下命令:

docker build -t test1 . && docker run test1

您会注意到:

  • echo a在构建时执行
  • echo becho cecho sleep在运行时执行

现在,您可以在文件中使用结构类似的COMMAND,它应该可以工作。

答案 2 :(得分:0)

如果我正确理解原始Dockerfile中的每一行RUN都对应一个服务(这是您要在Docker容器停止之前运行的进程)。问题在于,Docker容器需要一个在前台运行,在容器启动时启动并在容器停止时停止的主进程。另外,当主进程退出时(例如,由于引发异常),容器将自动停止。

为了在单个容器中运行多个进程,您需要使用一个进程管理器,该进程管理器将由该容器启动,然后将启动您的服务,监视它们并在出现故障的情况下重新启动它们,或者启动一个包装器脚本您的服务并检查它们是否还活着。 Docker documentation建议使用supervisord

在您的情况下,包装器将类似于:

#!/bin/bash

# Start the first process
/EscomledML/MLScripts/escomled_data_grid.sh -D
status=$?
if [ $status -ne 0 ]; then
  echo "Failed to start escomled_data_grid: $status"
  exit $status
fi

# Start the second process
/EscomledML/MLScripts/escomled_dirwatcher.sh -D
status=$?
if [ $status -ne 0 ]; then
  echo "Failed to start escomled_dirwatcher: $status"
  exit $status
fi

# Start the third process
/EscomledML/MLScripts/escomled_startmap.sh -D
status=$?
if [ $status -ne 0 ]; then
  echo "Failed to start escomled_startmap: $status"
  exit $status
fi

# Start the fourth process
/EscomledML/MLScripts/escomled_ml.sh -D
status=$?
if [ $status -ne 0 ]; then
  echo "Failed to start escomled_ml: $status"
  exit $status
fi

# Naive check runs checks once a minute to see if either of the processes exited.
# This illustrates part of the heavy lifting you need to do if you want to run
# more than one service in a container. The container exits with an error
# if it detects that either of the processes has exited.
# Otherwise it loops forever, waking up every 60 seconds

while sleep 60; do
  ps aux |grep escomled_data_grid |grep -q -v grep
  PROCESS_1_STATUS=$?
  ps aux |grep escomled_dirwatcher |grep -q -v grep
  PROCESS_2_STATUS=$?
  ps aux |grep escomled_startmap |grep -q -v grep
  PROCESS_3_STATUS=$?
  ps aux |grep escomled_ml |grep -q -v grep
  PROCESS_4_STATUS=$?
  # If the greps above find anything, they exit with 0 status
  # If they are not both 0, then something is wrong
  if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 -o $PROCESS_3_STATUS -ne 0 -o $PROCESS_4_STATUS -ne 0 ]; then
    echo "One of the processes has already exited."
    exit 1
  fi
done

尽管很可能您需要在while循环中修改grep条件,以准确匹配脚本正在启动的任何进程。然后假设您将脚本命名为“ wrapper.sh”

您将以下行放入Dockerfile中: COPY wrapper.sh /EscomledML/MLScripts/wrapper.sh ENTRYPOINT [“ EscomledML / MLScripts / wrapper.sh”]

我个人建议使用supervisored而不是包装脚本,但这取决于您。