いますぐ実践! Linuxシステム管理

いますぐ実践! Linux システム管理 / Vol.264 / 読者数:2662名

こんばんは、うすだです。

日々、追われて生きていると、変化に気づかないことがあります。

健康診断では、経年劣化の分を差し引くと、 今までおおむね変わらない値をキープしています。ですが、先日、 風呂場で自分の体を鏡で見たとき、 足がヒョロヒョロになっていることに気づいてしまいました。

…ええ、もちろん突然そうなったわけではありません。年月を経て衰えたことに、 ようやく気づいただけです。

人間、歳はとりますから、髪や皺など、 アンチできないエイジングがあることは確かです。 (お金持ちの人は、プロペシアなどございますが。)

ですが、家や車などと同じで、ちゃんと手入れしてあげれば、 長く使えるようになるはず。もう少しメンテしてあげねば、と思いました。

そして、知識や技術も、体と同様、昔知っていたから今も、と過信するのではなく、 定期的な確認や、新たな情報の取得など、 メンテをしてあげる必要があるのではないでしょうか。

…とは思いつつも、年とともに、気力も失われつつあるように思います。
いろんな意味でうまく年齢を重ねていくというのは、難しいですね。

しょっぱなからおっさん臭さ満載ですが、今回もはりきってまいります。

今回のお題 - Docker をもう少し深く使ってみる (レベル:初〜中級)

前回は、Docker の超簡単な説明と使い方を、ご紹介しました。

Vol.263 - Docker を使ってみる
http://www.usupi.org/sysad/263.html

今回は、もうちょっと踏み込んで、普段使いそうなことをやってみます。
具体的には、以下のとおりです。
(お察しの通り、独自な使い方的な内容は、含まれておりません。)

  • Apache を動かすためのコンテナを作る
  • Dockerfile でいつでもどこでも同じコンテナを作れるようにする
  • Docker Hub にイメージを登録する
  • cgroups によるCPUやメモリの制限を加える

あ、前回同様、dockerコマンドは「docker.io」と記しています。

Apache が動くコンテナを作ります

Docker を使うのですから、何らかのサービスを提供するコンテナを作りたい、 というのがありがちかつ身近な願望ではないでしょうか。

というわけで、安直に、Apacheを動かすためのコンテナを作りましょう。
ベースは CentOS 6 にしたいと思います。
まずは、新たにコンテナを作成します。手順は前回と同じです。

  $ sudo docker.io run -it --name mycent6 centos:centos6 /bin/bash
  bash-4.1#  (← コンテナの中で動いているbashのプロンプトです)

すでに作ってあって、それを使い回してもいいという場合は、 start して attach しましょう。

  $ sudo docker.io start mycent6
  $ sudo docker.io attach mycent6
  bash-4.1#  (← コンテナの中で動いているbashのプロンプトです)

「mycent6」というひねりのない名前をつけましたが、 センスのある貴兄はお好みの名前をつけていただいて構いません。

さて、この CentOS はミニマムな構成のため、Apache は含まれません。
ですので、Apache をインストールします。

  bash-4.1# yum install httpd

インストールしたら、お好みの設定にして、起動します。

  bash-4.1# vi /etc/httpd/conf/httpd.conf
  (お好みの設定に変更)
  bash-4.1# service httpd start

コンテナのIPアドレスは、おそらく以下のようになっています。

  bash-4.1# ip addr show eth0
  16: eth0:  mtu 1500 qdisc pfifo_fast state UP qlen 1000
      link/ether 00:11:22:33:44:55 brd ff:ff:ff:ff:ff:ff
      inet 172.17.0.2/16 scope global eth0
  ...後略...

ホストからつながりますので、アクセスしてみましょう。
(下記では telnet を使っていますが、お好みのブラウザでよいです。)

  $ telnet 172.17.0.2 80
  Trying 172.17.0.2...
  Connected to 172.17.0.2.
  Escape character is '^]'.
  GET / HTTP/1.0

  HTTP/1.1 200 OK
  Date: Sun, 31 Aug 2014 11:20:17 GMT
  Server: Apache/2.2.15 (CentOS)
  ...後略...

