コンテナ型仮想化技術Dockerを使って開発環境を整備できるか その3

スタッフブログ

インフラエンジニアのキリヤマです。

前回までのその1その2では、いろいろな手法で簡単にDockerを使った仮想環境が動くことや、WordPressを動かせるDockerの使用方法を試してきました。
実際に試してみてDockerの簡単さや速さ、手軽さを実感することはできましたが、実際に目指しているのはDockerを使った開発環境の整備です。ただWordPressが動けばいいというものではなく、開発メンバーやデザイナーたちに実際に開発環境として使ってもらえることが目標です。

今後は、実際にWordPressのテーマ開発などができそうな環境を目指す上で必要な対処を行っていきたいと思います。

コンテナのデータが消えてしまう問題

これまでの例では、WordPressが動く環境ではあるものの、コンテナを消してしまうとWordPressの設定も変更したテンプレートもデータベースの内容も復元されず、次に同じコンテナを起動してもWordPressの初期画面からやりなおしになってしまっていました。せっかくの開発中のデータが途中でなくなってしまうようでは使いやすい環境とは言えないので、今回はこの問題について調べてみました。

Dockerのマウント機能

このデータが消えてしまう問題は、Dockerでは基本的にコンテナを消すと中の状態を復元することができないことが理由です。コンテナ内で作成や編集をしたファイルやフォルダは、コンテナを削除してしまうと消えてしまいますが、Dockerのマウント機能を使えばコンテナを削除しても消えないようにすることができます。

Dockerのマウント機能には、この記事を書いている時点では以下の三種類のマウント方法があります。

方法 説明
バインドマウント (bind) Dockerホスト上のデバイスファイルやディレクトリをコンテナに見せる
ボリュームマウント (volume) Dockerホストが管理するボリュームをコンテナに見せる
一時ファイルシステムマウント (tmpfs) Dockerホストのメモリをファイルシステムとしてコンテナに見せる

今回は、Dockerでも初期の頃から提供されていて、データを保存する目的にも適している バインドマウント(bind) について重点的に調べてみました。
実際にコンテナを起動する際に使うと作成したファイルが保存されるのか、コンテナ内でファイルを作成して確認します。

$ docker run --rm --name test -v /Users/kiriyama/Documents/docker/testmount:/home -it debian:latest sh
Unable to find image 'debian:latest' locally
latest: Pulling from library/debian
e4c3d3e4f7b0: Pull complete
Digest: sha256:8414aa82208bc4c2761dc149df67e25c6b8a9380e5d8c4e7b5c84ca2d04bb244
Status: Downloaded newer image for debian:latest
# cd /home
# ls
# echo 'Hello World!!' > test.txt
# ls
test.txt
# exit

上記では -v オプションでコンテナ内のパス/homeを、ホスト側の/Users/kiriyama/Documents/docker/testmountにマウントしています。
コンテナの起動後、コンテナ内の/homeに移動し、テキストファイルtest.textを作成してexitでコンテナのシェルから抜けています。
起動時に--rmオプションをつけていますので、exitでコンテナの停止とともにコンテナは削除されますが、作成したファイルtest.txtが中身も含めてどうなっているか、もう1度同じコマンドで確認します。

$ docker run --rm --name test -v /Users/kiriyama/Documents/docker/testmount:/home -it debian:latest sh
# cd /home
# ls
test.txt
# cat test.txt
Hello World!!

再度起動したあとも/homeに保存したファイルが中身とともに残っていますね。このバインドマウントを使えば、データを永続的に使用することができそうです。

Docker Composeでのデータの保存

Dockerコマンドではマウント機能で保存できましたが、Docker Composeを使った場合にはどのようにするのが良いか、改めてこちらのマニュアルを確認してみると……

Compose は、サービスによって利用されているボリュームをすべて保護します。docker-compose up が実行されたときに、コンテナがそれ以前に実行されていたものであれば、以前のコンテナから現在のコンテナに向けてボリュームをコピーします。この処理において、ボリューム内に作り出されていたデータは失われることはありません。

