最速Docker研究会(DockerのTipsを20個上げていくぜ編)

にゃんぱす〜

最近Dockerにどっぷりなんですが、Dockerについて色々地雷Tipsがあるのでそれをベストプラクティス風にまとめてみました。
Dockerコマンドが動いたけど、これからプロジェクトのDockerfileを書くようにしてみたいんだけど。。。みたいな人にオススメ。

インストール編

1. MacでDockerのインストールで詰まった

なんかよくわからないエラーが出てインストール出来ないんだけど><
versionを確認して最新の環境にしましょう。とくにxCodeVirtualBoxvagrantのバージョンは最新のものでないとダメです。

$ brew -v
Homebrew 0.9.5

$ VirtualBox --help
Oracle VM VirtualBox Manager 4.3.6
(C) 2005-2013 Oracle Corporation
All rights reserved.

$ vagrant -v
Vagrant 1.4.3

$ docker version
Client version: 0.7.6
Go version (client): go1.2
Git commit (client): bc3b2ec
Server version: 0.7.6
Git commit (server): bc3b2ec
Go version (server): go1.2

Dockerで環境構築編

2. docker -t -i + docker commitはなるべく使わない

使うとしたら、バグっぽい動作しているDockerfileのentrypointを削除してdocker -t -i /bin/bashで入るとき。Dockerfileを作りましょう

3. docker build時には必ずタグを付ける。

タグ名は/。例えば、mainyaaのredisならmainyaa/redis。この時のはDocker indexにアップロードするときのユーザー名になる。

$ docker build -t mainyaa/redis .
4. fswatchで監視してビルドする(Mac only)

Dockerfileを編集してbuildしてのサイクルは自動化しましょう

$ brew install fswatch
$ fswatch . "docker build -t <yourname>/<tag> ."
5. dvmを使う

vagrant上で動かすのはなるべく軽いゲストOSを選ぶ(boot2dockerかcoreosがオススメ)。
vagrant sshなしでMac上からvagrantのdockerコマンドを叩けるdvmを入れる。dvmはvagrantの薄いラッパー&管理ツール。dvmはboot2dockerをゲストOSに使う。CoreOSより軽い。
Dockerはとにかくディスクを圧迫するので、常に軽くすることを意識する。
本体のVagrantfileは~/.dvm/にある。clangビルドしてるとメモリ足りないよーとかで、Dockerのメモリを増やしたいときなどは~/.dvm/dvm.confで設定できる
インストール:

$ brew install dvm

dvmの起動とenv設定:

$ dvm up
$ eval "$(dvm env)"
$ echo << 'EOF' >> ~/.bashrc
if [ -f dvm ]; then
  eval "$(dvm env)"
fi
EOF
source ~/.bashrc
6. GCEやAWS上のdockerを叩くときにsudoが聞かれてうざいとき。
$ sudo gpasswd -a <username> docker
$ sudo service docker restart
$ exit

シェルを初期化するために一旦ログアウトしてください。

Dockerfile編
さて、ここからが本編です!
個人的にはここが一番重要だと思ってます。ハマりどころがたくさんあるので、ここを参考に

7. Dockerfileのapt-get updateやyum updateの前にはミラーサーバーを書く
run echo "deb http://us.archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
8. 一つ前のコンテナIDを取得するalias
$ cat << 'EOF' >> ~/.bashrc
alias dl='docker ps -l -q'
EOF

使い方(ログを見たり):

$ docker logs`dl`
9. ディスクがいっぱいになってきたんだけど

/var/lib/dokcerを別のディスクに割り当てるといいかもしれません。

10. Dockerfileの各所で要らないものを削除する

Dockerはファイルサイズとの戦いです。少しでも削りましょう。

