LoginSignup
1
2
お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

Docker Compose を使わずに App / DB / Mail コンテナの開発環境を構築する

Last updated at Posted at 2024-07-03

はじめに

この記事では、App / DB / Mail コンテナの開発環境の構築手順について記載します。
今回は Docker Compose を使わずに構築します。

※Docker Compose を使った構築手順については、こちらの記事に記載しています。

開発環境

開発環境は以下の通りです。

  • Windows 11
  • Docker Engine 26.1.1
  • PHP 8.3
  • MySQL 8.4.0
  • Mailpit 1.18

要件を整理する

まず今回構築するコンテナの要件を整理します。

全体

  • コンテナ停止時に自動削除
  • コンテナはバックグラウンド実行
  • 日本標準時で動作
  • コンテナ間通信可能

App コンテナ app

  • ブラウザでアクセス可能
  • ソースコードはホストマシンで実装

DB コンテナ db

  • デバッグ用にホストマシンから接続可能
  • データはコンテナを削除しても残す
  • 初期データを用意

Mail コンテナ mail

  • ブラウザでアクセス可能
  • メールデータはコンテナを削除しても残す

ディレクトリを準備する

今後 Dockerfile や各種設定ファイルなどを作成していくために以下の構成のディレクトリを準備します。

├─docker
  ├─app
  ├─db
  └─mail
└─src

各コンテナのイメージを準備して、コンテナを起動する

次は各コンテナのイメージを準備して、コンテナを起動してみます。

App コンテナ app

ベースイメージはタグが 8.3 の PHP イメージを利用します。

また、MySQL サーバーとの接続やメール送信のための SMTP クライアント用に拡張モジュールが必要なため、/docker/app ディレクトリに Dockerfile を作成し、ベースイメージを拡張・ビルドします。

FROM php:8.3

RUN docker-php-ext-install pdo_mysql

RUN apt-get update
RUN apt-get install -y msmtp-mta

COPY ./msmtprc /etc/msmtprc

CMD ["/usr/local/bin/php", "--server", "0.0.0.0:8000", "--docroot", "/my-work"]
  • RUN docker-php-ext-install pdo_mysql : MySQL を利用するためのモジュール PDO_MYSQL をインストール

  • RUN apt-get install -y msmtp-mta : SMTP クライアント msmtp をインストール

  • COPY ./msmtprc /etc/msmtprc : メールサーバーのホストなどを指定するための設定ファイル msmtprc をホストマシンの ./msmtprc からイメージの /etc/msmtprc にコピー
  • CMD ["/usr/local/bin/php", "--server", "0.0.0.0:8000", "--docroot", "/my-work"] : コンテナ起動時、ビルドイン Web サーバーを起動
    • --server オプションで起動するアドレスとポートを指定
    • --docroot オプションでドキュメントルートを指定

php コマンドの絶対パスは、which コマンドで確認します。

docker run --rm php:8.3 which php

image.png

次は、上記の COPY インストラクションでコピー元となる msmtprc/docker/app ディレクトリに作成します。

host mail
port 1025
from "service@example.com"
timeout 5
  • host : Mail コンテナ
  • port : Mail コンテナのポート
  • from : メールの送信元アドレス

port1025 は、Mail イメージとして利用する Mailpit の SMTP サーバーのデフォルト値になります。1

必要なファイルが揃ったので、Dockerfile からイメージをビルドします。

docker image build --tag app:0.1.0 docker/app

image.png

イメージがビルドできたか確認します。

docker image ls app

image.png

ビルドしたイメージをもとに App コンテナを起動します。

docker container run `
--name app           `
--rm                 `
--detach             `
--publish 8000:8000  `
app:0.1.0            `
/usr/local/bin/php --server 0.0.0.0:8000 --docroot /

Dockerfile にドキュメントルートとして記載した /my-work ディレクトリはまだ作成していないので、現時点では / としています。

コンテナが起動できている場合、ブラウザで http://localhost:8000/ にアクセスすると、以下の画面が表示されます。

image.png

DB コンテナ db

ベースイメージはタグが 8.4.0 の MySQL イメージを利用します。

以下のコマンドでコンテナを起動します。

docker container run               `
--name db                          `
--rm                               `
--detach                           `
--env MYSQL_ROOT_PASSWORD=password `
--env MYSQL_USER=app               `
--env MYSQL_PASSWORD=password      `
--env MYSQL_DATABASE=sample        `
--env TZ=Asia/Tokyo                `
--publish 3306:3306                `
mysql:8.4.0

コンテナが起動できている場合、ホストマシンから DB コンテナに接続できます。

mysql --host=127.0.0.1 --port=3306 --user=app --password=password sample

また、DB コンテナが日本標準時になっています。

select now();

image.png

Mail コンテナ mail

ベースイメージはタグが v1.18 の Mailpit イメージを利用します。

以下のコマンドでコンテナを起動します。