という記載がありました。
以前のコンテナがあれば現在のコンテナに向けてコピーする機能のようですが、Docker Composeでもデータが保護される機能があるのは間違いなさそうです。
早速この機能を使って、前回のその2で作成したdocker-compose.ymlを元に、実際にデータが失われないかテストしてみます。

version: '3'

services:
    mysql:
        image: mysql
        restart: always
        volumes:                            # 今回追加
            - ./mysql:/var/lib/mysql        # ホスト側の ./mysql をコンテナ内の /var/lib/mysql にマウント
        environment:
            MYSQL_ROOT_PASSWORD: wordpress
            MYSQL_DATABASE: wordpress
            MYSQL_USER: wordpress
            MYSQL_PASSWORD: wordpress

    wordpress:
        depends_on:
            - mysql
        image: wordpress
        volumes:                            # 今回追加
            - ./wordpress:/var/www/html     # ホスト側の ./wordpress をコンテナ内の /var/www/html にマウント
        ports:
            - "8080:80"
        restart: always
        environment:
            WORDPRESS_DB_HOST: mysql:3306
            WORDPRESS_DB_USER: wordpress
            WORDPRESS_DB_PASSWORD: wordpress

上記のservices > mysql > volumesでは、 ホスト側のパス ./mysql にコンテナ内の/var/lib/mysqlをマウントする形を定義しています。WordPressのコンテンツも同様に保存されるようvolumesを設定しています。

$ docker-compose up -d
Creating network "part3_default" with the default driver
Pulling mysql (mysql:)...
latest: Pulling from library/mysql
  :
49e112c55976: Pull complete
Digest: sha256:8c17271df53ee3b843d6e16d46cff13f22c9c04d6982eb15a9a47bd5c9ac7e2d
Status: Downloaded newer image for mysql:latest
Pulling wordpress (wordpress:)...
latest: Pulling from library/wordpress
  :
Digest: sha256:20bffad04c9c3e696b3c6fbc48d769c5948718b57af8c9457d9a0f28b5066b4b
Status: Downloaded newer image for wordpress:latest
Creating part3_mysql_1 ... done
Creating part3_wordpress_1 ... done

一部省略していますが、コンテナの起動後は、ホスト側では以下のようなフォルダ構成になっています。

$ tree ./ -L 2
./
├── docker-compose.yml
├── mysql
│   ├── #ib_16384_0.dblwr
│   ├── #ib_16384_1.dblwr
│   ├── #innodb_temp
│   ├── auto.cnf
│   ├── binlog.000001
    :
    :
│   └── wordpress
└── wordpress
    ├── index.php
    ├── license.txt
    ├── wp-admin
    :
    :
    └── xmlrpc.php

この状態でブラウザからhttp://localhost:8080にアクセスして、WordPressの初期設定を行いました。

wordpress

これで、初期設定のデータベースのデータや一部のコンテンツファイルが書き換えられたはずですので、コンテナを停止しつつイメージも含めてクリーンな状態にします。

$ docker-compose down --rmi all
Stopping part3_wordpress_1 ... done
Stopping part3_mysql_1     ... done
Removing part3_wordpress_1 ... done
Removing part3_mysql_1     ... done
Removing network part3_default
Removing image mysql
Removing image wordpress
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
$

docker ps -a で見ても、コンテナは削除されています。再度、同じように起動します。

kiriyama:part3$ docker-compose up -d
Creating network "part3_default" with the default driver
 :
 :
Creating part3_mysql_1 ... done
Creating part3_wordpress_1 ... done

ブラウザで再度http://localhost:8080にアクセスすると、初期設定画面ではなく、設定したのWordPressの画面が表示されましたので、WordPressのコンテンツとデータベースのデータが保存されていることが確認できました。

Dockerを使って開発環境の整備はできるか

今回はコンテナを削除してしまうとコンテナ内のデータが削除されてしまう問題について調べてみました。
実際にマウント機能をつかってみると思った以上に簡単で、特にDocker Composevolumesの使い勝手がかなり良く、ホスト側から簡単に参照したり編集したりできるので、サーバ側ミドルウェアの設定のテスト等にも応用できそうです。

次回は、実際に開発メンバーが使っている統合開発環境やソースコードのバージョン管理システムに対応できるような、より現実的なDockerを使った開発環境を検証してみたいと思います。