200 とか返ってきますので、問題なさそうです。
これで OK だと思ったら、コンテナを終了します。

  bash-4.1# exit

次に、このコンテナをイメージに仕立て上げます。
イメージの名前は、「ユーザ名/リポジトリ名:タグ名」の形式にします。
(こちらも、センスのある名前をつけていただきたいと存じます。)

  $ sudo docker.io commit mycent6 kuriking/cent6_httpd:test

あとは、このサービスを提供する必要が出てきたら、このイメージをもとにして、 コンテナを作ればよいわけですね。
ここでは、「-p」オプションを使って、 コンテナの80番のポートをホストの 12380番ポートでアクセスできるようにしています。

  $ sudo docker.io run -p 12380:80 --name mycent6_httpd_test \
  kuriking/cent6_httpd:test service httpd start

ですが、上記を実行すると、コンテナがすぐ終了(停止)してしまいます。

これは、「run」コマンドで指定したコマンドが終了したとき、 コンテナが停止するためです。service コマンドにより httpd は動作し続けますが、 service コマンド自身は終了するため、コンテナも停止してしまうのですね。

では、httpd をフォアグラウンドで動かしましょう。
さっきのコンテナを消して、

  $ sudo docker.io rm mycent6_httpd_test

作り直します。以下のように httpd を直接指定しています。

  $ sudo docker.io run -p 12380:80 -d --name mycent6_httpd_test \
  kuriking/cent6_httpd:test /usr/sbin/httpd -DFOREGROUND

これなら、コンテナは動き続けてくださいます。
(docker ps で各自ご確認くださいませ。)

ただ、httpd がお亡くなりになると、コンテナが停止します。
それは困るという場合は、supervisor などの、 繰り返し起動してくれるデーモンを間にかませる必要があります。

Dockerfile でイメージを自動生成します

さっきは、centos6 をベースに、httpd が動くコンテナを作成しました。

イメージにしてしまえば、コンテナを大量生産できます。
ただ、このイメージがどういうものかというのは、 作業したときの記録が残っていないと、把握しづらいように思います。

また、ちょっと違うイメージをベースにした、 同等のサービスを提供するコンテナが必要になったとき、手順を記録していないと、 同等にすることが難しいのではないかと思います。

ですが、Docker には「Dockerfile」という強い味方があります。
Dockerfile を使うと、コンテナを生成して各種作業を行い、 イメージに仕立て上げるところまでを、全部自動で行ってくれます。(すごい!)

Dockerfile には、1行につき1つの命令を書きます。
主な命令は以下の通りです。

命令名指定する引数
FROMイメージ名
MAINTAINER作者名
RUNイメージ生成時に実行するコマンド
CMDコンテナ実行時のコマンド
EXPOSE公開するポートの番号...
ENV環境変数名 その値
ADD追加するファイル 追加する先のパス

実際の例で簡単に説明していきます。
まず、専用のディレクトリを作ります。名前は任意です。

  $ mkdir docker_httpd
  $ cd docker_httpd/

「Dockerfile」という名前のファイルを用意します。
前節とほぼ同じことをする Dockerfile は、以下の通りです。

FROM centos:centos6
MAINTAINER kuriking
RUN yum install -y httpd
RUN mv -f /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.ORG
ADD httpd.conf /etc/httpd/conf/httpd.conf
ADD index.html /var/www/html/index.html
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]

FROMで、ベースのイメージを「centos:centos6」に指定しています。
3行目のRUNでは、httpdパッケージをインストールしています。
4行目のRUNでは、httpd.confのバックアップをしています。
5行目のADDでは、 カレントディレクトリにある「httpd.conf」をコンテナに追加しています。
6行目のADDでは、同様に「index.html」をコンテナに追加しています。
7行目のCMDでは、コンテナ起動時のコマンドを指定しています。

