0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WSL2 + Docker で CentOS 7 の systemd が動かない問題と対策

0
Posted at

概要

新しい WSL2 カーネル(6.6系)では cgroup v2 がデフォルトになったため、CentOS 7 などの古い OS を Docker コンテナで動かす際に systemd が正常に動作しない問題が発生します。

この記事では、問題の原因と複数の対策方法を解説します。


1. 問題の症状

  • コンテナ内で service コマンドが動作しない
  • systemctl コマンドが失敗する
  • httpd, postgresql などのサービスが起動できない

エラー例:

Failed to get D-Bus connection: Operation not permitted

2. 原因

  • CentOS 7 の systemd (バージョン 219) は cgroup v1 のみ対応
  • 新しい WSL2 カーネルは cgroup v2 がデフォルト
  • systemd はプロセス管理に cgroup を使用するため、バージョン不一致で動作しない

3. cgroup とは何か

cgroup (Control Groups) は Linux カーネルの機能で、プロセスをグループ化し、システムリソースの割り当てと制限を行う仕組みです。

cgroup が管理するリソース

リソース 説明
CPU CPU 時間の割り当て、使用率の制限
メモリ メモリ使用量の制限、OOM 時の優先度
ブロック I/O ディスク読み書きの帯域制限
ネットワーク ネットワーク帯域の制限
デバイス デバイスへのアクセス制御
freezer プロセスの一時停止・再開

cgroup の主な用途

  1. コンテナの隔離 - Docker や LXC がコンテナごとにリソースを分離
  2. システムサービス管理 - systemd がサービスごとにプロセスをグループ化
  3. リソース制限 - 特定のアプリケーションが使えるリソースを制限
  4. 優先度制御 - 重要なプロセスにより多くのリソースを割り当て

cgroup ファイルシステム

cgroup は /sys/fs/cgroup 以下に仮想ファイルシステムとしてマウントされます。

v1 の場合:

/sys/fs/cgroup/
├── cpu/           # CPU 制御
├── memory/        # メモリ制御
├── blkio/         # ブロック I/O 制御
├── devices/       # デバイス制御
└── ...

v2 の場合(単一の階層に統合):

/sys/fs/cgroup/
├── cgroup.controllers    # 利用可能なコントローラ一覧
├── cgroup.procs          # このグループのプロセス一覧
├── cpu.max               # CPU 制限
├── memory.max            # メモリ制限
└── ...

4. docker-compose.yml の cgroup 関連設定の意味

設定例

services:
  dev:
    image: myapp-node
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:rw
    privileged: true
    cgroupns: host        # Docker Compose v2 以降

(A) /sys/fs/cgroup:/sys/fs/cgroup:rw

形式: <ホスト側パス>:<コンテナ側パス>:<オプション>

意味:

  • ホストの /sys/fs/cgroup をコンテナ内の同じパスにマウント
  • :rw は読み書き可能(read-write)でマウント

なぜ必要か:

  • systemd は /sys/fs/cgroup を通じて cgroup を操作する
  • コンテナはデフォルトで cgroup ファイルシステムにアクセスできない
  • このマウントにより、コンテナ内の systemd が cgroup を操作可能になる

図解:

┌─────────────────────────────────┐
│ ホスト (WSL2)                   │
│                                 │
│  /sys/fs/cgroup/                │
│  ├── cpu.max                    │
│  ├── memory.max                 │
│  └── ...                        │
│         │                       │
│         │ マウント(bind mount)│
│         ▼                       │
│  ┌─────────────────────────┐    │
│  │ Docker コンテナ         │    │
│  │                         │    │
│  │  /sys/fs/cgroup/        │    │
│  │  (ホストと同じ内容)   │    │
│  │                         │    │
│  │  systemd がここを操作   │    │
│  └─────────────────────────┘    │
└─────────────────────────────────┘

(B) cgroupns: host

意味:

  • コンテナが使用する cgroup namespace をホストと共有する
  • デフォルトは private(コンテナ専用の namespace)

cgroup namespace とは:

  • プロセスから見える cgroup 階層を隔離する機能
  • private: コンテナは自分の cgroup をルートとして認識
  • host: コンテナはホストの cgroup 階層全体を認識

図解:

【cgroupns: private(デフォルト)】

ホストから見た階層:
  /sys/fs/cgroup/
  └── docker/
      └── <container-id>/    ← コンテナの cgroup
          └── (プロセス)

