You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pod的preStop钩子执行sidekiqctl stop后后续命令中断问题求助

问题分析与解决方案

核心原因

你的preStop脚本执行到sidekiqctl stop后终止,本质是Sidekiq进程是容器的PID 1主进程:当sidekiqctl stop发送终止信号让Sidekiq退出时,K8s会立即触发容器回收流程,直接终止容器内所有剩余进程(包括正在运行的preStop脚本),导致后续的echo和rm命令根本没机会执行,最终触发preStopFailed事件。

解决方案

方案1:让Sidekiq以非PID 1进程运行

通过修改容器的启动命令,让Sidekiq作为子进程运行,避免它成为PID 1。这样当Sidekiq被终止时,容器的主进程(如tini或bash)不会立即退出,preStop脚本可以继续执行完成。

方式A:使用tini作为进程管理器

tini是轻量级的init进程,能妥善处理子进程的终止,同时保持自身作为PID 1运行。修改容器启动命令为:

tini -- bundle exec sidekiq

需要确保容器镜像中已安装tini(大部分官方Ruby镜像已包含,若没有可通过apt install tini或gem install tini安装)。

方式B:用bash脚本启动Sidekiq

创建一个启动脚本start_sidekiq.sh:

#!/bin/bash
# 启动Sidekiq并后台运行
bundle exec sidekiq &
# 等待Sidekiq进程结束,保持bash作为PID 1
wait $!

然后将容器的启动命令设置为:

bash /path/to/start_sidekiq.sh

方案2:调整preStop脚本逻辑(辅助优化)

在确认Sidekiq非PID 1后,还可以优化脚本的健壮性:

echo "Stopping sidekiq..."
# 先检查PID文件是否存在,避免空循环
if [ -d "$SIDEKIQ_PIDS" ] && [ -n "$(ls -A "$SIDEKIQ_PIDS"/*.pid 2>/dev/null)" ]; then
  for pid in "$SIDEKIQ_PIDS"/*.pid; do
    echo "Stopping specific pid: $(cat $pid)..."
    # 捕获sidekiqctl的退出状态,避免脚本因命令失败直接终止
    if bundle exec sidekiqctl stop "$pid" 30; then
      echo "removing pid file: $pid"
      rm -f "$pid"
    else
      echo "Failed to stop sidekiq with pid file $pid"
    fi
  done
else
  echo "No sidekiq pid files found"
fi
echo "done"
  • 增加PID文件存在性检查,避免空循环报错
  • 捕获sidekiqctl stop的执行状态,确保脚本不会因单进程终止失败而中断
  • 使用rm -f替代rm -rf,更安全地删除单个文件

内容的提问来源于stack exchange,提问作者Narendra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 06:20:03