メインコンテンツまでスキップ

プロセス管理

Linuxのプロセス、シグナル、デーモンの基礎を学びます。


目次

  1. プロセスとは
  2. プロセスの確認
  3. プロセスの状態
  4. シグナル
  5. フォアグラウンドとバックグラウンド
  6. デーモン
  7. コンテナのプロセス

プロセスとは

プロセスの概念

プロセスとは、実行中のプログラムのインスタンスです。

プログラム(実行ファイル)がディスクに保存された静的なコードであるのに対し、プロセスはそれがメモリに読み込まれ、CPUによって実行されている動的な状態を指します。

┌─────────────────────────────────────────────────────────────┐
│ プログラムとプロセスの違い │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【プログラム】 【プロセス】 │
│ ディスク上のファイル → メモリ上の実行状態 │
│ /usr/bin/nginx → nginx (PID 1234) │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ nginx │ 実行 │ プロセス │ │
│ │ (バイナリ) │ ─────► │ PID: 1234 │ │
│ │ │ │ メモリ使用中 │ │
│ │ 静的 │ │ CPU使用中 │ │
│ └──────────────┘ └──────────────┘ │
│ │
│ 同じプログラムから複数のプロセスを起動できる: │
│ /usr/bin/bash → bash (PID 100) │
│ → bash (PID 200) │
│ → bash (PID 300) │
│ │
└─────────────────────────────────────────────────────────────┘

なぜプロセスが必要か

┌─────────────────────────────────────────────────────────────┐
│ プロセスが提供するもの │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 分離(Isolation) │
│ - 各プロセスは独自のメモリ空間を持つ │
│ - あるプロセスの問題が他に影響しにくい │
│ - セキュリティの基盤 │
│ │
│ 2. 並行実行(Concurrency) │
│ - 複数のプログラムを同時に実行可能 │
│ - OSがCPU時間を公平に配分 │
│ │
│ 3. リソース管理 │
│ - メモリ、CPU、ファイルなどの使用を追跡 │
│ - 終了時にリソースを自動的に解放 │
│ │
└─────────────────────────────────────────────────────────────┘

プロセスの構成要素

各プロセスは以下の情報を持っています:

┌─────────────────────────────────────────────────────────────┐
│ プロセスの構成要素 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ プロセス │ │
│ │ ├── PID (プロセスID) │ │
│ │ ├── PPID (親プロセスID) │ │
│ │ ├── UID/GID (所有者) │ │
│ │ ├── 仮想メモリ空間 │ │
│ │ │ ├── テキスト (コード) │ │
│ │ │ ├── データ (変数) │ │
│ │ │ ├── ヒープ (動的割り当て) │ │
│ │ │ └── スタック (関数呼び出し) │ │
│ │ ├── ファイルディスクリプタ │ │
│ │ ├── 環境変数 │ │
│ │ └── シグナルハンドラ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
構成要素説明
PIDプロセスを一意に識別する番号(1以上の整数)
PPIDこのプロセスを生成した親プロセスのPID
UID/GIDプロセスの所有者(実行したユーザー)
仮想メモリ空間プロセス専用のメモリ領域
ファイルディスクリプタ開いているファイルへの参照
環境変数PATH, HOME などの設定値
シグナルハンドラシグナルを受けた時の処理方法

プロセスの生成(fork と exec)

Linuxでは、新しいプロセスは既存のプロセスからforkシステムコールで生成されます:

┌─────────────────────────────────────────────────────────────┐
│ fork と exec の仕組み │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【fork】親プロセスのコピーを作成 │
│ │
│ 親プロセス (PID 100) │
│ │ │
│ │ fork() │
│ │ │
│ ├──────────────────┐ │
│ │ │ │
│ ▼ ▼ │
│ 親 (PID 100) 子 (PID 101) │
│ (継続実行) (親のコピー) │
│ │
│ │
│ 【exec】プロセスの中身を別のプログラムに置き換え │
│ │
│ 子プロセス (PID 101) │
│ │ │
│ │ exec("/bin/ls") │
│ │ │
│ ▼ │
│ 子プロセス (PID 101) ← 中身がlsに変わった │
│ │
│ │
│ 【実例:シェルからコマンドを実行する場合】 │
│ │
│ bash (PID 100) │
│ │ │
│ │ ユーザーが "ls" と入力 │
│ │ │
│ │ fork() │
│ │ │
│ ├──────────────────┐ │
│ │ │ │
│ ▼ ▼ │
│ bash (PID 100) bash コピー (PID 101) │
│ (子の終了を待つ) │ │
│ │ exec("/bin/ls") │
│ ▼ │
│ ls (PID 101) │
│ │ │
│ │ 実行完了、終了 │
│ ▼ │
│ bash (PID 100) ◄── 子が終了したので再開 │
│ │
└─────────────────────────────────────────────────────────────┘

