1コマンドで作った。Dockerで開発環境を構築する方法
最終的にたった1コマンドで開発環境を作り上げてしまう事をゴールにプロジェクトを作成していきます。
前回の記事ではVagrantとDockerの違いに関して開設しましたが、実際にLAMPサーバーを1コマンドで立ち上げて行きたいと思います。
そもそもDockerは何を置き換えるものなのか
Vagrantは仮想マシン自体を管理します。
細かいアプリやシステム構成はAnsibleで整えて、全く同じマシンを用意することが目的でした。
対するDockerはアプリケーションの仮想化という概念で公開されています。
なので、置き換える対象はあくまでApacheやMySQL等のアプリケーションやその依存ライブラリになります。
上がVagrant+Ansibleで、下がDockerを含めた構成図です。
ちょっと待って、内容が増えただけで全然楽になってないじゃん!
そうなのです。
ローカルの開発環境に着目した場合、使うツールが増えた分環境を構築するコストは増えます。
しかし、無駄に複雑になったわけではありません。
Dockerは本番環境へのデプロイを見越して採用します。
思わぬ良い効果もあります。
今まではシステム構築する上でのアプリや依存ライブラリは全てAnsibleで用意する必要がありましたが、全てDockerに逃がせます。
AnsibleはDockerのインストールに集中するだけで良くなったのです。
もうプロジェクトの度にVagrantfileやPlaybookを切り貼りして似たようなファイルを大量に生成することはありません。
VagrantもAnsibleもDockerに置き換わりました
Vagrantに関する記事の執筆当初はVagrant+Ansible+Dockerを組み合わせて最強の開発環境を作る事をゴールにしていました。
既にDocker for WindowsやDocker for Macが正式版になって既に半年が経過しています。
もうVagrant+Ansibleに残っているメリットはクラウドマシンの操作と複数環境を立ち上げるくらいしか残っていません。
特殊な用途でVagrantを活用するケース以外、Dockerのみで開発環境を構築していくスタイルが主流になることでしょう。
よって、次の章からはDocker for WindowsとDocker for Macをベースにすすめていきます。
LAMP環境を立ち上げてみる
まずはDocker for Windows、もしくはDocker for Macを公式サイトからダウンロードしてインストールしましょう。
インストールが完了したら、ターミナルエミュレータを開き、dockerコマンドが利用出来ることを確認します。
確認にはdocker version
コマンドが利用できます。
$ docker version
Client:
Version: 1.13.1
API version: 1.26
Go version: go1.7.5
Git commit: 092cba3
Built: Wed Feb 8 08:47:51 2017
OS/Arch: darwin/amd64
Server:
Version: 1.13.1
API version: 1.26 (minimum version 1.12)
Go version: go1.7.5
Git commit: 092cba3
Built: Wed Feb 8 08:47:51 2017
OS/Arch: linux/amd64
Experimental: true
// Docker for xxxが立ち上がっていない場合
$ docker version
Client:
Version: 1.13.1
API version: 1.26
Go version: go1.7.5
Git commit: 092cba3
Built: Wed Feb 8 08:47:51 2017
OS/Arch: darwin/amd64
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
それではHelloWorldを出力するPHPファイルを生成し、
Dockerで作ったWebサーバーで確認するという事をやってみましょう。
$ cat << EOF > index.php
<?php
echo "Hello", "World";
EOF
$ docker run -d -p "80:80" -v "$PWD:/var/www/html" php:apache
8e7374e208e40776fa8b14742e054a7074ee6d0e815af15590aaff968f1a6c6f
$ curl localhost
HelloWorld
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8e7374e208e4 php:apache "docker-php-entryp..." 31 seconds ago Up 30 seconds 0.0.0.0:80->80/tcp condescending_goldwasser
このdocker run
コマンドが少々長くてややこしい以外はとても楽ですね。
本記事の目的である1コマンドにぐっと近づいたように思えます。
では、同様に初期状態のMySQLサーバーを立ち上げて接続してみましょう。
(mysqlコマンドのlocalhostは通信を行わずにプロセスを直接叩きに行きますので。接続できなければ127.0.0.1や0.0.0.0等を試してみてください。)
$ docker run -d -p "3306:3306" -e MYSQL_ROOT_PASSWORD=test mysql:latest
e5b3f76eb6f393185010326c9c324063abe4d61b3633d5555b097a77f3569118
$ mysql -h 127.0.0.1 -uroot -ptest -e "show databases;"
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f6ecc6d0c10c mysql:latest "docker-entrypoint..." 24 minutes ago Up 24 minutes 0.0.0.0:3306->3306/tcp clever_euler
8e7374e208e4 php:apache "docker-php-entryp..." 41 minutes ago Up 41 minutes 0.0.0.0:80->80/tcp condescending_goldwasser
こちらも1コマンドでMySQLサーバーが立ち上がりました。
これらのサーバーは何者?Docker Hubとの関係
少し脇道に逸れますが、コンテナの中身に迫っていきます。
1コマンドで動作するこれらのサーバーは一体何者なのでしょうか?
以降の流れはドットインストールさんの動画が参考になるので、イメージの湧かない箇所が出てきましたら、都度参考にしてみてください。
Docker入門 – ドットインストール
DockerはイメージというOSの雛形と、イメージを実体化したコンテナの2つで構成されています。
実体化したコンテナは、何時でもdocker commit
コマンドを使ってスナップショットを取るかのようにイメージに戻す事が出来ます。
例えばシステムを構築するために必要な依存モジュールをインストールしたコンテナをdocker commit
で再度イメージにして配布し、本番環境や同僚が利用できます。
DockerはDocker Hubというホスティングサービスもセットです。
ユーザーはDocker Hub上に無料で公開リポジトリを作成し、新たにチューニングを施したイメージを預ける事ができます。
しかし、手作業でソフトをインストールしてから「docker commit」でイメージを作っていてはブラックボックスに入ったままという問題が残ります。
これの対応策として、Dockerfileが用意されています。
Dockerfileを指定してdocker build
コマンド発行すると、プロビジョニングツールで構築するかの如く新しいイメージを生成することが出来ます。
何者か分からないイメージを使うのは怖い、見分け方は?
Vagrantでは誰が作ったか分からない怪しいボックスが雑多に配置され、怖くて使えないというユーザーが続出しました。
(その後公式イメージをユーザーが見分けやすいように整備が進んでいきました)
Docker Hubでは、ユーザーがアカウントを開設してリポジトリを作成した場合、「gladcube/php-apahce」という風に「ユーザー名/イメージ名」という形式で登録されます。
公式のイメージはユーザー部分がありません。
「php」や「mysql」等のようにリポジトリ名に/がありませんので、ユーザーは公式のイメージを簡単にみつけられます。
PHPコンテナはこうして作られた
それではDocker HubにあるPHPのリポジトリを確認してみましょう。
php – Docker Hub
画面上の方に大きくOFFICIAL REPOSITORYと書いてありますね。
これが公式リポジトリの証です。
そして「Full Description」の項目には「Supported tags and respective Dockerfile links」と記載があり。
詳細説明の上部で、サポートしているタグとそれぞれのDockerfileを紹介している事が読み取れます。
各種リポジトリはイメージをどのような流れで作ったかを公開する目的で、利用したDockerfileをGitHubのリポジトリを使って公開することが慣習となっています。
(ただし、これはあくまで自己宣告ですので公式以外のイメージを利用する際は注意してください)
Dockerfileの流れを追ってみよう
では、早速PHP(with Apache)のDockerfileの流れを追っていきましょう。
php/7.1/apache/Dockerfile – GitHub
プロジェクトの大型Dockerfileは慣れるまで読みづらいので、
私の方で抜粋しました。
# L.7: Debianイメージを利用する
FROM debian:jessie
# L.19: 開発用モジュールをインストール
RUN apt-get update
RUN apt-get install -y autoconf file g++ gcc libc-dev make pkg-config re2c ca-certificates curl libedit2 libsqlite3-0 libxml2 xz-utils --no-install-recommends
# L.33: Apacheモジュールをインストール
RUN apt-get install -y apache2-bin apache2.2-common --no-install-recommends
# L.140: PHPのソースコードをコンテナ内に注入
COPY docker-php-source /usr/local/bin/
# L.158: PHPのソースコードをビルド
RUN ./configure
RUN make install
# L.192: コンテナ起動時、Apacheを起動して80番ポートを開ける
EXPOSE 80
CMD ["apache2-foreground"]
普段我々がPHPをインストールする時はパッケージ管理を利用するケースが多いのですが、
沢山のバージョンを作る為にあえてソースコードからコンパイルしているのですね。
他にもApacheにPHPを組み込むあたりの記述もありますので、興味があれば読んでみてください。
中でも注目は7行目のFROM debian:jessie
です。
これはどのイメージを利用するかが記載されており、DockerHubのリポジトリ名:タグで表現されています。
DebianのjessieというコードネームはWikipediaの記事によると、「Debian 8.0(コードネーム: jessie)」と表記されており、
バージョン8.xの最新版である事が伺えます。
debian – Docker Hub
debianのリポジトリにも「8.7, 8, jessie, latest (jessie/Dockerfile)」と書いてあり、
jessieタグは8系の最新バージョンと同列であることがわかります。
FROM scratch
ADD rootfs.tar.xz /
CMD ["/bin/bash"]
因みにdebian:jessieのDockerfileはscratchというイメージを元に作られています。
これは何もファイルが入ってないブランクのイメージを指し、ルートディレクトリにOSの構成ファイルを丸ごと格納する作りになっているようです。
PHPイメージを調整してLAMP仕様に変更
さて、晴れてMySQLのコンテナとWebサーバのコンテナを立ち上げる事が出来ました。
早速PDOモジュールを利用してMySQLに接続していきましょう。
$ cat << EOF > initialize.php
<?php
$user = 'root';
$pass = 'test';
$dbh = new PDO('mysql:host=localhost;', $user, $pass);
$dbh->query("create database hogehoge");
$dbh->query("use hogehoge");
$dbh->query("create table users(id int, name text)");
EOF
$ curl localhost/initialize.php
<br />
<b>Fatal error</b>: Uncaught PDOException: could not find driver in /var/www/html/initialize.php:4
Stack trace:
#0 /var/www/html/initialize.php(4): PDO->__construct('mysql:host=loca...', 'root', 'test')
#1 {main}
thrown in <b>/var/www/html/initialize.php</b> on line <b>4</b><br />
残念、エラーが帰ってきました。
公式のPHPイメージは最小限のモジュールだけ組み込まれています。
「PHPリポジトリの詳細説明」には「PHP Core Extensions」という項目が用意されており、iconvやmcrypt等のパッケージを盛り込む設定例が記載されています。
また、下記のような記事でも紹介されており、丁度DockerでLAMP環境を構築する為に設定が書かれていますので設定内容をお借りしました。
Docker Hubのオフィシャルイメージを使ったLAMP環境(Apache+PHP+MySQL)構築 – Qiita
$ cat << EOF > Dockerfile
FROM php:apache
RUN docker-php-ext-install pdo_mysql mysqli mbstring
EOF
$ docker build -t myphp .
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
myphp latest 3efc7867dc9f 2 minutes ago 391 MB
php apache a05317fca519 6 days ago 389 MB
mysql latest 7666f75adb6b 4 weeks ago 406 MB
$ docker run -d -p "80:80" -v "$PWD/public:/var/www/html" myphp
5a8971798f1adc01fda296c711b86b152a1af7f53e52766999601a4c20a34dc0
$ curl localhost/initialize.php
<br />
<b>Fatal error</b>: Uncaught PDOException: SQLSTATE[HY000] [2002] No such file or directory in /var/www/html/initialize.php:4
Stack trace:
#0 /var/www/html/initialize.php(4): PDO->__construct('mysql:host=loca...', 'root', 'test')
#1 {main}
thrown in <b>/var/www/html/initialize.php</b> on line <b>4</b><br />
まだエラーが出ます。
これはPHPの乗っているApacheサーバーからMySQLのサーバーが見えていない事が原因です。
次の章ではそれぞれのサーバーを紐付ける設定を紹介していきます。
MySQLサーバーとPHPサーバーを接続する
立ち上げたコンテナ同士は異なる仮想マシンという扱いになり、
各々の仮想マシンには異なるIPアドレスが割り振られます。
(IPアドレスの確認コマンドはDockerのネットワークの基礎 – SOTAを参考にさせて頂きました)
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e5b3f76eb6f3 mysql:latest "docker-entrypoint..." 2 days ago Up 2 days 0.0.0.0:3306->3306/tcp ecstatic_boyd
5a8971798f1a myphp "docker-php-entryp..." 2 days ago Up 2 days 0.0.0.0:80->80/tcp condescending_goldwasser
$ docker inspect --format '{{ .NetworkSettings.IPAddress }}' e5b3f76eb6f3
172.17.0.3
$ docker inspect --format '{{ .NetworkSettings.IPAddress }}' 5a8971798f1a
172.17.0.2
docker run
にはlinkというオプションが存在します。
linkオプションを指定して立ち上げると、その対象のマシンのIPアドレスが/etc/hostsファイルに書き込まれます。
こうして他のコンテナにリンク名をすることで接続できます。
早速接続してみましょう。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e5b3f76eb6f3 mysql:latest "docker-entrypoint..." 2 days ago Up 2 days 0.0.0.0:3306->3306/tcp ecstatic_boyd
5a8971798f1a myphp "docker-php-entryp..." 2 days ago Up 2 days 0.0.0.0:80->80/tcp condescending_goldwasser
// 一度phpコンテナは削除
$ docker rm -f 5a8971798f1a
5a8971798f1a
$ docker run -d -p "80:80" -v "$PWD/public:/var/www/html" --link ecstatic_boyd:mysql myphp
b79bd2724e7f186fd9a57e5757bdf9285787b8bdf6ee673ade0fec98cee9df4c
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b79bd2724e7f myphp "docker-php-entryp..." 19 minutes ago Up 19 minutes 0.0.0.0:80->80/tcp wizardly_goldwasser
e5b3f76eb6f3 mysql:latest "docker-entrypoint..." 3 days ago Up 3 days 0.0.0.0:3306->3306/tcp ecstatic_boyd
$ docker exec b79bd2724e7f cat /etc/hosts | grep mysql
172.17.0.3 mysql e5b3f76eb6f3 ecstatic_boyd
$ cat << EOF > initialize.php
<?php
$user = 'root';
$pass = 'test';
$dbh = new PDO('mysql:host=mysql;', $user, $pass);
$dbh->query("create database hogehoge");
$dbh->query("use hogehoge");
$dbh->query("create table users(id int, name text)");
$result = $dbh->query("show create table users;");
var_dump($result);
EOF
$ curl localhost/initialize.php
object(PDOStatement)#2 (1) {
["queryString"]=>
string(24) "show create table users;"
}
おお、遂にPHPとMySQLが繋がりましたね!
概念は複雑ですが、慣れてしまえば殆どコードもコマンドも最小限にサーバーの定義が書けてしまいます。
Docker Composeを活用して1コマンド運用を実現する
1コマンドで簡単にサーバーが立ち上がるとはいえrunコマンド長すぎですね。
Shell Scriptにでもまとめて……というのはちょっと待って下さい。
公式がDocker Composeというオーケストレーションツールを用意してくださっています。
そのインストール方法も公開されています。
// パスの通っているフォルダにダウンロードします。
$ curl -L "https://github.com/docker/compose/releases/download/1.11.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
// 実行権限を付与
$ chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
docker-compose version 1.11.1, build 7c5d5e4
Docker ComposeはDockerコマンドをラッピングしているだけですので、
Docker for xxxからでも、DockerをインストールしたLinuxマシンでも同様のインストール方法で導入できます。
Docker Composeコマンドはカレントディレクトリにdocker-compose.ymlファイルが存在すると使用できます。
// 前章の2つのコンテナは削除
$ docker rm -f b79bd2724e7f e5b3f76eb6f3
b79bd2724e7f
e5b3f76eb6f3
$ cat << EOF > docker-compose.yml
version: "2"
services:
web:
build: .
container_name: web
image: myphp
ports:
- "80:80"
links:
- mysql
volumes:
- .:/var/www/html
restart: always
mysql:
container_name: mysql
image: mysql
environment:
MYSQL_ROOT_PASSWORD: test
ports:
- "3306:3306"
restart: always
EOF
$ docker-compose up -d
Creating mysql
Creating web
$ docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------
mysql docker-entrypoint.sh mysqld Up 0.0.0.0:3306->3306/tcp
web docker-php-entrypoint apac ... Up 0.0.0.0:80->80/tcp
docker-compose.ymlの書き方は最初はとっつきにくいですが、docker run
コマンドのオプションの定義が殆ど使えますので簡単に記述できます。
コマンドをシンプルにまとめる
docker-composeコマンドに慣れてしまえば上記で1コマンド達成と言っても良いかもしれません。
しかし、プロジェクトにはDockerに詳しくないメンバーが居る可能性もありますので、
頻出のコマンドをテキストファイルで残す事にしました。
$ mkdir bin
$ cat << EOF > bin/start
#!/bin/bash
script_dir="$(cd "$(dirname "${BASH_SOURCE:-${(%):-%N}}")"; pwd)"
cd "$script_dir/../"
docker-compose up -d
EOF
$ chmod +x bin/*
$ bin/start
Creating mysql
Creating web
これで新しく参入してきたメンバーにも簡単に1コマンドでサーバーを起動することが出来るようになります。
新しくジョインしたメンバーには、bin配下のシェルスクリプト読むように伝えればすぐに理解出来るかと思います。
今回はaddコマンドのみ作成しましたが、
幾つかの頻出コマンドをまとめてプロジェクトとして公開しました。
(またプロジェクトとして機能し易いようにディレクトリ分けも行いました)
簡単なコードばかりですので是非一度読んでみて下さい。
まとめ
いかがでしたでしょうか?
ついに目標であった1コマンドで環境構築を実現することが出来ました。
もちろんこれで全てが解決した訳ではありません。
デプロイするフローを考えたり、プロジェクトやソースコードの管理していくには様々な技術との組み合わせが必要になっていくことと思います。
その上で、開発環境構築という1分野に於いて少しでも参考になれば幸いです。
もし良ければこの方法にあなたのアイデアを盛り込んでいただき、
さらにクールな開発環境を構築してみてください。
以上、「1コマンドで作った。Dockerで開発環境を構築する方法」でした。
最後まで読んでいただきありがとうございました。
-
お問い合わせ
SiTest の導入検討や
他社ツールとの違い・比較について
弊社のプロフェッショナルが
喜んでサポートいたします。 -
コンサルティング
ヒートマップの活用、ABテストの実施や
フォームの改善でお困りの方は、
弊社のプロフェッショナルが
コンサルティングいたします。
今すぐお気軽にご相談ください。
今すぐお気軽に
ご相談ください。
(平日 10:00~19:00)
今すぐお気軽に
ご相談ください。
0120-315-465
(平日 10:00~19:00)
グラッドキューブは
「ISMS認証」を取得しています。
認証範囲:
インターネットマーケティング支援事業、インターネットASPサービスの提供、コンテンツメディア事業
「ISMS認証」とは、財団法人・日本情報処理開発協会が定めた企業の情報情報セキュリティマネジメントシステムの評価制度です。