Dockerをチョットだけ操作できるようになるチュートリアル

May 8, 2015   #docker 

もはや無視できない存在になってきたDocker、操作できますか? 本記事は、仮想化技術はある程度知ってるけどDockerは使ったことが無い…という方を対象に、チュートリアル形式で基本操作をまとめたものです。

Dockerって何?

Docker(ドッカー)とは、Docker社が開発しているオープンソースのコンテナ型仮想化ソフトのことです。

Docker - Build, Ship, and Run Any App, Anywhere

みなさんご存知の通り、Dockerが誕生する前から多くの仮想化用の製品がありました。 VMWare、Xen、Hyper-Vなどなど、様々なものがあります。 これらの製品は、アプリケーションレベルで仮想化する方式(例:VMWare Player)や、ハイパーバイザによる仮想化(例:VMWare ESXi)が主流です。

しかし、Dockerは従来の製品とは根本的に異なる仕組みで仮想化を行います。

Dockerは仮想マシンやハイパーバイザを使わずに、単一のホストOSを複数の実行環境に分離して仮想化しています。 ユーザの視点では従来の仮想化と同様に、ホストOSの上で複数のゲストOSが動いているように見えますが、Kernel視点ではグループ化されたプロセス(コンテナ)が動いているように見えます。

コンテナはそれぞれ分離されているため、複数のコンテナが動いていてもお互いが見えません。 また、コンテナ毎にCPUやメモリなどのリソース制限をかけることができます。

Dockerの良いところ・悪いところ

  • 良いところ
    • コンテナはホストOSのKernelを使うためオーバヘッドが小さくて高速。
    • Kernelを共有しているのでメモリやディスク消費量等の必要リソースを抑えられる。
    • リソースが少なくて済むので、多くのコンテナを立ち上げることが可能。
    • Kernelを立ちあげなくて良いのでコンテナが起動が高速。
  • 悪いところ
    • 難しいです。

インストール

EC2上でDockerを動かしてみます。 試したAMIはAmazon Linux AMI 2015.03 (HVM)です。

この記事で使用するdockerのバージョンは1.5.0です。 docker versionコマンドで確認できます。

sudo yum install docker
sudo service docker start
sudo docker version
Client version: 1.5.0
Client API version: 1.17
Go version (client): go1.3.3
Git commit (client): a8a31ef/1.5.0
OS/Arch (client): linux/amd64
Server version: 1.5.0
Server API version: 1.17
Go version (server): go1.3.3
Git commit (server): a8a31ef/1.5.0

ひとまず Hello World

Dockerを使うために、Docker Hubから基本イメージをダウンロードします。

Docker Hubとは、ユーザが作成したイメージをアップロードして公開・共有できるサービスです。 公開されているイメージは自由にダウンロードして自分のサーバで使うことができます(無料です)。

では、公式が提供しているUbuntuの基本イメージを自分のサーバにダウンロードしてみます。 Docker Hub上に存在するイメージを検索するには、docker searchコマンドを使います。

sudo docker search ubuntu
NAME                           DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
ubuntu                         Official Ubuntu base image                      1641      [OK]
ansible/ubuntu14.04-ansible    Ubuntu 14.04 LTS with ansible                   50                   [OK]
ubuntu-upstart                 Upstart is an event-based replacement for ...   25        [OK]
torusware/speedus-ubuntu       Always updated official Ubuntu docker imag...   24                   [OK]
tutum/ubuntu                   Ubuntu image with SSH access. For the root...   22                   [OK]
-- 省略 --

結果の一番上にオフィシャルのイメージが出てきました。 Docker Hubからイメージをダウンロードするには、docker pullコマンドを使います。

sudo docker pull ubuntu
Pulling repository ubuntu
07f8e8c5e660: Download complete
e9e06b06e14c: Download complete
a82efea989f9: Download complete
37bea4ee0c81: Download complete
Status: Downloaded newer image for ubuntu:latest

ダウンロードしたイメージを起動して、Hello Worldと表示してみます。 イメージをコンテナ(プロセス)として動かすには、docker runコマンドを使います。 また、docker runの引数として、コンテナで実行させたいコマンドを渡します。

sudo docker run ubuntu /bin/echo Hello World
Hello World

Hello Worldが表示されましたね。 イメージをひな形として、実際に処理を行うコンテナを起動することができました。

稼働中のコンテナを表示するdocker psコマンドを実行してみましょう。

sudo docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

さきほど実行したHello Worldのコンテナが表示されません。

実は、コンテナはフォアグラウンドの処理が完了すると自動的に停止状態になります。 今回の場合はechoが終わってやることがなくなってしまったので停止したわけです。 ただし、停止と言ってもコンテナ自体が消えるわけではなくファイルとしては存在しているので、いつでも再実行できます。

