Fragments of verbose memory

冗長な記憶の断片 - Web技術のメモをほぼ毎日更新(準備中)

May 5, 2025 - 日記

Dockerコンテナからホスト上のコマンドを実行する

nsenterコマンドを使ってDockerコンテナからホスト上のコマンドを実行する方法について紹介します。

nsenter を使ってホストのネームスペースに入る

コンテナを特権モードかつホストの PID ネームスペース共有で起動し、nsenter を用いるとホストのルートプロセス(PID 1)のネームスペース内でコマンドを実行できます。

docker run -it --rm \
  --privileged \
  --pid host \
  debian:stable-slim \
  nsenter -t 1 -m -u -n -i bash

nsenter コマンドは、既存のプロセスが属する名前空間(namespace)内で指定したプログラムを実行するためのコマンドです。オプションで指定したPIDのプロセスが持つマウント、UTS、IPC、ネットワーク、PID、ユーザー、cgroup、timeなどの名前空間に入ります。プログラムを指定しない場合はデフォルトで${SHELL}(通常は/bin/sh)が実行されます。

オプション説明

  • -t, –target PID
    指定したPIDのプロセスが所属する名前空間に入るための基準プロセスを設定します。例ではPID 1(initプロセス)を対象としています。 対応パス: /proc/1/ns/mnt , /proc/1/ns/uts , /proc/1/ns/ipc , /proc/1/ns/net , … など。

  • -m, –mount[=file]
    マウント名前空間(mount namespace)に入ります。マウント/アンマウント操作が他の名前空間に影響しなくなります。 fileを指定しなければ対象プロセスのマウント名前空間に入ります。

  • -u, –uts[=file]
    UTS名前空間(UTS namespace)に入ります。ホスト名やドメイン名の設定が他の名前空間に影響しなくなります。 fileを指定しなければ対象プロセスのUTS名前空間に入ります。

  • -n, –net[=file]
    ネットワーク名前空間(network namespace)に入ります。IPv4/IPv6スタック、ルーティングテーブル、ファイアウォールルール、ソケットなどが独立します。 fileを指定しなければ対象プロセスのネットワーク名前空間に入ります。

  • -i, –ipc[=file]
    IPC名前空間(IPC namespace)に入ります。POSIXメッセージキューやSystem V IPC(共有メモリ、セマフォ、メッセージキュー)が独立します。 fileを指定しなければ対象プロセスのIPC名前空間に入ります。

コマンド例

nsenter -t 1 -m -u -n -i bash

上記コマンドは、PID 1(init)のマウント、UTS、ネットワーク、IPC名前空間に入った状態でbashを起動し、まるでホスト上のシェルにいるかのように操作できます。

nsenterの実用的な活用例

1. コンテナからホストのシステム情報を確認

docker run -it --rm --privileged --pid host debian:stable-slim nsenter -t 1 -m -u -n -i sh -c "free -m && df -h && uptime"

このコマンドでコンテナからホストのメモリ使用状況、ディスク容量、システム負荷などを一度に確認できます。

2. コンテナのヘルスチェックをホストから実行

コンテナPIDを取得してそのネットワーク名前空間に入り、内部サービスの状態を確認:

# コンテナPIDの取得
CONTAINER_PID=$(docker inspect --format '{{.State.Pid}}' <コンテナID>)

# そのコンテナのネットワーク名前空間に入り、内部Webサービスをチェック
sudo nsenter -t $CONTAINER_PID -n curl -s http://localhost:8080/health

3. デバッグ困難なコンテナのトラブルシューティング

応答しないコンテナのプロセスリストを取得し診断する:

CONTAINER_PID=$(docker inspect --format '{{.State.Pid}}' <コンテナID>)
sudo nsenter -t $CONTAINER_PID -p -m ps aux

4. 別コンテナのファイルシステムへのアクセス

コンテナが起動していても停止していても、そのファイルシステムに直接アクセスできます:

CONTAINER_PID=$(docker inspect --format '{{.State.Pid}}' <コンテナID>)
sudo nsenter -t $CONTAINER_PID -m ls -la /app/logs

5. アプリケーションのプロファイリング

コンテナ内部で動作しているアプリケーションを、ホストのプロファイリングツールで分析:

CONTAINER_PID=$(docker inspect --format '{{.State.Pid}}' <実行中Javaコンテナ>)
sudo nsenter -t $CONTAINER_PID -p -m jstack <JavaプロセスのPID>

これらの活用例は、コンテナオーケストレーション環境でのデバッグやモニタリングに非常に便利です。ただし、特権アクセスが必要なため、セキュリティリスクを十分に理解した上で使用してください。

Dockerfileの例

専用のコンテナイメージを作ることもできます:

FROM alpine:latest
RUN apk add --no-cache bash util-linux
ENTRYPOINT ["nsenter", "-t", "1", "-m", "-u", "-n", "-i"]
CMD ["bash"]
docker build . -t nsenter-test
docker run -it --rm --privileged --pid host nsenter-test ls

ls の代わりに任意のコマンドに置き換えてください

このようにして、ホスト側のコマンドをコンテナから実行できます。すべてroot権限で動くため、本番環境での使用は慎重に検討してください。