オブジェクトの広場はオージス総研グループのエンジニアによる技術発表サイトです

コンテナ・マイクロサービス

さわって理解するDocker入門

第1回 Dockerのイメージ・コンテナ管理の仕組み
オージス総研
大西 洋平
2016年9月14日

Dockerは、シンプルながらも実用的な機能をもち、軽量という特徴を持つ仮想環境として、アプリケーションのデプロイにおいて急速に利用が広がっています。筆者も最近は主に開発環境の1つとして積極的に利用しており、アプリケーションのデプロイを簡単にしてくれる便利さを痛感しています。本連載では、Dockerに興味はありつつも、まだ触ったことのない方向けに、実際に触ってDockerについて理解していただくための記事を提供します。第1回の本記事では、Dockerの概要および最も基本であるイメージとコンテナの管理について実際の操作方法をステップごとに紹介します。

Dockerとは

Dockerとは、Linuxのコンテナ技術をベースにDocker社が開発した仮想化技術です。ここではDocker自体の概要について簡単に説明します。詳細な説明についてはDocker公式ドキュメントを参照してください。

Dockerの特徴

(1) 軽量

第1の特徴は、イメージ(注1)のダウンロードや起動が非常に軽量なことです。

(注1)イメージとは、後述のコンテナを作成するためのファイルシステムや設定をまとめたもの。

VirtualBoxなど従来のハイパーバイザ型の仮想マシン(下図左)は、ホストOS上にハイパーバイザと呼ばれるソフトウェアによって、仮想マシンを作り出し、その上でゲストOSを稼働させる方式です。ホストOSとゲストOSを分離できるメリットがありますが、ゲストOSと仮想マシンの分、イメージサイズが大きくなり、オーバヘッドが増えた分、動作も遅くなります。

一方、Dockerが採用しているコンテナ(注2)(下図右)では、各アプリケーションは、Linuxのコンテナ技術によりホストOSのカーネルは共有しつつも、各コンテナ内のアプリケーションは分離された名前空間の中で実行されます。図中のDocker Engineは、仮想マシンやカーネルのエミュレーションも行わないため、イメージサイズも小さく、ベアメタルに近いレベルで軽量に動作します。

(注2)コンテナとは、Dockerイメージを起動し、その内部でアプリケーションが稼動している状態。

ハイパーバイザ型との違い

また、複数のイメージでデータを共通化することでデータサイズを小さくする工夫も行っています。具体的には、コンテナ自身は複数のレイヤーで構成され、コンテナ上の操作(パッケージのインストールであったり、ファイルの作成など)は、各レイヤー上で行われます。この階層化の仕組みにより、イメージを取得したり、読み込む場合、レイヤーの差分だけ処理すれば良くなります。よって、扱うイメージのデータ量が少なくなるため、動作が軽量になります。

例えば、下図中のAppBとAppCのコンテナは、図右側のように三層で構成されています。AppBとAppCは第2層目(Layer2)まで共通の操作でコンテナが作成されているため、第2層まで共通化されています。よって、先にAppBのイメージを取得している場合、AppCのイメージを取得する際には差分の第3層目(Layer3)だけ取得すればよくなります。これは新たに取得するイメージのデータ量や、Docker Engineが読み込むデータ量の低減につながります。

イメージの階層化

(上記図は、「Digital Ocean - The Docker Ecosystem: An Introduction to Common Components」より引用)

(2) 充実したエコシステム:様々な環境にデプロイできる

Dockerとは、元々は、Docker社が開発した仮想化技術ですが、現在は、マイクロソフトやインテル、レッドハット、Google、AWSなど多くのベンダが発足した「Open Container Initiative」によって業界統一仕様として整理されています。多くのPaaSがサポートしたことにより、標準的なアプリケーション配布の方法として定着しつつあります。

主要なOSとしてLinux、Windows、Mac、主要なPaaSであるAWSGoogle CloudAzureがDockerをサポートしています(注3)。一度、アプリケーションをDockerコンテナのイメージとして作成すれば、そのまま様々なプラットフォーム上で実行できる環境が整備されてきました。これにより、アプリケーション配布手段としてDockerイメージを活用する動きが活発になってきました。プラットフォームごとの環境構築の手間を省くことができ、アプリケーション開発そのものに注力できます。

(注3)Windows、Macの場合はホストOS上にハイパーバイザ型の仮想マシンを立ち上げ、そのゲストOS上にDocker Engineを動かすという構成になります。Linux以外の場合は、Dockerの軽量であるというメリット完全に享受できない点にご注意ください。

