dockerとdocker-composeの基本が理解できるような記事にしたい。
技術系の記事投稿先を自前のBlogに移しました。初心者向け,AWSなど幅広いTechジャンルで記事投稿がんばってますので、よろしかったらこちらも参照ください!
準備
docker for mac を利用します。
インストールはおそらく簡単だと思います。うまくインストールされればメニューバーにクジラが現れ "Docker is running" となるはずです。
docker および docker-compose コマンドも合わせてインストールされているはずです
- docker
$ docker version
Client:
Version: 18.03.1-ce
API version: 1.37
Go version: go1.9.5
Git commit: 9ee9f40
Built: Thu Apr 26 07:13:02 2018
OS/Arch: darwin/amd64
Experimental: false
Orchestrator: swarm
Server:
Engine:
Version: 18.03.1-ce
API version: 1.37 (minimum version 1.12)
Go version: go1.9.5
Git commit: 9ee9f40
Built: Thu Apr 26 07:22:38 2018
OS/Arch: linux/amd64
Experimental: true
- docker-compose
$ docker-compose version
docker-compose version 1.21.1, build 5a3f1a3
docker-py version: 3.3.0
CPython version: 3.6.4
OpenSSL version: OpenSSL 1.0.2o 27 Mar 2018
docker
Docker Hubというdockerで利用できる様々なサーバイメージが保存されている。
主に使い方としては
- 利用したいものをそのまま利用する (Databaseやkvsなどすでにアプリケーションが機能として盛り込まれたイメージもたくさんある)
- 利用したい環境の土台となるイメージを利用し、それをカスタマイズして自分用に追加で機能が盛り込まれたイメージ作成し利用する
お試し起動(コンテナの起動と停止)
まずは docker の基本を抑えたいので、CentOS のOSがインストールされたシンプルなイメージを利用してみる。
$ docker run centos
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
469cfcc7a4b3: Pull complete
Digest: sha256:989b936d56b1ace20ddf855a301741e52abca38286382cba7f44443210e96d16
Status: Downloaded newer image for centos:latest
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9a9ebeb47eb4 centos "/bin/bash" 7 seconds ago Exited (0) 10 seconds ago boring_hamilton
3つコマンドを実行した。
まず docker run centos
で centos というイメージを起動するというコマンドを実行。
ローカルに指定のイメージがある場合はそこから起動、ない場合は前述のDocker Hubからダウンロードして起動する
次に docker ps
。 このコマンドで実行中のdocker(コンテナ)の一覧が表示される。が、何も表示されないはず。
最後に docker ps -a
。 -a オプションをつけることで終了したコンテナも含めて一覧される。ここに最初に起動したコンテナが終了済みとしてリストされるはず。 終了済みのコンテナに関しても再度復帰できるので停止状態のコンテナとして残り続ける。マシンのリソース(HDD)を消費してしまうので、再び起動しないならば、以下のコマンドで削除するとよい。
$ docker rm 9a9ebeb47eb4
9a9ebeb47eb4
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ここで 9a9ebeb47eb4
というあたいはコンテナIDと呼ばれ、特定のコンテナを指し示すIDである。よって、各環境でこれは異なるはずなので docker ps (-a)
を実行した時に表示されるIDを利用する。 (NAMEを指定してわかりやすいラベルでコンテナを特定することも可能)
Tips:コンテナIDにラベルをつける
# name をコンテナに付与して操作する例
$ docker run --name mycentos centos
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4f2b3e7b91b5 centos "/bin/bash" 3 seconds ago Exited (0) 7 seconds ago mycentos
$ docker rm mycentos
mycentos
コンテナ内での操作
centos イメージで起動したはずが即時終了してしまいこれでは意味がない。これは ps で見た時に確認できるが COMMAND = "/bin/bash"
とあり、centosを起動し /bin/bash
を実行 (この最初に起動するコマンドはイメージに仕込まれている)、それが即時(TTYがないので) exit(0)
されたのでコンテナも終了した状態となっている。
コンテナを起動しつつ、操作可能にするには docke run
に -it
オプションを付与して起動すればよい
$ docker run -it centos
[root@c7827f28ee8d /]#
[root@c7827f28ee8d /]# ls /
anaconda-post.log bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
[root@c7827f28ee8d /]# cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)
[root@c7827f28ee8d /]# exit
exit
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c7827f28ee8d centos "/bin/bash" 5 minutes ago Exited (0) 15 seconds ago suspicious_liskov
-it
を付与して起動したらプロンプトが変化する。コンソールはコンテナの中を操作する状態になる。 centos 環境にログインして操作しているのと同様の操作が可能でになる。作業を exit
で終了すると、mac側に制御が戻り、またコンテナは停止の状態となる。
Tips:Docker Imageの選択方法とImageの管理
今回利用したimageは centos であり初回利用時に Docker Hub からダウンロードしたと前述した。そのimageを確認するには docker images
コマンドを利用する
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest e934aafc2206 7 weeks ago 199MB
イメージは REPOSITORY:TAGで一意に識別される。今回 centos
とのみ指定してるがそれは centos:latest
でありそれは Docker Hubに記載されている通り centos7 を意味する。 centos6を利用したい場合は以下のようにTAGでそれを指定すればよい。以下はcentos6を選択した場合の操作になる。
$ docker run -it centos:6
Unable to find image 'centos:6' locally
6: Pulling from library/centos
987d765a926d: Pull complete
Digest: sha256:67b491e26d566ee9c55578bfd6115554a6e1b805a49502ead32cb1a324466f2c
Status: Downloaded newer image for centos:6
[root@01a74d994685 /]# cat /etc/redhat-release
CentOS release 6.9 (Final)
[root@01a74d994685 /]# exit
exit
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos 6 70b5d81549ec 7 weeks ago 195MB
centos latest e934aafc2206 7 weeks ago 199MB
不要なimage もリソースの無駄なので削除することも可能。その場合は docker rmi
コマンドを利用する。
$ docker rmi 70b5d81549ec
Error response from daemon: conflict: unable to delete 70b5d81549ec (must be forced) - image is being used by stopped container 01a74d994685
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
01a74d994685 centos:6 "/bin/bash" 2 minutes ago Exited (0) 2 minutes ago nifty_swanson
c7827f28ee8d centos "/bin/bash" 20 minutes ago Exited (0) 14 minutes ago suspicious_liskov
$ docker rm 01a74d994685
01a74d994685
$ docker rmi 70b5d81549ec
Untagged: centos:6
Untagged: centos@sha256:67b491e26d566ee9c55578bfd6115554a6e1b805a49502ead32cb1a324466f2c
Deleted: sha256:70b5d81549ec19aa0a10f8660ba5e1ab9966008dbb1b6c5af3d0ecc8cff88eef
Deleted: sha256:e0dec291ae94d0f486c2a6a98732bac23e45b0914f8f9e67c57c5e6a2cd7fed7
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest e934aafc2206 7 weeks ago 199MB
イメージの削除はdocker images
で表示されるイメージIDを指定する。上の例では docker rmi
で centos6 のイメージの削除を試みている。 しかし Error
となり削除が失敗していることが確認できる。これは停止中のコンテナが利用しているimageのためである。停止中のコンテナを削除してからイメージの削除した後、再び実行して正常に削除されていることが確認できる。
コンテナへのアタッチとデタッチ
さて、手順通り進めた場合、現在のコンテナの状況はcentos7のコンテナが停止中というステータスだと思う。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c7827f28ee8d centos "/bin/bash" 25 minutes ago Exited (0) 20 minutes ago suspicious_liskov
これを再び起動するには docker restart
を実行する
$ docker restart c7827f28ee8d
c7827f28ee8d
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c7827f28ee8d centos "/bin/bash" 27 minutes ago Up 21 seconds suspicious_liskov
$
ステータスが Up と表示され起動中に再びなったことがわかる。しかしコンソールの制御はmacにあり、起動したコンテナ内ではない。再びコンテナの中に入るには docker attach
コマンドを実行すればよい
$ docker attach c7827f28ee8d
[root@c7827f28ee8d /]# ls
作業中に一度macに制御を戻したい場合、 exit とすると先ほどの通りコンテナが停止状態になり再び利用したい場合 docker restart
からやり直さなければならず非効率である。コンテナを起動したまま制御をmacに戻したい場合は、コンテナ内で Ctrl + p q
(Ctrlを押したまま p q と続けて押す)とすればよい。コンテナを起動したままmacに制御が戻る。この操作をアタッチの逆でデタッチと呼ぶ。
コンテナ(イメージ)のカスタマイズ
コンテナのカスタマイズをしてみる。起動中のCentOSにhttpdをインストールしてウエブサーバ化してみる。(DockerHubには httpdのイメージも当然存在しこれを利用すればウエブサーバは簡単に利用できる。が今回はお勉強なので素のCentOSから自前で構築する )
$ docker attach c7827f28ee8d
[root@c7827f28ee8d /]# yum update -y
[root@c7827f28ee8d /]# yum install httpd -y
上のコマンドで httpd がコンテナの中にインストールされた。(普通にcentosを扱う感じで作業すればよい)
ただし起動に関しては通常と異なる。普段の場合はsystemctl等でhttpdサービスを起動するがコンテナ内でこのコマンドを実行すると
# systemctl
Failed to get D-Bus connection: Operation not permitted
と許可されない旨のメッセージが表示される。コンテナを起動した場合、通常にその制御が可能ものは起動プロセス(この場合は /bin/bash
以下であり、上位プロセスの制御は許可されないためである。これを回避する起動方法もあるが一般には利用しないケースが多い )
では、どうやってhttpdを起動するのかというと以下のように起動させる。
# /usr/sbin/httpd -DFOREGROUND
フォワグランドで起動しているためコンソールの制御がhttpdのループに入ってしまい操作できない。この対処はあとで解説するとしてまずは起動がされているかを確認する。 macで別のコンソールを開きそこでこのコンテナ内でコマンドを実行する
$ docker exec c7827f28ee8d ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 11828 2908 pts/0 Ss 04:01 0:00 /bin/bash
root 15 0.0 0.3 224028 7612 pts/0 S+ 04:01 0:00 /usr/sbin/httpd -DFOREGROUND
apache 16 0.0 0.2 224028 6052 pts/0 S+ 04:01 0:00 /usr/sbin/httpd -DFOREGROUND
apache 17 0.0 0.2 224028 6052 pts/0 S+ 04:01 0:00 /usr/sbin/httpd -DFOREGROUND
apache 18 0.0 0.2 224028 6052 pts/0 S+ 04:01 0:00 /usr/sbin/httpd -DFOREGROUND
apache 19 0.0 0.2 224028 6052 pts/0 S+ 04:01 0:00 /usr/sbin/httpd -DFOREGROUND
apache 20 0.0 0.2 224028 6052 pts/0 S+ 04:01 0:00 /usr/sbin/httpd -DFOREGROUND
root 33 0.0 0.1 51716 3508 ? Rs 04:02 0:00 ps -aux
$ docker exec c7827f28ee8d curl localhost
...
$ docker exec -it 00320d5b01de /bin/bash
↑ exec を -it 付きで /bin/bash 起動するとコンテナの中に入れる
確かにhttpdが起動していることがわかる。 (※ docker exec
というコマンドを利用したがこれは指定したコンテナの中で引数のコマンドを実行する操作である。別のmacでdocker attach
をした場合は目的のことはできないので、この場合は exec
とする。 attach
した場合どうなるのか試してみるのもよい)
さて、起動はできたものの、これでは実用的にイマイチ感がある思うのでさらに進める
イメージの作成
centosのイメージに自前でhttpdをインストールしたコンテナを作成した。これをイメージとして保存する。まずは起動中のhttpdを停止し(Ctrl+c) exitでコンテナを抜け、コンテナを停止状態にする
[root@c7827f28ee8d /]# exit
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c7827f28ee8d centos "/bin/bash" About an hour ago Exited (0) 7 seconds ago suspicious_liskov
この停止したコンテナ(c7827f28ee8d)をイメージ化する。イメージ化するには docker commit
コマンドを利用する
$ docker commit c7827f28ee8d mycentos_with_httpd
sha256:d1b7ab953d99d9675e2b8ef7b02bbed765845474c6fe1d7195e66f3640f7f3d2
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos_with_httpd latest d1b7ab953d99 Less than a second ago 453MB
centos latest e934aafc2206 7 weeks ago 199MB
以上により httpd入りのcentosイメージ mycentos_with_httpd がローカルに作成された。試しにこのイメージでコンテナ起動してみるとhttpdがインストール済みであることがわかる。
$ docker run -it mycentos_with_httpd
[root@2184a0e23ad1 /]# ls -l /usr/sbin/httpd
-rwxr-xr-x 1 root root 523688 Apr 20 18:11 /usr/sbin/httpd
[root@2184a0e23ad1 /]# exit
exit
コンテナのデーモン起動
作成したhttpd入りコンテナをhttpdを起動した状態でコンテナ起動させてみる。前回はログインした後、コマンドにて /usr/sbin/httpd -DFOREGROUND
と手動にて起動したがこれを docker run
の引数に与えることでそれが実現できる。さらに加えて -d
のオプションを加えるとコンテナの起動をデーモン化できる。実際にやってみると
$ docker run -d mycentos_with_httpd /usr/sbin/httpd -DFOREGROUND
9dee4a08b3e674031c142ffaafacf616743e57648b80af4276cf9eb19b10cfda
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9dee4a08b3e6 mycentos_with_httpd "/usr/sbin/httpd -DF…" 3 seconds ago Up 11 seconds practical_goldstine
上のように docker run
のあとも引き続きmacの制御下であるが docker ps
をみるとコンテナが起動中である。前の実験で試した別コンソールで...という確認をやってみても同様の結果となりコンテナ内でhttpdが動作していることが確認できるはず.
この状態で起動したコンテナを停止させる場合は docker stop
をすればよい。
$ docker stop 9dee4a08b3e6
9dee4a08b3e6
Tips: -rm でコンテナ起動でお掃除ラクラク
操作を試行錯誤すると docker ps -a
で確認できる停止中のコンテナが量産される。これを都度 docker rm
で消去するのは手間である。これを回避するために、停止した段階でrmも合わせて行ってくれる(再び起動する必要が無い場合は活用すると便利)
$ docker run -it --rm centos
[root@fc9882d2aa18 /]# exit
exit
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
※停止中のコンテナは無い!
PortマッピングとVolumeマッピング
これまでの起動方法ではコンテナと母艦であるmacとの関連が無いが、開発を行う上ではソースファイルの共有および動作確認等でmac側とコンテナの関連をもたせたいニーズはある。まずは先のhttpd入りのコンテナ上で起動したhttpをmac側のブラウザから確認するポートマッピングを行う。
$ docker run --rm -d -p 8080:80 mycentos_with_httpd /usr/sbin/httpd -DFOREGROUND
-p 8080:80
がそれにあたり、ローカル(mac)側の8080ポートをコンテナの80ポートにマッピングする指定である。これによりmac側でブラウザを開き http://localhost:8080/
でのアクセスでコンテナ内のhttpdにアクセスできる。
次にVolumeマッピングについて説明する。 ポートと同様にmacのファイルシステムをコンテナ側にマッピングする。
$ mkdir -p httpd/log
$ mkdir -p httpd/www
$ echo 'hello world' > httpd/www/index.html
$ docker run --rm -d -p 8080:80 -v `pwd`/httpd/log:/var/log/httpd -v `pwd`/httpd/www:/var/www/html mycentos_with_httpd /usr/sbin/httpd -DFOREGROUND
ef6eda9a9abdfa72ebc5bb536f0d5682138cafe6323044af90d8b619c8c96d17
これでmacよりhttp://localhost:8080/
でアクセスするとmac側のhttpd/www/index.html
で保存された'hello world'が表示され、かつ、httpdのアクセスログがmac側の `httpd/log/access_logに記録される
$ tail -f httpd/log/access_log
172.17.0.1 - - [26/May/2018:05:04:04 +0000] "-" 408 - "-" "-"
172.17.0.1 - - [26/May/2018:05:04:04 +0000] "-" 408 - "-" "-"
172.17.0.1 - - [26/May/2018:05:04:04 +0000] "-" 408 - "-" "-"
Dockerfile
簡単なhttpd入りのイメージを作成したがInfrastructure as Codeの考えでいくとこのプロセスはコードとして手順化されポータブルなものであるのが望ましい。それを実現するに Dockerfile
を説明する。
Dockerfileとは規定の文法で記載されたDocker Imageの作成が記録されたファイルである。詳細まで説明すると長くなるので基本のみ説明する。上で作成したcentosをベースにhttpdインストールされたイメージを構成するDockerファイルは以下のようになる。
(記事を書いた当初はcentosのlatestバージョンは7でしたが現在は8のため明示的にFROM centos:7 としなければいけません。2020.9.3)
FROM centos:7
RUN yum update -y \
&& yum install httpd -y \
&& echo "hello world from dockerfile" > /var/www/html/index2.html \
&& yum clean all
ADD ./httpd/www/index.html /var/www/html/
ENTRYPOINT ["/usr/sbin/httpd", "-DFOREGROUND"]
若干異なる点はイメージのサイズを削減するためにyum clean all
を行った上でイメージ化する。 index.html はmac上にあるファイルをイメージに含ませる。 index2.htmlを新たに作った。 外部に公開するPortも指定し(EXPOSE)、 ENTRYPOINTにてdocker run
したときにデフォルトの起動コマンドもここで指定できる。このファイルを Dockerfile
というファイル名で保存する
(Dockerfile内の EXPOSE 記述は不要であるとのご指摘がありましたので削除いたしました。 2021.8.18)
ここからimageの作成はdocker build
コマンドで行う。具体的には
$ docker build . -t mycentos_with_httpd_from_dockerfile
...
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos_with_httpd_from_dockerfile latest 348670313724 Less than a second ago 403MB
mycentos_with_httpd latest d1b7ab953d99 About an hour ago 453MB
centos latest e934aafc2206 7 weeks ago 199MB
とすればimageが作成される。起動時にはENTRYPOINTを指定ずみのため
$ docker run -d --rm -p 8080:80 mycentos_with_httpd_from_dockerfile
で起動できる. http://localhost:8080/index.html
と http://localhost:8080/index2.html
どちらもmacのブラウザから確認できる。
Dockerfileは Docker Hubで公開されているImageにもそれぞれのイメージの元となるDockerfileがありそれも確認できるのでDockerfileの描き方の参考になる。
Tips: Docker HubのMySQL入りのイメージを使ってみる
docker-composeの説明で簡単なアプリケーションを作成するがその前にそれに利用するDockerHubにあるMySQLイメージの使い方に慣れておく。 DockerHub MySQLのページを確認すると latest は最近リリースされたMySQL8であることがわかる(2018/5現在)
今回はMySQL5.7を利用する。
まずは単純にdocker run してみる
$ docker run mysql:5.7
Unable to find image 'mysql:5.7' locally
5.7: Pulling from library/mysql
f2aa67a397c4: Pull complete
...
Digest: sha256:f030e84582d939d313fe2ef469b5c65ffd0f7dff3b4b98e6ec9ae2dccd83dcdf
Status: Downloaded newer image for mysql:5.7
error: database is uninitialized and password option is not specified
You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD
imageはダウンロードされたがエラーがでて起動できない。ROOTパスワードを指定しなさいと書いてある。なので正解は
$ docker run -d --rm --env MYSQL_ROOT_PASSWORD=secret mysql:5.7
2e1ae9100124010771716cb93b2a0f843261fc3e4f28bfedee50bd7f12002b7f
である。これでMySQLコンテナがデーモンで起動する。 --env
にて環境変数を与えて起動する方法はよくあるので覚えとくと良い。
実際にコンテナ内のMySQLを利用してみる
$ docker exec -it 2e1ae9100124 /bin/bash
root@2e1ae9100124:/#
root@2e1ae9100124:/# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.22 MySQL Community Server (GPL)
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
mysql> show variables like 'version';
+---------------+--------+
| Variable_name | Value |
+---------------+--------+
| version | 5.7.22 |
+---------------+--------+
1 row in set (0.00 sec)
ここでcreate table で Tableを作成するも当然、コンテナが破棄され再び起動した場合はイメージから再び起動されるのでそのテーブルは存在しない(stopからrestartした場合はファイルシステムは生きたままなので残る)
mysql> create database test;
mysql> connect test;
Connection id: 3
Current database: test
mysql> create table sample ( msg varchar(64) );
Query OK, 0 rows affected (0.03 sec)
mysql> insert into sample values ('hello');
Query OK, 1 row affected (0.01 sec)
mysql> insert into sample values ('world');
Query OK, 1 row affected (0.01 sec)
mysql> select * from sample;
+-------+
| msg |
+-------+
| hello |
| world |
+-------+
2 rows in set (0.00 sec)
mysql>
データベースの情報を永続化するためにはmac側にDB情報を保存すればよく、それにはVolumeマッピングを利用すれば良い。
$ mkdir -p mysql/data
$ docker run -d --rm -v `pwd`/mysql/data:/var/lib/mysql --env MYSQL_ROOT_PASSWORD=secret mysql:5.7
54cf2b615ca1e9178966ff347354f1752b968351f0ed72f73865ffc0072c170a
$ ls mysql/data/
auto.cnf client-cert.pem ib_logfile0 ibtmp1 private_key.pem server-key.pem
ca-key.pem client-key.pem ib_logfile1 mysql public_key.pem sys
ca.pem ib_buffer_pool ibdata1 performance_schema server-cert.pem
mysql のコンテナを起動した際に初期DBが作成されそのファイルがvolumeマッピングしたmac上に保存されていることがわかる。テーブルを作成してコンテナを停止(破棄)した後、同コマンドで再び起動するとデータが永続化されていることが確認できる。
また今回使用したMySQL5.7のDockerfileを確認すると起動時にdocker-entrypoint.shというスクリプトが実行され
-
$DATADIR
が存在しない場合のみMySQLの初期DBの構築は行う。 -
/docker-entrypoint-initdb.d/
に保存されたユーザ定義の初期化スクリプトを起動時に実行する(初期tableデータ作成などに利用)
といった挙動をすることもわかる。
docker-compose
docker-compose は複数のコンテナを組み合わせて1つのアプリケーションとして構成を定義するファイルである。
具体的なイメージが湧きづらいので簡単なアプリケーションをこれを用いて構築する過程で説明する。
作成するアプリケーション
簡単な2層アーキテクチャのアプリケーションを想定する。フロントエンドとしてPHPが動作するhttpdサーバであり、そこから接続するMySQLという構成にする。PHPからMySQLに接続し、Userからのリクエストの延べ回数をカウントしDBに保存する。ユーザにはカウンタの値を表示し、DBは永続してそのカウンタ情報を保持する。
User <-−80--> HTTPD w/PHP <--3306--> MySQL
アプリケーションを構成するファイル群
./app
./app/counter.php
./mysql
./mysql/init
./mysql/init/init.sql
./mysql/data
./htdocs
./docker-compose.yml
./build
./build/phpapp
./build/phpapp/Dockerfile
docker-compose.yml
の中身は以下の通りになる
version: "2"
services:
mysql:
image: mysql:5.7
ports:
- "3306:3306"
volumes:
- "./mysql/init:/docker-entrypoint-initdb.d"
- "./mysql/data:/var/lib/mysql"
environment:
- MYSQL_ROOT_PASSWORD=secret
command: --innodb-use-native-aio=0
phpapp:
image: phpapp
build: ./build/phpapp
volumes:
- "./app:/var/www/html"
ports:
- "8080:80"
※services.mysq.command: --innodb-use-native-aio=0 の項目はwindows環境下で動作上必要との指摘ありましたので追記します (2020.9.2)
このdocker-composeファイルには以下のアーキテクチャの"仕様"が盛り込まれている
- このシステムは2つのコンテナ(サービス)で構成されそれぞれ "mysql"、"phpapp" という名称とする。
- "mysql"サービスはDocker Hubの mysql:5.7 というimageを利用する
- "phpapp"サービスはphpappというimageを利用する。そのimageは
./build/phpapp/Dockerfile
を利用して作成されたものを利用する - "mysql" コンテナは
./mysql/init
ディレクトリを/docker-entrypoint-initdb.d
にマウントする。 mysqlイメージの仕様からそこにある init.sql がコンテナ作成時に実行される - "mysql" コンテナは
./mysql/data
ディレクトリを/var/lib/mysql
にマウントする。これによりコンテナ内のMySQLデータはmac上で管理されそれは永続化される - MySQLのROOTパスワードを指定する
- "phpapp"コンテナは
./app
を/var/www/html
にマウントする. app内のファイルはphp実行ファイルでありhttpd上で動作するアプリケーションとなる - "phpapp"の80ポートはmac上の8080ポートにバインドする。
以下にそれぞれのファイルの中身を記す。
(Dockerfile内の EXPOSE 記述は不要であるとのご指摘がありましたので削除いたしました。 2021.8.18)
FROM centos
RUN yum update -y \
&& yum install httpd php php-mysql php-pdo -y \
&& echo "Hello from httpd" > /var/www/html/index.html \
&& echo "<?php phpinfo(); " > /var/www/html/index.php \
&& yum clean all
ENTRYPOINT ["/usr/sbin/httpd", "-DFOREGROUND"]
phpappを構成するDockerfileは先のhttpdで作ったものに類似している。異なる点は phpおよびphpからmysqlに接続するドライバ類(php php-mysql php-pdo)を合わせてインストールしている点である。
CREATE DATABASE IF NOT EXISTS test;
CONNECT test;
CREATE TABLE IF NOT EXISTS counter (
id INT AUTO_INCREMENT PRIMARY KEY,
create_at TIMESTAMP
);
MySQLのアプリケーションで利用するTable定義である。単純にアクセスを記録するTableである。
<?php
ini_set( 'display_errors', 1 );
date_default_timezone_set('Asia/Tokyo');
$pdo = new PDO(
'mysql:dbname=test;host=mysql;charset=utf8mb4',
'root',
'secret'
);
$stmt = $pdo->prepare("INSERT INTO counter () VALUE ()");
$stmt->execute();
$stmt = $pdo->prepare("SELECT * FROM counter ORDER BY id DESC limit 1");
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
?>
ユーザがアクセスするHTTPD上で動作するPHPアプリケーション。MySQLに接続してTableにアクセスを記録、取得している。
特筆する点として、PDO内で記載の host=mysql
の部分である。 docker-conpose で起動した各コンテナに関して、その割り当てられたサービス名をホスト名として相互にIP解決が可能なネットワーク内でコンテナが起動されることになる。
docker-composeの起動/停止
docker-compose.yml
が置かれているディクトリ内で以下のコマンドを実行する
$ docker-compose up -d
Starting app_phpapp_1 ... done
Starting app_mysql_1 ... done
mysql:5.7のイメージは先の手順通りに行った場合はDockerHubからインストル済み, phpappのイメージの作成がまず行われると思われる。
起動が終わるとmac側のブラウザで http://localhost:8080/counter.php
にて確認するとリロードごとにカウントUpされるようなアプリケーションが確認できる。
停止は以下で行う
$ docker-compose down
Stopping app_mysql_1 ... done
Stopping app_phpapp_1 ... done
Removing app_mysql_1 ... done
Removing app_phpapp_1 ... done
Removing network app_default```
再び起動すると前回のカウンタから+1された値が表示されMySQLデータが永続化されていることもわかる。
起動中のコンテナに入る場合は以下で行うサービス名を指定すればよい -it
のパラメータは不要
$ docker-compose exec mysql /bin/bash
root@ad984396ba7f:/#
root@ad984396ba7f:/# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.22 MySQL Community Server (GPL)
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.04 sec)
mysql> connect test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Connection id: 5
Current database: test
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| counter |
+----------------+
1 row in set (0.00 sec)
mysql> select * From counter;
+----+---------------------+
| id | create_at |
+----+---------------------+
| 1 | 2018-05-26 06:57:47 |
| 2 | 2018-05-26 06:57:48 |
| 3 | 2018-05-26 06:57:49 |
| 4 | 2018-05-26 06:57:52 |
| 5 | 2018-05-26 07:03:58 |
+----+---------------------+
5 rows in set (0.00 sec)
mysql>
おわりに
docker や docker-compose の基本がわかるような流れで解説をかいてみた。これらによりシステム(サービス)がアーキテクチャ含めてコードにより管理される事を体感できたのではないかと。
dockerってなんかよく分からない...
具体的な活用イメージが湧かない..と思ってる方への一助になれば幸いです。
技術系の記事投稿先を自前のBlogに移しました。初心者向け,AWSなど幅広いTechジャンルで記事投稿がんばってますので、よろしかったらこちらも参照ください!