停止状態のコンテナも含めて表示したい場合は、-aオプションを付けます。

sudo docker ps -a
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                      PORTS               NAMES
7eb446457cc5        ubuntu:14.04        "/bin/echo Hello Wor   21 seconds ago      Exited (0) 20 seconds ago                       stupefied_hoover

先ほど実行したコンテナが表示されました。 使ったイメージ、渡したコマンド、コンテナを作った時刻等が確認できます。

また、もう一度docker runをした上でdocker ps -aを実行してみます。

sudo docker run ubuntu /bin/echo Hello World
Hello World

sudo docker ps -a
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                      PORTS               NAMES
ec040f573d5f        ubuntu:14.04        "/bin/echo Hello Wor   3 seconds ago       Exited (0) 1 seconds ago                        sad_carson
7eb446457cc5        ubuntu:14.04        "/bin/echo Hello Wor   51 seconds ago      Exited (0) 50 seconds ago                       stupefied_hoover

1行増えてますね。 イメージをベースとして、docker runする度に同じ構成のコンテナを複数作成できます。

コンテナにApacheをインストールしてみる

先ほど使用した標準イメージをベースにApacheをインストールし、Webアクセスをしてみます。

標準イメージを対象にdocker runしますが、今回は下記のオプションを使用します。

  • -i, -t
    • /bin/bashでコンテナを操作する際に両方指定。インタラクティブモードで動作する。
  • -p
    • [ホストのポート番号]:[コンテナのポート番号]と指定してポートフォワードさせる。

では、実際にやってみましょう。 ホストの8080番ポートを、コンテナの80番ポートにフォワードします。

sudo docker run -it -p 8080:80 ubuntu /bin/bash

コンテナのシェルが表示されたと思いますので、下記2つのコマンドを投入します。

apt-get install -y apache2
apache2ctl start
/usr/sbin/apache2ctl: 87: ulimit: error setting limit (Operation not permitted)
Setting ulimit failed. See README.Debian for more information.
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.4. Set the 'ServerName' directive globally to suppress this message

ブラウザで、EC2インスタンスのグローバルIP:8080にアクセスしてみましょう。 デフォルトページが表示されるはずです(セキュリティグループで許可するの忘れずに)。

コンテナをデタッチしてホスト側に戻るには、Ctrl + pの後にCtrl + qを押します。

コンテナをコミットする

標準イメージから作成したコンテナにApacheを入れることができました。 では、Apacheが入ったコンテナが複数必要になった場合はどうすれば良いでしょうか。

Hello Worldの時に複数のコンテナを作ったようにdocker runでコンテナを量産すれば?と思った方、半分正解、半分ハズレです。

docker runでひな形に指定できるのはイメージです。コンテナをベースにはできません。 なので、コンテナをイメージ化するdocker commitを実行する必要があります。

イメージとコンテナの関係は下記の通りです。
イメージをベースにdocker runでコンテナ(プロセス)を生成し、コンテナの構成変更の保存(イメージ化)をdocker commitで行います。 コミットすれば、コミットされた状態を元にコンテナを生成することができます。

まずはコミット対象のコンテナIDを確認します。

sudo docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES
926556f6eed8        ubuntu:14.04        "/bin/bash"         4 minutes ago       Up 4 minutes        0.0.0.0:8080->80/tcp   berserk_lumiere

私の環境だと926556f6eed8でした。

IDが確認できたら、docker commit <container-id> <username>/<imagename>でコミットします。 <username>/<imagename>のところは任意の文字でOKです。

sudo docker commit 926556f6eed8 tanksuzuki/apache-ubuntu
a7bf2bb126461a95ab19ea371d6a71776168067d765d54c56280ef2d6b98be09

コミットしたイメージをもとに、別のコンテナを立ち上げてそれぞれにWebアクセスしてみましょう。 今回は-dオプションでバックグラウンドでコンテナを起動します。 また、コンテナにApacheをフォアグラウンドで動かす命令を渡し、コンテナが停止しないようにしておきます。

sudo docker run -d -p 8081:80 tanksuzuki/apache-ubuntu apache2ctl -DFOREGROUND

ブラウザで、EC2インスタンスのグローバルIP:8081にアクセスしてみましょう。

コンテナの変更内容を管理する

先ほど作ったApache入りのイメージと同じものをDockerfileで作ってみましょう。

Dockerfileとは、どのベースイメージに何の変更を加えるかを書いたファイルで、docker buildコマンドでイメージ化することができます。

そのため、Dockerfileを使えば、何をするコンテナなのかは一目瞭然になります。 手でコンテナの構成変更をするとブラックボックスになりがちなので、基本的にDockerfileを使いましょう。

Dockerfileは、1行につき命令と引数の組み合わせで書いていきます。 また、#から始まる行はコメント行として扱われます。

代表的な命令を紹介します。