(3) 充実したツール群

APIやツール群が充実しているのもDockerの大きなアドバンテージです。実用的な用途を網羅した以下のような充実したツール群を無償で利用できます。初見では、色々あってややこしいという印象を受けるかもしれませんが、1個ずつ使っていけば慣れていきます。

  • Docker Engine
    • Dockerコンテナ・イメージを実行管理するサーバおよびそれを操作するCLI(コマンドライン・インタフェース)を含む。v1.12.0からクラスタ管理機能も統合された。
  • Docker Compose
    • 複数のコンテナを実行・管理するためのツール。
  • Docker Registry
    • イメージを蓄積したり、配布したりするためのサーバソフトウェア。

また、イメージ管理用のサーバであるDocker Registryについては、利用人数が増えてくると負荷分散やデータのバックアップなども考慮する必要が出てきます。そのような状況では、以下のようなオプションも利用できます。

  • Docker Hub
    • Docker社が運営するPaaS版のDocker Registry。無償で利用可能。
    • OSSコミュニティのようにイメージを公開できるプロジェクトに最適。
  • Docker Trusted Registry
    • 商用サポート付き、オンプレにも対応したDocker Registry。
    • 社内など閉じたコミュニティでDockerイメージを配布する場合に良い。

Dockerを触ってみよう

これまでDocker自体について説明を書いてきましたが、筆者の経験上、Dockerを理解するには、まずは手を動かして試すのが一番です。ぜひ、一度、一通りチュートリアルをやってみてください。

Docker Engineのインストール

まずは、Dockerをインストールしてみましょう。Dockerは主要なOS(Linux、Windows、Mac)をサポートしています。利用の環境に合った方法でインストールしてください。

Linux上にインストール

ディストリビューションごとにインストール方法が異なります。公式ドキュメントでディストリビューションごとのインストール方法を参照してください。

Windows上にインストール

Windowsのバージョンによってインストール方法が異なります。それぞれインストーラを実行するだけでインストールできます。

  • Microsoft Windows 10 Professional または Enterprise 64-bit は、Docker CE for Windowsをインストールできます。
  • それ以外は、Docker Toolboxというツールが提供されています。

(注) Docker Ver. 1.12.0からHyper-V(Windows 8以降対応のハイパーバイザ型の仮想環境)をサポートしています。Windows 10では、OSが提供するハイパーバイザ型の仮想マシンの上でDockerが利用できるようになりました。それ以前は、Docker ToolboxによりVirtualBox上のLinuxにDocker Engineをインストールし、ホスト上のコマンドラインツールからアクセスするという手段を取ります。

Mac OS上にインストール

  • OS X Yosemite 10.10.3 以降は、Docker CE for Macをインストールできます。
  • それ以前は、Docker Toolboxというツールが提供されています。

(注) Docker Ver. 1.12.0からHyperKit(OS X Yosemite以降対応のハイパーバイザ型の仮想環境)をサポートしています。これにより、OS X 10.10 Yosemite以降では、OSが提供するハイパーバイザ型の仮想マシンの上でDockerが利用できるようになりました。それ以前は、Windows 8以前と同様にDocker Toolboxを使います。

筆者の実行環境

筆者は、以下の環境で本記事のサンプルを動作確認しました。

  • Linux
    • OS: Ubuntu Server 16.04 LTS
    • インスタンスタイプ: m4.large
    • Docker: 17.03.1-ce
  • Mac
    • OS: Mac OS 10.11.6 (El Capitan)
    • CPU: 2.9 GHz Intel Core i7
    • メモリ: 8 GB
    • Docker: 17.04.0-ce(Docker for Mac)
  • Windows
    • OS: Windows 7 64bit
    • CPU: Intel Core i3-3120M CPU 2.50GHz 2.50Hz
    • メモリ: 16 GB
    • Docker: 17.04.0-ce(Docker Toolbox)

インストールの動作確認

インストールができたら以下のコマンドでデーモンが動いているか確認してください。表示されない場合はインストールに失敗しています。再度、ドキュメントを参照してください。

% docker ps
CONTAINER ID  IMAGE  COMMAND  CREATED  STATUS  PORTS  NAMES

Hello Worldを動かしてみる

インストールできたら、早速、プログラマにはおなじみのhello worldをやってみましょう。

% docker run hello-world

