2014/05/25

Google Cloud Platformでdockerに入門する

dockerが何かよく分かってないのでとりあえず使ってみて「コレはなにか?」「何ができるのか?」を実践しながら理解する。

STEP1: Google Compute Engine(GCE)のセットアップ
Google Cloud ConsoleでCloud Projectを作ってCompute EngineをEnableにする。Billingを設定していないとCompute Engineは使えないので注意。
Cloud Projectの設定は
・PROJECT NAME: Docker Test
・PROJECT ID: docker-project
とする。PROJECT IDはデフォルトで設定されている値を使ってもよい。

STEP2: Google Cloud SDKをインストール
% curl https://dl.google.com/dl/cloudsdk/release/install_google_cloud_sdk.bash | bash
% gcloud auth login

ブラウザが開くのでGoogle Compute EngineをセットアップしたGoogleアカウントの認証を行う。
ログインが完了すると。
You are logged in as adamrocker@gmail.com
などとコンソールに表示される。

STEP3: GCEにインスタンスを追加する
ブラウザからGoogle Cloud Console経由でGCEにインスタンスを追加することもできる。GUIがあるので簡単だけど、今後の自動化を考慮してコンソールからCUIでインスタンスを作る。
利用できるインスタンスイメージを知る
% gcutil listimages --project=docker-project

Debianのインスタンスを作る場合、以下のコマンドを実行。
% gcutil addinstance docker-test --image=backports-debian-7-wheezy-v20140415 --project=docker-project

docker-testはインスタン名を意味するので好きな名前を設定してよい。
imageは利用できるインスタンスイメージを指定する。Debian以外にもCentOS,RedHat,SUSEなどが選べる。

CUI内でインスタンスを作るゾーンを選ばされるので、とりえあずネットワーク的に近いasiaにしておく。
Select a zone:
1: asia-east1-a
2: asia-east1-b
3: europe-west1-a  (maintenance starts in 68 days)
4: europe-west1-b
5: us-central1-a
6: us-central1-b
>>> 1
次はマシンタイプを選ばされるので一番安い(しょぼい)n1-standard-1を試す。
Select a machine type:
1: n1-standard-1 1 vCPU, 3.75 GB RAM
2: n1-standard-16 16 vCPUs, 60 GB RAM
3: n1-standard-2 2 vCPUs, 7.5 GB RAM
4: n1-standard-4 4 vCPUs, 15 GB RAM
5: n1-standard-8 8 vCPUs, 30 GB RAM
6: n1-highcpu-16 16 vCPUs, 14.4 GB RAM
7: n1-highcpu-2 2 vCPUs, 1.8 GB RAM
8: n1-highcpu-4 4 vCPUs, 3.6 GB RAM
9: n1-highcpu-8 8 vCPUs, 7.2 GB RAM
10: n1-highmem-16 16 vCPUs, 104 GB RAM
11: n1-highmem-2 2 vCPUs, 13 GB RAM
12: n1-highmem-4 4 vCPUs, 26 GB RAM
13: n1-highmem-8 8 vCPUs, 52 GB RAM
14: f1-micro 1 vCPU (shared physical core) and 0.6 GB RAM
15: g1-small 1 vCPU (shared physical core) and 1.7 GB RAM
>>> 1
十数秒だけ待つと完了する。
確認のため、ブラウザでCloud Consoleを見ると、確かにインスタンスが作られていた。

STEP4: GCE上にdockerをインストールして実行する
まずはSSHでGCEにログイン
% gcutil --project=docker-project ssh docker-test
adam@docker-test:~$

dockerをインストール
adam@docker-test:~$ curl get.docker.io | bash
このコマンドだけで、gitをインストールしたり、dockerのリポジトリとかを設定したり、そこからdockerのイメージをインストールしたり、、、とりえあずdockerを実行するのに必要なツール全部をインストールしてくれる。便利だが何をしているのか謎…。
とりあえずdockerのインストールが完了したので、実行してみる。
adam@docker-test:~$ sudo docker run busybox echo 'docker on GCE!!'
docker on GCE!!
なんか実行できた。
これでdockerコンテナを起動して、その上でechoコマンドを実行。
全コマンドが終了したのでdockerコンテナが終了した。
起動中のdockerコンテナを一覧するコマンドを叩いてみる。
$ sudo docker ps
CONTAINER ID    IMAGE    COMMAND    CREATED    STATUS    PORTS    NAMES

何もリストされていない。dockerコンテナが終了した事が確認できた。
docker runはコンテナプロセスの起動コマンド。
busyboxは起動するコンテナイメージ。
echo 'docker on GCE!!'はbusybox上で実行するコマンド。