docker container run `
--name mail          `
--rm                 `
--detach             `
--env TZ=Asia/Tokyo  `
--publish 8025:8025  `
axllent/mailpit:v1.18

Web UI にホストマシンのブラウザからアクセスできるようにコンテナの 8025 ポートをホストマシンの 8025 ポートにマッピングしています。8025 は Mailpit の Web UI のデフォルト値です。2

コンテナが起動できている場合、ブラウザで http://localhost:8025/ にアクセスすると、以下の画面が表示されます。

image.png

docker container ls でコンテナが3つ起動していることが確認できます。

image.png

起動確認できたので、コンテナを全て停止します。

docker container stop app db mail

image.png

要件の達成状況を確認する

現時点での要件の達成状況を確認します。

全体

  • ✅コンテナ停止時に自動削除
  • ✅コンテナはバックグラウンド実行
  • ✅日本標準時で動作
  • コンテナ間通信可能

App コンテナ app

  • ✅ブラウザでアクセス可能
  • ソースコードはホストマシンで実装

DB コンテナ db

  • ✅デバッグ用にホストマシンから接続可能
  • データはコンテナを削除しても残す
  • 初期データを用意

Mail コンテナ mail

  • ✅ブラウザでアクセス可能
  • メールデータはコンテナを削除しても残す

各コンテナで必要なリソースを準備する

残りの要件を満たすため、各コンテナで必要なリソースを準備します。

App コンテナ app

App コンテナで満たす必要がある残りの要件は、以下の2つです。

  • コンテナ間通信可能
  • ソースコードはホストマシンで実装

ネットワーク

コンテナ間通信のため、work-network というネットワークを作成します。

docker network create work-network

作成できたか確認します。

docker network ls --filter name=work-network

image.png

コンテナ起動時のパラメーターに --network オプションを追加し、作成した work-network へ接続します。

  • ✅コンテナ間通信可能

ソースコード

メールを送信するソースコードを実装します。
ホストマシンの src/index.php にファイルを追加して実装します。

index.php
<?php

$users = [];

try {
  // Connect to DB
  $dsn = 'mysql:host=db;port=3306;dbname=sample';
  $username = 'root';
  $password = 'password';
  $pdo = new PDO($dsn, $username, $password);

  // Get users table
  $statement = $pdo->query('select * from users');
  $statement->execute();
  while ($row = $statement->fetch()) {
    $users[] = $row;
  }

  // Disconnect
  $pdo = null;
} catch (PDOException $e) {
  echo '<p>Database connection failed: ' . $e . '</p>';
}
// Display users information
foreach ($users as $user) {
  echo '<p>id: ' . $user['id'] . ', name: ' . $user['name'] . '</p>';
}

// Send mail
$subject = 'Test Mail';
$message = 'Here is Docker Hub => https://hub.docker.com/';
foreach ($users as $user) {
  $success = mb_send_mail($user['email'], $subject, $message);
  if ($success) {
    echo '<p>Mail sent to ' . $user['name'] . '</p>';
  } else {
    echo '<p>Mail sending failed</p>';
  }
}

バインドマウント

ホストマシンに追加したソースコードをコンテナと共有するため、バインドマウントを利用します。
コンテナ起動時のパラメーターに --mount オプションを追加します。オプションの <key> / <value> は以下の通りです。

  • type=bind
  • source="$(pwd)" /src
  • target=/my-work

マウント先の /my-work は、Dockerfile にドキュメントルートとして記載したディレクトリです。

  • ✅ソースコードはホストマシンで実装

DB コンテナ

DB コンテナで満たす必要がある残りの要件は、以下の2つです。

  • コンテナ間通信可能
  • データはコンテナを削除しても残す
  • 初期データを用意

ネットワーク

コンテナ間通信のため、App コンテナと同じネットワークに接続する必要があります。
コンテナ起動時のパラメーターに --network オプションを追加し、work-network へ接続します。

  • ✅コンテナ間通信可能

ボリューム

データが消えないようにボリュームを利用します。
まず DB コンテナ用のボリュームを作成します。

docker volume create --name work-db-volume

image.png

次にコンテナ起動時のパラメーターへ --mount オプションを追加し、work-db-volume をマウントします。オプションの <key> / <value> は以下の通りです。

  • type=volume
  • source=work-db-volume
  • target=/var/lib/mysql

マウント先の /var/lib/mysql は、MySQL サーバーがデータを保存するデフォルトのディレクトリになります。MySQL 設定ファイル(/etc/my.cnf)で定義されています。

docker container run --rm mysql:8.4.0 cat /etc/my.cnf
[mysqld]
...
datadir=/var/lib/mysql
...
  • ✅データはコンテナを削除しても残す

初期データ

初期データとしてコンテナ起動時、users テーブルを作成し、Wyatt と Billy を登録するようにします。
上記のクエリをコンテナ起動時に実行する SQL ファイルをホストマシンの /docker/init/init-users.sql に作成します。

