Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What are the problem?
@morita-toyscreation

Docker ComposeでNginx+PHP+MySQL+Redis環境を構築

Docker ComposeでNginx+PHP+MySQL+Redis環境を構築

2021年現在最新のNginx+PHP+MySQL+Redis環境を構築しました
各サービス項目の説明まで

Docker構成

コンテナ ミドルウェア
Web Nginx
PHP PHP8
DB MySQL
Redis Redis

ディレクトリ構成

docker_lamp/  
|-- mysql  
|   |-- dump  
|   |   `-- setup.sql  
|   |-- logs
|   |-- mount  
|   `-- settings
|       `-- my.cnf
|-- php  
|   |-- logs  
|   |-- settings  
|   |   |-- php.dev.ini
|   |   |-- php.prod.ini
|   |   |-- www.dev.conf
|   |   `-- www.prod.conf  
|   `-- Dockerfile
|-- project  
|   `-- html
|        `-- public 
|            `-- index.php
|-- redis  
|   `-- mount  
|-- web  
|   |-- logs  
|   `-- settings
|       |-- default.conf
|       `-- nginx.conf
`-- docker-compose.yml

docker-compose.yaml

PHPはDockerfileを使って自分でイメージを作成
他は公式イメージを利用

一旦全体

version: '3'
services:
  web:
    image: nginx:alpine
    volumes:
      - "./web/settings/default.conf:/etc/nginx/conf.d/default.conf"
      - "./web/settings/nginx.conf:/etc/nginx/nginx.conf"
      - "./project/html:/var/www/html"
      - "./web/logs:/var/log/nginx"
    ports:
      - "8080:80"
    restart: always
    depends_on:
      - php
      - mysql
      - redis
  php:
    build: ./php
    volumes:
      - "./project/html:/var/www/html"
    restart: always
  mysql:
    image: mysql:8.0
    ports:
      - "13306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: p@ssw0rd
      MYSQL_DATABASE: test
      MYSQL_USER: dev
      MYSQL_PASSWORD: dev
      TZ: Asia/Tokyo
    volumes:
      - "./mysql/mount:/var/lib/mysql"
      - "./mysql/settings/my.cnf:/etc/mysql/conf.d/my.cnf"
      - "./mysql/dump/setup.sql:/docker-entrypoint-initdb.d/dump.sql"
      - "./mysql/logs:/var/log/mysql"
    restart: always
  redis:
    image: redis:alpine
    ports:
      - "16379:6379"
    volumes:
      - "./redis/mount:/data"

各項目説明

Nginx

  1. 外部アクセス用に8080ポートを公開
  2. 設定ファイル、プロジェクト、ログはvolumesで同期

※ 設定ファイルは後半に紹介

  web:
    image: nginx:alpine
    volumes:
      - "./web/settings/default.conf:/etc/nginx/conf.d/default.conf"
      - "./web/settings/nginx.conf:/etc/nginx/nginx.conf"
      - "./project/html:/var/www/html"
      - "./web/logs:/var/log/nginx"
    ports:
      - "8080:80"
    restart: always
    depends_on:
      - php
      - mysql
      - redis

PHP

プロジェクトはvolumesで同期

  php:
    build: ./php
    volumes:
      - "./project/html:/var/www/html"

Dockerfile

  1. PHP用イメージ
  2. Redis、MySQLを利用するためdocker-php-ext-installを使いPHP拡張をインストール
  3. 設定ファイルをCOPYを使い反映

※ 設定ファイルは後半に紹介

FROM php:8.0-fpm

RUN apt-get update && apt-get install -y git

RUN git clone https://github.com/phpredis/phpredis.git /usr/src/php/ext/redis
RUN docker-php-ext-install mysqli redis

COPY settings/php.dev.ini /usr/local/etc/php/conf.d/php.ini
COPY settings/www.dev.conf /usr/local/etc/php-fpm.d/www.conf

MySQL

  1. 外部アクセス用に13306ポートを公開
  2. environmentの設定を行うとコンテナ作成時に自動でパスワード作成、データベース作成などが自動で実行(今回はルートパスワード設定、データベース、ユーザー、タイムゾーンを設定)
  3. リソースはvolumesを使いmount以下に同期(Dockerを停止してもデータを残す)
  4. 設定ファイル、ログはvolumesで同期
  5. 作成時に実行させたいSQLはvolumesで /docker-entrypoint-initdb.d/dump.sql に同期すると自動で実行
  mysql:
    image: mysql:8.0
    ports:
      - "13306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: p@ssw0rd
      MYSQL_DATABASE: test
      MYSQL_USER: dev
      MYSQL_PASSWORD: dev
      TZ: Asia/Tokyo
    volumes:
      - "./mysql/mount:/var/lib/mysql"
      - "./mysql/settings/my.cnf:/etc/mysql/conf.d/my.cnf"
      - "./mysql/dump/setup.sql:/docker-entrypoint-initdb.d/dump.sql"
      - "./mysql/logs:/var/log/mysql"
    restart: always

