CentOS 7の仮想化、Docker、リソース管理(後編)
この連載が、書籍『CentOS 7 実践ガイド』になりました!
IT技術者のための現場ノウハウ CentOS 7 実践ガイド
CentOS 7を取り巻く市場動向、サーバーシステムの選定、システム設計、構築手順など巷で話題のDockerとは?
最近、巷で注目を浴びているオープンソースの一つに「Docker」(ドッカー)があります。Dockerは、コンテナと呼ばれる隔離空間を管理するためのツールです。CentOS 7は、この「コンテナ」と呼ばれるアプリケーションとOSをパッケージ化した実行環境をサポートしています。一般的に、Linux OS上での隔離空間を「Linuxコンテナ」と呼びます。Linuxコンテナは、KVMやXenなどのハイパーバイザー型の仮想化技術に比べて、CPU、メモリ、ストレージ、ネットワーク等のハードウェア資源の消費やオーバーヘッドが小さいとう利点が挙げられます。Dockerは、Linuxコンテナの機能に加えて、API、イメージフォーマット、環境を配布する仕組みを持っています。しかし、このDockerが注目される理由は、ハードウェア資源の消費のオーバーヘッドが小さいだけではありません。Dockerが注目される背景には、アプリケーション開発者が最も嫌うであろう「ハードウェアの調達やメンテナンス」の隠蔽が挙げられます。ハードウェアに関する部分は、アプリケーション開発者にとってあまり重要ではありません。従来のKVM等による仮想化は、アプリケーション開発者にとってのメリットというよりもむしろ、システム管理者にとって大きなメリットがありました。一方、Dockerのような軽量なコンテナ技術の発達により、アプリケーション単位での隔離、開発環境の容易な作成と廃棄ができるようになり、アプリケーションのメンテナンスの簡素化がより一層進むことになります。これは、システム管理者よりもアプリケーション開発者にとってのメリットが非常に大きいことを意味します。また、Dockerの仕組みによって、アプリケーションの開発と実環境への素早い展開と運用の両立が見えてきました。これは、近年、開発者やIT部門の間で話題になっている「DevOps環境」の実現に他なりません。アプリケーション開発者やIT部門にとっては、アプリケーションの開発、運用、廃棄等を、ハードウェア資源を意識しない「雲」の上で迅速に行える環境がDockerを使って整備されつつあります。
CentOS 7でdockerを使う
以下では、CentOS 7で採用されているdockerのインストールと基本的な利用方法について説明します。CentOS 7では、dockerパッケージが標準で含まれています。yumコマンドでインストールします。
# yum install -y docker # rpm -qa |grep docker docker-1.3.2-4.el7.centos.x86_64
docker pull centosでイメージをインターネット経由で入手しますが、もし企業内においてプロキシーサーバー経由でインターネットに接続する環境では、以下のように、/etc/sysconfig/dockerファイルにプロキシーサーバーを指定し、dockerサービスを再起動してください。
# vi /etc/sysconfig/docker … http_proxy=http://proxy.jpn.hp.com:8080 https_proxy=http://proxy.jpn.hp.com:8080 … # systemctl restart docker # docker pull centos
dockerサービスを起動します。
# systemctl start docker # systemctl enable docker ln -s '/usr/lib/systemd/system/docker.service' '/etc/systemd/system/multi-user.target.wants/docker.service'
これでDockerのインストールは完了です。Dockerでは、様々なOSとアプリケーションがパッケージ化された環境がDockerイメージとしてDockerリポジトリに用意されています。イメージファイルを一から作成することも可能ですが、すでにDockerリポジトリに用意されているイメージファイルを利用することができますので、コンテナへのOSやアプリケーションのインストール等の煩雑な作業をスキップすることができます。以下では、Dockerリポジトリに用意されているイメージファイルをDocker上で起動させてみます。
イメージファイルをDockerリポジトリから入手する前にSELinuxをdisableにしておきます。
# setenforce 0 # getenforce Permissive
イメージファイルをインターネット経由でDockerリポジトリから入手します。
# docker pull centos:centos5 Pulling repository centos bac0c97c3010: Download complete 511136ea3c5a: Download complete 5b12ef8fd570: Download complete Status: Downloaded newer image for centos:centos5 # docker pull centos:centos6 Pulling repository centos 510cf09a7986: Download complete 511136ea3c5a: Download complete 5b12ef8fd570: Download complete Status: Downloaded newer image for centos:centos6 # docker pull centos:centos7 Pulling repository centos 8efe422e6104: Download complete 511136ea3c5a: Download complete 5b12ef8fd570: Download complete Status: Downloaded newer image for centos:centos7
Dockerリポジトリから入手し、ローカルのCentOS 7サーバー上に保管されているイメージファイル一覧を確認します。
# docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE centos 5 bac0c97c3010 7 days ago 466.9 MB centos centos5 bac0c97c3010 7 days ago 466.9 MB centos 6 510cf09a7986 7 days ago 215.8 MB centos centos6 510cf09a7986 7 days ago 215.8 MB centos latest 8efe422e6104 7 days ago 224 MB centos 7 8efe422e6104 7 days ago 224 MB centos centos7 8efe422e6104 7 days ago 224 MB
上記のイメージファイル群のうち、centos6という名前の付いたタグの付いたイメージファイルから、コンテナを生成、起動し、そのコンテナ内で作業できるようにしてみましょう。Dockerのイメージファイルからコンテナを起動するには、docker runを実行します。--nameオプションに、コンテナの名前を指定します。今回は、test01という名前のコンテナを起動するように指定しました。-iオプションは、コンテナの標準入力を開いた状態にします。-tオプションを付与することにより、Dockerは、仮想端末を割り当てて、コンテナの標準入力にアタッチします。centos:centos6は、入手したイメージファイルのタグ付きのリポジトリ名です。最後に、/bin/bashを指定することで、コンテナ上のシェルを起動します。
# docker run --name test01 -i -t centos:centos6 /bin/bash [root@d962dc3be270 /]#
コンテナにログインし、作業してみます。コンテナのOSのバージョンを確認します。
[root@d962dc3be270 /]# cat /etc/redhat-release CentOS release 6.6 (Final)
すると、CentOS 6.6であることがわかります。ホスト名を確認してみます。
[root@d962dc3be270 /]# hostname d962dc3be270
ホスト名は自動的に「d962dc3be270」という名前で割り振られていることがわかります。さらにIPアドレスを確認し、ホストOSや外部と通信できるかを確認します。dockerでは、標準で、インタフェースdocker0を割り当てます。
[root@d962dc3be270 /]# ifconfig eth0 |grep inet inet addr:172.17.0.5 Bcast:0.0.0.0 Mask:255.255.0.0 inet6 addr: fe80::42:acff:fe11:5/64 Scope:Link [root@d962dc3be270 /]# ping -c 3 172.16.1.1 PING 172.16.1.1 (172.16.1.1) 56(84) bytes of data. 64 bytes from 172.16.1.1: icmp_seq=1 ttl=63 time=0.690 ms 64 bytes from 172.16.1.1: icmp_seq=2 ttl=63 time=0.281 ms 64 bytes from 172.16.1.1: icmp_seq=3 ttl=63 time=0.239 ms --- 172.16.1.1 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2373ms rtt min/avg/max/mdev = 0.239/0.403/0.690/0.204 ms [root@d962dc3be270 /]# nslookup www.hp.com<http://www.hp.com>
dockerのイメージファイルの仕組みを理解するため、まず、試しいdockerコンテナー上の/rootディレクトリにファイルtestfileを作成しておきます。
[root@d962dc3be270 /]# touch /root/testfile [root@d962dc3be270 /]# ls /root/ testfile
dockerコンテナのOS環境から離脱します。
[root@d962dc3be270 /]# exit exit #
ホストOS上で、過去に起動したコンテナ一覧を確認します。
# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d962dc3be270 centos:6 "/bin/bash" 9 minutes ago Exited (0) About a minute ago test01
先程作業したコンテナを再利用できるように、コンテナのイメージ化を行います。コンテナをイメージ化するには、コンテナをコミットします。先程作業したコンテナのコンテナIDとイメージを指定してコミットを行います。
# docker commit d962dc3be270 centos:centos6 5468f0e1072fbd5cdf0042efc76e3d0d8c778f235faf212bcbf9b2105ebdf30f
再び、現在のイメージファイルの一覧を確認します。
# docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE centos centos6 5468f0e1072f 24 seconds ago 215.8 MB centos centos5 bac0c97c3010 7 days ago 466.9 MB centos 5 bac0c97c3010 7 days ago 466.9 MB centos 6 510cf09a7986 7 days ago 215.8 MB centos centos7 8efe422e6104 7 days ago 224 MB centos latest 8efe422e6104 7 days ago 224 MB centos 7 8efe422e6104 7 days ago 224 MB
先程コミットしたイメージファイル「centos:centos6」を使って、別のコンテナtest02を生成してみます。
# docker run --name test02 -i -t centos:centos6 /bin/bash [root@5b2ac9622d6f /]#
コンテナtest02上の/rootを確認してみます。
[root@5b2ac9622d6f /]# ls /root/ testfile [root@5b2ac9622d6f /]#
コンテナtest02で、/root/testfile2を作成します。
[root@5b2ac9622d6f /]# touch /root/testfile2 [root@5b2ac9622d6f /]# exit exit # docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5b2ac9622d6f centos:centos6 "/bin/bash" 2 minutes ago Exited (0) About a minute ago test02 d962dc3be270 centos:6 "/bin/bash" 20 minutes ago Exited (0) 12 minutes ago test01 # docker commit 5b2ac9622d6f centos:testfile2 4eac0fb23ec1d4a212b4aa289637f43da3049dd975d48a91fd9890ca6a368cdd # docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE centos testfile2 4eac0fb23ec1 8 seconds ago 215.8 MB centos centos6 5468f0e1072f 7 minutes ago 215.8 MB centos 5 bac0c97c3010 7 days ago 466.9 MB centos centos5 bac0c97c3010 7 days ago 466.9 MB centos 6 510cf09a7986 7 days ago 215.8 MB centos centos7 8efe422e6104 7 days ago 224 MB centos latest 8efe422e6104 7 days ago 224 MB centos 7 8efe422e6104 7 days ago 224 MB
上記より、作業を行ったコンテナをコミットすることでその作業内容を反映したイメージファイルが生成でき、さらに作成したイメージファイルを再利用して、新たなコンテナを生成できていることがわかります。開発者は、アプリケーション毎に異なるコンテナを複数作成し、コミットしておけば、そのアプリケーションに特化したイメージファイルを持つことができ、すぐにアプリケーションが実行可能な環境をコンテナで利用することができます。
コンテナに含まれるファイルの確認方法
現在起動しているDockerコンテナのファイルシステム上にあるファイル等をホストマシンから確認したい場合があります。起動中のコンテナのファイルシステムは、/var/lib/docker/devicemapper/metadataディレクトリ配下にあるコンテナID の名前が付いたメタデータの情報を元に、Device Mapperを使ってアクセスできます。以下は、CentOS 6.6のDockerイメージからコンテナを起動し、そのコンテナのファイルシステムに存在する/etc/redhat-releaseファイルに記載されたCentOSのバージョンをホストマシンから確認する手順です。まず、Dockerに現在登録されているイメージファイルを確認します。今回、CentOS 6.6のDockerイメージ「centos:centos6.6」は、事前にCentOS 6のDockerイメージを入手し、yum updateによりパッケージを最新に更新することにより作成しました。
# docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE centos centos6.6 6e80aa2dad3a 23 seconds ago 215.8 MB centos testfile2 4eac0fb23ec1 4 minutes ago 215.8 MB centos centos6 5468f0e1072f 12 minutes ago 215.8 MB centos 5 bac0c97c3010 7 days ago 466.9 MB centos centos5 bac0c97c3010 7 days ago 466.9 MB centos 6 510cf09a7986 7 days ago 215.8 MB centos centos7 8efe422e6104 7 days ago 224 MB centos 7 8efe422e6104 7 days ago 224 MB centos latest 8efe422e6104 7 days ago 224 MB
上記のDockerイメージ「centos:centos6.6」から、コンテナを起動します。コンテナ名はtest001としました。
# docker run --name test0001 -i -t centos:centos6.6 /bin/bash [root@098686019f0d /]#
ホストマシンの別の端末で、起動中のコンテナを確認します。
# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 098686019f0d centos:centos6.6 "/bin/bash" 12 minutes ago Up 12 minutes test001
以下は、起動中のコンテナ「098686019f0d」のファイルシステムをホストマシンから確認する手順です。まず、コンテナ「098686019f0d」のメタデータから、コンテナのデバイスIDとサイズを確認します。
# cd /var/lib/docker/devicemapper/metadata # cat 098686019f0dec240ec5b0473046b78b5e56cb7dd0651e821d9e9216cfa9e37e |python -mjson.tool { "device_id": 6, "initialized": false, "size": 10737418240, "transaction_id": 121 }
上記より、このコンテナのデバイスIDは6、サイズが、10737418240であることがわかります。次に、起動しているコンテナがマウントされているループバックデバイスを表示します。
# ls -l /dev/mapper/ 合計 0 crw-------. 1 root root 10, 236 12月 17 17:46 control lrwxrwxrwx. 1 root root 7 1月 13 11:23 docker-8:3-84171797-098686019f0dec240ec5b0473046b78b5e56cb7dd0651e821d9e9216cfa9e37e -> ../dm-3 lrwxrwxrwx. 1 root root 7 1月 13 08:33 docker-8:3-84171797-pool -> ../dm-1 lrwxrwxrwx. 1 root root 7 1月 13 05:28 encrypted001 -> ../dm-2 lrwxrwxrwx. 1 root root 7 1月 13 05:28 pool001-lvol001 -> ../dm-0
上記のdocker-8:3-84171797-poolと先述のデバイスID、サイズを使って、テスト用のボリュームを作成します。具体的には、コンテナのサイズ「10737418240」と、デバイスIDの「6」をdmsetupコマンドの--tableオプションで指定します。
# dmsetup create testvol01 --table "0 $((10737418240 / 512)) thin /dev/mapper/docker-8:3-84171797-pool 6"
テスト用のボリュームtestvol01は/dev/mapperディレクトリ以下に作成されていますので、これをマウントします。
# mount /dev/mapper/testvol01 /mnt
/mntにマウントしたコンテナのディレクトリツリーと/etc/redhat-releaseファイルを確認します。
# ls -la /mnt/rootfs/ 合計 176 drwxr-xr-x. 21 root root 4096 1月 13 08:07 . drwxr-xr-x. 4 root root 4096 9月 9 06:30 .. dr-xr-xr-x. 2 root root 4096 1月 2 23:23 bin drwxr-xr-x. 4 root root 90112 1月 2 23:23 dev drwxr-xr-x. 45 root root 4096 1月 2 23:23 etc drwxr-xr-x. 2 root root 4096 9月 23 2011 home dr-xr-xr-x. 7 root root 4096 1月 2 23:23 lib dr-xr-xr-x. 6 root root 12288 1月 2 23:23 lib64 drwx------. 2 root root 4096 1月 2 23:21 lost+found drwxr-xr-x. 2 root root 4096 9月 23 2011 media drwxr-xr-x. 2 root root 4096 9月 23 2011 mnt drwxr-xr-x. 2 root root 4096 9月 23 2011 opt drwxr-xr-x. 2 root root 4096 1月 2 23:21 proc dr-xr-x---. 2 root root 4096 1月 2 23:23 root dr-xr-xr-x. 2 root root 4096 1月 2 23:23 sbin drwxr-xr-x. 3 root root 4096 1月 2 23:23 selinux drwxr-xr-x. 2 root root 4096 9月 23 2011 srv drwxr-xr-x. 2 root root 4096 1月 2 23:21 sys drwxrwxrwt. 2 root root 4096 1月 2 23:23 tmp drwxr-xr-x. 13 root root 4096 1月 2 23:21 usr drwxr-xr-x. 17 root root 4096 1月 2 23:21 var # cat /mnt/rootfs/etc/redhat-release CentOS release 6.6 (Final)
コンテナが持つファイルシステムを確認し終えたら、マウントを解除し、テスト用のボリュームは削除しておきます。
# cd # umount /mnt # dmsetup remove /dev/mapper/testvol01
【注意】
dmsetupコマンドにより、コンテナのファイルシステムを確認するためのテスト用のボリュームを作成する際に、デバイスIDを間違えると、別のコンテナのファイルシステムの中身を見ることになりますので十分注意して下さい。
Dockerfileを使ったイメージファイルの構築
Dockerイメージの作成や、イメージファイルからコンテナを起動する一連の手順は、先述のdockerコマンドでコマンドラインから入力することで可能ですが、イメージ作成作業、アプリケーションのインストール等の複数の作業をまとめて行いたい場合があります。そのような場合は、Dockerfileを使うと便利です。Dockerファイルは、開発環境におけるMakefileのように、一連の作業をDockerで定義された書式に従って事前に記述し、それに基づいてイメージの作成を行います。以下では、CentOS 7で稼働するApache Webサーバーが起動するコンテナのイメージファイルの作成、コンテナの起動、コンテナへのアクセス方法を述べます。まず、Apacheが稼働するコンテナ用のDockerfileを用意します。今回は、/root/apacheディレクトリを作成し、その下にDockerfileを作成します。
# mkdir /root/apache # cd /root/apache # vi Dockerfile FROM centos:centos7 ←使用するDockerイメージ名を指定 MAINTAINER Masazumi Koga ENV container docker RUN yum swap -y fakesystemd systemd ←systemdをDockerイメージにインストール RUN yum install -y initscripts RUN yum install -y httpd ←Apache WebサーバーのhttpdパッケージをDockerイメージにインストール RUN echo "Hello Apache." > /var/www/html/index.html ←テスト用のHTMLファイルをDockerイメージに配置 RUN systemctl enable httpd ←コンテナ起動時にhttpdサービスが起動するように設定 EXPOSE 80 ←Dockerコンテナが外部に開放するポート番号を指定
Dockerfile内では、FROM行に利用するイメージの種類を記述します。イメージ名はコマンドラインから「docker images」で確認可能ですので、一覧に表示されているイメージ名を記述します。ここではCentOS 7のイメージ「ceentos:centos7」を指定しています。RUN行では、Dockerのイメージを作成する際に実行したいコマンドを記述します。今回、RUN行に、「yum swap -y fakesystemd systemd」が指定されています。Dockerリポジトリに標準で用意されているCentOS 7のDockerイメージは、デフォルトでsystemdを利用しないものが用意されています。しかし、多くのCentOS 7向けのアプリケーションやサービスがsystemdを使用するため、Dockerイメージにsystemdをインストールしたい場合があります。今回は、yumコマンドで、fakesystemdを削除し、systemdをインストールしています。さらに、RUN行の「yum install -y httpd」は、Apache Webサーバーのhttpdパッケージをインストールする記述です。今回使用するDockerイメージは、CentOS 7のsystemdを有効にしますので、RUN行で「systemctl enable httpd」を記述し、コンテナが起動した際に、自動的にApache Webサーバーが起動するようにします。Apache Webサーバーのコンテナが外部に開放するポート番号をEXPOSE行で指定します。Dockerfileを記述したら、Dockerイメージを生成します。
# pwd /root/apache # ls -l 合計 4 -rw-r--r--. 1 root root 263 11月 9 17:09 Dockerfile # docker build -t centos7_apache .
Apache Webサーバー入りのDockerイメージ「centos7_apache」が作成されているかを確認します。
# docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE centos7_apache latest ac8e9d882d7e About a minute ago 381.9 MB ... ...
作成したDockerイメージ「centos7_apache」を使ってDockerコンテナを起動します。今回起動するコンテナ名は、「apache001」としました。
# docker run --name apache001 --privileged -i -t -d -p 80:80 centos7_apache /sbin/init 3db4623293db8c6a2e516ac788bb10fa32a73175c46d08c19a6b441d148b6838
DockerイメージがCentOS 7ベースで、コンテナ内でsystemdを使用する場合は、コンテナの起動オプションに、「--privileged」オプションが必要になります。またコンテナの起動に指定するコマンドは、「/sbin/init」を指定します。コンテナが起動したかを確認します。
# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3db4623293db centos7_apache:latest "/sbin/init" 15 seconds ago Up 15 seconds 0.0.0.0:80->80/tcp apache001
コンテナ「apache001」が起動していることがわかります。ホストマシンからコンテナ「apache001」にログインします。
# nsenter -t $(docker inspect --format '{{.State.Pid}}' apache001) -i -m -n -p -u /bin/bash [root@3db4623293db /]#
上記のようにログインプロンプトが「[root@3db4623293db /]」になったことで、コンテナにログインできていることがわかります。コンテナにログインできていますので、コンテナ上でApache Webサービスが起動しているかを確認します。
[root@3db4623293db /]# systemctl status httpd
コンテナがhttpdサービスを正常に起動できていることを確認できたら、コンテナに割り振られたIPアドレスをコンテナ上で確認します。
[root@3db4623293db /]# ip a |grep inet ... inet 172.17.0.26/16 scope global eth0 ...
コンテナが外部にWebサービスを提供できているかをホストマシンや他のクライアントマシンから確認します。コマンドラインから確認するには、curlコマンドが有用です。
# curl 172.17.0.26/index.html Hello Apache.
【注意】
本連載では、CentOS 7のDockerイメージにsystemdをインストールする方法を紹介しましたが、Dockerコンテナ上でのsystemdの利用については、全てのアプリケーションやデーモンについて、十分なテストが行われているわけではありません。したがって、利用者の自己責任の元で十分な動作確認を行って上記手順を利用するように下さい。