というわけですので、httpd.conf と index.html をご用意ください。
用意ができたら、「build」コマンドでイメージを自動生成します。
「-t」オプションで生成するイメージ名、 その後の引数で Dockerfile のあるパス(今はカレントディレクトリ)を指定します。

  $ sudo docker.io build -t kuriking/cent6_httpd:build .
  Uploading context 38.91 kB
  Uploading context 
  Step 0 : FROM centos:centos6
   ---> b1bd49907d55
  Step 1 : MAINTAINER kuriking
   ---> Running in 13bd72ec1b8f
   ---> 7878490aa3ea
  Step 2 : RUN yum install -y httpd
   ---> Running in b3b0ec6dbce5
  Loaded plugins: fastestmirror
  Setting up Install Process
  Resolving Dependencies
  ...中略...
  Complete!
   ---> 89e451f3004d
  ...中略...
  Step 7 : CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
   ---> Running in a103570a8310
   ---> 09904be04e62
  Successfully built 09904be04e62
  ...後略...

特にエラーとか言われなければ、できているはずです。

  $ sudo docker.io images
  REPOSITORY            TAG    IMAGE ID      CREATED         VIRTUAL SIZE
  kuriking/cent6_httpd  build  09904be04e62  55 seconds ago  301.1 MB
  ...後略...

ちなみに、もし途中で失敗しても、途中経過がコンテナとして残っているため、 次にトライするときは、自動的に途中から進めてくれます。
下記では、Step 1 と Step 2 で「Using cache」となっており、 前回実行したときの途中経過を利用していることがわかります。
(yum updateなど、実行する度に結果が異なる可能性のあるものについては、 使いまわされないようです。)

  $ sudo docker.io build -t kuriking/cent6_httpd:build .
  Uploading context 38.91 kB
  Uploading context 
  Step 0 : FROM centos:centos6
   ---> b1bd49907d55
  Step 1 : MAINTAINER kuriking
   ---> Using cache
   ---> 7878490aa3ea
  Step 2 : RUN yum install -y httpd
   ---> Using cache
   ---> 89e451f3004d
  ...後略...

というわけで、失敗したときは、途中経過のコンテナが残ります。
最終的にイメージができて、以下のように途中経過が残ってしまっているなら、 自力で消しましょう。

  $ sudo docker.io ps -a
  CONTAINER ID  IMAGE         COMMAND               CREATED ...
  63caec62aa3b  89e451f3004d  /bin/sh -c mv -f /et  About an ...
  b3b0ec6dbce5  7878490aa3ea  /bin/sh -c yum insta  About an ...
  ...中略...
  $ sudo docker.io rm 63caec62aa3b b3b0ec6dbce5

それはさておき、イメージができたら、動作確認しておきましょう。

  $ sudo docker.io run -p 12380:80 -d --name mycent6_built_test \
  kuriking/cent6_httpd:build

  $ telnet localhost 12380
  ...中略...

  $ sudo docker.io stop mycent6_built_test
  $ sudo docker.io rm mycent6_built_test

Docker Hub に登録してみましょうか

イメージは、下記の Docker Hub というところから取得できます。

Docker Hub Registry - Repositories of Docker Images
https://registry.hub.docker.com/

ここでアカウントを作ると、自分のイメージを登録することができます。
以降では、イメージを登録する方法をご紹介します。

まずは、右上の「Sign Up」をクリックして、アカウントを作ります。
作ったら、「login」コマンドでログインします。

  $ sudo docker.io login
  Username:  ← ユーザ名を入力
  Password:  ← パスワードを入力
  Email:     ← メールアドレスを入力
  Login Succeeded

