无法在 docker 入口点脚本中捕获信号
Unable to trap signals in docker entrypoint script
我有一个 docker 入口点脚本,它应该捕获发送到容器中进程的信号。主要应用程序是 tomcat - java 进程嵌入在 docker-entrypoint.sh 中,传递给 dumb-init。容器中的进程映射如下所示:
root@mycontainer:/usr/local/tomcat/webapps/datarouter-example# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 05:21 ? 00:00:00 dumb-init -- /docker-entrypoint.sh
root 6 1 0 05:21 ? 00:00:00 bash /docker-entrypoint.sh
root 14 6 1 05:21 ? 00:08:57 /jdk-13.0.1/bin/java -Djava.util.logging.config.file=....
Docker 文件:
FROM maven:3.6.3-jdk-13 as maven_builder
WORKDIR /app
COPY . /app
RUN ["mvn","clean","install","-T","2C","-DskipTests=true"]
FROM tomcat:9.0.31-jdk13-openjdk-buster
ARG dumbInitVersion='1.2.2'
# install dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
sudo \
wget \
dpkg-dev \
&& rm -rf /var/lib/apt/lists/*
ARG webappDir
WORKDIR $CATALINA_HOME/webapps/$webappDir/
ENV CATALINA_OUT $CATALINA_HOME/logs/catalina.out
ENV CATALINA_PID $CATALINA_HOME/catalina.pid
COPY docker-entrypoint.sh /
COPY --from=maven_builder /app/target/datarouter-example $CATALINA_HOME/webapps/$webappDir/
RUN wget https://github.com/Yelp/dumb-init/releases/download/v"$dumbInitVersion"/dumb-init_"$dumbInitVersion"_amd64.deb; \
dpkg -i dumb-init_*.deb; \
rm dumb-init_*.deb
EXPOSE 8080
ENTRYPOINT ["dumb-init", "--", "/docker-entrypoint.sh"]
这是简化的 docker-entrypoint.sh:
#!/usr/bin/env bash
start(){
echo "$(date +'%F %T,%3N') Starting tomcat..." >> "$CATALINA_OUT"
catalina.sh start && tail -f "$CATALINA_OUT"
}
stop(){
echo "$(date +'%F %T,%3N') starting stop" >> "$CATALINA_OUT"
# some fancy shutdown logic, e.g. calling our application's shutdown endpoint to cleanup (does not stop tomcat)
echo "$(date +'%F %T,%3N') Stopping tomcat..." >> "$CATALINA_OUT"
catalina.sh stop >> "$CATALINA_OUT"
wait $(cat "${CATALINA_PID}")
tailId=$(pgrep tail)
if [[ -n "$tailId" ]]; then
kill "$tailId"
fi
exit
}
trap stop SIGINT SIGQUIT SIGHUP SIGTERM
start
现在是问题。
每次从容器内部发出 docker stop
命令或 kill 1
时, java 应用程序都会收到一个信号,并在 stop
函数获取之前首先开始关闭到第一行。我确定是因为 Terminated
日志:
Terminated
++ stop
+++ date '+%F %T,%3N'
++ echo '2020-03-13 14:34:54,480 starting stop'
并在 catalina.out 中:
2020-03-12 04:08:27.079 INFO [Thread-13] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-apr-8080"]
2020-03-12 04:08:27,079 starting stop
2020-03-12 04:08:27.085 INFO [Thread-13] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-apr-8081"]
2020-03-12 04:08:27.090 INFO [Thread-13] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["https-openssl-apr-8443"]
2020-03-12 04:08:27.096 INFO [Thread-13] org.apache.catalina.core.StandardService.stopInternal Stopping service [Catalina]
......
我真的很困惑为什么会发生这种情况以及如何解决这个问题以便 catalina.sh stop
得到执行。
尝试一些更改后,以下脚本捕获 SIGTERM 并执行预期的步骤。
原始 docker-entrypoint、Dockerfile 的变化:
- 从 dumb-init 切换到 tini,只是为了尝试一下。
- 从 catalina start 切换到 catalin 运行 并自己将其置于后台并等待它
- 删除尾进程
我认为尾巴是导致最初描述的行为的原因。新入口点脚本的最大缺点是我在 运行 宁 docker logs ...
时丢失了容器日志。由于我们绑定挂载日志目录,我们仍然能够获取日志,但将进一步调查以取回 docker logs ...
如果有人有建议或其他解决方案,我仍在寻找更好的解决方案。
#!/usr/bin/env bash
trap stop SIGTERM SIGINT SIGQUIT SIGHUP ERR
start(){
local catalinaPid
touch "${CATALINA_PID}"
catalina.sh run >> ${CATALINA_OUT} 2>&1 &
catalinaPid=$!
echo "$catalinaPid" > "${CATALINA_PID}"
wait "$catalinaPid"
}
stop(){
echo "$(date +'%F %T,%3N') starting stop" >> "$CATALINA_OUT"
# some fancy shutdown logic, e.g. calling our application's shutdown endpoint to cleanup (does not stop tomcat)
echo "$(date +'%F %T,%3N') Stopping tomcat..." >> "$CATALINA_OUT"
catalina.sh stop 20 >> "$CATALINA_OUT"
wait $(cat "${CATALINA_PID}")
exit
}
start
我有一个 docker 入口点脚本,它应该捕获发送到容器中进程的信号。主要应用程序是 tomcat - java 进程嵌入在 docker-entrypoint.sh 中,传递给 dumb-init。容器中的进程映射如下所示:
root@mycontainer:/usr/local/tomcat/webapps/datarouter-example# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 05:21 ? 00:00:00 dumb-init -- /docker-entrypoint.sh
root 6 1 0 05:21 ? 00:00:00 bash /docker-entrypoint.sh
root 14 6 1 05:21 ? 00:08:57 /jdk-13.0.1/bin/java -Djava.util.logging.config.file=....
Docker 文件:
FROM maven:3.6.3-jdk-13 as maven_builder
WORKDIR /app
COPY . /app
RUN ["mvn","clean","install","-T","2C","-DskipTests=true"]
FROM tomcat:9.0.31-jdk13-openjdk-buster
ARG dumbInitVersion='1.2.2'
# install dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
sudo \
wget \
dpkg-dev \
&& rm -rf /var/lib/apt/lists/*
ARG webappDir
WORKDIR $CATALINA_HOME/webapps/$webappDir/
ENV CATALINA_OUT $CATALINA_HOME/logs/catalina.out
ENV CATALINA_PID $CATALINA_HOME/catalina.pid
COPY docker-entrypoint.sh /
COPY --from=maven_builder /app/target/datarouter-example $CATALINA_HOME/webapps/$webappDir/
RUN wget https://github.com/Yelp/dumb-init/releases/download/v"$dumbInitVersion"/dumb-init_"$dumbInitVersion"_amd64.deb; \
dpkg -i dumb-init_*.deb; \
rm dumb-init_*.deb
EXPOSE 8080
ENTRYPOINT ["dumb-init", "--", "/docker-entrypoint.sh"]
这是简化的 docker-entrypoint.sh:
#!/usr/bin/env bash
start(){
echo "$(date +'%F %T,%3N') Starting tomcat..." >> "$CATALINA_OUT"
catalina.sh start && tail -f "$CATALINA_OUT"
}
stop(){
echo "$(date +'%F %T,%3N') starting stop" >> "$CATALINA_OUT"
# some fancy shutdown logic, e.g. calling our application's shutdown endpoint to cleanup (does not stop tomcat)
echo "$(date +'%F %T,%3N') Stopping tomcat..." >> "$CATALINA_OUT"
catalina.sh stop >> "$CATALINA_OUT"
wait $(cat "${CATALINA_PID}")
tailId=$(pgrep tail)
if [[ -n "$tailId" ]]; then
kill "$tailId"
fi
exit
}
trap stop SIGINT SIGQUIT SIGHUP SIGTERM
start
现在是问题。
每次从容器内部发出 docker stop
命令或 kill 1
时, java 应用程序都会收到一个信号,并在 stop
函数获取之前首先开始关闭到第一行。我确定是因为 Terminated
日志:
Terminated
++ stop
+++ date '+%F %T,%3N'
++ echo '2020-03-13 14:34:54,480 starting stop'
并在 catalina.out 中:
2020-03-12 04:08:27.079 INFO [Thread-13] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-apr-8080"]
2020-03-12 04:08:27,079 starting stop
2020-03-12 04:08:27.085 INFO [Thread-13] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-apr-8081"]
2020-03-12 04:08:27.090 INFO [Thread-13] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["https-openssl-apr-8443"]
2020-03-12 04:08:27.096 INFO [Thread-13] org.apache.catalina.core.StandardService.stopInternal Stopping service [Catalina]
......
我真的很困惑为什么会发生这种情况以及如何解决这个问题以便 catalina.sh stop
得到执行。
尝试一些更改后,以下脚本捕获 SIGTERM 并执行预期的步骤。
原始 docker-entrypoint、Dockerfile 的变化:
- 从 dumb-init 切换到 tini,只是为了尝试一下。
- 从 catalina start 切换到 catalin 运行 并自己将其置于后台并等待它
- 删除尾进程
我认为尾巴是导致最初描述的行为的原因。新入口点脚本的最大缺点是我在 运行 宁 docker logs ...
时丢失了容器日志。由于我们绑定挂载日志目录,我们仍然能够获取日志,但将进一步调查以取回 docker logs ...
如果有人有建议或其他解决方案,我仍在寻找更好的解决方案。
#!/usr/bin/env bash
trap stop SIGTERM SIGINT SIGQUIT SIGHUP ERR
start(){
local catalinaPid
touch "${CATALINA_PID}"
catalina.sh run >> ${CATALINA_OUT} 2>&1 &
catalinaPid=$!
echo "$catalinaPid" > "${CATALINA_PID}"
wait "$catalinaPid"
}
stop(){
echo "$(date +'%F %T,%3N') starting stop" >> "$CATALINA_OUT"
# some fancy shutdown logic, e.g. calling our application's shutdown endpoint to cleanup (does not stop tomcat)
echo "$(date +'%F %T,%3N') Stopping tomcat..." >> "$CATALINA_OUT"
catalina.sh stop 20 >> "$CATALINA_OUT"
wait $(cat "${CATALINA_PID}")
exit
}
start