Skip to content

Docker コンテナにゾンビプロセスが蓄積する (init: true 未設定) #28

@takemi-ohama

Description

@takemi-ohama

概要

devbase で起動される Docker コンテナの PID 1 が tail -f /dev/null であり、orphan プロセスの reap を行わないため、ゾンビプロセスが蓄積する。

Docker Compose の init: true を設定することで、tini が PID 1 として挿入され、ゾンビが自動 reap される。

再現手順

# devbase コンテナ内で
ps -p 1 -o comm=
# → tail (proper init ではない)

# バックグラウンドプロセスを起動して終了させる
nohup sleep 1 &
disown
sleep 3

# ゾンビが残る
ps aux | grep 'Z.*defunct'
# → [sleep] <defunct>

影響

ndf:cross-review skill は codex/gemini CLI を nohup ... & disown で起動し、monitor.py で監視する。レビュー完了後にプロセスがゾンビ化し:

  1. 監視の誤動作: kill -0 がゾンビに対しても成功するため、monitor.py が「まだ実行中」と判定 → hard timeout (420s) まで待たされる
  2. ゾンビ蓄積: PID 1 が reap しないため、コンテナ再起動まで蓄積し続ける

関連 issue: devbasex/ai-plugins#21

根本原因

通常の Linux Docker (現状)
PID 1 = systemd → SIGCHLD で自動 reap PID 1 = tail -f /dev/null → reap しない

提案: generate_scaled_compose()init: true を注入

lib/devbase/volume/compose.pygenerate_scaled_compose() 内、dev サービスの複製ループで init: true を設定する:

for i in range(1, scale + 1):
    service = _deep_copy(dev_service)
    service['container_name'] = f"${COMPOSE_PROJECT_NAME}-{dev_service_name}-{i}"

    # ゾンビ防止: tini を PID 1 として挿入
    service.setdefault('init', True)

    # ... 既存処理

この方法の利点

  • 変更箇所が 1 行: 全プロジェクトに自動適用
  • 既存の init: false 指定を尊重: setdefault なので明示指定があれば上書きしない
  • アプリケーションコード変更不要: entrypoint.sh との互換性あり
  • Docker 公式推奨: tini は 20KB の軽量 init で、シグナル転送 + ゾンビ reap を行う

non-dev サービスへの適用

mysql, valkey 等の non-dev サービスにも同様に適用すると安全:

for service_name, service_config in services.items():
    if service_name != dev_service_name:
        copied = _deep_copy(service_config)
        copied.setdefault('init', True)
        # ...

検証方法

# 修正後
devbase up
devbase login

# PID 1 が tini になっていることを確認
ps -p 1 -o comm=
# → tini

# ゾンビが reap されることを確認
nohup sleep 1 &
disown
sleep 3
ps aux | grep 'Z.*defunct'
# → (なし)

環境

  • devbase: latest (2026-05-27 時点)
  • 確認コンテナ: ai-plugins 開発環境
  • PR_SET_CHILD_SUBREAPER は動作するが、Docker init: true の方がシンプルで確実

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions