注目の記事

公式チュートリアルで始めるDocker

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

そろそろコンテナやってみる

社内ではDockerを使った開発やインフラ構築が盛んですが、私はあまり触っていなかったので、今回公式チュートリアルを使って体験してみようと思います。

Dockerってなんですか?という方は、是非過去の記事をご覧になってください。

Developers.IO - タグ - Docker

Docker Toolbox

まずはセットアップということですが、Docker Toolboxというバイナリが用意されています。これをダウンロードしてインストールすれば直ぐに使えます。

screenshot 2016-05-01 2.34.25

私がインストールしたのは、バージョン1.11.1でした。

screenshot 2016-05-01 2.21.46

コンソールインタフェースとグラフィカルインタフェースが用意されています。

screenshot 2016-05-01 2.21.30

Docker Quickstart Terminal

クイックスタート用のアイコンをクリックすれば準備は整います。

bash --login '/Applications/Docker/Docker Quickstart Terminal.app/Contents/Resources/Scripts/start.sh'
Macintosh-2:~ satoshi$ bash --login '/Applications/Docker/Docker Quickstart Terminal.app/Contents/Resources/Scripts/start.sh'


                        ##         .
                  ## ## ##        ==
               ## ## ## ## ##    ===
           /"""""""""""""""""\___/ ===
      ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ /  ===- ~~~
           \______ o           __/
             \    \         __/
              \____\_______/


docker is configured to use the default machine with IP 192.168.99.100
For help getting started, check out the docs at https://docs.docker.com

試しにDockerと入力するとオプションが出てきます

$ docker
Usage: docker [OPTIONS] COMMAND [arg...]
       docker [ --help | -v | --version ]

A self-sufficient runtime for containers.

Options:

  --config=~/.docker                                       Location of client config files
  -D, --debug                                              Enable debug mode
  -H, --host=[]                                            Daemon socket(s) to connect to
  -h, --help                                               Print usage
  -l, --log-level=info                                     Set the logging level
  --tls                                                    Use TLS; implied by --tlsverify
  --tlscacert=~/.docker/machine/machines/default/ca.pem    Trust certs signed only by this CA
  --tlscert=~/.docker/machine/machines/default/cert.pem    Path to TLS certificate file
  --tlskey=~/.docker/machine/machines/default/key.pem      Path to TLS key file
  --tlsverify=true                                         Use TLS and verify the remote
  -v, --version                                            Print version information and quit

Commands:
    attach    Attach to a running container
    build     Build an image from a Dockerfile
    commit    Create a new image from a container's changes
    cp        Copy files/folders between a container and the local filesystem
    create    Create a new container
    diff      Inspect changes on a container's filesystem
    events    Get real time events from the server
    exec      Run a command in a running container
    export    Export a container's filesystem as a tar archive
    history   Show the history of an image
    images    List images
    import    Import the contents from a tarball to create a filesystem image
    info      Display system-wide information
    inspect   Return low-level information on a container or image
    kill      Kill a running container
    load      Load an image from a tar archive or STDIN
    login     Log in to a Docker registry
    logout    Log out from a Docker registry
    logs      Fetch the logs of a container
    network   Manage Docker networks
    pause     Pause all processes within a container
    port      List port mappings or a specific mapping for the CONTAINER
    ps        List containers
    pull      Pull an image or a repository from a registry
    push      Push an image or a repository to a registry
    rename    Rename a container
    restart   Restart a container
    rm        Remove one or more containers
    rmi       Remove one or more images
    run       Run a command in a new container
    save      Save one or more images to a tar archive
    search    Search the Docker Hub for images
    start     Start one or more stopped containers
    stats     Display a live stream of container(s) resource usage statistics
    stop      Stop a running container
    tag       Tag an image into a repository
    top       Display the running processes of a container
    unpause   Unpause all processes within a container
    update    Update configuration of one or more containers
    version   Show the Docker version information
    volume    Manage Docker volumes
    wait      Block until a container stops, then print its exit code

Run 'docker COMMAND --help' for more information on a command.

公式チュートリアル動画を見る

さて、Dockerの起動確認までできましたので、公式チュートリアル動画を見始めましょう。以下のサイトから確認することができます。

Tutorials - Docker Fundamentals

さて、ここからかなり端折った説明で進めていきたいと思います。

Imageレイヤー

Dockerは、カーネルの上に多階層のImageレイヤーがあり、一番下にベースとなるImageがあります。これは概ね、DebianとかUbuntuなどのOSに相当する部分です。そして、この上に、ミドルウェアの層が重なります。たとえば、emacsやApacheなどです。それぞれのレイヤーは、下位のレイヤーを参照しています。下位のレイヤーは読み取り専用です。また、最上位のレイヤーは、書き込みできるようになっていて、下位のレイヤーに機能を付け足して独自のImageになりえます。この書き込む操作がCommitです。

screenshot 2016-05-01 2.46.19

Commitをする際のコマンドは、以下のようになっています。

$ docker commit [options] [containar ID] [repository:tag]
例)
$ docker commit 1234567890 satoshi7/myapp:1.0

OSを起動してみる

試しにUtuntuを起動してみます。

$ docker run -it ubuntu:14.04 bash
root@09d4d84350d2:/#

あっさり起動しましたw。試しにcurlコマンドを打ってみます。しかし、そんなコマンドは無いと言われます。DockerのImageは最小構成のミドルウェアしか入っていません。必要なものを自分で追加する必要があります。

root@09d4d84350d2:/# curl 127.0.0.1
bash: curl: command not found

ミドルウェアを追加して新たなImageとする

curlコマンドを追加インストールして、新たなレイヤーとしてImageをコミットしたいと思います。

root@09d4d84350d2:/# apt-get install -y curl
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package curl

エラーになりました。これは、apt-getのパッケージ取得を全くおこなっていないためです。updateコマンドを実行して必要なパッケージを取り込んでからインストールします。ちゃんと動きましたね。

root@09d4d84350d2:/# apt-get -qq update
root@09d4d84350d2:/# apt-get install -y curl
....
root@09d4d84350d2:/# curl 127.0.0.1
curl: (7) Failed to connect to 127.0.0.1 port 80: Connection refused

無事に新しいミドルウェアが入りましたのでコミットしたいと思います。psコマンドで利用しているコンテナのIDが出てきます。

root@09d4d84350d2:/# exit
exit
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                        PORTS               NAMES
09d4d84350d2        ubuntu:14.04        "bash"              10 minutes ago      Exited (0) 36 seconds ago                         determined_snyder

先ほどセットアップしたImageのコンテナIDを指定してコミットして新しいImageを作成します。

$ docker commit 09d4d84350d2 satoshi7/curl:1.0
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
satoshi7/curl       1.0                 951c6ef7cae3        32 seconds ago      221.1 MB

Imageを指定して起動

新しいImageができましたので、このIDを指定して起動してみましょう。起動直後からcurlを使えるはずです。

$ docker run -it satoshi7/curl:1.0 bash
root@d8980b8a2220:/# curl 127.0.0.1
curl: (7) Failed to connect to 127.0.0.1 port 80: Connection refused

Dockerfileとは

Dockerの起動方法やコミットの方法が分かりました。次にDockerfileというものをご紹介します。これは、Dockerイメージ作成時のコンフィグファイルです。継続的インテグレーションや開発プロセスの役に立つはずです。

FROMでベースImageを指定します。RUNで自動実行するスクリプトを指定します。

screenshot 2016-05-01 3.26.38

このスクリプトは、Buildコマンドを実行時にパスを指定します。これでログインすることなく、新しいImagew作成できますね。

screenshot 2016-05-01 3.29.52

実際にやってみましょう。

$ mkdir DockerTest
$ cd DockerTest/
$ vi Dockerfile
FROM ubuntu:14.04
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y vim

作成したDockerfileを指定してBuildしてみます。

$ docker build -t satoshi7/testimage:1.0 .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM ubuntu:14.04
 ---> 8fa7f61732d6
Step 2 : RUN apt-get update
 ---> Running in 65c379dfb7e9

......

Successfully built b7726e1f74a0
$ docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
satoshi7/testimage   1.0                 b7726e1f74a0        2 minutes ago       264.3 MB

ちなみに、RUNコマンドは、複数行ではなく、1行にまとめて書くことで多段階にImageを作成することなく1回で作成できるので処理が早くなります。

コマンド実行

Dockerfile内でCMDキーワードを使うことでdocker runした際に、任意のコマンドを実行できます。

screenshot 2016-05-01 3.47.29

Dockerfileに書いてみましょう

FROM ubuntu:14.04
RUN apt-get update && apt-get install -y curl vim
CMD ping 127.0.0.1 -c 30

そしてbuildを実行します。

$ docker build -t satoshi7/testimage:1.1 .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM ubuntu:14.04
 ---> 8fa7f61732d6
Step 2 : RUN apt-get update && apt-get install -y curl vim
 ---> Using cache
 ---> f4e8c45becff
Step 3 : CMD ping 127.0.0.1 -c 30
 ---> Using cache
 ---> 3548ff10a927
Successfully built 3548ff10a927

ちなみに、Dockerfileの記述で過去に同じ指示をしている場合、Imageがキャッシュ化されていますので、Buildは高速に終わります。

docker runでコマンドが実行されるか確認してみましょう。

$ docker run -t satoshi7/testimage:1.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.035 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.043 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.036 ms

もし、起動時に他のコマンドを実行させたければ、引数の最後に指定することもできます。

$ docker run -t satoshi7/testimage:1.1 echo "hello world"
hello world

エントリーポイントの指定

Dockerを起動時にあらかじめ指定したコマンドを実行したいことがあります。この場合は、エントリーポイントを用います。以下の様にDockerfileを書きます。実行時には引数を指定することができます。

$ vi Dockerfile
FROM ubuntu:14.04
RUN apt-get update && apt-get install -y curl vim
ENTRYPOINT ["ping"]
$ docker build -t satoshi7/testimage:1.2 .
$ docker run -t satoshi7/testimage:1.2 127.0.0.1 -c 5
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.040 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.100 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.041 ms

コンテナの開始と停止

現在起動中のコンテナ一覧を表示したり、開始や停止を行うことができます。

$ docker ps -a
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS                      PORTS               NAMES
0605016b02e9        satoshi7/testimage:1.2   "ping 127.0.0.1 -c 5"    4 minutes ago       Exited (0) 4 minutes ago                        high_almeida
c5d63603a451        ef3af9c54122             "/bin/sh -c ping 127."   4 minutes ago       Exited (2) 4 minutes ago                        small_cori

$ docker stop 0605016b02e9
0605016b02e9

$ docker start 0605016b02e9
0605016b02e9

$ docker ps -a
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS                      PORTS               NAMES
0605016b02e9        satoshi7/testimage:1.2   "ping 127.0.0.1 -c 5"    6 minutes ago       Up 2 seconds                                    high_almeida
c5d63603a451        ef3af9c54122             "/bin/sh -c ping 127."   6 minutes ago       Exited (2) 6 minutes ago                        small_cori

ターミナルアクセス

ターミナルとは、コンテナのメインプロセスです。ターミナルにアクセスする方法としてEXECコマンドがあります。試しにTomcatを起動したコンテナにアクセスしてみます。

$ docker run -d tomcat:7
98779177af02013830c3b6e3a1266d07da80bb953910e66fcafa5d297a0e1f1d
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
98779177af02        tomcat:7            "catalina.sh run"   15 seconds ago      Up 14 seconds       8080/tcp            admiring_leakey

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
98779177af02        tomcat:7            "catalina.sh run"   5 minutes ago       Up 5 minutes        8080/tcp            admiring_leakey

$ docker exec -it 98779177af02 bash
root@98779177af02:/usr/local/tomcat# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  1 16:39 ?        00:00:04 /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/loggin
root        44     0  0 16:45 ?        00:00:00 bash
root        48    44  0 16:45 ?        00:00:00 ps -ef

root@98779177af02:/usr/local/tomcat# exit
exit
$

コンテナの削除

rmコマンドで削除できます。

$ docker rm 98779177af02
Error response from daemon: You cannot remove a running container 98779177af02013830c3b6e3a1266d07da80bb953910e66fcafa5d297a0e1f1d. Stop the container before attempting removal or use -f

$ docker rm -f 98779177af02
98779177af02

または

$ docker stop 98779177af02
$ docker rm 98779177af02

イメージの削除

イメージを削除するときは、rmiコマンドを用います。コンテナが起動中の場合には削除できませんので、停止して削除してから実行しましょう。

$ docker rmi ef3af9c54122
Error response from daemon: conflict: unable to delete ef3af9c54122 (must be forced) - image is being used by stopped container 1215cab46320

$ docker rmi 0c19b849e34f
Untagged: satoshi7/testimage:1.2
Deleted: sha256:0c19b849e34f7711501cfacd34dd63dcb523cb78ffb4068da1ba61dc92ebfd18

Docker Hubレポジトリ

ローカルで作成したイメージをみんなで共有することができます。Docker Hubのアカウントを作成済みであれば、アップロード可能です。pushコマンドを用います。

screenshot 2016-05-02 2.00.03

ボリューム

ボリュームは、コンテナのライフサイクルとは独立した、永続データを保管するディレクトリーです。コンテナ間で共有することが可能です。ボリュームの設定は、Dockerfile内で指定することも可能です。コンテナが削除されると永続化されます。

screenshot 2016-05-02 2.05.47

実際に、コンテナのライフサイクルと独立しているか確認してみましょう。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              14.04               8fa7f61732d6        5 days ago          188 MB

$ docker run -d -P -v /www/website1 nginx:1.7

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                           NAMES
4d93a2b27199        nginx:1.7           "nginx -g 'daemon off"   51 seconds ago      Up 51 seconds       0.0.0.0:32769->80/tcp, 0.0.0.0:32768->443/tcp   elated_brattain

ボリュームを指定したコンテナの起動を確認したらターミナルに入ります。次に、作成したボリューム内にテキストファイルを作成します。

$ docker exec -it 4d93a2b27199 bash
root@4d93a2b27199:/# ls
bin  boot  dev	etc  home  lib	lib64  media  mnt  opt	proc  root  run  sbin  selinux	srv  sys  tmp  usr  var  www
root@4d93a2b27199:/# cd www/website1/
root@4d93a2b27199:/www/website1# echo "hello" >> test
root@4d93a2b27199:/www/website1# cat test
hello
root@4d93a2b27199:/www/website1# exit
exit

コンテナから抜けて、停止をし、イメージを作成します。

$ docker stop 4d93a2b27199
4d93a2b27199
$ docker commit 4d93a2b27199 satoshi7/myimage:1.0
sha256:433097fcc4551e745669d4c51adcea3d4f1de90f4bcb7387d8922112b9135dcb

作成したイメージからコンテナを起動します。この際に、ボリュームの指定はしていません。

$ docker run -it satoshi7/myimage:1.0 bash
root@5a6c2cd607b0:/# ls
bin  boot  dev	etc  home  lib	lib64  media  mnt  opt	proc  root  run  sbin  selinux	srv  sys  tmp  usr  var  www
root@5a6c2cd607b0:/# cd www/website1/
root@5a6c2cd607b0:/www/website1# ls
root@5a6c2cd607b0:/www/website1#

ボリュームを指定しなかったので、先ほど作成したテキストファイルは見当たりませんでした。

ポートのマッピング

コンテナ内で起動しているプログラムのポートを割り当てることができます。nginx80から8080に割り当ててみます。

$ docker run -d -p 8080:80 nginx
b579e0249c538c5a619cebe522917a7b67dfec88ef2caa145ba73e5a11edf811
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                           NAMES
b579e0249c53        nginx               "nginx -g 'daemon off"   15 seconds ago      Up 15 seconds       443/tcp, 0.0.0.0:8080->80/tcp   gloomy_engelbart

$ curl http://192.168.99.100:8080/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
.....

ちなみに、-Pオプションをつけると自動的にポートを割り当てます。また、Dockerfile内でEXPOSEを指定してポート番号を指定することもできます。指定されたポートは、コンテナ外に知らせることができます。コンテナ間通信で活用されたりします。

コンテナ間のリンク

コンテナはリンクすることで相互に通信を行うことができます。リンクを設定する際には、ソースのコンテナから起動する必要があります。

screenshot 2016-05-02 2.50.23

$ docker run -d --name dbms postgres

$ docker run -it --name website --link dbms:db ubuntu:14.04 bash

root@0d79e00e45ca:/# cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.2	db 46140c452eba dbms
172.17.0.3	0d79e00e45ca
root@0d79e00e45ca:/# exit
exit

データベースのIPアドレスがHostsファイルに登録されていることを確認できました。

まとめ

Docker公式サイトのチュートリアル通りにコマンドを実行するだけで、簡単にDockerの使い方を把握することができました。Dockerという言葉だけ知っているレベルから、使ったことあるレベルまで到達することができました。さて、次のステップでは、具体的にどのようにDockerを使いこなすことで、継続的なインテグレーションなどインフラやミドルウェアの構築やメンテナンスに役立つのでしょうか。今は未だ正直まだフワっとしています。AnsibleとかCloudFormationとかとの使い分けやポジションなどもモヤモヤしています。ということで、ゴールデン・ウィーク明けに社内で議論を深めたいと思います。

参考資料

Docker Toolbox - Tutorials - Introduction to Docker