SIGTERM在pod删除时未发送



当删除一个pod或部署一个新版本的pod时,理论上kubernetes应该向正在运行的进程发送一个SIGTERM,然后等待gracePeriodSeconds(默认为30秒),然后再发送一个SIGKILL

我遇到了这个问题,这第一个SIGTERM似乎从来没有被发送。我的集群中的默认设置从未改变(kill在30秒后按预期发送),所以我的假设是可能有什么问题,权限或类似的,与我的Dockerfile(见下文)。

我已经排除了在优雅的关闭逻辑中有一个错误,通过kubectl exec-ing进入pod并在进程中使用kill -15来捕获可执行文件中的SIGTERM

Dockerfile如下所示:

FROM debian:bullseye-slim AS app
ARG USERNAME=app
ARG USER_UID=1000
ARG USER_GID=$USER_UID
RUN apt update && apt install -y libssl-dev zstd ca-certificates pkg-config
RUN groupadd --gid $USER_GID $USERNAME 
&& useradd --uid $USER_UID --gid $USER_GID -m $USERNAME
WORKDIR /home/$USERNAME
ARG RELEASE_DIR
ARG SERVICE 
USER $USERNAME
COPY $RELEASE_DIR .
EXPOSE 8080
ENV CMD=./${SERVICE}
CMD ${CMD}

这里有什么明显的错误吗?或者kubernetes需要一些额外的配置来实际发送预期的终止信号?

要使终止正常工作,您需要确保您的应用程序是主容器进程。对于shell形式CMD,您的容器运行的命令是/bin/sh -c '${CMD}',并且根据该环境变量中的内容和/bin/sh的实际内容,该shell包装器可能会继续作为主容器进程运行并拦截终止信号。

同样的机制适用于普通Docker和Kubernetes,如果您在本地docker stop容器,您应该会看到类似的问题。这可能更容易调试和迭代。

解决这个问题最简单的方法是使用CMD的exec形式,看起来像一个JSON数组。由于这不会运行shell,因此它也不能进行变量展开,并且您必须拼写出您希望命令的实际内容

CMD ["./service"]

这仍然很容易在运行时重写,实际上您根本不需要CMD:

# instead of `docker run -e CMD='...'`
docker run --rm my-image 
ls -l /home/app
# or in a Kubernetes pod spec
command:
- /home/app/another_app
args:
- --option

你可以类似地删除Dockerfile中几乎所有的ARG声明(容器用户的名称或数字uid不重要,例如,编译的应用程序文件名和主机构建路径通常是固定的),这将简化设置。

最新更新