続・Dockerことはじめ: コンテナにホスト側のディレクトリをマウントする
0. はじめに
前回の記事はこちら
- 前回はTensorFlow公式のDocker Imageを入手してコンテナを起動してみました.
- 今回は研究プロジェクトを実際にDocker コンテナを使って進めていく準備をしたいと思います.
動作環境
1. ホスト側のディレクトリをコンテナにマウントする
1-0. 何もマウントしないとどうなるか
自分の研究プロジェクトを共用GPUサーバーの /home/me/myproject
内に置いているとします.
me@server myproject$ pwd /home/me/myproject me@server myproject$ ls README.md data docs models myenv notebooks papers src
ここで, TensorFlow公式のDocker Imageからtoy_container
という名前のコンテナを作って起動してみます.
me@server myproject$ sudo docker run -it --name toy_contrainer \ > tensorflow/tensorflow:latest-gpu-jupyter \ > bash
________ _______________ ___ __/__________________________________ ____/__ /________ __ __ / _ _ \_ __ \_ ___/ __ \_ ___/_ /_ __ /_ __ \_ | /| / / _ / / __/ / / /(__ )/ /_/ / / _ __/ _ / / /_/ /_ |/ |/ / /_/ \___//_/ /_//____/ \____//_/ /_/ /_/ \____/____/|__/ WARNING: You are running this container as root, which can cause new files in mounted volumes to be created as the root user on your host machine. To avoid this, run the container by specifying your user's userid: $ docker run -u $(id -u):$(id -g) args...
コンテナ内部を少し探検してみます.
root@0123456789ab:/tf# pwd # 起動直後の作業ディレクトリはtfというディレクトリ /tf root@0123456789ab:/tf# cd ~ root@0123456789ab:~# pwd /root root@0123456789ab:~# ls # /rootの中身には何も入っていない root@0123456789ab:~# cd / root@0123456789ab:/# ls # ディレクトリツリーのトップをみてみる bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tf tmp usr var
私の研究プロジェクトが見当たりませんね.
どうやらこのままではコンテナのファイルシステムはホスト側のファイルシステムとは隔離されているため, ホスト側に置いてあるファイルやスクリプトをコンテナ内で利用できないようです.
一旦このコンテナからは抜けて, コンテナも削除しておきます.
root@0123456789ab:/# exit exit me@server myproject$ sudo docker rm toy_container toy_container
1-1. docker run -v
でマウントする
docker run -v ホスト側のディレクトリ:マウント先のディレクトリ
を使うと, ホスト側のディレクトリをマウントしたコンテナを作成し, 起動できます.
# ホスト側の /home/me 以下をコンテナ内の /home/me にマウントする # コンテナ内にもともと /home/me ディレクトリは存在しないが, 新しく作成される me@server myproject$ sudo docker run -it --name toy_contrainer \ > -v /home/me:/home/me \ > tensorflow/tensorflow:latest-gpu-jupyter \ > bash
________ _______________ ___ __/__________________________________ ____/__ /________ __ __ / _ _ \_ __ \_ ___/ __ \_ ___/_ /_ __ /_ __ \_ | /| / / _ / / __/ / / /(__ )/ /_/ / / _ __/ _ / / /_/ /_ |/ |/ / /_/ \___//_/ /_//____/ \____//_/ /_/ /_/ \____/____/|__/ WARNING: You are running this container as root, which can cause new files in mounted volumes to be created as the root user on your host machine. To avoid this, run the container by specifying your user's userid: $ docker run -u $(id -u):$(id -g) args...
root@123456789abc:/tf# cd /home/me/myproject root@123456789abc:/myproject# ls # たしかにホスト側のmyprojectの中身がコンテナの/home/me/myproject以下に置かれている README.md data docs models myenv notebooks papers src
これでホスト側のファイルをコンテナ内でも利用する準備ができそうです!
1-2. コンテナ内でホスト側のファイルを読み書き
コンテナ内でi_am_in_the_container.txt
という空のテキストファイルを作成してみます.
root@123456789abc:/myproject# touch i_am_in_the_container.txt root@123456789abc:/myproject# ls README.md data docs i_am_in_the_container.txt models myenv notebooks papers src
この状態でコンテナを抜けてホストに戻ると, i_am_in_the_container.txt
が残っています.
たしかにホスト側のディレクトリをコンテナ内から操作できていたことがわかります.
root@123456789abc:/myproject# exit exit me@server myproject$ ls README.md data docs i_am_in_the_container.txt models myenv notebooks papers src
docker inspect
で現在マウントされているディレクトリを確認できます.
me@server myproject$ sudo docker inspect toy_container ... (略) "Mounts": [ { "Type": "bind", "Source": "/home/me", "Destination": "/home/me", "Mode": "", "RW": true, "Propagation": "rprivate" } ], ... (略)
コンテナは一旦削除しておきます.
me@server myproject$ sudo docker rm toy_container
toy_container
1-3. 注意点
基本的に, ディレクトリのマウントはコンテナの作成と同時に行わなければならないようです.
一旦作成されたコンテナに対して後からディレクトリを新規にマウントすることはできないと考えた方が良さそうです.
2. root以外のユーザーとして使う
2-0. rootでコンテナを作成するとどうなるか
これでホスト側のファイルをコンテナ内から読み書きできるようになりました.
そういえば, さっきからコンテナ起動時に
WARNING: You are running this container as root, which can cause new files in mounted volumes to be created as the root user on your host machine.
というメッセージが出ているのは何なんでしょうね.
ファイルの権限を確かめてみましょう.
me@server myproject$ ls -al ... (中略) ... -rw-r--r--. 1 root root 0 4月 1 12:34 i_am_using_docker.txt
どうやら, 先ほどのi_am_using_docker.txt
はrootとして作成したことになっており, 一般ユーザーに編集権限がありません.
すると, Dockerコンテナ内で作成されたファイルはコンテナ外からは読み取り専用でしか開けなくなってしまいます.
これでは困りますね.
2-1. docker run -u
でユーザーを指定する
docker run -u ユーザー名:ユーザーグループ
によってコンテナを作成&起動すると, コンテナ内でもrootではなく指定したユーザーとして振舞うことができます.
なお, コンテナ内にはユーザー情報は格納されていないので, ホスト側の /etc/group
と /etc/passwd
をマウントすることも忘れないようにしましょう.
(/etc/group
と /etc/passwd
のマウントを忘れると, コンテナは未知のユーザー名を指定されたと思ってエラーを吐きます)
# -v foo:bar:ro のようにマウントしたディレクトリはコンテナ内では読み取り専用になる me@server myproject$ sudo docker run -it --name tf_contrainer \ > -v /home/me:/home/me \ > -v /etc/group:/etc/group:ro \ > -v /etc/passwd:/etc/passwd:ro \ > -u $(id -u $USER):$(id -g $USER) \ > tensorflow/tensorflow:latest-gpu-jupyter \ > bash
すると, 今までとは違い, ホスト側と同じユーザーでコンテナを作成&起動することができています.
________ _______________ ___ __/__________________________________ ____/__ /________ __ __ / _ _ \_ __ \_ ___/ __ \_ ___/_ /_ __ /_ __ \_ | /| / / _ / / __/ / / /(__ )/ /_/ / / _ __/ _ / / /_/ /_ |/ |/ / /_/ \___//_/ /_//____/ \____//_/ /_/ /_/ \____/____/|__/ You are running this container as user with ID 1234 and group 1234, which should map to the ID and group for your user on the Docker host. Great!
2-2. 一般ユーザーとしてホスト側のファイルを読み書き
この状態で, コンテナ内でi_am_in_the_container_as_nonroot.txt
という空のテキストファイルを作成してみます.
tf-docker /tf > cd /home/me/myproject tf-docker /myproject > touch i_am_in_the_container_as_non_root.txt tf-docker /myproject > ls README.md i_am_in_the_container.txt myenv data i_am_in_the_container_as_non_root.txt notebooks docs models src
コンテナを抜けると, i_am_in_the_container_as_nonroot.txt
は読み取り専用になってはいますが, オーナーは自分自身なので実質的にホスト側でも自由に編集可能です.
tf-docker /myproject > exit exit me@server myproject$ ls -al ... (中略) ... -rw-r--r--. 1 root root 0 4月 1 12:34 i_am_using_docker.txt -rw-r--r--. 1 me me 0 4月 1 12:45 i_am_in_the_container_as_non_root.txt
3. おわりに
Dockerコンテナからホスト側のファイルを読み書きできるようになりました.
これでDocker hubに上がっているDocker imageを自分の研究用プロジェクトに利用することができそうです.
参考にした記事:
https://qiita.com/yohm/items/047b2e68d008ebb0f001
https://qiita.com/Yarimizu14/items/52f4859027165a805630