この記事はOluyemi Olususiがこちらで公開した記事(英語)を日本語化したものです。
ソフトウェアをチーム間で開発すると、コードベースの管理や、開発者全員が問題なく使える開発環境の準備など、さまざまな困難が生じます。
Gitはバージョン管理において大きな役割を果たしており、誰もが問題なくコードベースを操作できるようになりましたが、作業環境が原因で混乱が生じるリスクがまだあります。
WindowsやmacOS、Linuxなど、開発者が好むオペレーティングシステムはさまざまであり、同じことがアプリケーションの導入環境にも当てはまります。
その結果、特定のエラーが発生すると、問題の原因を突き止めることが困難になります。エラーが1つのOSでのみ発生することが混乱に拍車をかける可能性もあります。開発者の間で有名なフレーズ、「It works on my machine」(私のマシンでは動作するのに)の状態につながります。
Dockerを開始する
小規模で軽量の実行環境であるコンテナにアプリケーションを作成することにより、アプリケーションの予測可能性が向上します。コンテナでは、基盤となるオペレーティングシステムカーネルを共有しますが、それ以外は互いから切り離して実行されます。
DockerをSymfonyプロジェクトに統合することにより、導入先に関係なく、アプリケーションの実行時に環境とその設定を常に同じにすることができます。
本稿では、SymfonyプロジェクトでDockerを使用する方法について紹介します。ここでは、NginxがWebサーバーとして使用され、PHP-FPMがPHPリクエストを処理し、MySQLがバックエンドデータベースになります。本稿では、著名な歴史家による有名な名言が表示されるアプリケーションを作成します。
必要条件
- Symfony、Twig、ORM(特にDoctrine)の経験。
- Dockerに関連する基本的な用語(コンテナ、イメージ、ネットワーク、サービス)の知識。Jeff Hale氏は、これらの用語について、連載記事で分かりやすく解説しています。これらの用語についてあまり知らない場合は、ぜひ読んでみてください。
- グローバルにインストールされているComposer。
- Docker Desktop
- Symfony CLIツール
はじめに
最初に、symfony_dockerという名前の新しいディレクトリを作成し、次のコマンドで、そのディレクトリに切り替えます。
mkdir symfony_docker
cd symfony_docker
Docker Composeの設定を作成する
アプリケーションを構成するさまざまなコンテナが通信する必要があるため、Docker Composeを使用し、それらを定義します。symfony_dockerディレクトリのルートで次のコマンドを使用し、docker-compose.ymlという名前の新しいファイルを作成します。
touch docker-compose.yml
このファイルには、コンテナのビルド方法から、コンテナにアクセス可能なネットワークやボリュームまで、アプリケーションのスタックで作成するコンテナのすべての設定が保持されます。
docker-compose.ymlに以下の設定を追加します。
version: '3.8'
services:
version
はスキーマバージョンを参照します。services
は、アプリケーションスタックを構成するコンテナのリストを定義します。services
は、実際は単なる「本番環境のコンテナ」です。
次の各セクションでは、MySQLデータベース、PHP、Nginx Webサーバーのコンテナについて説明します。
データベースコンテナを定義する
データベースコンテナを定義するには、docker-compose.ymlで、次のように services
要素を更新します。
services:
database:
container_name: database
image: mysql:8.0
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: symfony_docker
MYSQL_USER: symfony
MYSQL_PASSWORD: symfony
ports:
- '4306:3306'
volumes:
- ./mysql:/var/lib/mysql
container_name
では、Docker Composeでコンテナを生成するのではなく、実行時にコンテナの実際の名前を設定します。
image
では、コンテナのビルド元のイメージ(ブループリント)をDockerに認識させることができます。この場合、バージョン8のMySQLを使用するため、mysql:8.0
を指定します。
command
では、ユーザーの認証にMySQLで使用される認証プラグインを指定します。environment
キーを使用すると、データベースの名前、ユーザー、パスワード、ルートユーザーのパスワードなどの環境変数を指定できます。
データベースに接続するポートも必要です。ports
キーを使用して、ローカル開発マシンのポートを指定し、データベース接続の処理に使用されるコンテナのポートにマップします。
ポート4306は、MySQLサービスがすでにコンピューターで実行されている場合に指定します。
最後に、volumes
キーを使用してボリュームを宣言します。Docker公式ドキュメントによると:
ボリュームは、Dockerコンテナが生成、使用するデータを保持するための推奨メカニズムです。
コンテナの破棄または再ビルド時にデータベースが失われないようにするために、ボリュームを宣言します。
PHPコンテナを定義する
データベースコンテナとは異なり、PHPコンテナを設定するには、追加の指示を指定する必要があります。これを行うには、DockerfileからPHPコンテナをビルドします。ルートディレクトリsymfony_dockerに、phpという名前のディレクトリを作成します。次に、symfony_docker/phpに、Dockerfileという名前のファイルを作成します。
Dockerfileには拡張子がありません。
mkdir php
touch php/Dockerfile
続いて、symfony_docker/php/Dockerfileに、以下を追加します。
FROM php:8.0-fpm
RUN apt update \
&& apt install -y zlib1g-dev g++ git libicu-dev zip libzip-dev zip \
&& docker-php-ext-install intl opcache pdo pdo_mysql \
&& pecl install apcu \
&& docker-php-ext-enable apcu \
&& docker-php-ext-configure zip \
&& docker-php-ext-install zip
WORKDIR /var/www/symfony_docker
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN curl -sS https://get.symfony.com/cli/installer | bash
RUN mv /root/.symfony/bin/symfony /usr/local/bin/symfony
RUN git config --global user.email "you@example.com" \
&& git config --global user.name "Your Name"
symfony_docker/php/Dockerfileの最後の2行で、you@example.com
をご自身のメールアドレスに、Your Name
を名前に置き換えてください。
PHP-FPMイメージからコンテナの雛形を作成することに加えて、以下を実行します。
- Symfonyが依存するPHP拡張機能をインストールします。
- コンテナの作業ディレクトリを/var/www/symfony_dockerに設定します。
- Composerをインストールします。
- Symfony CLIをインストールします。
次に、データベース設定の後に、以下のサンプルをdocker-compose.ymlに追加します。
php:
container_name: php
build:
context: ./php
ports:
- '9000:9000'
volumes:
- ./app:/var/www/symfony_docker
depends_on:
- database
ご覧のとおり、PHPコンテナは異なる方法で定義されています。イメージを指定する代わりに、ビルドコンテキストを指定します。このように、docker-compose
コマンドを実行すると、php/Dockerfileに宣言された指示がコンテナのビルドに使用されます。
コンピューターのポート9000
は、コンピューターのポートをMySQLデータベースのコンテナのポートにマップしたのと同じように、コンテナのポート9000
にマップされます。
さらに、この場合もボリュームを宣言します。これは、コンテナで生成されたデータを保持するためです。この場合、SymfonyアプリケーションはPHPコンテナの/var/www/symfony_dockerディレクトリに作成され、プロジェクトのappディレクトリに保持されます。
最後に、depends_on
キーを使用します。PHPとデータベースコンテナの間に依存関係が作成されることにより、PHPコンテナの前にデータベースコンテナをビルドして開始するようにDockerに指示されます。
PHPコンテナを定義し、次のコマンドを使用して、プロジェクトのルートディレクトリにappディレクトリを作成します。これはコンテナで必要になります。
mkdir app
Nginxコンテナを定義する
Nginxコンテナをビルドする前に、サーバーのデフォルト設定を記述しましょう。プロジェクトのルートに、nginxという名前のディレクトリを作成し、その中に、次のコマンドを使用して、default.confという名前の設定ファイルを作成します。
mkdir -p nginx/default.conf
以下の設定をnginx/default.confに追加します。
server {
listen 80;
index index.php;
server_name localhost;
root /var/www/symfony_docker/public;
error_log /var/log/nginx/project_error.log;
access_log /var/log/nginx/project_access.log;
location / {
try_files $uri /index.php$is_args$args;
}
location ~ ^/index\\.php(/|$) {
fastcgi_pass php:9000;
fastcgi_split_path_info ^(.+\\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
internal;
}
location ~ \\.php$ {
return 404;
}
}
これは、Symfonyプロジェクトの実行に必要な基本的なNginx設定です。fastcgi_pass
で、PHPコンテナのポート9000を指定しています。ポート9000は、PHP-FPMがリクエストをリッスン(待機)するデフォルトのポートだからです。
次に、docker-compose.ymlにおいて以下のように、PHPコンテナの設定の後にNginxコンテナの設定を追加します。
nginx:
container_name: nginx
image: nginx:stable-alpine
ports:
- '8080:80'
volumes:
- ./app:/var/www/symfony_docker
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
- database
コンテナをビルドする
次のコマンドでコンテナをビルドします。
docker-compose up -d --build
コンテナがビルドされると、次のスクリーンショットのようにターミナルに表示されます。
Docker Desktopを開くと、次のスクリーンショットに示すように、新しく作成されたコンテナが表示されます。
Symfonyアプリケーションを作成する
Symfonyアプリケーションを作成するには、PHPコンテナ内でターミナルを起動します。これには2つの方法があります。
- Docker Desktopを使用する。
symfony_docker
アプリケーションを展開すると、このアプリケーションを構成するコンテナを確認できます。以下のスクリーンショットで矢印で示されているボタンをクリックすると、CLIを開始できます。docker exec
コマンドが実行され、操作するためのターミナルが開きます。
- docker execコマンドを直接実行する。これを行うには、次のコマンドを実行します。
docker-compose exec php /bin/bash
選択した方式に関わらず、新しく開いたターミナルで次のコマンドを実行することにより、設定がSymfonyアプリケーションの要件を満たしていることを確認します。
symfony check:requirements
要件を満たしている場合は、ターミナルに次の出力が表示されます。
[OK]
Your system is ready to run Symfony projects(Symfonyプロジェクトを実行する準備ができました)
次に、以下のコマンドを実行して新しいSymfonyプロジェクトを作成します。
symfony new .
成功すると、ターミナルに以下のテキストが表示されます。
[OK] Your project is now ready in /var/www/symfony_docker
アプリケーションが作成されたため、http://localhost:8080/に移動します。次の例のように、デフォルトのSymfonyインデックスページが表示されます。また、appディレクトリを見ると、Symfonyプロジェクトファイルが保持されていることが分かります。
PHPコンテナのCLIに戻り、作成中のアプリケーションの開発依存関係を追加します。次のコマンドを実行します。
composer req --dev maker ormfixtures fakerphp/faker
データベース内に著名な歴史家による有名な名言を格納し、取得するには、ORM(正確にはDoctrine ORM)が必要になります。また、フロントエンドをレンダリングするにはTwigテンプレートエンジンが必要になります。次のコマンドを実行し、これらの依存関係を追加します。
composer req doctrine twig
次に、プロジェクトの作成中にSymfonyが生成した既存の.envファイルから.env.localファイルを作成します。これを行うには、次のコマンドを実行します。
cp .env .env.local
最後に、.env.localのデータベースパラメーターを更新し、アプリケーションがデータベースコンテナに接続できるようにします。ファイルの現在のDATABASE_URL
エントリを以下に置き換えます。
DATABASE_URL="mysql://root:secret@database:3306/symfony_docker?serverVersion=8.0"
名言エンティティを作成する
次に、MySQLデータベースとの対話を処理するORMエンティティを作成します。これを行うには、Symfony Makerバンドルを使用し、次のコマンドを実行します。
symfony console make:entity Quote
一連の質問に対して次のように答えてください。
New property name (press <return> to stop adding fields):
> quote
Field type (enter ? to see all types) [string]:
> text
Can this field be null in the database (nullable) (yes/no) [no]:
> no
updated: src/Entity/Quote.php
Add another property? Enter the property name (or press <return> to stop adding fields):
> historian
Field type (enter ? to see all types) [string]:
> string
Field length [255]:
> 25
Can this field be null in the database (nullable) (yes/no) [no]:
> no
updated: src/Entity/Quote.php
Add another property? Enter the property name (or press <return> to stop adding fields):
> year
Field type (enter ? to see all types) [string]:
> string
Field length [255]:
> 5
Can this field be null in the database (nullable) (yes/no) [no]:
> no
updated: src/Entity/Quote.php
Add another property? Enter the property name (or press <return> to stop adding fields):
>
Quote.phpという名前のエンティティがsrc/Entityディレクトリに作成されます。src/Entity/Quote.phpを開き、次に示すようにコンストラクタ関数を追加します。
public function __construct($quote, $historian, $year) {
$this->quote = $quote;
$this->historian = $historian;
$this->year = $year;
}
次のコマンドを使用し、データベースを更新するための移行(migration
)を作成します。
symfony console make:migration
次のコマンドを使用し、移行を実行します。
symfony console doctrine:migrations:migrate
プロンプトが表示されたら「yes」を選択します。「quote」という名前の新しいテーブルでデータベースが更新されます。
作成されたことを確認するには、新しいターミナルウィンドウを開き、symfony_dockerディレクトリ内から次のコマンドを実行します。
docker-compose exec database /bin/bash
ターミナルが開いたら、次のコマンドを使用してデータベースに接続します。
mysql -u root -p symfony_docker
プロンプトが表示されたら、MYSQL_ROOT_PASSWORD
を入力します。接続するデータベースを指定したため、次のコマンドを使用してテーブルに対してクエリを実行できます。
> show tables;
次のような出力が表示されます。
mysql> show tables;
+-----------------------------+
| Tables_in_symfony_docker |
+-----------------------------+
| doctrine_migration_versions |
| quote |
+-----------------------------+
2 rows in set (0.00 sec)
名言フィクスチャを作成する
次に、生成された一連の名言をデータベースに読み込み、アプリの準備ができたとき、名言を取得して表示できるようにします。これを行うには、PHPコンテナで、次のコマンドを実行します。
symfony console make:fixture QuoteFixture
フィクスチャはsrc/DataFixtures/QuoteFixture.phpにあります。ファイルを開き、以下のように更新します。
<?php
namespace App\DataFixtures;
use App\Entity\Quote;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
use Faker\Factory;
class QuoteFixture extends Fixture {
private $faker;
public function __construct() {
$this->faker = Factory::create();
}
public function load(ObjectManager $manager) {
for ($i = 0; $i < 50; $i++) {
$manager->persist($this->getQuote());
}
$manager->flush();
}
private function getQuote() {
return new Quote(
$this->faker->sentence(10),
$this->faker->name(),
$this->faker->year()
);
}
}
データベースにフィクスチャを読み込むには、PHPコンテナで次のコマンドを実行します。
symfony console doctrine:fixtures:load
データベースにフィクスチャを読み込むように求められたら、「yes」と応答します。その後、データベースコンテナで次のコマンドを実行し、名言が読み込まれたことを確認します。
> SELECT * FROM quote
テーブルは次のようになっています。
mysql> SELECT * FROM quote limit 10;
+----+----------------------------------------------------------------------------------------------------+----------------------+------+
| id | quote | historian | year |
+----+----------------------------------------------------------------------------------------------------+----------------------+------+
| 1 | Aut eaque aut quos autem incidunt ut est quod tempore sed aut placeat. | Einar Lebsack DDS | 2001 |
| 2 | Eum autem sed aut quos impedit cupiditate harum voluptatem aut qui qui sunt ad. | Aliza Morissette | 1990 |
| 3 | Deserunt consequatur et sunt architecto enim quia deleniti consectetur est reprehenderit. | Zora Bailey | 1973 |
| 4 | Pariatur adipisci voluptatem rerum id adipisci doloremque porro maxime unde placeat ad autem sint. | Dallin Erdman | 1974 |
| 5 | Nobis magni eius voluptatibus blanditiis sequi praesentium aut aperiam et. | Pearlie Cremin PhD | 1982 |
| 6 | Aperiam labore cum delectus aut consequatur animi in. | Stone Harvey | 2008 |
| 7 | Reiciendis non quia libero omnis quis quae quo aut odit tempora aut. | Aurore Graham | 1988 |
| 8 | Earum aliquid quia reiciendis repudiandae non consequatur aliquid. | Lyric Towne | 1977 |
| 9 | Eos illo et unde sint esse tenetur. | Mr. Demarcus Klein V | 1988 |
| 10 | Maxime soluta veniam qui debitis sit maiores sint dolores culpa architecto aliquam est facere. | Francesca O'Connell | 1970 |
+----+----------------------------------------------------------------------------------------------------+----------------------+------+
10 rows in set (0.00 sec)
名言コントローラーを作成する
次に、新しいコントローラーを作成します。このコントローラーでは、ORMエンティティを使用してデータベースから名言を取得し、ビューに表示して閲覧できるようにします。これを行うには、PHPコンテナで、次のコマンドを実行します。
symfony console make:controller QuoteController
コマンドが完了すると、QuoteController.phpという名前の新しいコントローラーがsrc/Controllerディレクトリに作成されます。ファイルを開き、以下のように更新します。
<?php
namespace App\Controller;
use App\Repository\QuoteRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\\Annotation\Route;
class QuoteController extends AbstractController {
#[Route('/', name: 'index')]
public function index(
QuoteRepository $quoteRepository
)
: Response {
return $this->render(
'quote/index.html.twig',
[
'quotes' => $quoteRepository->findAll(),
]
);
}
}
ビューのスタイルを設定する
最後に、ビューの表示を整理し、読みやすくします。これを行うには、Bootstrapを使用してスタイルを設定します。以下のようにapp/templates/base.html.twigを更新します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6"
crossorigin="anonymous">
<title>{% block title %}Welcome!{% endblock %}</title>
{% block stylesheets %}
{% endblock %}
{% block javascripts %}
{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf"
crossorigin="anonymous">
</script>
</body>
</html>
次に、app/templates/quote/index.html.twigを開き、以下のように編集します。
{% extends 'base.html.twig' %}
{% block title %}Quotes{% endblock %}
{% block body %}
<style>
.wrapper {
margin: 1em auto;
width: 95%;
}
</style>
<div class="wrapper">
<h1>Great Quotes</h1>
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Quote</th>
<th scope="col">Historian</th>
<th scope="col">Year</th>
</tr>
</thead>
<tbody>
{% for quote in quotes %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ quote.quote }}</td>
<td>{{ quote.historian }}</td>
<td>{{ quote.year }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
アプリケーションをテストする
完成したアプリケーションをテストします。インデックスページをリロードし、データベースに保存されている有名な名言を表示します。
Dockerを使用してSymfonyプロジェクトを設定する方法は以上です
このチュートリアルでは、イメージとDockerfileからコンテナをビルドするだけでなく、相互に通信することもできました。これにより、Symfonyアプリケーションとデータベースを個別のコンテナで実行できました。
同じ仕様でコンテナをビルドすることにより、開発チームは同じコードベースだけでなく、同じ環境で作業できます。
このチュートリアルの全コードベースは、GitHubで入手できます。ぜひご確認ください。コーディングを楽しみましょう!
Oluyemiは、電気通信工学のバックグラウンドを持つテクノロジー愛好家です。ユーザーが直面する日々の問題を解決することに強い関心を持ち、プログラミングの道に進んで以来、Webとモバイルの両方のソフトウェア開発で問題解決能力を磨いてきました。
Oluyemiは、知識の共有に情熱を注ぐフルスタックのソフトウェアエンジニアであり、ブログで多数の技術記事とコンテンツをインターネットに公開しています。テクノロジーにも精通しており、趣味は新しいプログラミング言語とフレームワークを試すことです。
- Twitter: https://twitter.com/yemiwebby
- GitHub: https://github.com/yemiwebby
- Webサイト: https://yemiwebby.com.ng/