init-users.sql
create table users(id int, name varchar(32), email varchar(32));
insert users (id, name, email) values (1, "Wyatt", "wyatt@example.com");
insert users (id, name, email) values (2, "Billy", "billy@example.com");

バインドマウント

ホストマシンに追加した SQL ファイルをコンテナと共有するため、バインドマウントを利用します。
コンテナ起動時のパラメーターに --mount オプションを追加します。オプションの <key> / <value> は以下の通りです。

  • type=bind
  • source="$(pwd)"/docker/db/init
  • target=/docker-entrypoint-initdb.d

マウント先の値 /docker-entrypoint-initdb.d は、Docker Hub の MySQL リポジトリの Initializing a fresh instance に記載があります。3

  • ✅初期データを用意

Mail コンテナ mail

Mail コンテナで満たす必要がある残りの要件は、以下の2つです。

  • コンテナ間通信可能
  • メールデータはコンテナを削除しても残す

ネットワーク

コンテナ間通信のため、App / DB コンテナと同じネットワークに接続する必要があります。
コンテナ起動時のパラメーターに --network オプションを追加し、work-network へ接続します。

  • ✅コンテナ間通信可能

ボリューム

データが消えないようにボリュームを利用します。
まず Mail コンテナ用のボリュームを作成します。

docker volume create --name work-mail-volume

image.png

次にコンテナ起動時のパラメーターへ --mount オプションを追加し、work-mail-volume をマウントします。オプションの <key> / <value> は以下の通りです。

  • type=volume
  • source=work-mail-volume
  • target=/data

マウント先の value である /data は、Docker Hub の Mailpit リポジトリの Setting Mailpit options のサンプルでデータの保存先を指定する環境変数 MP_DATABASE と同じにしています。4

docker run -d \
--name=mailpit \
--restart unless-stopped \
-v /path/to/mailpit-data:/data \
-e MP_DATABASE=/data/mailpit.db \
-e MP_UI_AUTH_FILE=/data/authfile \
-e TZ=Europe/London \
-p 8025:8025 \
-p 1025:1025 \
axllent/mailpit
  • ✅メールデータはコンテナを削除しても残す

コンテナを起動する

全ての要件を満たすことができたので、3つのコンテナを起動します。

App コンテナ app

docker container run                                      `
--name app                                                `
--rm                                                      `
--detach                                                  `
--publish 8000:8000                                       `
--mount type=bind,source="$(pwd)"/src,target=/my-work `
--network=work-network                                    `
app:0.1.0                                                 `
/usr/local/bin/php --server 0.0.0.0:8000 --docroot /my-work

image.png

コンテナの起動状況を確認します。

docker container ls

image.png

DB コンテナ db

docker container run               `
--name db                          `
--rm                               `
--detach                           `
--env MYSQL_ROOT_PASSWORD=password `
--env MYSQL_USER=app               `
--env MYSQL_PASSWORD=password      `
--env MYSQL_DATABASE=sample        `
--env TZ=Asia/Tokyo                `
--publish 3306:3306                `
--mount type=volume,source=work-db-volume,target=/var/lib/mysql `
--mount type=bind,source="$(pwd)"/docker/db/init,target=/docker-entrypoint-initdb.d `
--network=work-network             `
mysql:8.4.0

image.png

コンテナの起動状況を確認します。

docker container ls

image.png

Mail コンテナ mail

docker container run                                          `
--name mail                                                   `
--rm                                                          `
--detach                                                      `
--env TZ=Asia/Tokyo                                           `
--env MP_DATABASE=/data/mailpit.db                            `
--publish 8025:8025                                           `
--network=work-network                                        `
--mount type=volume,source=work-mail-volume,target=/data `
axllent/mailpit:v1.18

コンテナの起動状況を確認します。

docker container ls

image.png

動作確認

ブラウザで動作確認をします。

App コンテナ( http://localhost:8000/ )にアクセスすると、以下の画面が表示されます。
ユーザー一覧と各ユーザーにメールを送信したことが確認できます。

image.png

Mail コンテナ( http://localhost:8025/ )にアクセスすると、以下の画面が表示されます。
2通のメールが確認できます。また、メールのタイトル、本文ともに実装通りの文言になっています。

image.png

所感

  • Docker を利用した Web サービスの開発環境構築の全体像の理解度が向上した
  • コンテナ一つひとつ管理するのは大変(Docker Compose 便利)5
  1. https://mailpit.axllent.org/docs/configuration/runtime-options/

  2. https://mailpit.axllent.org/docs/configuration/runtime-options/

  3. https://hub.docker.com/_/mysql

  4. https://hub.docker.com/r/axllent/mailpit

  5. 環境をはじめて起動するために必要なコマンド実行は全部で7回になります(docker image build : 1、docker volume create : 2、docker network create : 1、docker container run : 3)。また、docker container run のパラメーターは、30 も指定しています。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2