Dockerコンテナとコンテナイメージの管理

コンテナ型仮想化で広く使用されているDockerについて、その導入から管理まで解説します。(LinuCレベル2 主題:2.06.2)

最終更新日:2024年02月28日

Dockerの概要

コンテナ型仮想化で広く使用されているのがDockerです。Dockerの各コンテナは、コンテナの動作プラットフォーム(Docker Engineなど)上で動作します。

DockerはGo言語で書かれていて、Apache 2.0ライセンスの元でオープンソースソフトウェアとして公開されています。

さらにKubernetesなどコンテナオーケストレーション技術を用いると、複数コンテナを連動させて可用性の高いシステムを短時間に構築し稼働させることができるようになってきています。

ただし、Dockerを使いこなすためにはシステム構成を考え、それに適した構成定義ファイル(Dockerfile)などを作成するスキルが必要で、ある程度の知識が必要です。

Dockerの動作イメージ

コンテナのファイルシステムとイメージの関係

各コンテナはイメージと呼ばれるコンテナのテンプレートファイルから生成されます。ユーザーは独自にコンテナに含めるコンポーネントを定義してイメージを作成することもできますし、Docker Hub(https://hub.docker.com/)などの公開リポジトリなどから、公開されている既成のイメージを取り込んでコンテナを生成することもできます。

Docker Hubのサイト

Docker HubではubuntuなどのOS、mysql, mariadb, httpd, nginxなど各種アプリケーションやミドルウェアを含んでいるイメージが公開されています。

そして、docker pullコマンドを用いてイメージをダウンロードし、docker createコマンドでコンテナを生成、そしてdocker runコマンドでコンテナを実行できます。

Dockerの動作イメージ

Dockerの各コンテナはDocker Engine上で動作し、ホストマシンのカーネルを使用します。そのため、ハイパーバイザーや仮想マシンの負荷がないため、より軽量で高速な動作が期待されます。

コンテナ型仮想化(Docker)の動作イメージ

Dockerは各種ミドルウェアライブラリのインストールや環境設定をコード化(テキストファイルに定義を記述)して管理します。

構成ファイルを共有することで、

  • 誰でも同じ仮想環境を構築できる
  • 作成したシステム環境を配布しやすい(構成ファイルを提供すればよい)
  • コンテナの追加・削除が容易にできる

などの利点が得られます。

構成自動化ツール利用の利点

構成自動化ツールのセクションでも扱いましたが、各種設定をコード化して管理するInfrastructure as Codeを実現しています。コード化することにより、環境構築を自動化し、短時間に同じ環境を確実に再現できるため、システムの運用管理の負担軽減や、チーム開発時の環境構築の負荷軽減などに役立ちます。

開発段階からコンテナ上で開発を進め、本番環境に同じ環境を構築してデプロイ(本番環境に配置)することができるため、DevOps、開発(Development)と運用(Operation)の連携がスムーズになります。 開発メンバー間で設定ファイルを共有することで短時間に開発環境を生成し、バージョン調整やインストールなどの負担を減らせます。

Dockerの導入

Dockerコンテナを動作させるDocker Engineには、有償のEnterprise Edition(EE)と無償のCommunity Edition(CE)の2系統があります。初めてDockerを導入する場合にはCommunity版を使用するといいでしょう。

ここでは公式のインストール手順にしたがって、Docker CEをインストールしていきます。

まずはホスト名の確認を行います。

hostnameコマンドでホスト名が表示されることを確認しましょう。

$ hostname
centos7

続いてはrootに切り替えてから、Docker CEのインストールに必要なパッケージ、yum-utils、device-mapper-persistent-data、lvm2をインストールします。

  • yum-utilsはyumのユーティリティーでyum-config-managerを含みます。
  • device-mapper-persistent-dataとlvm2(論理ボリュームマネージャ)は、デバイスマッパーストレージドライバの動作に必要です。
# yum install -y yum-utils device-mapper-persistent-data lvm2

次にDocker Engineのインストールは、公式リポジトリを使用して行います。

まずはDocker社の提供するリポジトリを追加します。

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

リポジトリを追加したら、Docker Engine CEのインストールを実行します。

# yum install docker-ce docker-ce-cli containerd.io

Docker Engine CEがインストールされたら、起動してみましょう。

# systemctl start docker

動作確認のためにhello-worldイメージを動作させてみましょう。Docker Hubからhello-world(テスト用)イメージをダウンロードしてインスタンスを生成し、確認用のメッセージを出力します。runコマンドは、イメージの取得(pull)、コンテナの生成(create)、コンテナの起動(start)を連続して実行します。

# docker run hello-world

ホストOSの起動時にDockerを起動するには、systemd(CentOSやUbuntu最新安定版など)を使用しているのであれば以下のコマンドを実行します。

# systemctl enable docker

Dockerによるネットワークの構築

DockerのLinuxイメージを使用してコンテナを作成すると、通常はNAT(自動ポート変換)機能でホストOSのポートを自動的に変換してコンテナにIPアドレスを割り当てます。

しかしこの方式だと、名前解決ができずコンテナ名で相互にアクセスできないので、ブリッジ接続に変更して同一ネットワークに異なるIPアドレスで接続するように設定を変更し、コンテナ間の通信を可能にする場合があります。

まずはubuntu1,ubuntu2というコンテナを起動してネットワーク設定を調べてみます。最初にubuntu1という名前のコンテナを起動します。dは起動時に接続しない(detouch)というオプションです。

$ docker run -itd –-name ubuntu1 ubuntu /bin/bash

コンテナの起動に成功したら設定をinspectコマンドで確認します。

$ docker inspect ubuntu1

Networksという項目の内容をチェックしてみましょう。

[
{
         (中略)
            "Networks": {
                "bridge": {
                    ,,,
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
					,,,
                }
 			 ,,,
]

すると172.17.0.2というIPアドレスが設定されています。

同様にubuntu2というコンテナも起動します。

$ docker run -itd –name ubuntu2 ubuntu /bin/bash

ubuntu2も設定をinspectコマンドで確認します。

$ docker inspect ubuntu2
[
    	(中略)
            "Networks": {
                "bridge": {
                    ,,,
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.3",
                    ,,,
               }
			}
]

すると、ubutnu2には、172.17.0.3という異なるIPアドレスが割り当てられています。

次にubuntu1からubuntu2にpingで疎通確認をしてみたいと思います。まずはコンテナを起動して、bashシェルを起動します。execは指定したコマンドを実行するオプションです。

$ docker exec -it ubuntu1 /bin/bash 

次にpingコマンドを使うために、iputils-pingをインストールします。

root@d3ce49845646:/# apt-get update && apt install iputils-ping

インストールが成功したら、ubuntu1からubuntu2へpingを実行してみましょう。

root@d3ce49845646:/# ping -c 3 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=1.46 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=1.70 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=1.63 ms

続いて、コンテナ名でpingを送信してみましょう。

root@d3ce49845646:/# ping -c 5 ubuntu2
ping unknown host ubuntu2

デフォルトのネットワーク構成ではコンテナ名でアクセスできないので、ユーザー自身でブリッジネットワークを定義して、コンテナ名でアクセスできるようにしましょう。

まずは、独自のネットワークを定義します。ここではnw1とします。

$ docker network create nw1

続いて、ubuntu1,2のコンテナをnw1に接続します。

$ docker network connect nw1 ubuntu1
$ docker network connect nw1 ubuntu2

もう一度inspectコマンドを実行してnw1の情報を確認します。

$ docker inspect ubuntu1

するとネットワークのセクションに、”nw1”が表示されます。

続いては、ubuntu1に接続してpingを実行していきます。まずは、docker execコマンドでubuntu1コンテナに接続します。

$ docker exec -it ubuntu1 /bin/bash

コンテナに接続してコマンドプロンプトが切り替わったら、コンテナ名でpingを実行してみましょう。

root@d3ce49845646:/# ping -c 3 ubuntu2
PING ubuntu2(172.19.0.3) 56(84) bytes of data.
64 bytes from 172.19.0.3: icmp_seq=1 ttl=64 time=1.46 ms
64 bytes from 172.19.0.3: icmp_seq=2 ttl=64 time=1.70 ms
64 bytes from 172.19.0.3: icmp_seq=3 ttl=64 time=1.63 ms

これで、コンテナ名で通信ができるようになりました。

このようにして、独自に定義したブリッジネットワークを使用すると、同じホストにつながるコンテナ間で、シンプルなネットワークを構築することができます。 さらに異なるホスト上で動作するコンテナ間で通信を行うためには、各ホストOSにブリッジインターフェースを追加し、異なるホスト上で動作するコンテナを同一のL2ブリッジネットワークに接続して、通信を可能にするフラットなネットワークを構成することもあります。

Dockerコンテナの管理コマンド

Dockerのインストール直後に、docker runコマンドを実行して、hello-worldイメージをダウンロードしてコンテナを生成、動作させました。

Dockerにはこれ以外にもコンテナの操作をするコマンドが用意されています。

  • docker ps/statsコマンドを使うと、稼働中のコンテナ一覧や詳細を表示できます。
  • docker run/create/restart コマンドを使うと、コンテナの実行、イメージからの作成、再起動ができます。
  • docker pause/unpauseコマンドを使うと、実行中のDockerコンテナのプロセスの一時中断、および再開を実行できます。
  • docker stop/killコマンドを使うと、実行中のコンテナを停止したり、強制終了したりできます。
  • docker rmを使うと、既存のコンテナを削除できます。

コンテナの接続してプロセスを実行する

docker attachやexecコマンドを使うと、実行中のコンテナに接続して、コマンドを実行することができます。

$ docker exec <コンテナ名> <コマンド名>

という書式で使用します。

例えば、CentOSが動作しているコンテナに接続してbash(シェル)を起動してみましょう。

$ docker exec -it ubuntu /bin/bash
  • -iオプションは標準出力を開き続ける
  • -tオプションは疑似ターミナルを割り当てる

というオプションで、この二つを指定すると、ホストOSからコンテナ内のシェルにコマンドを投入できるようになります。例えば、以下のようにホストOSのコマンドプロンプトがコンテナのシェルのコマンドプロンプトに切り替わります。コンテナ上でexitコマンドを実行するとホストOSのコマンドプロンプトに戻ります。

# [root@centos ~]# docker run -it ubuntu bash
root@d3ce49845646:/#

コンテナイメージの管理

Dockerレジストリは、Dockerイメージの管理(保管や提供)をする仕組みです。複数のリポジトリを持つことができ、それぞれ複数のイメージを格納しておけます。

リポジトリは、イメージを保存しておく領域のことで、ユーザーが名前をつけてイメージを識別したり、リポジトリ内のイメージを参照してコンテナを生成することもできます。

Docker Hubのように公開のレジストリも存在しますが、会社や組織内だけで公開せずにイメージを使いたい場合には、プライベートリポジトリを運用するのが適しています。

Dockerレジストリのイメージ

Dockerレジストリの開始方法

Dockerレジストリ(コンテナ)を開始するには、以下のようにdocker runコマンドを使用します。

$ docker run -d -p 5000:5000 –-name registry registry:2
  • -d は、デタッチオプション、コマンド実行時にコンテナに接続しないオプションです。
  • -p は、ホストのポートをコンテナのポートを関連付けるオプションです。
  • nameオプションでレジストリ名を指定します。
  • registry:2 は取得するレジストリのイメージの名前を指定しています。

docker imagesコマンドを使用すると、ローカルリポジトリ内のイメージ一覧を表示できます。

$ docker images

docker pull コマンドを使用すると、Docker Hub(公開リポジトリ)からイメージを取得します。例えば、下記はubuntuのイメージを取得します

$ docker pull ubuntu

docker tagコマンドを使うと、自分のレジストリ上にタグをつけて保存できます。例えば、先ほど取得した、ローカルにあるイメージにタグをつけるには、以下のようにします。

$ docker tag ubuntu localhost:5000/ubuntu

作成したイメージをローカルレジストリに登録するには、以下のようにpushコマンドで送信します。

$ docker push localhost:5000/ubuntu

登録したイメージをローカルのレジストリから取得するにはpullコマンドを用います。

$ docker pull localhost:5000/ubuntu

Dockerレジストリを停止・削除するには以下のコマンドを用います。

$ docker stop registry && docker rm -v registry

-vオプションで削除するレジストリ名を指定します。

docker importコマンドを使用するとアーカイブ(圧縮された)ファイルからイメージを生成します。例えば、以下のようなフォーマットでコマンドを実行すると、tgzファイルからイメージを生成します。ただし、タグ付けされていないイメージが生成されます。

$ docker import http://example.com/exampleimage.tgz

URLではなく、ローカルファイルシステムから読み込むことも可能です。その場合はURLの部分をファイルへのPATHにします。
より詳細なオプションは、Dockerの公式ドキュメントを参照してください。

http://docs.docker.jp/engine/reference/commandline/import.html

docker commitコマンドを使うと、既存のコンテナに名前をつけてイメージとして保存することができます。

$ docker commit default httpd

イメージの一覧を表示するには、docker imagesコマンドを使用します。

$ docker images
REPOSITORY     TAG      IMAGE ID       CREATED          SIZE
httpd     		4f0aa49f1e67   48 seconds ago   197MB

上記の例ではdefaultがhttpdという名前のイメージとして保存されます。また、既存のイメージにタグをつけて保存することも可能です。

例えば、centosのイメージにhttpdをインストールし、centos:httpdという名前(前者がイメージ名で後者がタグ)でイメージを保存できます

$ docker commit centos centos:httpd

イメージの削除

イメージを削除するには、docker rmi (remove image)コマンドを使います。ただし、削除を実行するにはイメージを使用しているコンテナを停止しておく必要があります。

$ docker rmi httpd(イメージ名)

Dockerfile

ここまでは、docker pull/runコマンドでDocker Hubからイメージを取得したり、commitコマンドでコンテナからイメージを作成したりする手順を紹介しました。

しかし、この方法だとイメージを転用する際に不便な場合があります。例えば、イメージの構成内容をドキュメント化したり、イメージから生成したコンテナに対して手作業で設定を変更したりしなくてはならないケースが出てきます。

そこでプログラムのビルドに使用されるMakefileのように、コンテナの構成内容をドキュメントではなく、テキストファイルに定義しておいて、できるだけ手作業を減らして構成を自動化するための仕組みがDockerfileです。 Dockerfileを作成しておくと、テキストファイル内でイメージに含むアプリケーションやミドルウェアを定義して、docker buildコマンドでDockerコンテナのイメージをコマンドライン(docker buildコマンド)から自動生成できます。そのため、作業負担や操作ミス、作業時間などを減らせます。

Dockerfileの書式

Dockerfileは、以下のフォーマットで記述します。

# コメント
<命令> <引数>

主な命令には以下のようなものがあります。FROMだけでも実行できますが、主にRUNとADDを用いてカスタマイズされたイメージを作成します。

命令操作内容
FROM元となるDockerイメージの指定
MAINTAINER作成者の情報
RUNコマンドの実行
ADDファイル/ディレクトリの追加
CMDコンテナの実行コマンド 1
ENTRYPOINTコンテナの実行コマンド 2
WORKDIR作業ディレクトリの指定
ENV環境変数の指定
USER実行ユーザーの指定
EXPOSEポートのエクスポート
VOLUMEボリュームのマウント

カスタマイズイメージ作成の例

例えば、Ubuntuのイメージをベースにして、nginxをインストールしたイメージを生成してみましょう。

$ mkdir mynginx
$ cd mynginx
$ vi Dockerfile

としてviエディターを起動し、以下のような内容を記述します。

FROM ubuntu
MAINTAINER Foo Bar foo@example.jp
RUN apt-get install -y nginx
ADD index.html /usr/share/nginx/html/

また、別途index.htmlファイルを作成しておきましょう。例えば、メッセージを1行だけ含むファイルを生成します。

$ echo “Hello Nginx on Docker!” > index.html

Dockerfileとindex.htmlが用意できたら、docker buildコマンドを実行してイメージを生成してみます。

$ docker build -t <イメージ名>:<タグ名> <Dockerfileのディレクトリ>

という書式でDockerfileからイメージを生成します。

$ docker build -t foo/mynginx:1.0 .

イメージを生成したら、imagesコマンドでイメージが追加されたことを確認しましょう。リポジトリ名とタグがDockerfileと一致していることを確認しましょう。

$ docker images
REPOSITORY     TAG      IMAGE ID       CREATED          SIZE
foo/mynginx   1.0   4f0aa49f1e67   48 seconds ago   198MB
centos         7        2d194b392dd1   2 weeks ago      195MB

イメージからコンテナを生成・起動し、動作確認をしてみます。

$ docker run -d -p 80:80 –name foo/mynginx:1.0 /usr/sbin/nginx -g ‘daemon off;’ -c /etc/nginx/nginx.conf

起動したら、コマンドラインから、コンテナのhttpポートにアクセスして動作を確認してみましょう。

$ curl localhost
Hello Nginx on Docker!

というようにindex.htmlファイルに記述した内容が表示されたら成功です。

もしもこのコンテナが不要な場合は、コンテナの停止、削除を実行しましょう。

$ docker stop mynginx
mynginx
$ docker rm mynginx
mynginx

執筆者紹介

・太田 俊哉

・井上 博樹



このドキュメントは、LinuCレベル2の学習用の教材から抜粋して作成されたものです。教材全体は以下のPDFファイルをご覧ください。
LinuCレベル2学習教材

ページトップへ