プロセスの親子関係

┌─────────────────────────────────────────────────────────────┐
│ プロセスツリー │
│ │
│ init/systemd (PID 1) │
│ ├── sshd │
│ │ └── sshd (session) │
│ │ └── bash │
│ │ └── vim │
│ ├── nginx (master) │
│ │ ├── nginx (worker) │
│ │ └── nginx (worker) │
│ ├── postgres │
│ │ ├── postgres (writer) │
│ │ └── postgres (background worker) │
│ └── containerd │
│ └── containerd-shim │
│ └── java (コンテナ内) │
│ │
└─────────────────────────────────────────────────────────────┘

プロセスの確認

ps コマンド

# 基本
ps # 現在のセッションのプロセス
ps aux # 全プロセス(BSD形式)
ps -ef # 全プロセス(System V形式)

# よく使うオプション
ps aux | grep nginx # 特定プロセスを検索
ps aux --sort=-%mem # メモリ使用量順
ps aux --sort=-%cpu # CPU使用量順
ps -ef --forest # ツリー表示

# 特定の情報を表示
ps -eo pid,ppid,user,%cpu,%mem,command
ps -p 1234 -o pid,ppid,stat,command

# 出力例
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
# root 1 0.0 0.1 169936 13376 ? Ss Dec21 0:05 /sbin/init

top / htop

# top - リアルタイム監視
top
top -p 1234 # 特定PIDのみ
top -u username # 特定ユーザーのみ

# top の操作キー
# P: CPU順ソート
# M: メモリ順ソート
# k: プロセスをkill
# q: 終了
# 1: CPUコアごとの表示

# htop - より見やすいtop
htop
# F5: ツリー表示
# F6: ソート
# F9: シグナル送信

pstree

# プロセスツリー表示
pstree
pstree -p # PID付き
pstree -u # ユーザー名付き
pstree 1234 # 特定PIDのサブツリー

/proc ファイルシステム

# プロセス情報
ls /proc/1234/
cat /proc/1234/status # ステータス
cat /proc/1234/cmdline # コマンドライン
cat /proc/1234/environ # 環境変数
ls -l /proc/1234/fd/ # ファイルディスクリプタ
cat /proc/1234/limits # リソース制限

# システム全体
cat /proc/loadavg # 負荷平均
cat /proc/uptime # 稼働時間

プロセスの状態

プロセス状態

┌─────────────────────────────────────────────────────────────┐
│ プロセス状態遷移 │
│ │
│ fork() │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Created │ │
│ └──────┬──────┘ │
│ │ スケジュール │
│ ▼ │
│ ┌─────────────┐ I/O待ち ┌─────────────┐ │
│ │ Running │ ───────────────► │ Sleeping │ │
│ │ (R) │ ◄─────────────── │ (S/D) │ │
│ └──────┬──────┘ 完了 └─────────────┘ │
│ │ │
│ │ 停止シグナル │
│ ▼ │
│ ┌─────────────┐ │
│ │ Stopped │ │
│ │ (T) │ │
│ └──────┬──────┘ │
│ │ 終了 │
│ ▼ │
│ ┌─────────────┐ wait() ┌─────────────┐ │
│ │ Zombie │ ───────────────► │ Terminated │ │
│ │ (Z) │ └─────────────┘ │
│ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

状態コード(STAT)

コード状態説明
RRunning実行中または実行待ち
SSleeping割り込み可能なスリープ
DDisk sleep割り込み不可のスリープ(I/O待ち)
TStoppedシグナルで停止
ZZombie終了したが親が回収していない
追加フラグ説明
<高優先度
N低優先度
sセッションリーダー
lマルチスレッド
+フォアグラウンドプロセスグループ