Redis

  1. 外部アクセス用に16379ポートを公開
  2. リソースはvolumesを使いmount以下に同期(Dockerを停止してもデータを残す)
  redis:
    image: redis:alpine
    ports:
      - "16379:6379"
    volumes:
      - "./redis/mount:/data"

設定ファイル

デフォルトで動かしてもいいですが、ECS運用も考慮して設定ファイルを用意

Nginx

default.conf

※ 構築時にCodeigniter, FuelPHP環境の構築を考えていたのでこの形になった
ポイントは fastcgi_pass php:9000; ホストをdocker-composeのサービス名(php)に変更

server {
    listen  80 default;
    server_name  localhost;

    charset utf-8;

    root /var/www/html/public;
    index index.php index.html index.htm;

    location / {
        index index.php index.html index.htm;
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location /admin {
        auth_basic "Restricted";
        auth_basic_user_file /etc/nginx/.htpasswd;
        index index.php index.html index.htm;
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location /reploxy {
        internal;
        resolver 8.8.8.8;
        set $reproxy $upstream_http_x_reproxy_url;
        proxy_pass $reproxy;
        proxy_set_header Authorization "";
    }

    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param FUEL_ENV "development";
        fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
        include fastcgi_params;
    }
}

nginx.conf

ログの場所など指定

user  nginx nginx;
worker_processes  2;
pid  /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;
    error_log  /var/log/nginx/error.log warn;

    sendfile off;
    tcp_nopush on;
    tcp_nodelay  off;
    keepalive_timeout  30;
    send_timeout 60;

    gzip  on;
    gzip_http_version 1.0;
    gzip_comp_level 6;
    gzip_proxied any;
    gzip_min_length 10000;
    gzip_types  text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
    gzip_disable "MSIE [1-6] \.";

    include /etc/nginx/conf.d/*.conf;
}

PHP

php.ini、www.conf設定ファイルは以下サイトを参考にさせていただきました

MySQL

my.cnf

文字コード、ログの場所など指定

[mysqld]
# 文字コード/照合順序の設定
character-set-server = utf8mb4
collation-server = utf8mb4_bin

# タイムゾーンの設定
default-time-zone = SYSTEM
log_timestamps = SYSTEM

# デフォルト認証プラグインの設定
default-authentication-plugin = mysql_native_password

# エラーログの設定
log-error = /var/log/mysql/mysql-error.log

# スロークエリログの設定
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 5.0
log_queries_not_using_indexes = 0

# 実行ログの設定
general_log = 1
general_log_file = /var/log/mysql/mysql-query.log

[mysql]
default-character-set = utf8mb4

[client]
default-character-set = utf8mb4

実行ファイル

PHP

index.php

サンプルでMySQLとRedisを使う
ポイントは接続ホストにDockerのサービス名を使うmysql redis

<?php

// MySQLテスト
echo "MySQLテスト<br />";
$mysqli = mysqli_connect("mysql", "dev", "dev", "test");
$query = "SELECT * FROM `user`";
$result = $mysqli->query($query);
$rows = array();
while ($row = $result->fetch_assoc()) {
    $rows[] = $row;
}
var_dump($rows);

echo "<hr />";

// Redisテスト
echo "Redisテスト<br />";
$redis = new Redis();
$redis->connect("redis", 6379);
$redis->set('key', 'value');
echo $redis->get('key');

MySQL

setup.sql

サンプル用のSQL "./mysql/dump/setup.sql:/docker-entrypoint-initdb.d/dump.sql" の設定でコンテナ作成時にクエリ実行

use test;

DROP TABLE IF EXISTS `test`;

CREATE TABLE `user` (
  `name` VARCHAR(255) NOT NULL COMMENT 'Name',
  `age` INT(10) unsigned NOT NULL COMMENT 'Age',
  `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='テスト用';

INSERT INTO `user` VALUES ("TAKASHI", 34, "0000-01-01", "9999-12-31");

docker-compose 実行

ビルドして実行

$ docker-compose up --build

確認

http://127.0.0.1:8080/ にアクセス、表示を確認

スクリーンショット 2021-05-11 9.25.47.png


次回はこの環境下にComposer、Xdebug、PHPフレームワーク(Codeigniter予定)、UnitTest等を使えるようしていきます。
いいね!と思ったら フォロー、LGTM お願いします :clap::clap::clap:

【PR】プログラミング新聞リリースしました! → https://pronichi.com
【PR】週末ハッカソンというイベントやってます! → https://weekend-hackathon.toyscreation.jp/about/

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
2
Help us understand the problem. What are the problem?