コンテナから見た階層:
  /sys/fs/cgroup/            ← 自分の cgroup がルートに見える
  └── (プロセス)

→ コンテナは自分の cgroup しか見えない(隔離されている)


【cgroupns: host】

ホストから見た階層:
  /sys/fs/cgroup/
  └── docker/
      └── <container-id>/
          └── (プロセス)

コンテナから見た階層:
  /sys/fs/cgroup/            ← ホストと同じ階層が見える
  └── docker/
      └── <container-id>/
          └── (プロセス)

→ コンテナはホストの cgroup 階層全体を認識できる

なぜ必要か:

  • 古い systemd は cgroup namespace を理解しない
  • host にすることで、ホストと同じ cgroup の見え方になる
  • これにより古い systemd でも cgroup を正しく操作できる

注意:

  • Docker Compose v1 (docker-compose コマンド) では未サポート
  • Docker Compose v2 (docker compose コマンド) で利用可能
  • セキュリティ上、本番環境での使用は非推奨

(C) privileged: true

意味:

  • コンテナに全ての Linux capabilities を付与
  • ホストのデバイスへのフルアクセスを許可
  • cgroup 操作を含む特権操作を許可

付与される権限:

  • 全ての capability (CAP_SYS_ADMIN, CAP_NET_ADMIN 等)
  • /dev 配下の全デバイスへのアクセス
  • cgroup の作成・変更
  • カーネルモジュールのロード(一部)

なぜ必要か:

  • systemd はサービス管理のために多くの特権操作を行う
  • cgroup の作成・削除・変更には特権が必要
  • 通常のコンテナはこれらの操作が禁止されている

セキュリティ上の注意:

  • privileged コンテナはホストとほぼ同等の権限を持つ
  • 本番環境での使用は避けるべき
  • 開発環境やテスト環境での使用に限定すること

5. cgroup v1 と v2 の違い

項目 cgroup v1 cgroup v2
階層構造 複数(cpu, memory 等が別々) 単一の統一された階層
リソース管理 各サブシステムが独立 統合された制御
対応 systemd 219 以降 232 以降(完全対応は 239 以降)
ステータス レガシー(非推奨) 現行の標準

6. なぜ cgroup v2 がデフォルトになったか

(1) Linux カーネルの公式方針

  • cgroup v1 は「レガシー」として位置づけ
  • カーネル 4.5 (2016年) で cgroup v2 が安定版に
  • 5.x 系以降で v2 への移行を推進

(2) cgroup v2 の技術的優位性

  • 統一された階層構造による管理の簡素化
  • より正確なメモリ管理(OOM killer の改善)
  • I/O とメモリの連携した制御
  • Pressure Stall Information (PSI) によるリソース監視
  • rootless コンテナのサポート改善

(3) コンテナエコシステムの移行

  • Docker, Kubernetes, systemd が cgroup v2 対応を完了
  • 主要ディストリビューション(Ubuntu, Fedora 等)が v2 をデフォルト化

(4) WSL2 での採用

  • Ubuntu/Debian 系カーネル設定がベース
  • これらのディストリビューションの方針に追従

7. systemd が cgroup を必要とする理由

systemd は以下の機能で cgroup を使用します。

(1) サービスのプロセス管理

  • サービスに属する全プロセスをグループ化
  • サービス停止時に関連プロセスを確実に終了
  • fork したプロセスも同じグループで管理(「逃げ」を防止)

(2) リソース制限

  • CPU、メモリ、I/O の使用量制限
  • サービスごとのリソース分離

(3) 状態監視

  • サービスの実行状態を追跡
  • 異常終了の検知と自動再起動

(4) 依存関係の管理

  • サービス間の起動順序制御
  • 障害時の連鎖的な停止処理

8. 対策方法

【方法 A】WSL2 で cgroup v1 を有効にする

既存環境を変更したくない場合に推奨。

手順:

  1. Windows 側で設定ファイルを作成/編集

    • ファイル: %USERPROFILE%\.wslconfig
  2. 以下の内容を記述

[wsl2]
kernelCommandLine = systemd.unified_cgroup_hierarchy=0
  1. WSL を再起動
wsl --shutdown

その後 WSL を再度起動

  1. 確認
cat /sys/fs/cgroup/cgroup.controllers

ファイルが存在しなければ v1 モード

注意: WSL2 カーネル 6.6 系では、この設定が効かない場合があります。


【方法 B】新しい OS ベースのコンテナに移行する

長期的な解決策として推奨。

cgroup v2 対応の OS を使用します。

