Dockerを基本から復習してみる Part2
今回は前回に引き続きDockerについての復習記事を書いていきます。
前回はDockerfileのみを使ったコンテナの構築について書きましたが、今回はDocker-composeを使ったコンテナの構築について基礎から書いてみます。
Docker-composeを使うことでより簡単かつ便利に複数のDockerコンテナを管理することができます。
では始めます。
前回のPart1で使ったファイルを少し変更して使ってます
使用ファイル解説
ディレクトリ構成
docker_test(作業用ディレクトリ)
| ------ docker-compose.yml (docker-composeの設定ファイル)
| ------ Dockerfile
| ------ db.dockerfile(DBコンテナ用のDockerfile)
| ------ index.php (トップページ表示のためのファイル)
| ------ nginx.repo (yumのリポジトリにnginxを追加するためのファイル)
| ------ function.php(関数用のファイル)
docker-compose.yml
version: '3'
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- .:/usr/share/nginx/html
depends_on:
db:
condition: service_healthy
ports:
- 8080:80
environment:
MYSQL_HOST: db
MYSQL_USER: test_user
MYSQL_PASSWORD: password
privileged: true # 権限の有効化
command: /sbin/init
db:
platform: linux/x86_64 # M1チップ対応のため追記
build:
context: .
dockerfile: db.dockerfile
healthcheck:
test: mysqlshow -u $$MYSQL_USER -p$$MYSQL_PASSWORD
interval: 3s
retries: 10
ports:
- '3308:3306'
environment:
MYSQL_DATABASE: test_container
MYSQL_USER: test_user
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
今回はappコンテナとdbコンテナの2つを立てています。
まずappコンテナについて解説していきます。
build:
context: .
dockerfile: Dockerfile
「context: . 」についてはビルドコンテキストがカレントディレクトリであることを宣言しています。ビルドコンテキストに指定された階層のファイルはDocker Daemonに読み込まれるため、不要なファイルができる限り置かない方が良い。
「dockerfile: Dockerfile」についてはビルドコンテキストで使うdockerfile名を指定しています。
よって今回はカレントディレクトリ上にある Dockerfileを元に イメージが作成されることになります。
volumes:
- .:/usr/share/nginx/html
volumesでは : の左側にホストマシンのディレクトリを
:の右側に Dockerコンテナのディレクトリを指定することでこの左右のディレクトリを同期することが可能になります。
よってホストマシンのカレントディレクトリにある6つのファイル(docker-compose.yml,DockerFile,db.dockerfile,function.php,index.php,nginx.repo)が コンテナ内の /usr/share/nginx/html の下に同期されます。
同期されるのでホストマシン側で 同期ファイル内容の変更をしても、コンテナ内のファイル内容が変更されますし、その逆も同様です。
depends_on:
db:
condition: service_healthy
depends_onについてですが、これは dbコンテナの立ち上げが完了してからこのコンテナを立ち上げるという設定になります。
さらに condion: service_healthyを指定することによって 「dbコンテナの立ち上げが完了 かつ dbコンテナに指定したヘルスチェックが OKの場合」起動するという条件をつけることが可能です。
dbコンテナに指定したヘルスチェックの内容については後述します。
ports:
- 8080:80
こちらは ホストマシンの 8080番ポートとコンテナの80番ポートを同期しています。
environment:
MYSQL_HOST: db
MYSQL_USER: test_user
MYSQL_PASSWORD: password
ここでは環境変数を設定することができます。
privileged: true # 権限の有効化
command: /sbin/init
この部分についてはこれを指定しないとコンテナ立ち上げ後に systemctlコマンドを実行したときに 「Failed to get D-Bus connection Operation not permitted」エラーが発生して systemctlコマンドを使えないため、設定しています。
次はdbコンテナの内容について説明します。
appコンテナで解説した build,ports,environmentの項目については割愛します。
platform: linux/x86_64 # M1チップ対応のため追記
この部分についてはM1チップのMacBookを使用している場合はこれがないとエラーが発生しますが、それ以外の場合は必要ありませんので消して大丈夫です。
healthcheck:
test: mysqlshow -u $$MYSQL_USER -p$$MYSQL_PASSWORD
interval: 3s
retries: 10
上の方のappコンテナ立ち上げの際に行われるdbコンテナのヘルスチェックの設定をここで行っています。
mysqlshowコマンドを使って データベースの一覧表示 が可能かどうかを判断しています。今回は 3秒ごとに 合計10回 mysqlshowコマンドを行なって 問題がなければヘルスチェック合格ということになります。
Dockerfile
# CentOS7のイメージをDocker Hubから取り込む
FROM centos:7
ADD nginx.repo /etc/yum.repos.d/
# nginx & curl をインストール
RUN yum -y install nginx \
yum -y install php-fpm php-mysql php-mbstring php-pear php-gd \
curl
# カレントディレクトリ上の index.htmlファイルを /usr/share/nginx/html/ にコピーする
ADD index.php /usr/share/nginx/html/
# ポート設定
EXPOSE 8080
CMD ["nginx","-g","daemon off;"]
# /usr/share/nginx/html ディレクトリに移動
WORKDIR /usr/share/nginx/html/
こちらについては前回のPart1で解説しているのでそちらも参照いただければと思います。変更点としては今回はphpを使いたいので php-fpmをインストールしています。
db.dockerfile
FROM mysql:5.7
EXPOSE 3308
Docker Image は mysql:5.7を使用、コンテナの3308ポートを公開するという設定
nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
こちらは yumリポジトリに nginxを追加する設定
index.php
<?php
require('function.php');
?>
<h1> Hello World From Nginx</h1>
<h2>user from Database</h2>
<ul>
<li><?= getUser(1)['name']; ?></li>
</ul>
トップページで表示予定のファイル。
dbコンテナの usersテーブルから id:1のユーザデータの名前を取得して表示するだけの簡単なもの
function.php
<?php
// DB接続関数
function dbConnect(){
//DBへの接続準備
$dsn = "mysql:dbname=test_container;host=docker_test-db-1;charset=utf8;";
$user = 'root';
$password = 'password';
$options = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT,
// デフォルトフェッチモードを連想配列形式に設定
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
);
// PDOオブジェクト生成
$dbh = new PDO($dsn,$user,$password,$options);
return $dbh;
}
function queryPost($dbh,$sql,$data){
//クエリー作成
$stmt = $dbh->prepare($sql);
//プレースフォルダに値をセットし、SQL文を実行
if(!$stmt->execute($data)){
return false;
}
return $stmt;
}
function getUser($u_id){
// 例外処理
try{
// DBへ接続
$dbh = dbConnect();
// SQL文作成
$sql = 'SELECT * FROM users WHERE id = :u_id';
$data = array(':u_id' => $u_id);
// クエリ実行
$stmt = queryPost($dbh, $sql, $data);
// クエリ結果のレコードを1レコード返却
if($stmt){
return $stmt->fetch(PDO::FETCH_ASSOC);
}else{
return false;
}
} catch (Exception $e) {
var_dump($e);
}
}
PDOオブジェクトを使用して データベースからユーザデータを取得してくるための関数を用意しています。
コンテナ立ち上げ手順
まずdocker-compose を使ってイメージを作成
$ docker-compose build --no-cache
次に イメージから バックグラウンドで コンテナを立ち上げる
$ docker-compose up -d
コンテナが立ち上がってるか確認
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fc5562f19543 docker_test_app "/sbin/init" 51 seconds ago Up 6 seconds 8080/tcp, 0.0.0.0:8080->80/tcp docker_test-app-1
e142b74694ae docker_test_db "docker-entrypoint.s…" 51 seconds ago Up 50 seconds (healthy) 3308/tcp, 33060/tcp, 0.0.0.0:3308->3306/tcp
この時点で http://localhost:8080 に接続しても下の画像のようにうまくいかない
次に立ち上げた appコンテナに入って設定を変更していく
vi /etc/php.ini
;date.timezone =
date.timezone = Asia/Tokyo
タイムゾーンを Asia/Tokyoに設定
vi /etc/php-fpm.d/www.conf
user = nginx
group = nginx
;listen.owner = nobody
;listen.group = nobody
listen.owner = nginx
listen.group = nginx
;listen = 127.0.0.1:9000
listen = /var/run/php-fpm/php-fpm.sock
user,groupはデフォルトでは apacheになっているので両方ともnginxに修正
$ systemctl start php-fpm
$ systemctl enable php-fpm
Created symlink from /etc/systemd/system/multi-user.target.wants/php-fpm.service to /usr/lib/systemd/system/php-fpm.service.
php-fpmデーモンをsystemctl経由で起動してphp-fpmの自動起動を有効に設定。
$ systemctl status php-fpm
● php-fpm.service - The PHP FastCGI Process Manager
Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; disabled; vendor preset: disabled)
Active: active (running) since Thu 2022-03-10 07:09:32 UTC; 3min 39s ago
Main PID: 90 (php-fpm)
Status: "Processes active: 0, idle: 5, Requests: 0, slow: 0, Traffic: 0req/sec"
CGroup: /docker/fc5562f195438a78548bd478b20cbaaa480a4b0f550a4be2683c7ebb7fe1a3a0/system.slice/php-fpm.service
├─90 php-fpm: master process (/etc/php-fpm.conf)
├─92 php-fpm: pool www
├─93 php-fpm: pool www
├─94 php-fpm: pool www
├─95 php-fpm: pool www
└─96 php-fpm: pool www
‣ 90 php-fpm: master process (/etc/php-fpm.conf)
Mar 10 07:09:32 fc5562f19543 systemd[1]: Starting The PHP FastCGI Process Manager...
Mar 10 07:09:32 fc5562f19543 systemd[1]: Started The PHP FastCGI Process Manager.
PHPデーモンの起動状態を確認。activeになっているのがわかる
/etc/nginx/conf.d/default.conf
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm index.php;
}
location ~ \.php$ {
root /usr/share/nginx/html;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include fastcgi_params;
}
}
/etc/nginx/conf.d/default.conf を編集して phpが動くように設定
$ systemctl restart nginx
ここまで編集したら nginxをリスタートしてコンテナを一旦抜けます。
次にdbコンテナ内にusersテーブルを作成する
$ docker exec -it docker_test-db-1 /bin/bash
まずdbコンテナに入る
root@e142b74694ae:/# mysql -u root -p
rootユーザでデータベースに接続。パスワードを求められるので正しいパスワードを入力すると接続できる。
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test_container |
+--------------------+
5 rows in set (0.00 sec)
show databases を実行すると5つのデータベースが存在するので test_containerを選択する。
mysql> use test_container
Database changed
mysql> create table users (id int, name varchar(10));
Query OK, 0 rows affected (0.06 sec)
usersテーブルを作成(今回はnameのみの簡易的なもの、本当はidにprimary_key んどもつけないといけないが、あくまでappコンテナとdbコンテナでやりとりができるか確認するためのものなので省略)
mysql> INSERT INTO users VALUES (1,'test1');
Query OK, 1 row affected (0.02 sec)
一つレコードを挿入する
mysql> select * from users;
+------+-------+
| id | name |
+------+-------+
| 1 | test1 |
+------+-------+
1 row in set (0.02 sec)
usersテーブルにレコードが入っているのが確認できる
この状態で http://localhost:8080/ にアクセスすると データベースからユーザデータを取得できているのが確認できました!
次回は ECS(起動タイプ : EC2)について書こうと思います。今度はLaravelの簡易的なアプリを動かせるようにしたいです。その次は ECS(起動タイプ : Fargate)とか書きたいと思います。