dockerを触ってみる

centosのイメージを持ってくる

公式に解説があるので、それを参考にする。 https://hub.docker.com/_/centos/

途中で公式が解決方法を提供している問題をひとつずつ踏みながら、理解しつつ進むので少しまどろっこしい方法で理解する。

以下のようなDockerfileを作成する。

# cat Dockerfile
FROM centos:7
MAINTAINER "you" 
ENV container docker
RUN yum -y swap -- remove fakesystemd -- install systemd systemd-libs
RUN yum -y update; yum clean all; \
(cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]

イメージをビルドする

Dockerfileからイメージをビルドする。

# docker build --rm -t local/c7-systemd .

作成されたことを確認する。

# docker images
REPOSITORY                          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
local/c7-systemd                    latest              55328d2ac5c8        6 minutes ago       229.4 MB

コンテナを起動する

次に、このイメージからコンテナを作成して、シェルを実行させる。 dockerにおけるコンテナは起動後に必ず一つのプロセスを動かす必要があるようだ。 シェルからapacheをインストールして、起動してみる。

# docker run -it local/c7-systemd  /bin/bash
[root@4747003b4111 /]#
[root@4747003b4111 /]# yum install httpd
[root@4747003b4111 /]# systemctl start httpd.service
Failed to get D-Bus connection: No connection to service manager.
[root@42ebe1f0dcb4 /]# ps auxww
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.2  0.1  11744  1872 ?        Ss   05:09   0:00 /bin/bash
root        18  0.0  0.1  19764  1228 ?        R+   05:09   0:00 ps auxww

コンテナのシェルのプロンプトが現れる。 「-it」はstdinを有効にするために必要らしい。 httpdをインストールして起動してみたが、エラーが出る。 psコマンドを見てもシェルから起動したプロセスしか現れない。これがコンテナか。

Dockerfileを以下のように書き換えて再実行。 apacheをインストールして、systemctlでhttpを起動してinitを実行する。

# cat Dockerfile
FROM centos:7
MAINTAINER "you" 
ENV container docker
RUN yum -y swap -- remove fakesystemd -- install systemd systemd-libs
RUN yum -y update; yum clean all; \
(cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
FROM local/c7-systemd
RUN yum -y install httpd; yum clean all; systemctl enable httpd.service
EXPOSE 80
CMD ["/usr/sbin/init"]

先ほどと同様の方法で起動するが、失敗する。

# docker run -it local/c7-systemd
Usage of loopback devices is strongly discouraged for production use. Either use `--storage-opt dm.thinpooldev` or use `--storage-opt dm.no_warn_on_loop_devices=true` to suppress this warning.
                                                                                                                                                                                                systemd 208 running in system mode. (+PAM -LIBWRAP -AUDIT +SELINUX -IMA +SYSVINIT -LIBCRYPTSETUP -GCRYPT -ACL -XZ)
Detected virtualization 'docker'.

Welcome to CentOS Linux 7 (Core)!

Initializing machine ID from container UUID.
No control group support available, not creating root group.
Please start this container with '-v /sys/fs/cgroup:/sys/fs/cgroup'
Failed to allocate manager object: Operation not permitted

エラーが出て停止する。cgroupに関するエラーのようだ。

これは以下のようにコンテナを実行すると回避できる。

# docker run --privileged -ti -v /sys/fs/cgroup:/sys/fs/cgroup:ro -p 80:80 local/c7-systemd

今度はエラーが出ない。起動時の表示が出たまま 以下のようにすると起動していることを確認できる。

# docker ps
CONTAINER ID        IMAGE                     COMMAND             CREATED             STATUS              PORTS                NAMES
0c3958d6a846        local/c7-systemd:latest   "/usr/sbin/init"    4 minutes ago       Up 4 minutes        0.0.0.0:80->80/tcp   adoring_almeida

変な名前「adoring_almeida」が付いている。なんだろこれ。

試しにホストのlocalhostの80版ポートにアクセスしてみる。

# telnet localhost 80
Trying ::1...
Connected to localhost.
Escape character is '^]'.
GET /

index.htmlが返ってくる。

GETできたので成功だ。

あとは終了して、コンテナを終了しておく。

# docker stop adoring_almeida 
adoring_almeida

他の方法

以下のようにすれば、もっと簡単に検証できらしい。 参照: CentOS 7のDockerコンテナ内でsystemdを使ってサービスを起動する

$ sudo docker run --privileged -d -p 80:80 --name httpd centos:centos7 /sbin/init
$ sudo docker exec -it httpd /bin/bash
# yum install httpd -y
# systemctl enable httpd.service
# systemctl start httpd.service
# exit
$ curl -s http://localhost/ | head -n 1

docker runとdocker execの違いを理解していないため、よくわからなくなってしまった。 以下がそれぞれのコマンドの役割である。

  • docker run コンテナを起動する
  • docker exec 実行中のコンテナで新しいコマンドを実行する

docker runで起動中のコンテナ上で新しいコマンドを起動したければdocker execを使う。

うえのほうで実行していたapacheのインストールと起動が失敗した理由は単純にDockerfileから起動したものに対してシェルを起動したつもりになっていて実はそうなっていなかったのかも。