Less is Best

rubyが好き。技術の話とスタートアップに興味があります。

Dockerでnginxサーバー立ててみた。あとDockerの使い方とか。

Dockerすごい面白そうです。 最近ハッカソンに行ったりして、プロダクション環境へのデプロイ周りですごいはまった。特にお金もない自分は1つのサーバーの中にいろいろとアプリケーションをデプロイしちゃっている訳ですが、もうごちゃごちゃになって触りたくなくなりそう...。新しくサーバーをデプロイしたいけども、既存のサービスまで影響が及ぶ危険性もあり、めんどくさいなー。あと、あとできっと破棄するだろうけど、もとに戻すこともかなりめんどくさいし、そんなことやりたくないしなー。もっとアプリケーション毎に気軽に(そしてお安く)デプロイ出来ればいいのになー。

と思っていた訳ですが、最近Dockerというものを目にしまして。

主にここらへんのお話を見て(こういうハッカソンおもしろそうすぎる。参加してみたい)これ使えば問題解決できるんじゃね!?と思った訳です。っという訳で触ってみることにしました。

使い方まとめて、Nginx動かすDockerfileを作ってみました。

ソースはこっちにあげておきます。

そもそもDockerとは?

公式ページ Docker is an open-source project to easily create lightweight, portable, self-sufficient containers from any application.

カンタンに言うとLinuxのなかでLinuxを動かすやつ。(通常のVMよりもめっちゃ軽い・ポータビリティ◯) ポータブルな環境構築ができるようになるアプリケーション。

インストール方法 on Mac

これだけ、かんたん!

git clone https://github.com/dotcloud/docker.git
cd docker
vagrant up --provider virtualbox

使い方

cd docker
vagrant ssh
docker

