DockerでCakePHP4.4の環境構築(AlmaLinux8 +php7.4 + PostgreSQL)

## はじめに

最近、Dockerを利用してCakePHP環境を整える必要があったのですが、要求された構成の環境を構築するのにかなり手間取ったのでまとめとして残しておきます。

Dockerのバージョンは26.1.3、Docker Composeのバージョンは2.27.0です。


## 想定環境

構築したい環境の構成は下記の通り

- OS
  - Red Hat Enterprise Linux8相当
    
- パッケージ類
  - PHP 7.4
  - CakePHP 4.4
  - Apache 2.4
  - PostgreSQL12
    
RHEL8相当の環境が必要ということでCentOS8を使用したいところですが、残念ながらサポート終了となっています。

今回は同じRHELのクローンディストリビューションであるAlamaLinuxを使用してみることにしました。

## ファイル構成

まずはファイル構成です。

```
myapp/
├── docker/
│   ├── initdb/
│   │ 
│   ├── web/
│   │   └── Dockerfile 
│   │ 
│   ├── docker-compose.yml
│   └── .env
│
└── html/   
```

- initdbにはPostgreSQLコンテナ起動時に実行するSQLファイルを格納します。今回は特段格納していません。

## DockerFileの作成

```dockerfile
FROM almalinux:8

RUN yum update &&\
    yum install -y vim &&\
    # unzipコマンド(composerで使用)
    yum install -y unzip &&\
    # apacheインストール
    yum install -y httpd &&\
    # apache自動起動設定
    systemctl enable httpd &&\
    # EPELリポジトリの追加
    yum -y install epel-release &&\
    #  Remiリポジトリ追加
    yum -y install http://rpms.famillecollet.com/enterprise/remi-release-8.rpm &&\
    # php7.4と拡張モジュールインストール
    yum install -y php74 php74-php php74-php-intl php74-php-pgsqllmalinux8
```

イメージのベースはalmalinux8を使用します。

PHPは7.4を指定してインストールを行いたいためRemiリポジトリから入手する必要があります。
PHPの拡張モジュールはyumコマンドの依存関係の解決でインストールされるものは記述していません。
調べたところによると下記がCakePHPの仕様に必須なモジュールとのことなので、インストールが行われない場合は必要に応じてインストールしてください。

- php74-php-mbstring
- php74-php-pdo
- php74-php-xml
- php74-php-intl
  
::: note info
remiリポジトリからバージョン指定してインストールしているのでphp74-が接頭につきます
:::

## ※追記
`yum install`コマンドではなく`dnf module install`コマンドを使用することも以前のバージョンのPHPのインストールが可能なようです。
また、`dnf install`コマンドを使用することで拡張モジュールはphp74-*の接頭を付けずとも正しいバージョンのパッケージがインストールできます。
``` bash
# php7.4のインストール
dnf module install -y php:remi-7.4
# 拡張モジュールのインストール
#php-*とするだけで正しいバージョンがインストールされる
dnf install -y php-intl php-pgsql
```
この場合`php74`でなく`php`でコマンド実行が可能になります。
特段理由がなければこちらを使う方がよさそうですね。

## docker-compose.ymlの作成

構成は下記の通り

```yml
services:
  myapp:
    # コンテナ名
    container_name: myapp
    # Dockerfileでイメージをビルド
    build:
      context: ./web
      dockerfile: Dockerfile
    # コンテナ内でsystemctlコマンドを使えるようにするための設定
    privileged: true
    command: /sbin/init
    # myapp-web起動後にmydbを起動
    depends_on:
      - mydb
    # 8888番ポートを割り当て
    ports:
      - "8888:80"
    # htmlフォルダをコンテナの/var/www/htmlにマウント
    volumes:
      - "../html:/var/www/html"
    #ネットワーク設定
    networks:
      app_net:
        ipv4_address: 172.10.0.2

  mydb:
    #コンテナ名
    container_name: mydb
    # イメージ
    image: postgres:12.1
    volumes:
      - "psql12_database:/var/lib/postgresql/data"
      - "./initdb:/docker-entrypoint-initdb.d"
    # データベース設定
    environment:
      POSTGRES_DB: sampledb
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASS}
    # ネットワーク設定
    networks:
      app_net:
        ipv4_address: 172.10.0.3

# ネットワーク設定
networks:
    app_net:
      driver: bridge
      ipam:
        driver: default
        config:
          - subnet: 172.10.0.0/24

# 名前付きvolumeの設定
volumes: 
  psql12_database:

```

