こんにちは、横山です。

先日、Docker Meetup Tokyo #21 に参加してきました。

今回は、Dockerを使った開発の効率化の話や、コンテナオーケストレーションツールのひとつであるKubernetesの話がありました。
(参考:今さら人に聞けない Kubernetes とは?

今回に限らず、Dockerを使った開発効率化の発表はされているので、ぜひ探して参考にしてみるとよいと思います。

また、Kubernetesについては、Dockerで公式採用した話も最近あり、Dockerを本格的に使っていこうとしている人は、動向を追っておくと良いと思います。

はじめに

第一回では、Dockerとはどのようなもので、何が良いのか紹介しました。今回の第二回では、実際にDockerをインストールして、Dockerコンテナを動かし、Dockerイメージとコンテナの関係、コンテナの基本操作について説明します。

今回は、無償版のDocker CE (Docker Community Edition) を使います。Docker EE (Docker Enterprise Edition)という商用版もあり、詳細については、Docker Enterprise Editionを参照していただくとよいと思います。

サーバー準備

Dockerを使用する環境を準備しましょう。本連載では、CentOSを前提として説明していきます。

さくらのクラウドを利用する場合は、仮想サーバと仮想ディスク – 「さくらのクラウド入門」(1)を参照していただくとよいと思います。

Docker for Mac/Windowsなどを使っても、Dockerを動かすことはできますので、その場合は、Get started with Docker for Windows
Get started with Docker for Macを参照ください。(Docker for Windowsは、64bit Windows 10 Proの環境が必要です。)

Dockerのセットアップ

yumのリポジトリ設定などを行って、Docker CEをインストールします。

Dockerインストールのためのリポジトリ設定

まず、yum-utilsと、devicemapperで必要とされるパッケージをインストールします。Dockerとdevicemapperの関係について詳しく知りたい方は、Docker で devicemapper を使う設定を参照ください。

# yum install -y yum-utils \
  device-mapper-persistent-data \
  lvm2

Docker CEをインストールするため、yumのリポジトリを追加します。

# yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

# ll /etc/yum.repos.d/
合計 32
-rw-r--r--. 1 root root 1664 4月 1 2015 CentOS-Base.repo
-rw-r--r--. 1 root root 1309 4月 1 2015 CentOS-CR.repo
-rw-r--r--. 1 root root 649 4月 1 2015 CentOS-Debuginfo.repo
-rw-r--r--. 1 root root 1331 4月 1 2015 CentOS-Sources.repo
-rw-r--r--. 1 root root 1002 4月 1 2015 CentOS-Vault.repo
-rw-r--r--. 1 root root 290 4月 1 2015 CentOS-fasttrack.repo
-rw-r--r--. 1 root root 2424 2月 24 09:32 docker-ce.repo

docker-ce.repoが追加されていることが確認できます。

Dockerインストール

Docker CEをインストールします。

# yum install docker-ce

これでDocker CEがインストールできました。以下のコマンドでインストールされているか確認しておきましょう。

# yum list installed | grep docker-ce
docker-ce.x86_64 17.12.0.ce-1.el7.centos @docker-ce-stable

Dockerサービスの起動

Dockerサービスを起動します。

# systemctl start docker

Dockerサービスが起動しているか確認しましょう。

# systemctl status docker

以下のコマンドでサービス自動起動設定をしておくと、マシン再起動後も自動でDockerサービスが起動されます。

# systemctl enable docker

以下のコマンドでDockerについての情報を見ることができます。

# docker info

これでDockerを使用する準備が整いました。

Dockerコンテナの基本操作

公開されているDockerイメージを使用し、コンテナの基本的な操作を行ってみましょう。

今回は、公開されているDockerイメージの取得、それをもとにコンテナを起動、起動の確認ができたら、コンテナの停止・削除、Dockerイメージの削除を行い、基本となるDockerイメージ、コンテナのライフサイクルを確認しましょう。
docker_images_container

初期状態の確認

以下のコマンドでローカル環境のDockerイメージの一覧を確認できます。

# docker images
REPOSITORY   TAG   IMAGE   ID   CREATED   SIZE

現状ではヘッダーのみで、何も表示されません。
Docker Hub」という、公開されているDockerイメージを管理しているところからダウンロードしたり、自分でDockerイメージを作成したりすることで初めて一覧に表示されます。

以下のコマンドでは、ローカル環境のDockerコンテナの一覧を確認できます。(Dockerコンテナとは、Dockerイメージをもとに起動させたコンテナのことを指します。)

# docker ps -a
CONTAINER ID   IMAGE   COMMAND   CREATED   STATUS   PORTS   NAMES

コンテナ起動はまだ行っていないため、この結果も同様にヘッダーのみしか表示されません。

hello-worldイメージを使ってコンテナを動かしてみる

それでは、以下のコマンドを実行し、公開されているhello-worldというDockerイメージを取得、コンテナを起動させます。

# docker run hello-world
Unable to find image 'hello-world:latest' locally  ・・・①
latest: Pulling from library/hello-world           ・・・②
ca4f61b1923c: Pull complete
Digest: sha256:083de497cff944f969d8499ab94f07134c50bcf5e6b9559b27182d3fa80ce3f7
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.
    (amd64)
 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 ID:
 https://cloud.docker.com/

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

これだけだと何が起きたのかわかりにくいですね。簡単に説明していきます。

実行コマンドの「docker run」は、Dockerイメージを使用して、コンテナを起動するコマンドです。今回で言えば、「hello-world」というDockerイメージを使用して、コンテナを起動させようとしています。

しかし、①に出力されているように、最初はローカル環境にはDockerイメージはありません。そのため、Docker Hubに探しに行き、存在すればDockerイメージをダウンロードします。それが②の部分になります。

hello-worldイメージのダウンロードが完了したら、そのイメージを使用してコンテナを起動させています。このhello-worldイメージは、コンテナ起動をしたら、コンテナの中で③以降のメッセージを出力するようなDockerイメージとなっています。

(実は、今説明したことが、出力内容の1.~4.に書かれていますね。)

以下を実行してDockerイメージが取得できているか確認しましょう。

# docker images
REPOSITORY    TAG      IMAGE ID       CREATED        SIZE
hello-world   latest   f2a91732366c   3 months ago   1.85kB

今度は、hello-worldという行がありますね。これが、先ほどのdocker runコマンドを実行して、Docker HubからダウンロードしたDockerイメージです。また、今回はdocker runコマンドを実行して、Dockerイメージのダウンロードからコンテナの起動まで実行されましたが、以下のコマンドで、Dockerイメージのダウンロードだけを行うことも可能です。

# docker pull hello-world

次にコンテナの状態を見てみましょう。

# docker ps -a
CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                      PORTS   NAMES
c1b9013f9f66   hello-world   "/hello"   27 minutes ago   Exited (0) 27 minutes ago           distracted_swirles

一行出力されていますね。
左から、コンテナのID、使用したDockerイメージ、コンテナ起動時にコンテナ内で実行するコマンド、コンテナを作成したタイミング、コンテナ状態(起動中、停止中など)、ポートフォワード設定、コンテナの名前、となっています。
COMMANDに書かれているように”/hello”というファイルで、上記の③の内容を出力するようになっています。
コンテナの名前は、指定しなければ今回のように自動で設定されます。(コンテナの名前の指定の仕方は後ほど出てきます。)

また、このコンテナのステータスは「Exited」となっていて、停止している状態です。(起動中は「Up」になります。)
コンテナは、1プロセスは動いている必要があります。
今回のhello-worldイメージでは、メッセージを出力するだけのプロセスだったため、そのプロセスが終了したタイミングでコンテナは停止しています。

Dockerコンテナ、イメージを削除する

次に作成したDockerコンテナと取得したDockerイメージを削除してみましょう。

以下のコマンドでhello-worldコンテナを削除することができます。

# docker rm <コンテナ名> (今回でいえば「distracted_swirles」)
または
# docker rm <CONTAINER ID> (今回でいえば「c1b9013f9f66」)

以下のコマンドを実行し、コンテナが削除されていることを確認しましょう。停止中のものをそのままにしておくと、ゴミデータが残ったままになったり、ディスク圧迫にもつながるので、不要になったものは削除を忘れないようにしましょう。

# docker ps -a
CONTAINER ID   IMAGE   COMMAND   CREATED   STATUS   PORTS   NAMES

「docker ps」(「-a」を付けない)と実行すると、停止中のコンテナは表示されないので、注意してください。気づいたらたくさんの不要コンテナが溜まっていた、ということにもなりかねません。

また、コンテナを削除しても、Dockerイメージまでは削除されません。Dockerイメージの削除は以下のコマンドで行えます。

# docker rmi <Dockerイメージ名> (今回でいえば「hello-world」)
または
# docker rmi <IMAGE ID> (今回でいえば「f2a91732366c」)

以下のコマンドを実行し、イメージが削除されていることを確認しましょう。

# docker images
REPOSITORY   TAG   IMAGE   ID   CREATED   SIZE

イメージについても、不要なイメージは削除しましょう。特に、JenkinsなどのCI(Continuous Integration) ツールを使用して、Dockerイメージの作成やコンテナ起動を自動で実行するような場合、気づかないうちに不要データが残り続けて、ディスクを圧迫することになるので注意しましょう。(Disk Fullを起こすと、Docker環境の復元も困難になる場合があるので、十分注意したほうが良いです。)

Nginxイメージを使ってコンテナを動かしてみる

次に、NginxのDockerイメージを使ってみましょう。
まずNginxのDockerイメージを取得します。

# docker pull nginx

取得したNginxイメージを使用してコンテナを起動します。

# docker run -d --name nginx-container -p 8181:80 nginx

上記実行によりNginxコンテナが起動するので、8181ポートに外からアクセスできるように設定すれば(Firewallなど)、以下のURLでNginxにアクセスすることができます。
http://<作成したインスタンスのIPアドレス>:8181/

nginx

実行コマンドのオプションについて説明します。

-d コンテナをバックグラウンド実行します。このオプションを付けない場合、コンテナ起動時に実行されるコマンドを実行した状態になり、例えばそのコマンドのコンソール出力が表示された状態になります。
–name コンテナ名を指定します。
(hello-worldの例では、指定しなかったので自動で名前がついていました。)
-p ホストとコンテナ間のポートフォワード設定。
基本的には、「-p <ホスト側のポート>:<コンテナ側のポート>」で書きます。(ホスト側を省略すると自動で設定されます。)
コンテナは、Dockerにより作成されるネットワークに属するため、このオプションを使わないと、ホストのIPアドレスを用いて、コンテナで使用しているポートにはアクセスができません。

また、Nginxイメージの場合は、コンテナ起動時にnginxプロセスが実行されたままの状態になるため、コンテナも停止せずに起動状態となります。
docker ps コマンドで見てみると、STATUSが「Up」となっています。

# docker ps -a
CONTAINER ID   IMAGE   COMMAND                  CREATED      STATUS         PORTS                  NAMES
a61413193f44   nginx   "nginx -g 'daemon ..."   7 days ago   Up 8 seconds   0.0.0.0:8181->80/tcp   nginx-container

コンテナを停止するには、以下のコマンドを実行します。

# docker stop nginx-container
nginx-container
# docker ps -a
CONTAINER ID   IMAGE   COMMAND                  CREATED      STATUS                     PORTS                  NAMES
a61413193f44   nginx   "nginx -g 'daemon ..."   7 days ago   Exited (0) 3 seconds ago   0.0.0.0:8181->80/tcp   nginx-container

削除については、hello-worldの例と同様です。

Dockerの設定の注意点

Proxy設定

忘れがちなこととして、Proxy配下でDockerを使用する場合は、設定が必要です。設定していないと、Docker HubからDockerイメージの取得ができないので注意しましょう。(Docker for Mac/Windowsでも設定する箇所があります。)

具体的には以下で設定が可能です。

# mkdir -p /etc/systemd/system/docker.service.d
# vi /etc/systemd/system/docker.service.d/http-proxy.conf

[Service]
Environment="HTTP_PROXY=http://<プロキシサーバのIPアドレス>:<プロキシサーバのポート>/ HTTPS_PROXY=http://<プロキシサーバのIPアドレス>:<プロキシサーバのポート>/"

# systemctl daemon-reload
# systemctl restart docker

まとめ

今回は、さくらのクラウドを利用して、Dockerのインストールとコンテナの起動について紹介しました。次回は、コンテナ内へのアクセスやファイルコピーなど、コンテナ操作についてさらに説明していく予定です。