成功と言われていますが、「info」コマンドでも確認できます。

  $ sudo docker.io info
  ...中略...
  Username: ユーザ名
  Registry: [https://index.docker.io/v1/]
  ...後略...

方法とか言いながら、あとは「push」コマンドで登録するだけです。
引数には、登録するイメージ名を指定します。

  $ sudo docker.io push kuriking/cent6_httpd
  The push refers to a repository [kuriking/cent6_httpd] (len: 2)
  Sending image list
  Pushing repository kuriking/cent6_httpd (2 tags)
  ...後略...

Docker Hub で検索などすると、ちゃんと出てきます。
あるいは、以下のように、「search」コマンドでも検索できます。

  $ sudo docker.io search kuriking
  NAME                  DESCRIPTION  STARS  OFFICIAL  AUTOMATED
  kuriking/cent6_httpd               0

CPUとメモリに制限を加えます

最後に、CPUとメモリに制限をかける方法を、ご紹介します。

「run」コマンドで実行する際、「-c」オプションでCPUの配分の重みを、 「-m」オプションでメモリ使用量の上限を、指定できます。

たとえば、「-c 512」と指定してコンテナを実行してみます。

  $ sudo docker.io run -c 512 -d --name cputest centos:centos6

デフォルトでは、cgroups の「cpu.shares」は「1024」です。

  $ cat /sys/fs/cgroup/cpu/docker/cpu.shares 
  1024

ですが、生成したコンテナでは、指定した「512」になっています。
(1024の半分ですので、半分の時間しか割り当てられなくなります。)

  $ cat /sys/fs/cgroup/cpu/docker/ID*/cpu.shares 
  512

次に、「-m 128m」と指定してみましょう。

  $ sudo docker.io run -m 128m -d --name memtest centos:centos6

デフォルトでは、なんだか天文学的(?)な数値になっています。
(2^64 - 1 == 16エクサバイト - 1 でしょうか。)

  $ cat /sys/fs/cgroup/memory/docker/memory.limit_in_bytes 
  18446744073709551615

ですが、生成したコンテナでは、指定した「128MB」になっています。

  $ cat /sys/fs/cgroup/memory/docker/ID*/memory.limit_in_bytes 
  134217728

ちなみに、cgroups については、過去に取り上げております。

Vol.228 - cgroup について理解する
http://www.usupi.org/sysad/228.html
Vol.229 - cgroup でメモリと走行時間に制限を加える
http://www.usupi.org/sysad/229.html

おわりに

以上、Dockerfile などもろもろをご紹介しました。

私自身理解できていないというのもあり、 細かいところまでは説明できていないのですが、 ざっくりと簡単なところは網羅できたのではないかと、勝手に思っています。

よくわからなくっても、まずは使ってみることが大事だと思います。
まずは、身近なところで使うようにしてみてください。

宿題の答え

前回の宿題は、

  コンテナのプロセスなどがどうなっているか、コンテナの外から確認をしてみましょう。

でした。

では、コンテナを動かして確認してみましょう。
以下では、前回作った停止中のコンテナ「myubuntu」を起動しています。

  $ sudo docker.io start myubuntu
  myubuntu
  $ sudo docker.io attach myubuntu
  root@370f0a0e6b72:/# 

前回もやりましたが、コンテナの中でpsコマンドを実行します。
実質 bash しかいないことがわかります。

  root@370f0a0e6b72:/# ps aux
  USER  PID %CPU %MEM    VSZ   RSS TTY  STAT START  TIME COMMAND
  root    1  0.0  0.0  18160  1964 ?    Ss   00:50  0:00 /bin/bash
  root    9  0.0  0.0  15568  1140 ?    R+   00:51  0:00 ps aux

ホスト(コンテナの外)で確認すると、2つほどいらっしゃいました。
ですが、VSZ などの値を見る限り、PID が 16902 の方だと思われます。

  $ ps aux | grep /bin/bash | grep -v grep
  root  16902  0.0  0.0 18160 1964 pts/46 Ss+ 09:50 0:00 /bin/bash
  root  28623  0.0  0.0 31252 7224 pts/11 S   8月19 0:00 /bin/bash

 

次に、ファイルシステムを確認してみましょう。
コンテナの中から見ると、こうなっています。
(ホストからだと、cat /proc/16902/mounts で同じものが見えます。)

  root@370f0a0e6b72:/# mount
  none on / type aufs (rw,relatime,si=105368ab9d65fdf1)
  /dev/disk/by-uuid/UUIDです on /.dockerinit type ext4 \
  (ro,relatime,errors=remount-ro,data=ordered)
  /dev/disk/by-uuid/UUIDです on /.dockerenv type ext4 \
  (ro,relatime,errors=remount-ro,data=ordered)
  /dev/disk/by-uuid/UUIDです on /etc/resolv.conf type ext4 \
  (ro,relatime,errors=remount-ro,data=ordered)
  /dev/disk/by-uuid/UUIDです on /etc/hostname type ext4 \
  (ro,relatime,errors=remount-ro,data=ordered)
  /dev/disk/by-uuid/UUIDです on /etc/hosts type ext4 \
  (ro,relatime,errors=remount-ro,data=ordered)
  proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
  sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
  ...後略...

前回説明した通り、/ は AUFS です。
それから、/etc/hostname や /etc/resolv.conf などは、 コンテナ生成時に用意されたものになっています。「ro」であることから、 コンテナ自身が変更することはできません。

  root@370f0a0e6b72:/# cat /etc/hostname 
  370f0a0e6b72
  root@370f0a0e6b72:/# ehoc hoge > /etc/hostname
  bash: /etc/hostname: Read-only file system

ちなみに、ホストの「/var/lib/docker/containers/ID*/」以下に、 そのファイルがあります。

  $ sudo cat /var/lib/docker/containers/370f0a0e6b72*/hostname
  370f0a0e6b72

 

最後に、ネットワークを確認してみます。
コンテナ内ではこうなっています。

  root@370f0a0e6b72:/# ifconfig eth0
  eth0      Link encap:Ethernet  HWaddr dd:ee:ff:00:11:22
            inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
            inet6 addr: fe80::dcee:ffff:fe00:1122/64 Scope:Link
  ...中略...

  root@370f0a0e6b72:/# ip link show
  ...中略...
  18: eth0:  mtu 1500 qdisc pfifo_fast state \
  UP mode DEFAULT group default qlen 1000
      link/ether dd:ee:ff:00:11:22 brd ff:ff:ff:ff:ff:ff

ホスト側ではこうなっています。

  $ brctl show
  bridge name  bridge id          STP enabled  interfaces
  docker0      8000.88898a8b8c8d  no           veth9930
  virbr0       8000.000000000000  yes

  $ ifconfig veth9930
  veth9930  Link encap:Ethernet  HWaddr 88:89:8a:8b:8c:8d
            inet6 addr: fe80::8c89:8aff:fe8b:8c8d/64 Scope:Link
  ...中略...

  $ ifconfig docker0
  docker0   Link encap:Ethernet  HWaddr 88:89:8a:8b:8c:8d
            inet addr:172.17.42.1  Bcast:0.0.0.0  Mask:255.255.0.0
            inet6 addr: fe80::8c89:8aff:fe8b:8c8d/64 Scope:Link
  ...後略...

「docker0」というブリッジに「veth9930」がつながっています。
そして、その veth9930 と、コンテナの「eth0」が、veth のペアであるっぽいですね。 ethtool で確認してみますと、

  $ ethtool -S veth9930
  NIC statistics:
       peer_ifindex: 18

相手のインデックスが 18 であることがわかります。
これは、コンテナのeth0のインデックスと同じですので、 ペアであることが確認できました。

今回の宿題

今回の宿題は、

  Dockerで、GUIを動かすためのコンテナを作ってみましょう。

です。

Docker のコンテナで Eclipse など動かしたい、というニーズはあるかもしれません。 やってみましょう。

…で、できるかな…。

あとがき

昔、パソコンが8ビットだった頃、 紙芝居みたいなアドベンチャーゲームが流行りました。
(気になる方は「8ビット アドベンチャーゲーム」で検索してください。)

例を挙げると、「ポートピア連続殺人事件」や「サラダの国のトマト姫」あたりが、 有名ではないかと思います。
(気になる方は検索を…。)

当時は、CPUもメモリも小さく、2次記憶装置はフロッピーディスクという、 スローでプアーな環境でした。(あるいはカセットテープですかね。)
ですので、質問など入力しても、 マシーンの香りが漂う固定的な返事しか得られなかった記憶が、かすかにあります。

ですが、時は過ぎ、われわれは当時の1万倍以上のリソースを得ました。
人工知能などの技術も格段に進歩しました。

そこで、基本的な構成はそのままで、最新の技術を駆使した、 人間に近い受け答えをするアドベンチャーゲームを作ったらどうなるんだろう? などという、割とどうでもいいことを思いつきました。

犯人探しをせず、相棒のヤスとくだらない会話をして楽しんだりするのでしょうか。 楽しみ方としては間違っていないかもしれませんし、 作った側も嫌な気はしないと思います。ですが、どこか、 人間として一線を越えてしまっているようにも思います。

…と書いたところで、いまの、コンピュータと対話するゲームが、 それに近いモノを提供しているのではないか、という気がしてきました。

とはいえ、いまのゲームがどうなっているのか、全然知らないのですが。
もしご存じな方は、ご教示いただけますと幸いです。

 

80年代のチープな画像と、いまの高度な技術との組合せが面白いのでは、 と思ったのですが、書いてみるとそうでもない気がしてきました。

ですが、もう、あとがきを差し替えるだけの気力が、残っておりません。
このまま発行させていただきたいと存じます。

というわけで、経年劣化の荒波に抗いつつ、気力を養う方法を、 これから模索していきたいと思います。がんばろー…。

 

今回も、ここまで読んでいただき、誠にありがとうございました。
次回は、9月21日(日) 未明にお会いしましょう!

 

「いますぐ実践! Linux システム管理」はこちらです。
メルマガの解除、バックナンバーなども、以下からどうぞ。
http://www.usupi.org/sysad/ (まぐまぐ ID:149633)

その他、作者に関するページは、概ね以下にございます。
http://www.usupi.org/kuri/ (まぐまぐ ID:126454)
http://usupi.seesaa.net/ (栗日記ブログ)
http://twitter.com/kuriking/ (twitter)
http://facebook.com/kuriking3 (facebook)


[バックナンバーのトップへ] [Linux システム管理のトップへ]

トップ

バックナンバー
    [日付順] [目的別]

プロフィール

▼ リンク

独学Linux
Linuxデスクトップ環境に関する情報が満載です。 メルマガもありますよ。
Server World
CentOS 6をサーバとしたときの設定例が、これでもかというくらいたくさん載っています。 CentOS以外のディストリビューション(Fedora, Ubuntu)も充実しています。
LINUXで自宅サーバーを構築・導入(Fedora9)
Fedora9のインストールの仕方から管理方法まで、詳しく載っています。 SearchManには情報がもりだくさんです。
マロンくん.NET
〜サーバ管理者への道〜
Linuxをサーバとして使用するための、いろいろな設定方法が載っています。 マロンくんもかわいいです。 なんといっても、マロンくんという名前がいいですね!!
日経Linux
今や数少なくなってしまったLinuxの雑誌。ニュースやガイドもあります。
Linux Square − @IT
@ITが提供する、Linux の情報が満載。 載っていない設定方法はないんじゃないでしょうか。
gihyo.jp…技術評論社
Linuxに限らず様々な技術情報が満載のサイト。 SoftwareDesign誌も、 ソフトウェア技術者は必見です。
SourceForge.JP Magazine
Linux に限らず、オープンソース関連の記事が網羅されています。
ITmediaエンタープライズ:Linux Tips 一覧
Tips というより FAQ 集でしょうか。わからないことがあれば覗きましょう。
IBM developerWorks : Linux
開発者向けですが、勉強になりますよ。
Yahoo!ニュース - Linux
Yahoo!のLinuxに関するニュース一覧です。
栗日記
システム管理とかと全然関係ありませんが、毎日栗の絵を描いています。
システム管理につかれちゃったとき、癒されたいときに、ご覧ください。:-)
WEB RANKING - PC関連
ランキングに参加してみました。押してやってください。

▼ 作ってみました

Add to Google

▼ せんでん




▼ 最近読んだ本

▼ 気に入ってる本