Dockerfile内でsystemctlを使用していますが、デフォルトのままでは使用できません。そのためprivileged を有効(true)にして、起動を/sbin/initで実行する必要があります。

ネットワーク設定ではmyappとmydbのIPアドレスを固定しています。

PostgreSQLの環境変数は外部ファイルに記述します。

## .envファイルの作成

PostgreSQLの設定を記述します

ここではユーザー名とパスワードを記述しています。

```.env
DB_USER=postgres
DB_PASS=postgres
```

## イメージのビルド

dockerディレクトリに移動して下記コマンドでビルドとコンテナの起動を行います。

```bash
docker compose up -d
```

## composer.pharのインストール

コンテナ内に入りcomposer.pharをインストールします。

インストール場所は/var/www/htmlです。

なおremiリポジトリからphp7.4を指定してインストールを行った場合phpのコマンドは`php`ではなく`php74`になるようです。

```bash
docker exec -it myapp /bin/bash

cd /var/www/html

php74 -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php74 -r "if (hash_file('sha384', 'composer-setup.php') === 'dac665fdc30fdd8ec78b38b9800061b4150413ff2e3b6f88543c636f7cd84f6db9189d43a81e5503cda447da73c7e5b6') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php74 composer-setup.php
php74 -r "unlink('composer-setup.php');"
```

## プロジェクトの作成

composerのcreate-projectコマンドにてCakePHPをインストールします。プロジェクト名はcakeとしました。

```bash
php74 composer.phar create-project --prefer-dist cakephp/app:4.4.* cake
```

## PostgreSQL接続設定

CakePHPのデフォルトの設定はMySQLになっているのでPostgreSQLの設定の書き換えます。

設定するファイルはconfig/app.phpで行います。

```php
<?php

use Cake\Cache\Engine\FileEngine;
use Cake\Database\Connection;
//use Cake\Database\Driver\Mysql;
use Cake\Log\Engine\FileLog;
use Cake\Mailer\Transport\MailTransport;
use Cake\Database\Driver\PostgreSQL;
//・・・

    'Datasources' => [
        //・・・
        'default' => [
            'className' => Connection::class,
            'driver' => Postgres::class,　// ←変更
            'persistent' => false,
            'timezone' => 'UTC',
                ],

        //・・・
        'test' => [
            'className' => Connection::class,
            'driver' => Postgres::class,　// ←変更
            'persistent' => false,
            'timezone' => 'UTC',
            //'encoding' => 'utf8mb4',
            'flags' => [],
            'cacheMetadata' => true,
            'quoteIdentifiers' => false,
            'log' => false,
            //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
        ], 
    ],
    //・・・


```

続いて接続情報の修正を行います。

設定するファイルはconfig/app_local.phpで行います。

書き換える値はdocker-compose.yml及び.envに記載した内容です。

```php
    //・・・
    'Datasources' => [
        'default' => [
            'host' => '172.10.0.3', // ←DBコンテナのアドレス
            //・・・
            'username' => 'postgres', // ←ユーザー名
            'password' => 'postgres', // ←パスワード

            'database' => 'sampledb', // ←データベース名
            //・・・
        ],

        'test' => [
            'host' => '172.10.0.3',
            //'port' => 'non_standard_port_number',
            'username' => 'postgres',
            'password' => 'postgres',
            'database' => 'sampledb',
            //・・・
        ],
    ],
    //・・・
```

## Apacheの設定変更

この状態で`「http://localhost:8888/cake」`にアクセスするとCakePHPのページが開きますが、下記のようなエラーが出ています。

これを解消するためにはApacheの設定を修正する必要があります。

![2024-06-05-22-32-15-image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635129/3bd38273-d934-82b5-581b-198fd25d3dc0.png)


設定ファイルは/etc/httpd/conf/httpd.confになります。Dockerfileにてvimを入れているのでviで編集できます。

```bash
vi /etc/httpd/conf/httpd.conf
```

/var/www/htmの記載のあるDirectoryブロック内でAllowOverrideのNoneをAllに書き換えます。

```text
・・・
<Directory "/var/www/html">
    ・・・
    AllowOverride All ←Noneから変更
    ・・・
</Directory>
・・
```

## CakePHPの画面確認

最後に「http://localhost:8888/cake/」でCakePHPのページが表示されることを確認します。

![2024-06-05-22-47-38-image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635129/d95b5311-5751-8268-eeee-de5bf94058ca.png)


いい感じです。

## おわりに

公式のイメージは便利ですが、細かい指定ができないのでピンポイントで環境を構築したい場合は今回のようにOSのイメージをベースに構築をする必要がありそうです。