環境は以下。
Host OS | Docker version |
---|---|
Ubuntu 16.04 | 1.12.3 |
Dockerは、imageやその他データをデフォルトでは /var/lib/docker に格納する。 ただし、ディスク容量の関係で別の場所に変更したいことがある。その方法をまとめる。
基本的には簡単なことで、docker daemonの起動オプションに
-g /path/to/directory
を与えるだけである。
ただdockerをsystemd経由で起動してる場合は(大半はそうであると思うが)、設定ファイルに書く必要がある。 設定ファイルはデフォルトで lib/systemd/system/docker.service にあるが、 基本は /etc/systemd/system/docker.service.d に別途設定ファイルを置いて反映させる。
# /etc/systemd/system/docker.service.d/options.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// -g /path/to/directory
設定ファイルの反映
sudo systemctl daemon-reload
sudo systemctl restart docker
ホストのディレクトリをマウントしたコンテナ内で、そのマウントした場所にホストのuid/gidでファイルを作成したいことがある。 そうすることで、開発コードと実行環境を分ける事ができる。
以下では ruby image を用いた簡単な例を示す。
SinatraやRailsのプロジェクトを作成する際にGemfileを用意すると思うが、これをコンテナで生成してみる。
mkdir hello_project && cd hello_project
docker run --rm -w /workdir -v $(pwd):/workdir ruby bundle init
するとホストの /path/to/hello_project に以下のファイルが出来ている。
$ ls -l
合計 4
-rw-r--r-- 1 root root 75 11月 3 16:31 Gemfile
このGemfileはuid/gidがrootのになっているので、ホストで編集する際にはroot権限で扱う必要があり面倒である。
user namespaceの機能を使うと、ホストのuid/gidをコンテナのuid/gidにマップすることが出来る。 この機能を使うことで、生成されたGemfileの所有者をホストのuserにすることが出来る。
ホストuserのuid/gidを確認する。
$ id
uid=1000(ubuntu) gid=1000(ubuntu) ...
/etc/subuid と /etc/subgid を編集する。
# /etc/subuid
ubuntu:1000:65536
# /etc/subgid
ubuntu:1000:65536
docker daemonの起動オプションを設定する。
# /etc/systemd/system/docker.service.d/options.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// --userns-remap=ubuntu
設定ファイルの反映
sudo systemctl daemon-reload
sudo systemctl restart docker
以上の状態で先程と同じようにGemfileを生成すると、ファイルの所有者がホストuserになっている。
本来user namespaceは、ホストに存在しないuid/gidをコンテナのuid/gidにマップすることでセキュリティレベルを上げるのに利用される。 なので上記の手法は、開発環境でのみ利用すること。
Dockerはインストール時に、docker0という名前の仮想ブリッジを作成する。
$ ip a
...
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:ce:78:31:14 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:ceff:fe78:3114/64 scope link
valid_lft forever preferred_lft forever
...
ホストとコンテナはこの仮想ブリッジを通してパケットの送受信が可能なので、 コンテナの起動時にdocker0のipを渡すことで、ホストで起動中の何らかのサーバにアクセスできる。
host_ip=`ip a list docker0 | grep "inet " | awk '{print $2}' | cut -d/ -f1`
docker run -e some_endpoint=$host_ip some_image
コンテナでone-offコマンドを実行するためのaliasを設定する。
.bashrc のサンプル
# ~/.bashrc
ruby_cmds=("ruby" "irb" "bundle")
node_cmds=("node" "npm")
declare -A imageCmdsMap
imageCmdsMap=( \
["ruby:2.3-slim"]=${ruby_cmds[@]} \
["node:6.4.0-slim"]=${node_cmds[@]} \
)
local_images=(`docker images | awk 'NR > 1 {print $1 ":" $2}'`)
for image in ${!imageCmdsMap[@]}; do
if [[ " ${local_images[*]} " == *" $image "* ]]; then
cmds=${imageCmdsMap[$image][@]}
for cmd in ${cmds[@]}; do
alias $cmd="docker run -it --rm -w /app -v \$(pwd):/app $image $cmd"
done
unset cmd
fi
unset cmds
done
unset image
上記を .bashrc に設定しておくとホストからコンテナのコマンドを以下のように利用できる。
$ pry
$ bundle install
$ npm install
ただ、カレントディレクトリ以下にないファイルはコマンドに渡せない、ポートの設定などが出来ない等の問題があるので 汎用的には使えない。