命令 意味
FROM ベースとするイメージを指定します。
MAINTAINER 作成者の情報を記載します。
RUN コマンドを実行します。
ADD ファイルやディレクトリを追加します。
CMD コンテナとして実行される時のコマンドを指定。似ているものにENTRYPOINTがありますが、細かい話になってしまうので今回は割愛します。

実際に書いたDockerfileが以下のものです。 ファイル名はDockerfileとしてください。

FROM ubuntu
MAINTAINER TankSuzuki
RUN apt-get install -y apache2
CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

ほぼシェルスクリプトなので、割ととっつきやすいかと思います。 見ての通りubuntuをベースにApacheを入れてHTMLを追加しています。 また、CMDでコンテナとして起動するときにApacheを立ち上げるようにしています。

それではイメージを作ってみます。 docker build -t <username>/<imagename> <Dockerfileのディレクトリ>を実行します。 最後に.があるのでご注意ください。

sudo docker build -t tanksuzuki/apache-ubuntu2 .
-- 省略 --
Successfully built cbccc06825e0

次に、作成したイメージをdocker runします。

docker run -d -p 8082:80 tanksuzuki/apache-ubuntu2

ブラウザで、EC2インスタンスのグローバルIP:8082にアクセスしてみましょう。 おなじみの画面が表示されるはずです。

コンテナの終了と後片付け

アタッチした状態でCtrl + Dを押すか、ホスト側のdocker stop <container-id>で停止できます。 これまで動かしてきたコンテナを止めてみましょう。

ちなみにコンテナはdocker start <container-id>で起動できます。

コンテナを削除する

不要になったコンテナは、ディスクを圧迫する可能性があるので必要に応じて削除します。 docker ps-asオプションを付けると、コンテナの容量を確認できます。

sudo docker ps -as
CONTAINER ID        IMAGE                              COMMAND                CREATED             STATUS                        PORTS               NAMES               SIZE
7c35e3ec93c2        tanksuzuki/apache-ubuntu2:latest   "/usr/sbin/apache2ct   3 minutes ago       Exited (137) 42 seconds ago                       determined_mayer    666 B
abeb9ab63bdc        tanksuzuki/apache-ubuntu:latest    "apache2ctl -DFOREGR   7 minutes ago       Exited (137) 24 seconds ago                       boring_bohr         2.238 kB
926556f6eed8        ubuntu:14.04                       "/bin/bash"            57 minutes ago      Exited (1) 16 seconds ago                         berserk_lumiere     14.5 MB
ec040f573d5f        ubuntu:14.04                       "/bin/echo Hello Wor   58 minutes ago      Exited (0) 58 minutes ago                         sad_carson          0 B
7eb446457cc5        ubuntu:14.04                       "/bin/echo Hello Wor   59 minutes ago      Exited (0) 59 minutes ago                         stupefied_hoover    0 B

たったこれだけと思われたかもしれませんが、今回のケースではApacheを入れただけですので肥大化していません。

コンテナを削除するには、docker rm <container-id>を使います。 実際に削除してみましょう。

sudo docker rm 7c35e3ec93c2
7c35e3ec93c2

イメージを削除する

コンテナと同じく、イメージも状況に応じて消します。 まずはdocker imagesコマンドでイメージの一覧を見てみましょう。

sudo docker images
REPOSITORY                  TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
tanksuzuki/apache-ubuntu2   latest              cbccc06825e0        8 minutes ago       202.7 MB
tanksuzuki/apache-ubuntu    latest              a7bf2bb12646        54 minutes ago      202.7 MB
ubuntu                      trusty-20150427     07f8e8c5e660        2 days ago          188.3 MB
ubuntu                      14.04               07f8e8c5e660        2 days ago          188.3 MB
ubuntu                      14.04.2             07f8e8c5e660        2 days ago          188.3 MB
ubuntu                      latest              07f8e8c5e660        2 days ago          188.3 MB
ubuntu                      trusty              07f8e8c5e660        2 days ago          188.3 MB

イメージを消すには、docker rmi <image-id>を使います。

sudo docker rmi cbccc06825e0
Untagged: tanksuzuki/apache-ubuntu2:latest
Deleted: cbccc06825e043344b6b2554e86ea1f1974fcad603577c817db94ba5c66c833e
Deleted: 338409b52c656e4c47d8aabbe27776981bab5b562b7983979473e623d2fa5d17
Deleted: 81b91bf2e0921b556623f3b21329b561910705271c783c20d9aefa1c56c7d71e

イメージが削除できましたね。

まとめ

今回はコマンドで基本操作をしてみましたが、コンテナをGUIで管理できるツールも色々あります。 また、複数のコンテナを立てて連携させる場合は、コンテナ間のネットワークについても知っておく必要があります。

そのあたりについても、別途まとめます。