ある程度簡単にdocker-composeで開発環境を構築する手順です
この手の記事はよくあるので、設定自体は全然煮詰まってないかもしれませんが、
このやり方以下のポイントを意識しています
- dockerイメージのビルドをしない(公式のイメージのまま利用)
- SSL対応
- WEBコンテナのユーザIDをホスト側のユーザIDに合わせる
1が個人的1番のポイントで好みですが、取り急ぎテスト的に環境作って始めるときに、使い捨てになるかもしれないイメージをローカルに作りたくないという動機です。
(開発環境として安定したらビルドしたほうが環境の立ち上げが早くなるし良いと思います)
2は本番環境はSSLなのでローカルもできるだけSSLにしたい、
3はホスト側とコンテナ側でユーザIDが合わないと開発中にファイルのパーミッションでこけることがちょくちょくあるので合わせるようにしています。
Laravel限定のネタではないですが、例としてLaravelの環境を構築します、
初期準備ファイル
$ tree -L 3
.
├── docker-compose.yml
└── docker_config
└── web
├── logs ※ディレクトリ
├── make_env.sh
└── web.conf
docker-compose.yml
php-apache, nodejs, mysql, mailhogのコンテナが含まれています。
見ての通りですが、buildは行わず、commnad でコンテナの立ち上げ時に初期設定を行います。そのため、ビルド済みのイメージに比べてコンテナが利用できる状態になるまでに多少時間がかかります。
冒頭に書いた公式のイメージのままビルドせずに利用するのですが、なんとなくプロジェクトごとにかっちりとイメージをビルドするのが面倒なのでとりあえずこれでスタートしています。
command の中で変数で LOCALGID
LOCALGID
を埋め込んでいますが、ホスト側のユーザID,グループIDを受け渡すことで、コンテナ内の www-data ユーザをホスト側のIDで作り直し、パーミッション関連の問題が発生しないように努めています。
.envに変数定義しておけば、docker-compose.yml内で利用できます。
version: '3'
volumes:
db_volume:
services:
web:
image: php:8.1-apache-buster
ports:
- "443:443"
volumes:
- ./:/var/www/html/
- ./docker_config/web/web.conf:/etc/apache2/sites-available/web.conf
- ./docker_config/web/ssl.crt:/etc/ssl/certs/ssl.crt
- ./docker_config/web/ssl.key:/etc/ssl/private/ssl.key
working_dir: /var/www/html/project_root
tty: true
env_file:
- ./.env
entrypoint: /bin/bash
command: >
-c "
#update
apt-get update;
apt-get install -y libzip-dev;
#php拡張インストール
docker-php-ext-install zip;
docker-php-ext-install pdo_mysql mysqli;
#xdebugインストール
pecl install xdebug && docker-php-ext-enable xdebug;
#www-dataユーザの削除、再作成(ローカルユーザIDと合わせる)
userdel -r www-data;
groupadd -g ${LOCALGID} www-data;
useradd -M -u ${LOCALUID} -g ${LOCALGID} -s /sbin/nologin www-data;
#apacheモジュールの有効化
a2enmod ssl;
a2enmod rewrite;
#apacheサイトの有効化
a2ensite ssl;
a2ensite web;
#apacheデフォルトサイトの無効化
a2dissite 000-default;
#php.iniのコピー
cp /usr/local/etc/php/php.ini-development /usr/local/etc/php/php.ini;
#php.iniのメモリリミットの拡張
sed -i.bk -e 's/memory_limit = 128M/memory_limit = 8192M/gi' /usr/local/etc/php/php.ini ;
#apacheコンフィグテスト
apachectl configtest;
#composerのインストール
curl -sS https://getcomposer.org/installer | php -- --version=2.1.14 ;
mv composer.phar /usr/local/bin/composer ;
composer -v;
#xdebugの有効化
echo '#コメントアウト' > /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini ;
echo '#extension=xdebug' >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini ;
echo 'zend_extension=xdebug.so' >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini ;
echo 'xdebug.mode=coverage' >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini;
#apacheの起動
apache2-foreground
"
nodejs:
image: node:14.16.1-alpine
working_dir: /opt/project_root
volumes:
- ./project_root:/opt/project_root
user: ${LOCALUID}
tty: true
db:
image: mysql:8.0.23
environment:
- MYSQL_DATABASE=db_name
- MYSQL_USER=db_user
- MYSQL_PASSWORD=db_pass
- MYSQL_ROOT_PASSWORD=root_db_pass
- TZ=Asia/Tokyo
- BIND-ADDRESS=0.0.0.0
volumes:
- db_volume:/var/lib/mysql
ports:
- "33306:3306"
tty: true
command: >
--character-set-server=utf8mb4
--collation-server=utf8mb4_bin
--sql-mode=NO_ENGINE_SUBSTITUTION
--default-authentication-plugin=mysql_native_password
--local-infile=1
mailhog:
image: "mailhog/mailhog"
ports:
- "8025:8025"
tty: true
.envファイル作成用スクリプト
上述した LOCALGID
LOCALGID
を記述した.envファイルを作成するためのスクリプトです。
初回に docker-compose.yml up
する前に一回だけ実行します。
$ cat docker_config/web/make_env.sh
#!/bin/bash
THIS_DIR=$(cd $(dirname $0);pwd)
set -eu
cat <<EOT > ${THIS_DIR}/../../.env
LOCALUID=`id -u`
LOCALGID=`id -g`
EOT
実行すると .env が生成されます。
$ bash docker_config/web/make_env.sh
$ tree -La 1
├── .env
├── docker-compose.yml
└── docker_config
$ cat .env
LOCALUID=1000
LOCALGID=1000
ssl関連ファイル作成
$ cd docker_config/web/
$ openssl genrsa -out ssl.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
..............................................+++++
.........+++++
e is 65537 (0x010001)
$ openssl req -new -sha256 -key ssl.key -out ssl.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:localhost
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
$ echo "subjectAltName = DNS:localhost" > san.txt
$ openssl x509 -req -sha256 -days 3650 -signkey ssl.key -in ssl.csr -out ssl.crt -extfile san.txt
Signature ok
subject=C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = localhost
Getting Private key
SSl関連ファイル作成後のディレクトリ構成は以下のようになります
$ tree -L 3
.
├── docker-compose.yml
└── docker_config
└── web
├── logs ※ディレクトリ
├── make_env.sh
├── san.txt
├── ssl.crt
├── ssl.csr
├── ssl.key
└── web.conf
apache用コンフィグファイル
$ cat docker_config/web/web.conf
<IfModule mod_ssl.c>
<VirtualHost _default_:443>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html/project_root/public
ErrorLog /var/www/html/docker_config/web/logs/error.log
CustomLog /var/www/html/docker_config/web/logs/access.log combined
SSLEngine on
SSLCertificateFile /etc/ssl/certs/ssl.crt
SSLCertificateKeyFile /etc/ssl/private/ssl.key
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>
</VirtualHost>
</IfModule>
docker-compose up
コンテナを立ち上げます
$ docker-compose up -d
Creating network "[作業ディレクトリ]_default" with the default driver
Creating [作業ディレクトリ]_nodejs_1 ... done
Creating [作業ディレクトリ]_mailhog_1 ... done
Creating [作業ディレクトリ]_db_1 ... done
Creating [作業ディレクトリ]_web_1 ... done
docker logs -f コンテナ
でコンテナ内の出力を追います。
apache2 -D FOREGROUND
が表示されたらapacheの起動完了となります。
$ docker logs -f webコンテナ
AH00112: Warning: DocumentRoot [/var/www/html/project_root/public] does not exist
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.27.0.5. Set the 'ServerName' directive globally to suppress this message
AH00112: Warning: DocumentRoot [/var/www/html/project_root/public] does not exist
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.27.0.5. Set the 'ServerName' directive globally to suppress this message
[Tue Dec 21 15:59:41.322194 2021] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.38 (Debian) PHP/8.1.0 OpenSSL/1.1.1d configured -- resuming normal operations
[Tue Dec 21 15:59:41.322232 2021] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
コンテナに入ります。
-u $(id -u)
をつけることで、そのユーザIDでコンテナにアタッチされます。
つけない場合は、rootでログインされるので、コンテナ内でファイルの作成などすると、ホスト側でファイルの削除ができないなどの事象に当たる場合があったりします。
$ docker exec -u $(id -u) -it livewire_web_1 /bin/bash
ホスト側と同一のユーザIDでWEBユーザ(www-data)が作成されていることを確認します
www-data@16d3e36d1d88:/var/www/html$ id
uid=1000(www-data) gid=1000(www-data) groups=1000(www-data)
composerでlaravelのプロジェクトをインストールします
www-data@16d3e36d1d88:/var/www/html$ composer create-project laravel/laravel project_root
・・・
Package manifest generated successfully.
77 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> @php artisan vendor:publish --tag=laravel-assets --ansi --force
No publishable resources for tag [laravel-assets].
Publishing complete.
> @php artisan key:generate --ansi
Application key set successfully.
https://localhost にアクセスしてlaravelの初期ページが表示されることを確認します
警告が表示されていますが、最初に作った証明書ファイルをブラウザにインポートすれば警告表示も表示されなくなります。