Dockerコンテナからホスト側カレントディレクトリにアクセス

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オプションと組み合わせて使います。
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.