シグナル

シグナルとは

シグナルとは、プロセス間で送受信される通知メッセージです。

OSやユーザーがプロセスに対して「何かをしてほしい」と伝えるための仕組みです。電話の着信やドアベルのようなもので、プロセスはシグナルを受け取ると、それに応じた処理を行います。

┌─────────────────────────────────────────────────────────────┐
│ シグナルの仕組み │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【送信側】 【受信側】 │
│ │
│ ユーザー ──┐ │
│ (Ctrl+C) │ │
│ │ │
│ OS ────────┼──── シグナル ────► プロセス ──► 処理 │
│ (エラー) │ (番号) │
│ │ │
│ 他プロセス ─┘ │
│ (kill) │
│ │
│ │
│ 【例:Ctrl+C を押した時】 │
│ │
│ ターミナル プロセス │
│ ┌────────┐ ┌────────┐ │
│ │ Ctrl+C │ ─── SIGINT ───►│ nginx │ → 終了 │
│ │ を押す │ (番号2) │ │ │
│ └────────┘ └────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

なぜシグナルが必要か

┌─────────────────────────────────────────────────────────────┐
│ シグナルの用途 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. プロセスの終了 │
│ - ユーザーが実行中のプログラムを止めたい時 │
│ - システムがプロセスを停止させたい時 │
│ │
│ 2. 設定の再読み込み │
│ - サーバーを再起動せずに設定を反映 │
│ - nginx や Apache でよく使われる │
│ │
│ 3. エラー通知 │
│ - 不正なメモリアクセス(SIGSEGV) │
│ - 0での除算(SIGFPE) │
│ │
│ 4. プロセス間通信 │
│ - 親プロセスが子プロセスに指示を送る │
│ - アプリケーション固有の通知 │
│ │
└─────────────────────────────────────────────────────────────┘

シグナルの種類

シグナルは番号で識別されます。よく使うものを覚えておきましょう:

┌─────────────────────────────────────────────────────────────┐
│ 重要なシグナル │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【プロセス終了系】 │
│ ┌────────────────────────────────────────────────────┐ │
│ │ SIGTERM (15) : 「終了してください」 │ │
│ │ プロセスに丁寧にお願いする │ │
│ │ プロセスは後処理ができる │ │
│ │ │ │
│ │ SIGKILL (9) : 「今すぐ終了しろ」 │ │
│ │ プロセスは拒否できない │ │
│ │ 後処理なしで即座に終了 │ │
│ │ 最後の手段として使う │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ 【ユーザー操作系】 │
│ ┌────────────────────────────────────────────────────┐ │
│ │ SIGINT (2) : Ctrl+C で送信される │ │
│ │ 「割り込み」= 中断してほしい │ │
│ │ │ │
│ │ SIGTSTP (20) : Ctrl+Z で送信される │ │
│ │ プロセスを一時停止 │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ 【設定再読み込み】 │
│ ┌────────────────────────────────────────────────────┐ │
│ │ SIGHUP (1) : 「設定を再読み込みして」 │ │
│ │ 多くのサーバーがこれを使う │ │
│ │ kill -HUP nginx │ │
│ └────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

主なシグナル一覧

シグナル番号説明デフォルト動作
SIGHUP1ハングアップ(設定再読み込みにも使用)終了
SIGINT2割り込み(Ctrl+C)終了
SIGQUIT3終了(Ctrl+\)コアダンプ
SIGKILL9強制終了終了(捕捉不可)
SIGTERM15終了要求終了
SIGSTOP19停止停止(捕捉不可)
SIGCONT18再開再開
SIGUSR110ユーザー定義1終了
SIGUSR212ユーザー定義2終了

シグナルの処理方法

プロセスはシグナルを受け取った時、3つの方法で対応できます:

┌─────────────────────────────────────────────────────────────┐
│ シグナルの処理オプション │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. デフォルト動作 │
│ - シグナルごとに決まっている動作を実行 │
│ - 多くのシグナルはプロセスを終了させる │
│ │
│ 2. カスタムハンドラ │
│ - プログラムが独自の処理を定義 │
│ - 例:SIGTERMを受けたら接続を閉じてから終了 │
│ │
│ 3. 無視 │
│ - シグナルを受けても何もしない │
│ - 注意:SIGKILL と SIGSTOP は無視できない │
│ │
│ │
│ 【捕捉不可のシグナル】 │
│ ┌────────────────────────────────────────────────────┐ │
│ │ SIGKILL (9) : 絶対に終了させる │ │
│ │ SIGSTOP (19) : 絶対に停止させる │ │
│ │ │ │
│ │ → プロセスがハングした時の最終手段 │ │
│ │ → これらは無視もハンドラも設定不可 │ │
│ └────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

シグナルの送信

# kill コマンド
kill 1234 # SIGTERM (デフォルト)
kill -15 1234 # SIGTERM
kill -TERM 1234 # SIGTERM
kill -9 1234 # SIGKILL (強制終了)
kill -KILL 1234 # SIGKILL

# killall (名前で)
killall nginx
killall -9 nginx

# pkill (パターンマッチ)
pkill nginx
pkill -u username # ユーザーの全プロセス
pkill -f "java.*myapp" # フルコマンドラインでマッチ

# シグナル一覧
kill -l

優雅な終了(Graceful Shutdown)

# 推奨される終了手順
# 1. まず SIGTERM を送信
kill -TERM 1234

# 2. プロセスが終了しない場合、待機
sleep 10

# 3. それでも終了しない場合 SIGKILL
kill -KILL 1234

フォアグラウンドとバックグラウンド

実行制御

# フォアグラウンドで実行
./long-running-script.sh

# バックグラウンドで実行
./long-running-script.sh &

# フォアグラウンドからバックグラウンドへ
# 1. Ctrl+Z で停止
# 2. bg で再開
Ctrl+Z
bg

# バックグラウンドからフォアグラウンドへ
fg

# ジョブ一覧
jobs
jobs -l # PID付き

nohup

# ログアウト後も実行継続
nohup ./script.sh &
nohup ./script.sh > output.log 2>&1 &

# disown でジョブを切り離し
./script.sh &
disown %1

デーモン

デーモンとは

デーモン(daemon)とは、バックグラウンドで動作し続けるプロセスです。

ユーザーの操作とは独立して、常にシステム上で待機し、特定のサービスを提供します。名前は「守護神」を意味するギリシャ語に由来しています。

┌─────────────────────────────────────────────────────────────┐
│ 通常のプロセスとデーモンの違い │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【通常のプロセス】 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ - ユーザーがコマンドを実行して起動 │ │
│ │ - ターミナルに接続している │ │
│ │ - ターミナルを閉じると終了する │ │
│ │ - 処理が終わると自動的に終了 │ │
│ │ │ │
│ │ 例:ls, grep, vim など │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 【デーモン】 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ - システム起動時に自動で起動 │ │
│ │ - ターミナルに接続していない │ │
│ │ - 明示的に停止するまで動き続ける │ │
│ │ - リクエストを待ち受けて応答 │ │
│ │ │ │
│ │ 例:sshd, nginx, postgres など │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

なぜデーモンが必要か

┌─────────────────────────────────────────────────────────────┐
│ デーモンの役割 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 常時稼働サービス │
│ - Webサーバー:常にHTTPリクエストを待ち受け │
│ - SSHサーバー:いつでもリモートログインを受け付け │
│ - データベース:常にクエリを処理 │
│ │
│ 2. 定期実行タスク │
│ - cron:スケジュールされたジョブを実行 │
│ - ログローテーション:ログファイルの管理 │
│ │
│ 3. システム管理 │
│ - systemd:他のサービスの管理 │
│ - syslogd:システムログの収集 │
│ - networkd:ネットワーク設定の管理 │
│ │
└─────────────────────────────────────────────────────────────┘

デーモンの特徴