docker runはイメージからコンテナを起動するコマンドです。上記のコマンドの場合、hello-worldというイメージからコンテナを起動するという意味になります。ただし、ローカルにhello-worldイメージがないため、Dockerデーモンがhello-worldイメージをDocker Hub(Docker社が運営するPaaS型のDocker Registry)からダウンロードし、イメージからコンテナを起動します。このコンテナは以下の標準出力を出して終了します。

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c04b14da8d14: Pull complete
Digest: sha256:0256e8a36e2070f7bf2d0b0763dbabdd67798512411de4cdcf9431a1feb60fd9
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker Hub account:
 https://hub.docker.com

For more examples and ideas, visit:
 https://docs.docker.com/engine/userguide/

コンテナでLinuxを動かしてみる

先ほどのhello-worldの例で、コマンドラインでイメージの取得とコンテナ起動が簡単にできることがおわかりいただけたと思います。

次に、もう少し複雑な例として、Alpine Linuxというコンテナ向けに開発されている軽量Linuxディストリビューションのコンテナを操作する例を紹介します。このチュートリアルにより、Dockerを使う上で最も基本となる以下のことが学べます。

  • イメージの取得(pull)
  • イメージの一覧表示(images)
  • コンテナのライフサイクル管理
    • 作成(create)
    • 起動(start)
    • 停止(stop)
    • 削除(rm)
  • コンテナの一覧表示(ps)

まずはalpineのイメージを取得しましょう。イメージの取得にはpullコマンドを使います。

docker pull alpine
Using default tag: latest
latest: Pulling from library/alpine
e110a4a17941: Pull complete
Digest: sha256:3dcdb92d7432d56604d4545cbd324b14e647b313626d99b889d0626de158f73a
Status: Downloaded newer image for alpine:latest

imagesコマンドで取得済みのイメージ一覧を確認できます。先ほどのhello worldとalpineのイメージが表示されています。

docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              c54a2cc56cbb        9 weeks ago         1.848 kB
alpine              latest              4e38e38c8ce0        10 weeks ago        4.799 MB

では、次にalpineイメージからコンテナを起動してみましょう。コンテナの起動にはrunコマンドを使います。

書式は docker run <イメージ名> <コンテナで起動するコマンド>です。runは、コンテナを作成(create)し、そのコンテナを起動(start)まで行います。詳細なオプションは、Docker公式ドキュメントを参照して下さい。

% docker run alpine echo "hello from alpine"
hello from alpine

<コンテナで起動するコマンド>として、echoコマンドを指定したため、コンテナを起動した直後にechoコマンドを実行し、コンテナは終了しています。

これまではコンテナ起動時に1個だけコマンドを実行して、終了する例ばかりでした。一方、コンテナの中で対話的に作業をしたい場合は、runコマンドにオプション -it をつけ、コンテナに接続します。以下の例の場合は、コンテナ起動後にシェルを起動しているため、コンテナ内でLinuxコマンドが使えることが分かると思います。

% docker run -it alpine bin/sh
/ # ls
bin      etc      lib      media    proc     run      srv      tmp      var
dev      home     linuxrc  mnt      root     sbin     sys      usr

もう1個のターミナルを開き、psコマンドを実行してみてください。psコマンドは現在起動中のコンテナを確認するコマンドです。現在、もう1個のターミナルでalpineイメージからコンテナを起動し、bin/shコマンドを実行していることが分かります。

docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
d483da6aee04        alpine              "bin/sh"            3 minutes ago       Up 3 minutes                            nauseous_yonath

ここでstopコマンドを実行すると、コンテナを停止できます。先ほどalpineコンテナを起動していたターミナルを開くと、コンテナが停止していることが分かります。

docker stop d483da6aee04
d483da6aee04

stopはコンテナを終了するわけではなく、あくまで停止状態にするだけです。停止したコンテナをstartコマンドで再開できます。psコマンドでコンテナが確かに起動していることを確認しましょう。

docker start d483da6aee04
d483da6aee04
docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
d483da6aee04        alpine              "bin/sh"            11 minutes ago      Up 6 seconds                            nauseous_yonath

ただし、このままでは再びコンテナを操作できません。ターミナルからコンテナにアタッチするには、attachコマンドを使います。引数はコンテナIDです。

docker attach d483da6aee04
/ # ls
bin      etc      lib      media    proc     run      srv      tmp      var
dev      home     linuxrc  mnt      root     sbin     sys      usr