run apt-get update && apt-get upgrade -y # こうではなく
run apt-get update && apt-get upgrade -y && apt-get clean && rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/* #こう書きましょう
run apt-get install -y openssh-server # こうではなく
run apt-get install -y openssh-server --no-install-recommends # --no-install-recommendsオプションを付ける
11. ローカルの1週間以上前のコンテナを削除

ローカルのコンテナはどんどん消しても問題ありません。
Dockerfileさえあればいつでも元に戻せます

$ docker ps -a | grep 'weeks ago' | awk '{print $1}' | xargs docker rm
12. ローカルの1週間以上前のコンテナを削除はよく使うのでaliasも設定しておこう
$ cat << 'EOF' >> ~/.bashrc
alias dkwrm="docker ps -a | grep "weeks ago" | awk '{print $1}' | xargs docker rm"
EOF
13. docker run時に WARNING: IPv4 forwarding is disabled. って出るんだけど

IPv4 forwardingの設定をしましょう

$ sysctl -w net.ipv4.ip_forward=1
$ echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf
14. apt-get updateで変なエラーが出るんだけど!(debian/ubuntu)
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
    LANGUAGE = (unset),
    LC_ALL = (unset),
    LC_CTYPE = "UTF-8",
    LANG = "en_US"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory

対策:Dockerfileに以下の行を足しましょう。

run locale-gen en_US.UTF-8
run update-locale LANG=en_US.UTF-8
env LC_ALL C
env LC_ALL en_US.UTF-8

補足:これはMacのiTermがlocaleのenvを自動送信しているのが原因です。
Preferences > Profiles > Terminalの “Set locale environment variables on startup” のチェックを外せばうまくいくらしいですが、試してないです。
これのおかげで特に設定しなくてもツールやmanが日本語になっていたりします。

15. apt-getするとpromptのところで止まってしまう

Dockerfileに、

env DEBIAN_FRONTEND noninteractive

を設定しましょう。

まとめ

さて、以上の地雷を回避したDockerfileはこんなかんじになると思います
(後述するDockerfileをTDDするためにはopenssh-serverも必要かもしれません。

from ubuntu:12.04
maintainer KazuyukiMori <mainya@gmail.com>

# set locale
run locale-gen en_US.UTF-8
run update-locale LANG=en_US.UTF-8
env DEBIAN_FRONTEND noninteractive
env LC_ALL C
env LC_ALL en_US.UTF-8

run echo "deb http://us.archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
run apt-get update 
run apt-get install -y redis-server --no-install-recommends
run apt-get upgrade -y && apt-get clean && rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/* 

expose 6379
entrypoint ["/usr/bin/redis-server"]
15. Advanced Tips: DockerfileをCIで回す

serverspec
configspec ならDockerfileまではけていいですが出来たてなので、とりあえず、開発が活発そうなserverspecで。configspecはserverspecの冪等性を捨てただけのものです。

僕もまだちゃんとした環境を作れてないので、以下のブログを参考にしてください。
serverspecとdocker-apiでDockerfileをTDD
これの何が嬉しいかというと、Dockerは差分ビルドなので、ビルドがあっという間に終わり、書いてて楽しいということです。

Dockerfileの中身はただのshellscriptなので、スクラッチから環境構築をいつでもやり直せるという安心感があります。
普段あなたが叩いているビルドコマンドやデプロイコマンドをDockerfileに書くだけです。Chef/puppetが使いたい人は別に使っても良いのです。
AWSが嫌になったらGoogle Compute EngineでもDegial OcealでもRackspaceでも、どこでもほぼ確実にプロダクション環境が用意できる

なお、Dockerのproduction環境で動かすのは推奨されていません。気をつけてね☆

あれ?数えてみたら15個しかなかった。まあいいか。

参考にしたリンク

via: The Docker Guidebook
via: Dockerfile Best Practice
via: serverspecとdocker-apiでDockerfileをTDD
via: 以前開催したGCE + Dockerハンズオンの発表資料
https://docs.google.com/presentation/d/1EgNM6DTtctEwFlUl_7iBbRRr36LIo14FnCaQQBzt-Cc/pub?start=false&loop=false&delayms=3000