1. 基本
    • Dockerfileの命令
    • トラブル


    基本

    コンテナイメージの自動作成手順をまとめたのが、Dockerfileになります。 中身は以下のようなテキストになります。

    # Dockerfile sample
    FROM docker.io/centos:6
    MAINTAINER vagrant
    
    ADD hosts /etc/hosts
    RUN yum -y install screen
    CMD service iptables stop && bash

    Dockrefaleでは実行する命令を上から順番に書いていきます。 上記の命令は、上から順に、"FROM"、"MAINTAINER”、"ADD"、"RUN"、"CMD"となります。 各命令の右側がDockerfileの命令のパラメータになります。

      Dockerfileの命令

      Dockerfileの主な命令は以下になります。

      FROM作成元のコンテナイメージ
      MAINAINER作成者の名前
      ENVRUNコマンド実行時の環境変数を設定します。
      RUN指定コマンドを実行します。※
      ADDコンテナの中にファイルをコピーします。
      EXPOSEコンテナの中で動作するプログラムが使用するポートを登録
      CMD/ENTRYPOINTコンテナが起動したときに実行される命令を指定

      ※RUNコマンドは複数指定することができますが、1個につき中間イメージ1個が作成されます。 そのため、RUNコマンドを減らせば、使用ディスク容量が減ります。

      • サンプル

      • 開発用MySQLサーバーのDockerfileサンプルです。 MySQLは、公式レポジトリからyumでインストールします。

        # Dockerfile for MySQL server
        # docker build -t my:mysql ./mysql/
        
        FROM docker.io/centos:6
        MAINTAINER vagrant
        
        # MySQL 5.6
        RUN yum -y install http://dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm
        RUN yum -y install mysql-community-server
        EXPOSE 3306
        
        # MySQL initialize
        RUN service mysqld start && mysql -e "GRANT ALL ON *.* to 'root'@'%'; FLUSH PRIVILEGES;" && service mysqld stop
        
        ADD init.sh /usr/local/bin/init.sh
        RUN chmod u+x /usr/local/bin/init.sh
        CMD ["/user/lobal/bin/init.sh"]

        init.shは、Dockerのstopコマンドでmysqlサーバーを停止するためのものです。

        #!/bin/bash
        
        cat <<EOF >> ~/.bashrc
        trap 'service mysqld stop; exit 0' TERM
        EOF
        
        exce /bin/bash
        
        参考 コンテナ停止時にサービスが停止しない

        Dockerfileとinstall.shを同じディレクトリに置くと、buildコマンドでコンテナイメージを作成できます。 今回の例では、mysqlというディレクトリを作成し、そこにDockerfileとinstall.shファイルを置き、そのディレクトリを指定してbuildコマンドを実行します。

        # docker build -t my:mysql ./mysql/

      トラブル

      • サービスが起動しない

      • runコマンドでは、コンテナで実行するコマンドを指定できますが、これを指定するとDockerfileのCMDが実行されません。 DockerfileのCMD命令でサービスの起動を指定している場合、サービスが止まったままになります。

        例 DockerfileのCMDでmysqldを起動するようにしている場合、以下を実行してコンテナを起動してもmysqldは停止しています。
        # docker run -itd --name mysql my:mysql /bin/bash
                          

        対策としては、runコマンドで実行コマンドを指定しないか、DockerfileのCMDをENTRYPOINTに変更するかになります。

        ENTRYPOINT ["/usr/local/bin/init.sh"]

      • コンテナ停止時にサービスが停止しない

      • コンテナを停止して再度起動したとき、mysqldのログをみると、mysqlサーバーが正常にシャットダウンしていなくて、 リカバリー処理が実行さたと記録されていました。 stopコマンドでコンテナを停止しても、コンテナで動作しているサービスは自動で停止しないようです。

        2016-04-11 03:13:56 250 [Note] InnoDB: Database was not shutdown normally!
        2016-04-11 03:13:56 250 [Note] InnoDB: Starting crash recovery.
        2016-04-11 03:13:56 250 [Note] InnoDB: Reading tablespace information from the .i
        bd files...
        2016-04-11 03:13:56 250 [Note] InnoDB: Restoring possible half-written data pages
        2016-04-11 03:13:56 250 [Note] InnoDB: from the doublewrite buffer...
        2016-04-11 03:13:56 250 [Note] InnoDB: 128 rollback segment(s) are active.
        2016-04-11 03:13:56 250 [Note] InnoDB: Waiting for purge to start
        2016-04-11 03:13:56 250 [Note] InnoDB: 5.6.29 started; log sequence number 1626007
        ...
        参考 mysqlが正常終了した場合、以下のようなメッセージがログに記録されます。
        2016-04-11 03:16:27 250 [Note] /usr/sbin/mysqld: Normal shutdown

        そこで調べると、stopコマンドはコンテナ内のプロセスID:1のプロセスを停止して終了するだけのようです。 そのため、Dockerのstopコマンドでサービスも停止したい場合は、対策が必要になります。

        一つの方法として、DockerfileのCMDで以下のようなシェルスクリプト(init.sh)を実行する方法があります。

        #!/bin/bash
        
        cat <<EOF >> ~/.bashrc
        trap 'service mysqld stop; exit 0' TERM
        EOF
        
        exec /bin/bash
        これは、停止させられるコンテナのプロセス(プロセスID 1)が、子プロセスにTERMシグナルを送るのを利用しています。

        参考

        ※参考サイトは、参考書籍「 Docker実践入門――Linuxコンテナ技術の基礎から応用まで 」の著者で、本に詳細な説明があります。