コンテナを終了(停止 + 削除)するには、コンテナにアタッチした状態で、Ctrl+Cを実行します。

あるいはstopコマンドで停止させ、rmコマンドでコンテナを削除することもできます。

% docker stop d483da6aee04
d483da6aee04
% docker rm d483da6aee04
d483da6aee04

いったんコンテナを削除すると、そのコンテナをstartコマンドで再開できなくなります。

% docker start d483da6aee04
Error response from daemon: ContainerInspect failed
Error: failed to start containers: d483da6aee04

コンテナでWebサーバを動かしてみる

これまでAlpine Linuxのイメージを例に、イメージとコンテナの管理方法について説明してきました。

次は、本記事の最後の例として、もう少し実用的な例としてDockerによるWebサーバのデプロイを紹介します。

ここでは、seqvence/static-siteというDocker Hubで公開されているイメージを使います。このイメージのコンテナ内部では、Nginx(Webサーバ)が立ち上がり、アクセスしてきたWebブラウザにコンテナ内の静的なWebページを提供します。Dockerはゲスト側のポートをホスト側にマッピングさせることができるため、Webブラウザによるホスト上のポートへのアクセスをゲストに転送できます。こうして、Docker上にWebサーバを立ち上げ、Webアプリケーションを提供できます。

まずはコンテナを立ち上げてみましょう。"Your Name"の箇所は適当な名前に置き換えてください。

% docker run --name static-site -e AUTHOR="Docker" -d -p 80:80 seqvence/static-site
9fb06bb3c1b51c0c958157f976c76a6dfa367ba66b41e23ad6ac9fc1fb6a5950

上記のコマンドのオプションは以下の通りです。

オプション 意味
–name static-site コンテナ名としてstatic-siteを指定する。
-e AUTHOR=“Docker” コンテナに環境変数 Author として “Docker” を渡す。このコンテナでは環境変数AuthorをWebページの表示に使っている。
-d デタッチモードで起動する(コンテナがデーモンとしてバッグクラウドで起動する)。
-p 80:80 コンテナ上の開放対象のポート(80番)をホスト上のポート(80番)に割り当てる。

上記の場合、ゲスト上の80番ポートをホストの80番ポートに割り当ててたため、Webブラウザで80番ポートにアクセスすると、Dockerコンテナ上のWebアプリケーションが生成したWebページを表示できます。

static-siteの実行結果

(注)使っているDocker Engineによって、アクセスするURIが異なります。

  • Linux、Docker for Windows(Windows 10以降)、Docker for Mac(OS X 10.10 Yosemite以降)の場合は、localhost:80で結果を確認できます。
  • それ以外の場合は、docker-machine ip defaultでDockerデーモンのIPアドレスを確認してください。上記図の場合は、192.168.99.100でした。

なお、-pオプションを変更し、ホスト側の別のポートに割り当てることも可能です。以下の場合、2つ目のコンテナを立ち上げ、ゲスト側の80ポートをホストの8080ポートに割り当てています。よってWebブラウザでlocalhost:8080にアクセスするとWebページを表示できます。

% docker run --name static-site2 -e AUTHOR="My second Docker" -d -p 8080:80 seqvence/static-site
2d275934457b9b4d27059248c10a795f59cac212a7d62e18e2cc015f9e0cd922

以上、簡単な例を使ってホストからDockerコンテナ内のWebサーバにアクセスできることを確認しました。ファイアウォールの設定(Linuxで言えばiptables)を変更し、外部からホストのHTTPポートにアクセス可能にすればDocker内のWebサーバを外部に公開できます。

この仕組を応用すると、クラウド上のサーバにDockerをインストールしておけば、Dockerコマンドで、イメージ取得からコンテナ内のWebサーバ起動までを含むデプロイ作業を簡単に行えます。また、Webページの内容を変更した場合は、ホスト側で再度新しいDockerイメージを取得し、コンテナを起動するだだけです。

まとめ

本記事では、Dockerの概要、既存イメージおよびコンテナの操作方法を説明しました。最後にWebサーバをデプロイする方法も紹介しました。今回の記事でイメージやコンテナの管理は難しくなく、アプリケーションのデプロイも簡単に行えることが理解いただけたと思います。ただし、実際に、Dockerでアプリケーションをデプロイする上では、自分のイメージを作成・配布する必要があります。次回は、このイメージの作成について紹介します。

更新記録

  • 2017/5/9: Docker のバージョンアップに伴い、インストール手順を修正。