┌─────────────────────────────────────────────────────────────┐
│ デーモンの特徴 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 技術的な特徴: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. 制御端末を持たない │ │
│ │ - ターミナルからの入力を受け付けない │ │
│ │ - ps の TTY が「?」になる │ │
│ │ │ │
│ │ 2. バックグラウンドで動作 │ │
│ │ - フォアグラウンドを占有しない │ │
│ │ - 他の作業を妨げない │ │
│ │ │ │
│ │ 3. 親プロセスは init (PID 1) │ │
│ │ - 起動後、親から切り離される │ │
│ │ - systemd や init が管理 │ │
│ │ │ │
│ │ 4. 設定ファイルで動作を制御 │ │
│ │ - /etc/ 以下に設定ファイル │ │
│ │ - SIGHUP で再読み込み │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 命名規則: │
│ - 名前は通常 "d" で終わる │
│ - sshd (SSH daemon) │
│ - httpd (HTTP daemon) │
│ - crond (cron daemon) │
│ │
└─────────────────────────────────────────────────────────────┘

デーモンの動作イメージ

┌─────────────────────────────────────────────────────────────┐
│ Webサーバー(nginx)の例 │
├─────────────────────────────────────────────────────────────┤
│ │
│ システム起動 │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ nginx (デーモン) │ │
│ │ - ポート80/443で待機 │ │
│ │ - 設定ファイル: /etc/nginx/nginx.conf │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ │ リクエストが来るまで待機... │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ クライアント │ │
│ │ からリクエスト │ ─────────────────────────────────────┤│
│ └─────────────────┘ ││
│ │ ││
│ ▼ ▼│
│ ┌─────────────────────────────────────────────────────┐ │
│ │ nginx: リクエスト処理 │ │
│ │ - HTMLファイルを返す │ │
│ │ - アプリケーションにプロキシ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ │ 処理完了後、また待機状態に戻る │
│ │ │
│ ▼ │
│ [待機中...] ← 次のリクエストを待つ │
│ │
└─────────────────────────────────────────────────────────────┘

主なデーモン

デーモン説明
sshdSSHサーバー
nginx/httpdWebサーバー
postgresPostgreSQLデータベース
crond定期実行スケジューラ
rsyslogdログ収集
dockerdDockerデーモン

コンテナのプロセス

PID 1 の重要性

┌─────────────────────────────────────────────────────────────┐
│ コンテナの PID 1 │
│ │
│ 通常のLinux: │
│ - PID 1 = init/systemd │
│ - 孤児プロセスの親になる │
│ - シグナルハンドリング │
│ │
│ コンテナ: │
│ - PID 1 = アプリケーション (通常) │
│ - シグナルが直接アプリに届く │
│ - 孤児プロセスの処理が必要 │
│ │
│ 問題: │
│ - アプリがシグナルを適切に処理しないと終了できない │
│ - ゾンビプロセスが発生する可能性 │
│ │
│ 解決策: │
│ - tini, dumb-init などの軽量initを使用 │
│ - アプリケーションでシグナルハンドリングを実装 │
│ │
└─────────────────────────────────────────────────────────────┘

コンテナ内のプロセス確認

# コンテナのプロセス
docker top container-name
docker exec container-name ps aux

# ホストから見たコンテナのプロセス
docker inspect -f '{{.State.Pid}}' container-name
ps aux | grep <pid>

# 名前空間を考慮したプロセス確認
docker exec container-name cat /proc/1/status

tini / dumb-init

# tini を使用
FROM alpine
RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["./myapp"]

# dumb-init を使用
FROM alpine
RUN apk add --no-cache dumb-init
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["./myapp"]

# Docker の --init オプション
# docker run --init myimage

シグナルの伝播

# コンテナ停止時のシグナル
docker stop container-name # SIGTERM → 10秒後 SIGKILL
docker stop -t 30 container-name # タイムアウト30秒
docker kill container-name # SIGKILL

# 特定のシグナルを送信
docker kill --signal=SIGHUP container-name
docker kill --signal=SIGUSR1 container-name

まとめ

重要なコマンド

コマンド説明
ps auxプロセス一覧
top/htopリアルタイム監視
pstreeプロセスツリー
killシグナル送信
jobs/fg/bgジョブ制御

ベストプラクティス

  • SIGKILL (kill -9) は最後の手段
  • まず SIGTERM で優雅な終了を試みる
  • コンテナでは適切な init プロセスを使用
  • ゾンビプロセスに注意

次のステップ


参考リソース