試しに別のコマンドを実行してみる。
adam@docker-test:~$ sudo docker run -i -t busybox:latest
# cd /tmp
# echo 'Hello, docker!' > test
# cat test
Hello, docker!
# exit
-iオプションはインタラクションモード。dockerコンテナ内で作業ができる。終わったらexitでホストOSに抜け出す。
-tオプションはタグの指定。イメージ(busybox)のブランチを指定して起動している。
コンテナイメージの/tmpの下にtestというファイルを作ったが、ホストOS上では
adam@docker-test:~$ cat /tmp/test
cat: /tmp/test: No such file or directory
となり、ファイルが読み込めない。
これはコンテナ毎にファイルシステムが独立して管理されているから。
AUFS(Another Union File System)というらしい。
read-onlyでファイルシステム(busybox:latest)を読み込む。
read-onlyで読み込んだファイルシステムに更新が生じたら、
writeできるファイルシステムに当該ファイルをcopyしてwrite。
いわゆるcopy-on-write。
コンテナから見えるファイルシステムは、ベース(read-only)のファイルシステムとwriteできるファイルシステムを透過的に重ね合わせられている。

つまり、/tmp/testファイルはread-onlyのファイルシステムではなくwritableなファイルシステムから読み込んでいるのに対して、それ以外のファイル、例えば/bin/bashなどはread-onlyのファイルシステムから読み込んでいる。

CD(DVD)ブートしたOSと似たようなイメージ。
writableなファイルシステムをメモリ(RAM)上に構築して、OSとして普通に使えるようにしていて、CD(DVD)を取り出したら当然、writeしたファイルも全部消えちゃう。

STEP5: コンテナイメージを作る
コンテナ上でファイルを作ってもコンテナを終了するとファイルもなく(みえなく)なってしまうのでは、dockerを起動するたびにファイルをイチから作らなければならないので面倒だ。
ということで、ファイルを作成したコンテナの状態を新たなコンテナイメージにすれば良い。
言い換えるとbusybox:latestというイメージを起動し、/tmp/testというファイルを作り、それを新たなコンテナイメージ(例えばbusybox2)にする。testというファイルを利用したければbusybox2というコンテナイメージを起動すれば良い。

早速やってみる。
adam@docker-test:~$ sudo docker ps -a
CONTAINER ID        IMAGE                       COMMAND                CREATED             STATUS                         PORTS               NAMES
bfbdf28957c2        busybox:buildroot-2014.02   /bin/sh                4 minutes ago        Exited (127) 2 minutes ago                         prickly_ptolemy   
44449bb3a8e7        busybox:buildroot-2014.02   echo 'docker on GCE!   About an hour ago   Exited (0) About an hour ago                       prickly_tesla       
09ff9045e8e6        busybox:buildroot-2014.02   echo 'Docker has bee   About an hour ago   Exited (0) About an hour ago                       naughty_torvalds   
実は、いままでdockerコンテナを起動しread-write系のコマンドを実行していたものは全て別コンテナとして存在している。
つまりbusyboxイメージのブランチイメージとして存在する。docker runコマンドを打つたびにあらたなコンテナをドンドン作っていたことになる。
ということなので、testファイルを作ったコンテナ(ID: bfbdf28957c2)をコンテナイメージとして登録してみる。
adam@docker-test:~$ sudo docker commit bfbdf28957c2 busybox:busybox2
利用できるコンテナイメージの一覧を見る。
adam@docker-test:~$ sudo docker images
REPOSITORY          TAG                   IMAGE ID            CREATED             VIRTUAL SIZE
busybox             busybox2              1772b0d9129c        8 seconds ago       2.433 MB
busybox             latest                4c0f792ebd1e        29 hours ago        2.433 MB
早速、busybox2を起動してみる。
adam@docker-test:~$ sudo docker run -i -t busybox:busybox2
# cat /tmp/test
Hello, world!
ちゃんと/tmp/testファイルが残っていた。
コレができるようになると、コンテナイメージをどんどん作れる。試しに作ってみて、上手くいかなかったら消す。上手くいったところまでをcommitしてセーブしておく。システム構築がgitでソース管理するかのように気軽にできるようになる。

ちなみにコンテナを削除するには
$ sudo docker rm <CONTAINER ID>
まとめて削除するには
$ sudo docker rm `sudo docker ps -a -q`

STEP5: dockerをOS起動時から使えるようにしておく
おまけとして、dockerデーモンを起動スクリプトに追加しておき、OS起動時からdockerが使えるようにしておく。
$ sudo update-rc.d docker defaults


参考:
docker.io - Google Cloud Platform
Dockerを支える技術
GoogleのDockerレポジトリ