Dockerコンテナ上のツール等からホスト側のファイルやディレクトリにアクセスする場合、これらをdocker cp
でホスト↔コンテナ間移動するのは結構に手間です。
以下のようにコンテナ側からホスト側のカレントディレクトリがアクセスできるようにオプション設定することで、この手間を省くことができます。ツール等をDockerコンテナとして配布している場合、そのツールでホスト側のファイルやディレクトリを指定したり、ツールが出力したファイルをホスト側にそのまま格納したい時などにはとても便利です。
コマンドの雛形
docker run --rm \
--user $UID -v $PWD:$PWD -w $PWD \
<Dockerイメージ> \
<コマンド文字列>
-
<Dockerイメージ>
には任意のイメージを指定します。 -
<コマンド文字列>
にはdocker run/create等で指定するコマンド文字列を指定します。なお後述する通り、コンテナ上でパイプラインやリダイレクト等を使う場合はbash -c "<コマンド文字列>"
とする必要があります。この落とし穴にハマる人は結構多いです。
使用例
最も簡単な使用例。コンテナ上でtouchコマンドを使ってhello.txtを作成し、このファイルがホスト側のカレントディレクトリに配置されていることを確認します。
docker run --rm \
--user $UID -v $PWD:$PWD -w $PWD \
alpine \
touch hello.txt
ls hello.txt
Pythonで特定のPythonライブラリ+依存関係をまとめてダウンロードする場合、以下のようにpip3コマンドを実行します。
mkdir my-py-library
docker run --rm \
--user $UID -v $PWD:$PWD -w $PWD \
python:3.6 \
pip3 install docker -t my-py-library
ls my-py-library
留意事項
ホスト側カレントディレクトリは$HOMEより下にする
カレントディレクトリを$HOMEよりも上位のディレクトリにして本コマンドを実行することにより、アクセスできるファイルとディレクトリの範囲が広がります。しかしコンテナが想定通り動作しなくなったり、ホスト側のディレクトリやファイルを破壊する危険性があるためお勧めしません。また後述する通り$HOME直下をカレントディレクトリにするのも同様に危険なため、$HOMEよりも一つ下以降のディレクトリをカレントディレクトリにしましょう。
ホスト側の$HOMEは局所化して利用する
本記事で紹介しているdockerコマンドを応用して、下記のいずれかの条件で実行すれば、コンテナ上でホスト側の$HOMEにアクセスできます。
- $HOMEをカレントディレクトリにする
-
-v $HOME:$HOME
を指定する
コンテナ上からホスト側の$HOMEにアクセスすることにより、各種設定やキャッシュ等にアクセスすることができるため、使い方によっては作業効率を改善できます。ただし、異なるバージョンのプログラムを使用することにより、アクセスしたディレクトリやファイルを意図しない形で破壊するリスクが発生します。このため$HOMEの各種設定やキャッシュ等にアクセスしたい場合は、それぞれを明示的にv
オプションで指定することをお勧めします。
例えばコンテナ上からホスト側のGradle関連キャッシュ等にアクセスしたい場合は、-v $HOME/.gradle:$HOME/.gradle
と指定してコンテナ側で必要なディレクトリのみに範囲を制限しましょう。
リダイレクト、パイプライン等を含む場合はbach -cを使用する
docker run
に記述するコマンド文字列にリダイレクト、パイプライン、セミコロンは直接使うことができません。使った場合は以下のようにホスト側に対しての入出力やコマンドが実行されてしまいます。
- リダイレクトのファイル出力先はホスト側となる
- パイプライン以降はホスト側のコマンドで実行される
- セミコロン以降はホスト側のコマンドが実行される
NOTE: なおこれはDockerコマンドの仕様ではなく、bash等のシェルの仕様です。
これらを使用する場合は、以下のようにbash -c
を使ってコマンドを実行する必要があります。コンテナ上で実行するコマンド文字列全体は、必ずシングルクオートまたはダブルクオートで囲ってください。
# bash -cの引数として指定されたコマンド文字列は全てコンテナ上で実行される
docker run --rm \
--user $UID -v $PWD:$PWD -w $PWD \
python:3.6 \
bash -c 'python3 -V > python_version.txt; cat python_version.txt'
NOTE: ちなみに上記の例だと、bash -cを使っても使わなくても結果は変わりません。
-v $PWD:$PWD -w $PWD
を削ると結果が変わります。
ただし実際に結果が変わってしまうケースに遭遇する場合、原因解明に少し手間取る可能性があります。このためリダイレクトやパイプライン等を含む時には、基本的にbash -cを使うという方針でよいと思います。
補足: Dockerオプション解説
本記事のDockerコマンドで使用している各オプションについて説明しています。
-
--rm
オプションでDockerコンテナのプロセス(コマンド)が終了した時点でコンテナを破棄します。コマンド終了後にDockerコンテナ上のファイルを色々とアクセスしたい場合は外しても構いません。 -
--user
オプションでホスト側のUIDを指定します。指定しない場合、生成したファイル等の所有者がroot:rootとなるためホスト側のユーザが編集したり削除したりできません。 -
-v $PWD:$PWD
オプションで、ホスト側カレントディレクトリとコンテナ側カレントディレクトリのボリューム内容を一致させます。 -
-w $PWD
オプションで、ホスト側カレントディレクトリとコンテナ側カレントディレクトリのディレクトリパスを一致させます。-v $PWD:$PWD
オプションと組み合わせて使います。