Usage: docker [OPTIONS] COMMAND [arg...]
 -H=[unix:///var/run/docker.sock]: tcp://host:port to bind/connect to or unix://path/to/socket to use

A self-sufficient runtime for linux containers.

Commands:
    attach    Attach to a running container
    build     Build a container from a Dockerfile
    commit    Create a new image from a container's changes
    cp        Copy files/folders from the containers filesystem to the host path
    diff      Inspect changes on a container's filesystem
    events    Get real time events from the server

単発コマンドの実行方法

とりあえず、Dockerを動かして見る。起動するコンテナには、使い慣れているCentOSを選択しておく。

docker run centos /bin/echo "hello world"

でリモートリポジトリからbaseイメージをpullしてきてコンテナを起動、/bin/echo "hello world"をその中で実行する。その後、コンテナを終了する。

コンテナの中に入って操作する

docker run -i -t centos /bin/bash

-i -tについては以下の設定のよう

-t=false: Allocate a pseudo-tty -i=false: Keep stdin open even if not attached

コンテナから出るときには

exit

バックグラウンドでコンテナを起動する

vagrant@precise64:~/docker$ docker run -i -t -d centos /bin/ping -i 5 google.com
13554990c22fd701490a3e29a52cee602e11d56cd2c9bc81d3890393cb45f7ec

vagrant@precise64:~/docker$ docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
13554990c22f        centos:6.4          /bin/ping -i 5 googl   8 seconds ago       Up 8 seconds                            mad_lovelace 

-dオプションについては以下のよう -d=false: Detached mode: Run container in the background, print new container id

コンテナの中の状態を覗いて見る。

docker logs <ID>

vagrant@precise64:~/docker$ docker logs 1355
PING google.com (173.194.126.134) 56(84) bytes of data.
64 bytes from 173.194.126.134: icmp_seq=1 ttl=61 time=21.1 ms
64 bytes from 173.194.126.134: icmp_seq=2 ttl=61 time=19.9 ms
64 bytes from 173.194.126.134: icmp_seq=3 ttl=61 time=22.1 ms
64 bytes from 173.194.126.134: icmp_seq=4 ttl=61 time=22.0 ms
64 bytes from 173.194.126.134: icmp_seq=5 ttl=61 time=23.2 ms
64 bytes from 173.194.126.134: icmp_seq=6 ttl=61 time=21.1 ms
64 bytes from 173.194.126.134: icmp_seq=7 ttl=61 time=23.7 ms
64 bytes from 173.194.126.134: icmp_seq=8 ttl=61 time=22.6 ms
64 bytes from 173.194.126.134: icmp_seq=9 ttl=61 time=22.1 ms
64 bytes from 173.194.126.134: icmp_seq=10 ttl=61 time=22.4 ms
64 bytes from 173.194.126.134: icmp_seq=11 ttl=61 time=20.2 ms
64 bytes from 173.194.126.134: icmp_seq=12 ttl=61 time=25.8 ms

実行中のコンテナ一覧を取得する

docker ps

vagrant@precise64:~/docker$ docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
b16cf59771cb        centos:6.4          /bin/ping -i 5 googl   4 seconds ago       Up 3 seconds                            trusting_torvalds   

コンテナにアタッチしてみる

vagrant@precise64:~/docker$ docker attach 1355
64 bytes from 173.194.126.134: icmp_seq=57 ttl=61 time=24.1 ms
64 bytes from 173.194.126.134: icmp_seq=58 ttl=61 time=24.1 ms
64 bytes from 173.194.126.134: icmp_seq=59 ttl=61 time=23.5 ms
*
*

コンテナをデタッチする

アタッチ中の端末は Ctrl-p Ctrl-q でデタッチできる。(このとき use of closed network connection っていうエラーが出る場合 Ctrl-c で抜けるしかないっぽい。バグレポートは上がっているので、じきに直ると思う。)

なるほど、そんなバグも発生する可能性があるみたいですね。

生成したコンテナのプロセスを消す

vagrant@precise64:~/docker$ docker kill 1355
1355

コンテナ一覧を表示する。

docker ps -a -notrunc

実行されたコンテナは全て残っているようです -aコマンドを付けることで、実行完了したコンテナを表示。 -notrunc で詳細情報まで表示。

vagrant@precise64:~/docker$  docker ps -a -notrunc
CONTAINER ID                                                       IMAGE               COMMAND                     CREATED             STATUS              PORTS               NAMES
13554990c22fd701490a3e29a52cee602e11d56cd2c9bc81d3890393cb45f7ec   centos:6.4          /bin/ping -i 5 google.com   7 minutes ago       Exit 137                                mad_lovelace            
2ef126977876e9816525b4875a52267f23d9ec58604e849ddbe77c76ab3f4290   centos:6.4          /bin/bash                   9 minutes ago       Exit 0                                  ecstatic_pike           
801aaf7f07a27cc2d8cc43a44025691a435d7810b7c4224abe81e57492ee10ad   centos:6.4          /bin/bash                   13 minutes ago      Exit 0                                  compassionate_pasteur   
4816df705e27ffda96f42578600f996393b8c1633a8b7b714bf38e58263f7562   centos:6.4          bash                        22 minutes ago      Exit 127                                insane_babbage          
7eb03f1209869722cf384df3f0ee3a2ccae37e5f5e279a11bcc58796231b1288   centos:6.4          biash                       22 minutes ago      Exit 127  

コンテナの実体は/var/lib/docker/containers/以下にID名で保存されているようです。

コンテナを消去する

docker rm <ID>

vagrant@precise64:~/docker$ docker rm 1355
1355

コンテナをイメージとして保存する

docker commit <ID> <USERNAME/CONTAINER_NAME>

作業領域として今まで使用していたコンテナをイメージとして保存する。あとから使い回せるようになる。ユーザー名/名称 が一般的なようです。

vagrant@precise64:~/docker$ docker commit b16 yss44/ping
2cea6b12c43f1ad1f57f47ef0cc9fde6341a87b0fb7afac4f5b2fa95ec593c40

イメージ一覧を取得する

docker images

vagrant@precise64:~/docker$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
yss44/ping          latest              2cea6b12c43f        8 seconds ago       300.6 MB
centos              6.4                 539c0211cd76        8 months ago        300.6 MB
centos              latest              539c0211cd76        8 months ago        300.6 MB

イメージは複数の名称をタグ付けできるようになっており、base:latest, base:ubuntu-12.10 といった形で異なるイメージを呼び出せるようになっている。省略時は base:latest と同じ。 なるほど

イメージをレポジトリから検索する

docker search

vagrant@precise64:~/docker$ docker search base
NAME                                     DESCRIPTION                                     STARS     OFFICIAL   TRUSTED
base/devel                               Archlinux 2013.10.01 adds base-devel to ba...   3                    
base/arch                                Archlinux 2013.10.01 Minimal arch installa...   8                    
base                                     DEPRECATED (use "ubuntu"): Another general...   2                    
modolo/base                              Base para outros projetos                       0                    
zumbrunnen/base                          Base image with supervisord                     0                    [OK]

pull してくるイメージは https://index.docker.io/ から情報を持ってくる。コマンドラインで検索したい場合は search コマンドを利用する。

ローカルのイメージを削除する

docker rmi <IMAGEID>

vagrant@precise64:~/docker$ docker rmi 2ce
Untagged: 2cea6b12c43f1ad1f57f47ef0cc9fde6341a87b0fb7afac4f5b2fa95ec593c40
Deleted: 2cea6b12c43f1ad1f57f47ef0cc9fde6341a87b0fb7afac4f5b2fa95ec593c40

イメージの詳細情報を取得する

docker inspect <IMAGEID>

vagrant@precise64:~/docker$ docker inspect 539
[{
    "id": "539c0211cd76cdeaedbecf9f023ef774612e331137ce7ebe4ae1b61088e7edbe",
    "comment": "Imported from -",
    "created": "2013-04-01T01:20:58.331937915-07:00",
    "container_config": {
        "Hostname": "",
        "Domainname": "",
        "User": "",

ネットワーク

公式サイトのドキュメントを見て設定してみた。

docker run -p <PORT>

# Bind port 4444 of this container, and tell netcat to listen on it
JOB=$(sudo docker run -d -p 4444 ubuntu:12.10 /bin/nc -l 4444)

# Which public port is NATed to my container?
PORT=$(sudo docker port $JOB 4444 | awk -F: '{ print $2 }')

# Connect to the public port
echo hello world | nc 127.0.0.1 $PORT

# Verify that the network connection worked
echo "Daemon received: $(sudo docker logs $JOB)"

Dockerfile使う方法

Dockerfileからコンテナをビルドする

コマンドラインから指定してコンテナを生成するだけでなく、設定ファイルからイメージの作成も可能

cd docker
vim Dockerfile
FROM centos
RUN /bin/echo hi
docker build .

を行うことで、docker run centos /bin/echo hiと同じことが出来る

vagrant@precise64:~/docker$ docker build .
Uploading context 10.24 kB
Step 1 : FROM centos
 ---> 539c0211cd76
Step 2 : RUN /bin/echo hi
 ---> Running in ee829ee9a714
hi
 ---> f910e14e1f39
Successfully built f910e14e1f39

使用出来るコマンド

FROM ベースとなるイメージを指定 MAINTAINER メンテナの名前を指定 RUN ビルド中に実行したいコマンドを指定 CMD 起動後のコンテナで実行したいコマンドを指定 EXPOSE [ ...] 外部に晒すポートの指定 ENV 環境変数の設定 INSERT deprecated なので ADD を利用すること ADD ファイルを配置

RUNとCMDとの違い

FROM centos
RUN /bin/echo run | tee /tmp/run.log
CMD /bin/echo cmd | tee /tmp/cmd.log

ビルドの実行

vagrant@precise64:~/docker$ docker build .
Uploading context 10.24 kB
Step 1 : FROM centos
 ---> 539c0211cd76
Step 2 : RUN /bin/echo run | tee /tmp/run.log
 ---> Running in a90496e48805
run
 ---> e67b0f5a30b4
Step 3 : CMD /bin/echo cmd | tee /tmp/cmd.log
 ---> Running in 2fa46bcdf5f9
 ---> bbc2b6efbb20
Successfully built bbc2b6efbb20

RUN,CMDの実行結果の確認

vagrant@precise64:~/docker$ docker run bbc /bin/ls /tmp
run.log

=> cmdがまだ実行されていない

vagrant@precise64:~/docker$ docker run bbc             
cmd

=> cmdが実行される

  • CMDはコンテナの実行時に実行される
  • RUNはコンテナのビルド時に実行される

生成されたコンテナの詳細

vagrant@precise64:~/docker$ docker inspect bbc
[{
    "id": "bbc2b6efbb20237d3cef264932d9eecd1ea9ee56ba32c61139a212c497b7629e",
    "parent": "e67b0f5a30b4698e8b72971c7005f7bf8977e6fc0b3d70463d10a34402f78d95",
    "created": "2013-12-26T23:27:46.019628733Z",
    "container": "2fa46bcdf5f99e2d6c4af4c4c07bdba3ad0e48cadf06e3a391dcd32c6635c52d",
    "container_config": {
        "Hostname": "a90496e48805",
        "Domainname": "",
        "User": "",
        "Memory": 0,
        "MemorySwap": 0,
        "CpuShares": 0,
        "AttachStdin": false,
        "AttachStdout": false,
        "AttachStderr": false,
        "PortSpecs": null,
        "ExposedPorts": {},
        "Tty": false,
        "OpenStdin": false,
        "StdinOnce": false,
        "Env": [
            "HOME=/",
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
        ],
        "Cmd": [
            "/bin/sh",
            "-c",
            "#(nop) CMD [/bin/sh -c /bin/echo cmd | tee /tmp/cmd.log]"
        ],
        "Dns": null,
        "Image": "e67b0f5a30b4698e8b72971c7005f7bf8977e6fc0b3d70463d10a34402f78d95",
        "Volumes": {},
        "VolumesFrom": "",
        "WorkingDir": "",
        "Entrypoint": null,
        "NetworkDisabled": false
    },
    "docker_version": "0.7.2",
    "config": {
        "Hostname": "a90496e48805",
        "Domainname": "",
        "User": "",
        "Memory": 0,
        "MemorySwap": 0,
        "CpuShares": 0,
        "AttachStdin": false,
        "AttachStdout": false,
        "AttachStderr": false,
        "PortSpecs": null,
        "ExposedPorts": {},
        "Tty": false,
        "OpenStdin": false,
        "StdinOnce": false,
        "Env": [
            "HOME=/",
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
        ],
        "Cmd": [
            "/bin/sh",
            "-c",
            "/bin/echo cmd | tee /tmp/cmd.log"
        ],
        "Dns": null,
        "Image": "e67b0f5a30b4698e8b72971c7005f7bf8977e6fc0b3d70463d10a34402f78d95",
        "Volumes": {},
        "VolumesFrom": "",
        "WorkingDir": "",
        "Entrypoint": null,
        "NetworkDisabled": false
    },
    "architecture": "x86_64",
    "Size": 0
}]

Memcached入りコンテナを作って見る

FROM ubuntu

RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
RUN apt-get install -y memcached
docker build .
docker run -t -i 3b8 /bin/bash
memcached 
> can't run as root without the -u switch

ホストからコンテナのMemcachedにアクセスする

ソースは公式から

# Memcached
#
# VERSION       42

# use the ubuntu base image provided by dotCloud
FROM ubuntu

MAINTAINER Victor Coisne victor.coisne@dotcloud.com

# make sure the package repository is up to date
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update

# install memcached
RUN apt-get install -y memcached

# Launch memcached when launching the container
ENTRYPOINT ["memcached"]

# run memcached as the daemon user
USER daemon

# expose memc

実際にコンテナをビルドして起動して見る

vagrant@precise64:~/docker$ docker build .
vagrant@precise64:~/docker$ docker run -d -p 11211 4fd
c976600f5345be6e26041aeaaaa763767e8c5011bec6c0539fc879b83bd2be56

起動されたコンテナの状態を確認

vagrant@precise64:~/docker$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                      NAMES
c976600f5345        4fd2c196ce20        memcached           55 seconds ago      Up 54 seconds       0.0.0.0:49160->11211/tcp   sleepy_shockley 

vagrant@precise64:~/docker$ docker port c97 11211
0.0.0.0:49160

どうやら、localhost:49160にポートフォワーディングされているようなので、localhost:49160にアクセスする

Memcachedにアクセスしてみる

import memcache

ip = 'localhost'
port = 49160

mc = memcache.Client(["{0}:{1}".format(ip, port)], debug=0)
mc.set("MDM", "Guillaume J. C.")
value = mc.get("MDM")

print value
vagrant@precise64:~/docker$ python test.py 
Guillaume J. C.

-- ホスト側でのポートを指定して起動も出来るみたい

vagrant@precise64:~/docker$ docker run -d -p 11211:11211 4fd
c976600f5345be6e26041aeaaaa763767e8c5011bec6c0539fc879b83bd2be56

これでホスト側からは11211でアクセスできる

DockerでNginxサーバー

Dockerfile

# Memcached
#
# VERSION       42

# use the ubuntu base image provided by dotCloud
FROM centos

MAINTAINER yoshiso

RUN yum -y update

# make sure the package repository is up to date
ADD nginx.repo /etc/yum.repos.d/nginx.repo
RUN chmod 0644 /etc/yum.repos.d/nginx.repo

# install memcached
RUN yum install -y nginx

ADD nginx.conf /etc/nginx/nginx.conf
Add default.conf /etc/nginx/conf.d/default.conf

# Nginx public directory

ADD src /var/www

# expose memcached port
EXPOSE 80

CMD ["service","nginx","start"]

Dockerfileはこんなかんじ。 詳細の設定ファイルはここを参照

コンテナをビルドして見る

docker build -t yoshiso/nginx .

これで、コンテナのビルド完了。 最後に作成したNginxコンテナを起動する

docker run -d -p 80:80 .

ホストから確認のためにリクエストを送ってみる。

curl http://localhost:80
> Hello, Nginx!

無事起動していることを確認しました。