OS systemd version cgroup v2 対応
CentOS 7 219 ❌ 非対応
CentOS 8 239 ✅ 対応
Rocky Linux 8 239 ✅ 対応
Rocky Linux 9 252 ✅ 完全対応
AlmaLinux 8 239 ✅ 対応
AlmaLinux 9 252 ✅ 完全対応

【方法 C】service コマンドを使わずに直接サービスを起動する

cgroup 設定を変更したくない場合に推奨。開発環境では最も手軽な方法です。

systemd を使わず、サービスを直接起動することで cgroup 問題を回避できます。

例: Apache httpd の場合

# 環境変数を設定してから直接起動
export $(cat /etc/sysconfig/myapp)
export PHPRC=/usr/local/myapp/config
mkdir -p /var/run/httpd
httpd -f /usr/local/myapp/config/httpd.conf -k start

起動スクリプトの例:

#!/bin/bash
#
# myapp-ctl - Development Container Control Script
#

set -e

DBENV_PATH=/etc/sysconfig/myapp
HTTPD_CONF=/usr/local/myapp/config/httpd.conf
PID_DIR=/var/run/httpd

# Build environment variables for httpd
build_env() {
    local env_vars=""
    if [ -f "$DBENV_PATH" ]; then
        env_vars=$(cat "$DBENV_PATH" | tr '\n' ' ')
    else
        echo "Error: Environment file not found: $DBENV_PATH"
        exit 1
    fi
    env_vars="$env_vars PHPRC=/usr/local/myapp/config HOSTNAME=${HOSTNAME}"
    echo "$env_vars"
}

mkdir -p "$PID_DIR"

case "$1" in
    start)
        echo "Starting httpd..."
        env $(build_env) httpd -f "$HTTPD_CONF" -k start
        echo "httpd started."
        ;;
    stop)
        echo "Stopping httpd..."
        env $(build_env) httpd -f "$HTTPD_CONF" -k stop
        echo "httpd stopped."
        ;;
    restart)
        echo "Restarting httpd..."
        env $(build_env) httpd -f "$HTTPD_CONF" -k restart
        echo "httpd restarted."
        ;;
    status)
        if pgrep -f "httpd -f $HTTPD_CONF" > /dev/null; then
            echo "httpd is running."
            ps aux | grep "[h]ttpd"
        else
            echo "httpd is not running."
        fi
        ;;
    *)
        echo "Usage: $0 {start|stop|restart|status}"
        exit 1
        ;;
esac

exit 0

メリット:

  • docker-compose.yml の privileged や cgroup 設定が不要
  • コンテナがより軽量・セキュアになる
  • WSL2 のカーネルバージョンに依存しない

デメリット:

  • OS 起動時の自動起動ができない(開発環境では問題なし)
  • service コマンドが使えない

9. Docker Compose 設定例

CentOS 7 + cgroup v1 環境(WSL で v1 を有効にした場合)

services:
  app:
    image: centos:7
    container_name: my-app
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:rw
    tty: true
    privileged: true

Rocky Linux 9 + cgroup v2 環境

services:
  app:
    image: rockylinux:9
    container_name: my-app
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:rw
    tty: true
    privileged: true

方法 C を使う場合(最小権限・推奨)

services:
  app:
    image: centos:7
    container_name: my-app
    volumes:
      - ./myapp:/home/user/myapp
    tty: true
    # privileged や cgroup 設定は不要

最小権限での設定(本番環境向け)

services:
  app:
    image: rockylinux:9
    container_name: my-app
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:rw
    tty: true
    cap_add:
      - SYS_ADMIN
    security_opt:
      - seccomp:unconfined

10. 確認コマンド

cgroup バージョンの確認

# v2 の場合、このファイルが存在する
cat /sys/fs/cgroup/cgroup.controllers

# v1 の場合、サブディレクトリが存在する
ls /sys/fs/cgroup/cpu

systemd バージョンの確認

systemctl --version

Docker の cgroup ドライバー確認

docker info | grep -i cgroup

WSL2 カーネルバージョンの確認

uname -r

まとめ

方法 メリット デメリット 推奨ケース
A: cgroup v1 有効化 既存環境をそのまま使える WSL2 カーネル依存、将来性なし 一時的な対応
B: 新 OS に移行 根本的解決 移行作業が必要 長期的な運用
C: 直接起動 設定変更不要、軽量 自動起動不可 開発環境

開発環境であれば 方法 C が最も手軽でおすすめです。


参考リンク

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?