💢
PHP(Debian + Apache) + MongoDBの構成でDocker環境を構築 + エラー解決の記録
概要
慣れているPHPで環境構築を行った結果、泥沼にハマったのでメモ。
環境
HomeBrewとDocker Desktop for MacとVSCodeが入ったMacOS
前提知識
- Docker
- Docker-compose
- PHP
Docker構成だけ知りたい人用
ディレクトリ構成
.
├── docker
│ ├── app
│ │ └── dockerfile
│ └── config
│ ├── 000-default.conf
│ └── php.ini
...省略...
├── vendor
├── composer.json
├── composer.lock
└── docker-compose.yml
./docker/app/dockerfile
# composer
FROM composer:latest AS composer
# PHP
FROM php:8.0.7-apache-buster
# 設定ファイルをコピー
COPY ./docker/config/php.ini /usr/local/etc/php/
COPY ./docker/config/000-default.conf /etc/apache2/sites-available/000-default.conf
# composer実行ファイルをコピー
COPY /usr/bin/composer /usr/bin/composer
# パッケージインストール
RUN \
# Apache rewriteモジュール有効化
a2enmod rewrite \
&& apt-get update \
&& apt-get install -y unzip libzip-dev zlib1g-dev \
&& apt-get install -y libcurl4-openssl-dev pkg-config libssl-dev \
# Extension
&& docker-php-ext-install zip \
# MongoDB driver
&& pecl install mongodb \
# Extension有効化
&& docker-php-ext-enable zip mongodb
/docker/config/000-default.conf
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
<Directory /var/www/html>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
./docker/config/php.ini
[Date]
date.timezone = "Asia/Tokyo"
[Mbstring]
default_charset = "UTF-8"
mbstring.language = "Japanese"
./docker-compose.yml
version: "3.8"
services:
# App Server
app:
build:
context: .
dockerfile: ./docker/app/Dockerfile
container_name: mongo_app
volumes:
- .:/var/www/html
ports:
- 8180:80
networks:
- mongo
# MongoDB
mongo:
image: mongo:latest
container_name: mongo_db
restart: always
environment:
# 接続情報
MONGO_INITDB_ROOT_USERNAME: fendi
MONGO_INITDB_ROOT_PASSWORD: fendi
volumes:
- mongo:/data/db
ports:
- "27017:27017"
networks:
- mongo
# MongoDB GUI
mongo_express:
image: mongo-express:latest
container_name: mongo_express
restart: always
ports:
- "8181:8081"
environment:
# MongoDBの接続情報
ME_CONFIG_MONGODB_ADMINUSERNAME: fendi
ME_CONFIG_MONGODB_ADMINPASSWORD: fendi
# MongoDBのポート
ME_CONFIG_MONGODB_PORT: 27017
# MongoDBのコンテナ名
ME_CONFIG_MONGODB_SERVER: mongo_db
networks:
- mongo
networks:
# 起動時のdefaultネットワーク再生成防止のためにdefaultを明示
default:
external:
name: bridge
mongo:
name: mongo_db
volumes:
mongo:
driver: local
MongoDB PHP Library
MongoDBをPHPで操作するためのライブラリが公式で配布されている。
docker-compose exec app composer require "mongodb/mongodb"
ディレクトリ構成
.
├── docker
│ ├── app
│ │ └── dockerfile
│ └── config
│ ├── 000-default.conf
│ └── php.ini
...省略...
├── vendor
├── composer.json
├── composer.lock
└── docker-compose.yml
./docker/app/dockerfile
# composer
FROM composer:latest AS composer
# PHP
FROM php:8.0.7-apache-buster
# 設定ファイルをコピー
COPY ./docker/config/php.ini /usr/local/etc/php/
COPY ./docker/config/000-default.conf /etc/apache2/sites-available/000-default.conf
# composer実行ファイルをコピー
COPY /usr/bin/composer /usr/bin/composer
# パッケージインストール
RUN \
# Apache rewriteモジュール有効化
a2enmod rewrite \
# debianパッケージ
&& apt-get update \
&& apt-get install -y unzip libzip-dev zlib1g-dev \
# Extension
&& docker-php-ext-install zip \
# MongoDB driver
&& pecl install mongodb \
# Extension有効化
&& docker-php-ext-enable zip mongodb
/docker/config/000-default.conf
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
<Directory /var/www/html>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
./docker/config/php.ini
[Date]
date.timezone = "Asia/Tokyo"
[Mbstring]
default_charset = "UTF-8"
mbstring.language = "Japanese"
./docker-compose.yml
version: "3.8"
services:
# App Server
app:
build:
context: .
dockerfile: ./docker/app/Dockerfile
container_name: mongo_app
volumes:
- .:/var/www/html
ports:
- 8180:80
networks:
- mongo
# MongoDB
mongo:
image: mongo:latest
container_name: mongo_db
restart: always
environment:
# 接続情報
MONGO_INITDB_ROOT_USERNAME: fendi
MONGO_INITDB_ROOT_PASSWORD: fendi
volumes:
- mongo:/data/db
ports:
- "27017:27017"
networks:
- mongo
# MongoDB GUI
mongo_express:
image: mongo-express:latest
container_name: mongo_express
restart: always
ports:
- "8181:8081"
environment:
# MongoDBの接続情報
ME_CONFIG_MONGODB_ADMINUSERNAME: fendi
ME_CONFIG_MONGODB_ADMINPASSWORD: fendi
# MongoDBのポート
ME_CONFIG_MONGODB_PORT: 27017
# MongoDBのコンテナ名
ME_CONFIG_MONGODB_SERVER: mongo_db
networks:
- mongo
networks:
# 起動時のdefaultネットワーク再生成防止のためにdefaultを明示
default:
external:
name: bridge
mongo:
name: mongo_db
volumes:
mongo:
driver: local
手順
1. Docker起動
docker-compose up -d --build
MongoDBドライバのインストールを確認。
MongoDBにも問題なく接続できる。
2. 「MongoDB PHP Library」をインストール
MongoDBをPHPで操作するためのライブラリが公式で配布されているのでcomposerでインストールを行う。
docker-compose exec app composer require "mongodb/mongodb"
3. テスト
とても簡単なスクリプトを実行して動作チェック。
test.php
<?php
// composerライブラリをインクルード
require './vendor/autoload.php';
use MongoDB\Client;
// MongoDBに接続
$mongo = new Client('mongodb://fendi:fendi@localhost:27017');
// $mongo = new Client(
// 'mongodb://localhost:27017',
// [
// 'username' => 'fendi',
// 'password' => 'fendi',
// ]
// );
// client->db->collectionの順にインスタンスを生成
$collection = $mongo
->test_db
->test_collection;
// jsonデータを登録
$collection->insertOne([
'test_1' => 'データを登録',
'test_2' => 'データを挿入',
]);
上記スクリプトを実行したところ謎のエラーが発生。
MongoDB\Driver\Exception\ConnectionTimeoutException: No suitable servers found (`serverSelectionTryOnce` set): [connection refused calling ismaster on 'localhost:27017'] in /var/www/html/vendor/mongodb/mongodb/src/functions.php on line 431
4. エラー解決
サーバーの接続先が見つからないのがエラーの原因らしい。
PHPのバージョンを落とす、Dockerコンテナ構成を変える、Laravel上でLaravel-mongodbを導入するなど色々試して解決を図るもうまくいかず。
ググっても解決手段が分からず、GitHubのissueでも同様の報告が多数上がっているよう。
解決できずissueの片隅で悲鳴を上げている人もちらほら。
ふとDBへ接続する際のホスト名をlocalhostからコンテナ名に変更してみたところ…
./test.php
<?php
// composerライブラリをインクルード
require './vendor/autoload.php';
use MongoDB\Client;
// ホストをlocalhostからコンテナ名に変更
$mongo = new Client('mongodb://fendi:fendi@mongo_db:27017');
...省略...
また別のエラーが発生。
MongoDB\Driver\Exception\AuthenticationException: The SCRAM_SHA_256 authentication mechanism requires libmongoc built with ENABLE_SSL in /var/www/html/vendor/mongodb/mongodb/src/Operation/InsertOne.php on line 134
調べたところibmongoc SSLがdisabledになっているのがエラーの原因のようなのでsslパッケージを追加して再度コンテナをビルド。
./docker/app/dockerfile
...省略...
# composer実行ファイルをコピー
COPY /usr/bin/composer /usr/bin/composer
# パッケージインストール
RUN \
# Apache rewriteモジュール有効化
a2enmod rewrite \
# debianパッケージ
&& apt-get update \
&& apt-get install -y unzip libzip-dev zlib1g-dev \
# Extension
&& docker-php-ext-install zip \
# mongodb接続用sslパッケージ
&& apt-get install -y libcurl4-openssl-dev pkg-config libssl-dev \
# MongoDB driver
&& pecl install mongodb \
# Extension有効化
&& docker-php-ext-enable zip mongodb
インストール成功。
再度スクリプトを実行すると…
うおおおおおおおおお!!!
Discussion