pod 删除时未发送 SIGTERM

abc*_*bet 4 docker kubernetes

当删除 pod 或部署新版本的 pod 时,kubernetes 理论上应该向正在SIGTERM运行的进程发送.gracePeriodSecondsSIGKILL

我遇到了这个问题,这第一个SIGTERM似乎永远不会被发送。我的集群中的默认设置从未更改(kill 在 30 秒后按预期发送),因此我的假设是我的 Dockerfile 可能存在错误、权限或类似问题(见下文)。

我已经排除了优雅关闭逻辑中存在的错误,SIGTERM通过kubectl exec-ing 进入 pod 并kill -15在按预期工作的进程上使用来捕获可执行文件中的 。

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}
Run Code Online (Sandbox Code Playgroud)

这里有明显的错误吗?或者 kubernetes 是否需要一些额外的配置才能真正按预期发送终止信号?

Dav*_*aze 8

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

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

解决此问题的最简单方法是使用看起来像 JSON 数组的exec 形式。CMD由于这不会运行 shell,因此它也无法进行变量扩展,并且您必须清楚地说明您希望命令实际是什么

CMD ["./service"]
Run Code Online (Sandbox Code Playgroud)

这在运行时仍然很容易覆盖,实际上您根本不需要它CMD

# instead of `docker run -e CMD='...'`
docker run --rm my-image \
  ls -l /home/app
Run Code Online (Sandbox Code Playgroud)
# or in a Kubernetes pod spec
command:
  - /home/app/another_app
args:
  - --option
Run Code Online (Sandbox Code Playgroud)

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