Dockerコンテナにどうやって入る?docker exec
を徹底解説
はじめに
Dockerは、アプリケーションとその依存関係をコンテナと呼ばれる軽量でポータブルな単位にパッケージ化するためのデファクトスタンダードとなりました。開発環境の構築、マイクロサービスのデプロイ、CI/CDパイプラインなど、様々な場面で活用されています。
Dockerコンテナの大きな特徴の一つは、ホストシステムから分離された独立した実行環境であることです。これにより、環境依存性の問題を解消し、どこでも同じようにアプリケーションを実行できるようになります。
しかし、コンテナは分離されているがゆえに、内部で何が起こっているのかを確認したり、一時的に設定を変更したり、デバッグ作業を行ったりする必要が生じることがあります。まるで、物理的なサーバーや仮想マシンにSSHでログインして操作するような感覚で、コンテナ内部に「入りたい」と感じる場面があるでしょう。
Dockerには、このような要望に応えるための強力なコマンドが用意されています。それが、本記事の主題である docker exec
コマンドです。
docker exec
コマンドを使えば、実行中のコンテナ内で新しいプロセスを起動し、そのプロセスを通じてコンテナ内部のファイルシステムを操作したり、コマンドを実行したりすることができます。これは、開発段階でのデバッグ、運用中の問題調査、あるいは一時的な管理作業など、多岐にわたるシーンで不可欠な機能です。
本記事では、この docker exec
コマンドについて、その基本的な使い方から、詳細なオプション、様々な実践的な利用例、さらには使う上での注意点やベストプラクティスまで、約5000語をかけて徹底的に解説します。この記事を読み終える頃には、あなたは docker exec
を自在に操り、Dockerコンテナとのより深いインタラクションを実現できるようになっているでしょう。
それでは、さっそく docker exec
の世界に飛び込んでいきましょう。
Dockerコンテナへの「入り方」の概念
物理的なサーバーや仮想マシンでは、通常SSHプロトコルを使ってリモートログインし、シェルを起動して対話的に操作を行います。この感覚に慣れていると、「Dockerコンテナにもログインする」という表現を使ってしまいがちです。
しかし、Dockerコンテナへのアクセスは、SSHログインとは概念が少し異なります。Dockerコンテナは、特定のアプリケーションやサービスを実行するために設計されており、そのライフサイクルは比較的短く、「使い捨て」が基本原則とされています。コンテナが起動したら、定義されたメインプロセス(例えばWebサーバーやデータベースプロセス)が実行され、そのプロセスが終了すればコンテナも停止するのが基本的な挙動です。
従来のSSHサーバーのように、コンテナ起動時からバックグラウンドでSSHデーモンを起動し、いつでもログインできる状態にしておくのは、Dockerの哲学にはそぐわない場合が多いです。これは、コンテナをシンプルに保ち、必要最低限のプロセスだけを実行させるという考え方からです。SSHデーモンを起動することは、コンテナの起動時間やリソース消費を増やし、また攻撃対象となりうるサービスを余分に増やすことにも繋がります。
そこで登場するのが docker exec
です。docker exec
は、実行中のコンテナの中に、後から、任意のコマンドを実行するための新しいプロセスを起動します。SSHのようにコンテナの起動時から存在するプロセスにログインするのではなく、必要になったときに一時的にプロセスを作り出すイメージです。
コンテナ内部で作業する主な目的は、以下のようなものが考えられます。
- デバッグ: アプリケーションが期待通りに動作しない原因を探る。ファイルシステムの状態、ログファイルの内容、実行中のプロセス、ネットワーク設定などを確認する。
- 設定確認: コンテナ内の設定ファイルや環境変数が正しく読み込まれているかを確認する。
- 一時的な管理操作: データベースのダンプ、キャッシュのクリア、特定のスクリプトの一回限りの実行などを行う。
これらの作業は、コンテナの恒久的な状態を変更するためではなく、あくまで一時的な調査や操作のために行われるべきです。Dockerのベストプラクティスでは、コンテナは可能な限り不変(Immutable)であるべきだと考えられています。つまり、コンテナが一度起動したら、その内部状態を外部から変更するのではなく、状態を変更したい場合は新しい設定やコードを含む新しいイメージを作成し、そのイメージから新しいコンテナを起動するというアプローチが推奨されます。
docker exec
はこの不変性の原則に反する操作(コンテナ内部の状態を「その場で」変更する)を可能にしてしまう側面もあります。そのため、docker exec
を使う際は、その操作が一時的なデバッグや確認のためのものであることを強く意識し、永続的な変更はDockerイメージの再構築やコンテナの再作成によって行うように心がけることが重要です。
このように、docker exec
は「コンテナにログインする」というよりは「実行中のコンテナ内で一時的にコマンドを実行する」ためのツールであると理解するのが正確です。
docker exec
コマンドの基本
docker exec
コマンドの最も基本的な使い方は、実行中のコンテナ内で指定したコマンドを実行することです。
コマンドの基本構文は以下のようになります。
bash
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
[OPTIONS]
:docker exec
コマンド自体のオプションを指定します(後述します)。CONTAINER
: コマンドを実行したいコンテナを指定します。コンテナ名またはコンテナIDを使用できます。COMMAND
: コンテナ内部で実行したいコマンドを指定します。[ARG...]
:COMMAND
に渡す引数を指定します。
最も一般的な使用例: シェルを起動して対話的に操作する
前述の通り、docker exec
の典型的なユースケースは、コンテナ内部でインタラクティブなシェルを起動し、対話的に操作を行うことです。これは、物理マシンや仮想マシンにSSHでログインしてシェルを使う感覚に最も近いです。
例えば、my-web-app
という名前で実行中のコンテナがあるとします。そのコンテナ内で Bash シェルを起動して操作したい場合、以下のコマンドを実行します。
bash
docker exec -it my-web-app /bin/bash
または、コンテナに /bin/bash
が含まれていない場合は /bin/sh
を使うことも多いです。
bash
docker exec -it my-web-app /bin/sh
このコマンドの重要な部分は -it
オプションです。これは -i
と -t
という二つのオプションを組み合わせたものです。
-i
,--interactive
: 標準入力を開いたままにします。これにより、シェルのプロンプトが表示された後、キーボードから入力を受け付けることができるようになります。このオプションがないと、コマンドは実行されてすぐに終了してしまい、対話的な操作ができません。-t
,--tty
: 擬似端末 (pseudo-TTY) を割り当てます。これにより、コマンドの出力が整形され、シェルが適切に動作するようになります。例えば、色付きの出力やカーソル移動などが正しく機能するために必要です。このオプションがないと、シェルが「非対話的」なモードで起動されたと判断し、プロンプトが表示されなかったり、コマンドの出力が見づらくなったりします。
したがって、対話的なシェル操作を行うためには、-i
と -t
の両方が必要です。この二つを組み合わせた -it
は、docker exec
で最も頻繁に使用されるオプションと言えるでしょう。
このコマンドを実行すると、ホストマシンのターミナルが、指定したコンテナ内部で実行されているシェルのセッションに切り替わります。まるでコンテナ内部に「入った」かのように、ls
, cd
, cat
, ps
などのコマンドを実行して、コンテナ内のファイルシステムやプロセスなどを操作・確認できます。
シェルセッションを終了するには、通常通り exit
コマンドを入力するか、Ctrl+D
を押します。シェルが終了すると、docker exec
によって起動されたプロセスも終了し、ホストマシンのターミナルに戻ります。
重要な注意点: docker exec
で起動されたシェルプロセスは、コンテナのメインプロセスとは独立しています。シェルプロセスが終了しても、コンテナのメインプロセス(そしてコンテナ自体)は引き続き実行されます。これは、docker attach
との大きな違いです(後述します)。
docker exec
のオプション詳解
docker exec
コマンドには、様々な挙動を制御するためのオプションが用意されています。ここでは、特によく使われる、あるいは知っておくべきオプションについて詳しく解説します。
-d
, --detach
: バックグラウンドでコマンドを実行
このオプションを指定すると、docker exec
で実行するコマンドをバックグラウンドで実行させることができます。コマンドの標準出力や標準エラー出力は、デフォルトではホスト側のターミナルには表示されません。
bash
docker exec -d my-container touch /app/timestamp.txt
この例では、my-container
の /app/
ディレクトリに timestamp.txt
という空のファイルを作成するコマンドをバックグラウンドで実行します。コマンドの実行結果(成功したかどうかなど)はすぐにフィードバックされず、コマンド自体はコンテナ内部で独立して実行されます。
バックグラウンド実行は、コンテナ内部で時間のかかる処理や、常に実行しておきたいスクリプトなどを一時的に起動したい場合に便利です。ただし、コンテナのメインプロセスが終了すると、docker exec -d
で起動したプロセスも通常は終了します。
-e
, --env
: 環境変数を設定してコマンドを実行
このオプションを使うと、docker exec
で実行するコマンドに対して、特定の環境変数を設定することができます。これは、コンテナ自体の起動時に設定された環境変数に追加または上書きする形で適用されます。
bash
docker exec -e "MY_VAR=my_value" my-container env | grep MY_VAR
上記の例では、my-container
内で env
コマンドを実行する際に、MY_VAR
という環境変数に my_value
という値を設定します。そして、その出力から MY_VAR
を含む行を grep
で抽出しています。
複数の環境変数を設定することも可能です。-e
オプションを複数回指定するか、カンマ区切りでまとめて指定します。
“`bash
オプションを複数回指定
docker exec -e “VAR1=value1” -e “VAR2=value2” my-container env
カンマ区切り(古いDockerバージョンの場合)
docker exec -e “VAR1=value1,VAR2=value2” my-container env # 非推奨、新しいバージョンでは動作しない可能性あり
推奨される方法: オプションを複数回指定
docker exec \
-e “DATABASE_URL=postgresql://user:pass@host:port/dbname” \
-e “API_KEY=abcdef12345” \
my-container printenv
“`
環境変数は、コンテナ内のアプリケーションが設定を読み込むためによく利用されます。docker exec -e
は、コンテナ自体を再起動することなく、特定の環境変数を一時的に変更してコマンドの挙動をテストしたい場合に有効です。ただし、この方法で設定された環境変数は、docker exec
で起動されたプロセスとその子プロセスにのみ有効であり、コンテナのメインプロセスや、他の docker exec
で起動されたプロセスには影響しません。
機密情報(パスワードなど)を環境変数として渡す場合は、シェルの履歴に残らないように注意が必要です。可能であれば、環境変数ファイルを使用したり、機密情報は別の安全な方法でコンテナに渡したりすることを検討しましょう。しかし、docker exec
自体には環境変数ファイルを指定するオプションはありません。docker run
の場合は --env-file
オプションがありますが、exec
の場合は -e
で直接指定するか、以下のようにシェルスクリプトを介して実行する必要があります。
“`bash
環境変数ファイルから読み込んでexecする場合の工夫例
env_vars.txt の内容:
MY_VAR=my_value
OTHER_VAR=other_value
docker exec my-container sh -c ‘export $(cat env_vars.txt) && your_command’
“`
ただし、上記の例ではホスト側のファイル env_vars.txt
を直接コンテナ内部に読み込むわけではないため、ファイルの内容をコマンド文字列に埋め込む形になります。機密情報の場合は依然として注意が必要です。より安全な方法は、docker exec
を使うのではなく、イメージビルド時や docker run
時に環境変数を設定することです。docker exec -e
は、一時的なデバッグ用途に限定するのが良いでしょう。
-u
, --user
: 指定したユーザーでコマンドを実行
このオプションを使用すると、コンテナ内部でコマンドを実行するユーザーを指定できます。ユーザー名またはUID (User ID) と、オプションでグループ名またはGID (Group ID) を指定できます。
“`bash
ユーザー名を指定
docker exec -u www-data my-container whoami
UIDを指定
docker exec -u 33 my-container whoami
UIDとGIDを指定 (UID:GID の形式)
docker exec -u 1000:1000 my-container id
ユーザー名とグループ名を指定 (ユーザー名:グループ名の形式)
docker exec -u root:root my-container id
“`
コンテナ内で実行されるプロセスは、デフォルトではDockerfileで USER
命令によって指定されたユーザー、または指定されていない場合はrootユーザーで実行されます。セキュリティの観点から、コンテナ内部の操作はroot以外の権限の低いユーザーで行うことが推奨される場合があります。-u
オプションを使えば、一時的にroot以外のユーザーとしてコマンドを実行し、権限に関する問題をデバッグしたり、意図せずシステム全体に影響を与えるような操作を防いだりできます。
ただし、指定するユーザーやグループは、コンテナイメージ内に存在している必要があります。存在しないユーザー/UIDやグループ/GIDを指定した場合、コマンドは失敗するか、予期しないユーザーで実行される可能性があります。
権限が低いユーザーで実行する場合、一部のディレクトリへのアクセスやコマンドの実行が拒否されることがあります。これはセキュリティ的には望ましい挙動ですが、デバッグ中に必要なファイルが見えなかったり、コマンドが実行できなかったりする場合があるため、その際は -u root
を一時的に使用することも検討が必要になるかもしれません。しかし、その場合は操作に十分注意が必要です。
-w
, --workdir
: 作業ディレクトリを指定してコマンドを実行
このオプションを使用すると、コマンドを実行する際の作業ディレクトリを指定できます。デフォルトでは、Dockerfileの WORKDIR
命令で指定されたディレクトリ、または指定されていない場合はルートディレクトリ (/
) が使用されます。
bash
docker exec -w /app/config my-container ls -l
この例では、my-container
の /app/config
ディレクトリを作業ディレクトリとして、ls -l
コマンドを実行します。これにより、/app/config
ディレクトリの内容が一覧表示されます。
作業ディレクトリを指定することで、コンテナ内部の特定のパスにあるファイルやディレクトリを操作する際に、cd
コマンドを使ってから別のコマンドを実行するよりも簡潔に記述できます。特に、複数のコマンドを連結して実行する場合などに便利です。
“`bash
作業ディレクトリを指定しない場合
docker exec my-container sh -c ‘cd /app/scripts && ./run.sh’
作業ディレクトリを指定した場合
docker exec -w /app/scripts my-container ./run.sh
“`
後者の例の方がシンプルに記述できます。
--privileged
: 拡張権限でコマンドを実行(非推奨、危険性)
このオプションを指定すると、コンテナ内部で実行されるコマンドにホストシステムへの広範なアクセス権限が与えられます。具体的には、コンテナ内のプロセスがホストのカーネル機能にほぼ無制限にアクセスできるようになります。これは、コンテナが独立した環境として機能するDockerの基本的なセキュリティモデルを破る行為です。
“`bash
絶対に必要な場合以外は使用しないでください!
docker exec –privileged my-container mount /dev/sdb1 /mnt
“`
--privileged
オプションは非常に強力で危険なオプションです。コンテナ内部からホストシステムのファイルシステムをマウントしたり、ホストのデバイスに直接アクセスしたりといった、通常は不可能な操作が可能になります。これは、コンテナの分離性が失われ、コンテナからのエスケープ(コンテナを抜け出してホストシステムにアクセスすること)が容易になることを意味します。
このオプションは、特定の特殊なユースケース(例:Dockerコンテナ内でDockerを動かす、特定のハードウェアデバイスにアクセスする必要がある)のために提供されていますが、通常の使用においては絶対に避けるべきです。 デバッグ目的であっても、まずは他の方法(ログの確認、権限の低いユーザーでの実行など)を試み、どうしても必要な場合にのみ、その危険性を十分に理解した上で限定的に使用すべきです。
もし、コンテナ内で特定のデバイスへのアクセスや特定のカーネル機能の使用が必要な場合は、--cap-add
, --cap-drop
, --device
などのより限定的なオプションを使用することを検討してください。これらのオプションは --privileged
ほど広範な権限を与えることなく、必要な権限のみをコンテナに付与することができます。
その他のオプション
他にもいくつかのオプションがありますが、利用頻度は前述のものほど高くありません。
--env-file=[]
: 残念ながらdocker exec
にはこのオプションはありません。環境変数をファイルから読み込みたい場合は、前述のようにsh -c 'export $(cat ...)
のようなシェルトリックを使う必要があります。--interactive
/-i
: 標準入力を開いたままにする。対話的なシェルには必須。--tty
/-t
: 擬似端末を割り当てる。対話的なシェルには必須。
これらのオプションを適切に組み合わせることで、docker exec
の柔軟性は大幅に向上します。
docker exec
の実践的な利用例
ここでは、docker exec
を実際にどのような場面で活用できるのか、具体的なコマンド例を交えて紹介します。
デバッグ
アプリケーションの動作がおかしい、エラーが発生しているといった状況で、コンテナ内部の状態を調査するために docker exec
は非常に役立ちます。
-
ログの確認:
アプリケーションが出力するログファイルがコンテナ内部に保存されている場合、docker exec
でそのファイルの内容を確認できます。bash
docker exec my-web-app cat /var/log/my-app/error.logもしログファイルが大きすぎる場合は、
tail
コマンドを使うこともできます。bash
docker exec my-web-app tail -f /var/log/my-app/access.log
-f
オプションを付けることで、リアルタイムでログの追記を確認できます。この場合も、対話的なセッションとして実行するために-it
を付けると良いでしょう。bash
docker exec -it my-web-app tail -f /var/log/my-app/access.log -
プロセスリストの確認:
コンテナ内でどのようなプロセスが実行されているかを確認できます。想定外のプロセスが動いていないか、必要なプロセスが起動しているかなどをチェックします。bash
docker exec my-web-app ps aux
または、より詳細な情報やツリー表示が必要な場合はpstree
など、コンテナに含まれているコマンドを使用します。 -
ネットワーク状態の確認:
コンテナ内部からのネットワーク接続を確認したり、開いているポートを調べたりできます。(ただし、これらのコマンドが含まれているイメージである必要があります)“`bash
開いているポートを確認 (netstat が含まれている場合)
docker exec my-web-app netstat -tulnp
DNS解決をテスト (ping が含まれている場合)
docker exec my-web-app ping -c 3 google.com
ネットワークインターフェースとIPアドレスを確認 (ip が含まれている場合)
docker exec my-web-app ip addr show
“` -
ファイルシステムの確認:
コンテナ内のファイルやディレクトリの存在、パーミッション、内容などを確認します。“`bash
特定のディレクトリの内容を一覧表示
docker exec my-web-app ls -l /app/config
特定のファイルの内容を表示
docker exec my-web-app cat /etc/nginx/nginx.conf
ファイルのパーミッションを確認
docker exec my-web-app stat /app/data/some_file
“` -
特定のコマンドの実行と出力確認:
アプリケーションの一部機能のみをコンテナ内部で実行して、その出力を直接確認します。“`bash
データベースコンテナで特定のSQLクエリを実行 (psql が含まれている場合)
docker exec some-postgres-db psql -U myuser -d mydb -c “SELECT COUNT(*) FROM users;”
アプリケーションのヘルスチェックコマンドを実行
docker exec my-api-service ./bin/healthcheck.sh
“`
設定確認
コンテナに渡した環境変数や設定ファイルが正しく反映されているかを確認します。
-
環境変数の確認:
コンテナ内部から見える環境変数を確認します。bash
docker exec my-web-app env
特定の環境変数のみを確認したい場合は、grep
などと組み合わせます。bash
docker exec my-web-app env | grep DATABASE_URL -
設定ファイルの読み取り:
アプリケーションが使用する設定ファイルの内容を直接確認します。bash
docker exec my-web-app cat /etc/app/settings.yaml
一時的な操作
コンテナの稼働を維持したまま、一度だけ実行したい管理タスクなどを行います。
-
データベースのバックアップ・リストア:
データベースコンテナ内で、ダンプツールを使ってデータベースのバックアップを作成したり、リストアを実行したりします。“`bash
PostgreSQLのダンプを作成し、ホストに保存(ボリュームや標準出力を利用)
docker exec some-postgres-db pg_dump -U myuser mydb > latest_backup.sql
MySQLのダンプを作成し、ホストに保存
docker exec some-mysql-db mysqldump -u myuser -p’mypassword’ mydb > latest_backup.sql
バックアップファイルからリストア (ホストからコンテナへのファイルコピーは別コマンドが必要、例えば
docker cp
)まずホストからコンテナにファイルをコピー
docker cp my_backup.sql some-postgres-db:/tmp/my_backup.sql
コンテナ内部でリストア実行
docker exec some-postgres-db psql -U myuser -d mydb < /tmp/my_backup.sql
一時ファイルを削除
docker exec some-postgres-db rm /tmp/my_backup.sql
``
docker exec` の利用例として示したものです。
データベースのバックアップ・リストアは重要かつデリケートな操作なので、手順をよく確認し、必要に応じて公式ドキュメントなどを参照してください。上記の例はあくまで -
キャッシュのクリア:
アプリケーション内部のキャッシュをクリアするコマンドを実行します。bash
docker exec my-php-app php artisan cache:clear
docker exec my-ruby-app bundle exec rails cache:clear -
特定のスクリプトの実行:
コンテナイメージには含まれているが、メインプロセスとは別に実行したいスクリプトを実行します。bash
docker exec my-worker-app ./scripts/run_migrations.sh
複数のコマンド実行
docker exec
は本来一つのコマンドとその引数を実行するためのものですが、シェルを介することで複数のコマンドを連結して実行することも可能です。これは、コンテナ内部で一連の操作を行いたい場合に便利です。
Unix系のシェルでは、セミコロン (;
) や &&
(論理AND) を使って複数のコマンドを一行で記述できます。これを docker exec
の COMMAND
部分に指定するシェル(例: /bin/sh
や /bin/bash
)の引数として渡します。
“`bash
セミコロンで連結: 前のコマンドの成否に関わらず次のコマンドを実行
docker exec my-container sh -c ‘cd /app && ls -l; echo “Done”‘
&&
で連結: 前のコマンドが成功した場合のみ次のコマンドを実行
docker exec my-container sh -c ‘cd /app && ./run_script.sh && echo “Script executed successfully”‘
“`
上記の例で重要なのは、sh -c '...'
のようにシェルを明示的に指定し、そのシェルに対して実行したいコマンド文字列を引数として渡している点です。これにより、シェルがコマンド文字列を解釈して複数のコマンドを実行してくれます。
また、パイプ (|
) を使ってコマンドの出力を別のコマンドの入力として渡すことも可能です。
“`bash
ps aux の結果を grep でフィルタリング
docker exec my-container sh -c ‘ps aux | grep my_process’
“`
複数のコマンドを連結する場合、コマンド文字列全体のクォーテーション(一重引用符 '
や二重引用符 "
)や、コマンド内の特殊文字(スペース、パイプ |
、リダイレクト >
, ;
, &
, $
など)のエスケープに注意が必要です。一般的には、一重引用符 '
でコマンド文字列全体を囲むことで、その中の特殊文字がホスト側のシェルではなく、コンテナ内部のシェルによって解釈されるようにするのが安全です。
これらの例からもわかるように、docker exec
はデバッグから一時的な管理タスクまで、コンテナ内部での様々な操作を可能にする非常に柔軟なツールです。
docker exec
の高度なトピック
対話的なシェルがないコンテナ
一部の軽量なコンテナイメージ(例: alpine
, busybox
, または scratch
をベースにしたイメージ)には、完全なBashやZshのようなシェルが含まれていない場合があります。特に、scratch
イメージは最小限のバイナリしか含まないため、/bin/bash
や /bin/sh
といったシェルは存在しません。
このようなコンテナに対して docker exec -it my-minimal-container /bin/bash
のようなコマンドを実行しようとすると、「executable file not found in PATH」といったエラーが表示され、シェルが起動できません。
しかし、シェルがない場合でも、docker exec
はコンテナに含まれている個別の実行可能ファイルを起動することは可能です。例えば、/bin/ls
や /bin/cat
といった基本的なコマンドがコンテナに含まれていれば、それらを直接実行できます。
“`bash
シェルはないが /bin/ls があるコンテナの場合
docker exec my-minimal-container /bin/ls /app
“`
シェルがないコンテナでデバッグを行う必要がある場合、以下のような選択肢が考えられます。
- コンテナに含まれている基本的なコマンドのみでデバッグを行う:
ls
,cat
,ps
(もし含まれていれば) など、利用可能な最小限のツールで情報を収集します。 -
一時的にデバッグツールを追加する: デバッグに必要なツール(例:
curl
,ping
,netstat
, デバッガなど)を、docker exec
と別のコマンド(例:apk add
(Alpine Linuxの場合) やapt-get update && apt-get install
(Debian/Ubuntuベースの場合))を組み合わせて一時的にインストールします。“`bash
Alpine Linux ベースのコンテナで curl を一時的にインストールして使う例
docker exec my-alpine-container apk update
docker exec my-alpine-container apk add curl
docker exec my-alpine-container curl http://localhost:8080/health
docker exec my-alpine-container apk del curl # 使い終わったら削除するのが望ましい
“`
ただし、この方法はコンテナのファイルシステムに一時的な変更を加えることになり、不変性の原則に反します。また、インストールしたツールを削除し忘れると、コンテナイメージに余分なものが残ってしまう可能性もあります。デバッグ後はコンテナを再起動(新しいイメージで再作成)することを強く推奨します。
3. デバッグ用のイメージを作成する: 運用環境用の軽量なイメージとは別に、デバッグ用のツールをあらかじめ含めた別のDockerイメージを作成しておき、問題発生時にそのイメージで新しいコンテナを起動するか、実行中のコンテナをそのデバッグイメージのコンテナに置き換えるというアプローチもあります。これは、コンテナを使い捨てるというDockerの思想に合致したより良い方法と言えます。
exec権限がないユーザー
-u
オプションで権限の低いユーザーを指定して docker exec
を実行した場合、そのユーザーが実行権限を持っていないコマンドは実行できません。例えば、/root
ディレクトリの中身を見ようとしたり、システム設定ファイルを変更しようとしたりすると、Permission denied エラーが発生します。
これはセキュリティ上は望ましい挙動ですが、デバッグ中に必要な情報にアクセスできない場合は困ります。このような場合、以下のような対応が考えられます。
- 一時的にrootユーザーで実行する: デバッグに必要な操作に限って、
-u root
オプションを付けてdocker exec
を実行します。ただし、この操作は非常に危険なので、細心の注意を払って、必要な操作だけを行い、すぐに終了することが重要です。 - コンテナ内部に
sudo
をインストールし、設定する: コンテナイメージ自体にsudo
コマンドを含め、権限の低いユーザーが特定のコマンドをsudo
経由でroot権限で実行できるように設定します。ただし、これはイメージを大きくし、設定も必要になるため、単純なデバッグ目的には過剰かもしれません。 - 必要な情報をコンテナ外部に出力させる: デバッグに必要な情報(ログファイルの内容、設定ファイルの内容など)を、
docker logs
コマンドで取得できるように標準出力/標準エラー出力にリダイレクトするか、共有ボリューム (-v
) を使ってホスト側にファイルとして出力するようにアプリケーションやコンテナの設定を変更することを検討します。これにより、docker exec -u root ...
のような危険な操作を回避できる場合があります。
非対話的なコマンド実行
-it
オプションを付けずに docker exec
を実行すると、コマンドは非対話的に実行されます。この場合、標準入力は閉じられ、擬似端末も割り当てられません。これは、コンテナ内部で単一のコマンドを実行してその出力を取得したり、バックグラウンドで特定の処理を開始したりする場合に使用します。
“`bash
非対話的にlsコマンドを実行し、結果をホスト側のターミナルに表示
docker exec my-container ls -l /app
非対話的にバックグラウンドでスクリプトを実行 (-d
と組み合わせることが多い)
docker exec -d my-container /app/scripts/background_job.sh
“`
非対話的な実行では、コマンドの標準出力 (stdout) と標準エラー出力 (stderr) は、デフォルトでは docker exec
コマンドを実行したホスト側のターミナルに表示されます。コマンドが成功したか失敗したかは、docker exec
コマンド自体の終了コードを確認することで判断できます。docker exec
の終了コードは、コンテナ内部で実行されたコマンドの終了コードを反映します。
“`bash
コマンドを実行し、終了コードを表示
docker exec my-container ls /non_existent_directory
echo $? # 直前のコマンドの終了コードを表示 (bashの場合)
-> 2 (lsがファイルが見つからない場合などに返す終了コード)
docker exec my-container ls /app
echo $?
-> 0 (lsが成功した場合に返す終了コード)
“`
スクリプトから docker exec
を実行して自動化する場合など、対話的な操作が不要な場合は、-it
を付けずに非対話的に実行するのが一般的です。
docker exec
と他のコンテナ操作コマンドとの比較
Dockerには、docker exec
以外にもコンテナを操作するためのコマンドがいくつかあります。docker exec
の位置づけを理解するために、それらのコマンドと比較してみましょう。
docker run
docker run
コマンドは、指定したイメージから新しいコンテナを作成し、その中でコマンドを実行する際に使用します。
bash
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
docker exec
: 実行中の既存のコンテナに対して新しいプロセスを起動し、コマンドを実行します。docker run
: 新しいコンテナを作成・起動し、そのコンテナのメインプロセスとしてコマンドを実行します。
docker run
はコンテナのライフサイクルの開始点です。アプリケーションのデプロイや、一度だけ実行するバッチ処理用のコンテナなどを起動する際に使用します。docker exec
は、既に起動しているコンテナの状態を調べたり、一時的な操作を行ったりする際に使用します。
例えば、「ubuntu」イメージを使って簡単なコマンドを実行したい場合:
“`bash
新しいコンテナを作成して ls コマンドを実行し、コンテナは終了する
docker run ubuntu ls -l /
既存の ubuntu コンテナ (例えば run されてバックグラウンドで動いているもの) に対して ls コマンドを実行
(まずコンテナ名やIDを確認する必要がある: docker ps)
docker exec ls -l /
“`
docker attach
docker attach
コマンドは、実行中のコンテナの標準入出力や標準エラー出力、または擬似端末に「アタッチ」します。これにより、コンテナのメインプロセス(通常は docker run
の COMMAND
または Dockerfileの CMD
/ENTRYPOINT
で指定されたプロセス)と直接対話できるようになります。
bash
docker attach [OPTIONS] CONTAINER
docker exec
: 新しいプロセス(例:/bin/bash
)をコンテナ内部で起動し、そのプロセスと対話します。docker exec
で起動したプロセスが終了しても、コンテナのメインプロセスは影響を受けません。docker attach
: コンテナのメインプロセスにアタッチします。アタッチしたセッションでexit
を入力するなどしてメインプロセスが終了すると、通常コンテナ自体も停止します。
docker attach
は、コンテナのメインプロセスが出力するログをリアルタイムで見たい場合や、メインプロセスが対話的なコマンド(例: データベースのシェル)である場合に役立ちます。しかし、メインプロセスを誤って終了させてしまうリスクがあるため、デバッグなどでコンテナ内部に入りたい場合は、安全な docker exec -it /bin/bash
の方が一般的に推奨されます。
例えば、docker run -it ubuntu /bin/bash
で起動したコンテナにアタッチすると、そのコンテナのBashセッションに入れます。ここで exit
するとコンテナが停止します。一方、docker run -d ubuntu sleep infinity
でバックグラウンド起動したコンテナに対し、docker exec -it <container_id> /bin/bash
で入ったセッションで exit
しても、コンテナは sleep infinity
を実行し続けて停止しません。
docker exec
を使う上での注意点とベストプラクティス
docker exec
は強力で便利なツールですが、その特性を理解せずに使用すると、予期せぬ問題を引き起こしたり、Dockerのベストプラクティスから外れてしまったりする可能性があります。以下に、使う上での注意点と推奨されるプラクティスをまとめます。
不変性 (Immutability) の原則を理解する
Dockerコンテナは、可能な限り不変(Immutable)であるべきという思想に基づいています。これは、一度ビルドされたコンテナイメージから起動したコンテナは、その実行中に内部状態を外部から変更するべきではなく、状態を変更したい場合は新しい設定やコードを含む新しいイメージを作成し、そのイメージから新しいコンテナを起動・デプロイするという考え方です。
docker exec
を使ってコンテナ内部でファイルシステムを変更したり、設定を書き換えたりすることは、この不変性の原則に反します。docker exec
による変更は、そのコンテナが停止・削除されると失われてしまいます。また、同じイメージから別のコンテナを起動しても、docker exec
で行った変更は引き継がれません。
したがって、docker exec
は主に以下の目的に限定して使用するのが適切です。
- デバッグと調査: 問題発生時にコンテナの現在の状態を確認する。
- 一時的な操作: 一度だけ実行する必要がある管理タスク。
恒久的な変更や設定の適用は、以下のような代替手段を検討すべきです。
- Dockerfileを変更してイメージを再ビルドする: アプリケーションコードや設定ファイルを変更する場合。
- コンテナ起動時にボリュームマウントで設定ファイルを注入する: アプリケーションの実行時設定を変更する場合。
- コンテナ起動時に環境変数を設定する: アプリケーションの実行時設定を環境変数で渡せる場合。
- 新しい設定やコードを含む新しいイメージでコンテナを再作成する: デプロイや設定変更の標準的な手順。
デバッグツールについて
運用環境で動作するコンテナイメージは、セキュリティやサイズを考慮して、必要最低限のファイルやツールのみを含むように軽量化されていることが一般的です。ping
, curl
, netstat
, vim
などのデバッグや管理ツールは、運用イメージには含まれていないことがあります。
このような場合、デバッグのために一時的に必要なツールを docker exec
を使ってコンテナ内部にインストールすることは可能ですが(前述の「対話的なシェルがないコンテナ」の項を参照)、これはあくまで一時的な手段として限定すべきです。
より良いアプローチとしては、以下のようなものが考えられます。
- デバッグ用のイメージを別途用意する: 運用イメージをベースにしつつ、デバッグ用のツール(シェル、ネットワークツール、エディタなど)を追加したイメージを作成しておきます。問題発生時は、このデバッグイメージを使って新しいコンテナを起動し、ボリュームマウントなどで問題が発生しているコンテナと同じデータにアクセスして調査を行います。
- マルチステージビルドを活用する: アプリケーションのビルドに必要なツール(コンパイラ、リンター、テストツールなど)はビルドステージのみに含め、最終的な実行可能イメージには含めないようにします。これにより、運用イメージは軽量に保ちつつ、必要であればビルドステージで使われたツールを含むイメージをデバッグに利用することも可能です。
セキュリティに関する注意
docker exec
は、実行中のコンテナ内部で任意のコマンドを実行できる強力な機能です。悪意のあるユーザーや、意図しないコマンド実行によって、コンテナ内部やホストシステムに損害を与える可能性があります。
特に以下の点に注意が必要です。
--privileged
オプションは避ける: 前述の通り、このオプションはコンテナのセキュリティ分離をほぼ無効にしてしまいます。絶対に必要な場合以外は使用しないでください。- root権限での実行を最小限にする:
-u root
オプションを使用する場合、その操作がシステム全体に影響を与える可能性があることを常に意識し、必要最低限の操作に限定します。可能な限り、権限の低いユーザー (-u <username>
) で操作するようにします。 - アクセス制御を適切に行う:
docker exec
コマンドを実行できるのは、ホストマシンのDockerデーモンにアクセスできるユーザーです。Dockerデーモンへのアクセス権限は慎重に管理し、信頼できるユーザーのみに付与するようにします。Dockerデーモンはデフォルトではroot権限で動作することが多いため、デーモンへのアクセス権限は実質的にroot権限と同等の強力な権限を意味します。 - コンテナ内部に入れる情報を限定する: コンテナイメージに機密情報(パスワード、APIキーなど)を直接含めないようにします。これらは環境変数やボリュームマウントでコンテナに渡すのが一般的ですが、
docker exec env
のようなコマンドで容易に見えてしまう可能性があります。機密情報は、Docker Secrets や Kubernetes Secrets といった安全な方法で管理することを検討すべきです。 - シェル履歴に注意する: 対話的なシェル (
-it
) でコマンドを実行した場合、そのコマンド履歴はコンテナ内部のユーザーのホームディレクトリなどに保存される可能性があります。機密情報を含むコマンドを実行した場合は、履歴に残らないように注意するか、実行後に履歴ファイルを削除することを検討してください。(ただし、履歴ファイルの保存場所やフォーマットはシェルや設定によって異なります。)
ロギング
docker exec
コマンド自体は、ホストシステムのDockerイベントログに残ります(例えば docker events
コマンドで見ることができます)。しかし、docker exec
で起動したシェルセッション内で実行された個々のコマンドやその操作内容のログは、デフォルトではDockerのログ機構では記録されません。
コンテナ内部での操作を監査したい場合は、コンテナイメージ内にシェル履歴の保存設定を強化したり、コマンド実行を記録するツール(例: auditd
や特定のシェルのロギング機能)を組み込む必要があります。これは高度な設定であり、コンテナイメージのサイズや複雑性を増加させる可能性があります。
代替手段の検討
繰り返しになりますが、docker exec
によるコンテナ内部の「その場での変更」は、Dockerの不変性という思想とは少し異なります。もしあなたが docker exec
を使って以下のような操作を頻繁に行っている場合、それはより良い代替手段がある可能性を示唆しています。
- 設定ファイルの変更: ボリュームマウント (
-v
) でホスト側の設定ファイルをコンテナにマウントし、ホスト側でファイルを編集して変更を反映させる。あるいは、新しい設定ファイルを含んだイメージを再ビルドし、コンテナを再作成する。 - 新しいファイルの追加: 新しいファイルを含んだイメージを再ビルドする。あるいは、データ永続化用のボリューム (
-v
) をマウントし、ホスト側からファイルをボリュームにコピーする (docker cp
)。 - データベースマイグレーションや初期データの投入: アプリケーションの起動時にマイグレーションを自動実行するようにするか、別のコンテナ(例: マイグレーション実行用のワンオフコンテナ)を
docker run
で起動して実行する。 - 定期的なタスクの実行: コンテナ内部でcronのようなスケジューラを動かすか、ホスト側のcronや別のスケジューラから
docker exec
を定期的に実行するスクリプトを起動する。ただし、定期的なタスクは専用のコンテナ(cronコンテナなど)として分離するのが一般的な設計です。
docker exec
はデバッグや緊急時の対応に特化したツールと位置づけ、日常的な運用やデプロイの手順には組み込まないようにするのが、Dockerをより効果的かつ安全に活用するためのベストプラクティスと言えます。
スクリプト化について
複数の docker exec
コマンドを連続して実行したり、docker exec
の出力を他のコマンドで処理したりする場合、それらをシェルスクリプトとしてまとめることがよくあります。
例えば、複数のコンテナのログファイルの一部をまとめて取得するスクリプトなどです。
“`bash
!/bin/bash
CONTAINERS=(“web-app-1” “web-app-2” “web-app-3″)
LOG_FILE=”/var/log/app/production.log”
for container in “${CONTAINERS[@]}”; do
echo “— Logs from $container —”
docker exec “$container” cat “$LOG_FILE” | tail -n 100
echo “”
done
“`
スクリプト化することで、手作業によるミスを減らし、繰り返しの作業を効率化できます。ただし、前述のように、docker exec
で行う操作は不変性の原則に反しない、一時的なものに限定すべきです。スクリプト化するほどの繰り返し作業であれば、それはコンテナのビルドプロセスや、コンテナオーケストレーションツール(Kubernetes, Docker Swarmなど)の機能を使って実現できないかを検討するのが望ましいでしょう。
まとめ
本記事では、Dockerコンテナの内部にアクセスするための主要なコマンドである docker exec
について、その基本から応用、そして注意点までを詳しく解説しました。
docker exec
は、実行中のコンテナ内に新しいプロセスを起動することで、コンテナのファイルシステムを操作したり、コマンドを実行したりすることを可能にします。これは、開発中のデバッグ、運用環境での問題調査、一時的な管理タスクなど、多岐にわたる場面で非常に役立つ機能です。
最も一般的な使い方は、-it
オプションを使用して対話的なシェル(/bin/bash
や /bin/sh
)を起動し、コンテナ内部でコマンドを自由に入力・実行することです。-i
は標準入力の維持に、-t
は擬似端末の割り当てにそれぞれ必要であり、対話的な操作には不可欠な組み合わせです。
また、-d
(バックグラウンド実行), -e
(環境変数設定), -u
(ユーザー指定), -w
(作業ディレクトリ指定) など、様々なオプションを活用することで、docker exec
の挙動を細かく制御できます。特に -u
オプションは、セキュリティのために権限の低いユーザーでコマンドを実行する際に重要です。ただし、--privileged
オプションのように強力すぎる権限を与えるオプションは、その危険性を十分に理解し、避けるべきです。
docker exec
を使う上では、Dockerコンテナが「使い捨て」であり、不変(Immutable)であることを理解することが非常に重要です。docker exec
によるコンテナ内部への変更は一時的なものであり、コンテナの再起動や再作成によって失われます。永続的な設定変更やアプリケーションの更新は、Dockerイメージの再ビルドやボリュームマウント、環境変数の設定といった、よりDockerの哲学に則った方法で行うべきです。docker exec
はあくまで、一時的なデバッグや調査のためのツールとして活用するのがベストプラクティスです。
シェルが含まれていない軽量イメージでの docker exec
の使い方や、非対話的な実行によるスクリプトからの利用方法、そして docker run
や docker attach
といった関連コマンドとの違いについても解説しました。これらの知識を持つことで、Dockerコンテナとのインタラクションにおいて、状況に応じて最適なコマンドを選択できるようになります。
docker exec
は非常に強力なツールである反面、セキュリティリスクも伴います。-u root
や --privileged
の使用は最小限に留め、Dockerデーモンへのアクセス制御を適切に行うなど、セキュリティ上の注意点を守ることが重要です。
本記事を通じて、あなたは docker exec
コマンドの様々な側面について深く理解できたはずです。ぜひこの知識を活かして、Dockerコンテナでの開発、デバッグ、運用をより効率的かつ安全に進めてください。
付録/参考情報
docker exec --help
:docker exec
コマンドのすべてのオプションと簡単な説明を確認できます。- Docker公式ドキュメント: https://docs.docker.com/engine/reference/commandline/exec/
- 関連するDockerコマンド:
docker ps
: 実行中のコンテナ一覧を表示します。docker exec
するコンテナのIDや名前を確認する際に使用します。docker logs
: コンテナの標準出力/標準エラー出力に記録されたログを取得します。ファイルではなく標準出力にログを出力するようにアプリケーションが設定されている場合、こちらの方が簡単にログを確認できます。docker attach
: 実行中のコンテナのメインプロセスにアタッチします。docker exec
とは異なる用途で使用されます。
これらのリソースも活用しながら、あなたのDockerスキルをさらに磨いていってください。