かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

Docker Nginx + PHP + MySQL + Redis な環境作った。

Docker 一年生なので、雰囲気で作っています。

構成

/-- docker-compose.yml
 |- /web
 |   |- /html … web root
 |- /mysql
 |   |- Dockerfile
 |   |- my.conf
 |   |- /init
 |      |- 1_dd.sql … DB 初期化
 |- /nginx
 |   |- nginx.conf
 |   |- /log
 |      |- access.log
 |      |- error.log
 |- /php
 |   |- Dockerfile
 |   |- php.ini
 |- /redis

docker-compose.yml

version: '3'
services:
  nginx:
    image: nginx:latest
    ports:
      - 8080:80
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
      - ./nginx/log/access.log:/var/log/nginx/access.log
      - ./nginx/log/error.log:/var/log/nginx/error.log
      - ./web:/var/www
    depends_on:
      - web

  web:
    build:
      context: ./php
      dockerfile: Dockerfile
    volumes:
      - ./web:/var/www
    depends_on:
      - db
      - redis
    tty: true

  db:
    build:
      context: ./mysql
      dockerfile: Dockerfile
    ports:
      - 13306:3306
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
      - ./mysql/init:/docker-entrypoint-initdb.d
    environment:
      # root ユーザーのパスワードを root に設定
      MYSQL_ROOT_PASSWORD: root
    command: mysqld --character-set-server=utf8 --collation-server=utf8_general_ci

  phpmyadmin:
    image: phpmyadmin/phpmyadmin:latest
    ports:
      - 8888:80
    depends_on:
      - db

  redis:
    image: redis:latest
    volumes:
      - ./redis/data:/data
    ports:
      - 6379:6379
    command: redis-server

PHP composer, PDO, Redis

/php/Dockerfile

FROM php:7.4-fpm
RUN apt-get update
RUN apt-get install -y vim
RUN apt-get install -y zip unzip git
RUN git clone https://github.com/phpredis/phpredis.git /usr/src/php/ext/redis

RUN docker-php-ext-install pdo_mysql redis

COPY php.ini /usr/local/etc/php/
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

/php/php.ini

date.timezone = "Asia/Tokyo"

nginx.conf

/nginx/conf

server {
    listen 80;
    server_name localhost;

    root  /var/www/html;
    index index.php index.html;
    
    underscores_in_headers on;

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

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

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

underscores_in_headers on; の設定をしておくと Authorization_ (アンダースコア)を含むカスタムヘッダーを PHP$_SERVER で取得できるようになる。
カスタムヘッダーなどが取得できない時はこの設定を追加してみると良いかも。
cf. PHP - Get Custom Headers when Using Nginx with php-fpm - Stack Overflow

MySQL

/mysql/Dockerfile

FROM mysql:5.7

COPY init/* /docker-entrypoint-initdb.d/

CMD ["mysqld"]

/mysql/my.conf

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

[client]
default-character-set=utf8

/mysql/init/ … このディレクトリ内にあるスクリプトが順番に実行される。database, table を初期化時に作成したりデータを入れたりする sql ファイルを置いておく

e.g. _dd.sql

CREATE DATABASE IF NOT EXISTS test;

CREATE TABLE IF NOT EXISTS test.users (...);

INSERT INTO test.users …;

build・動作確認

$ docker-compose build
$ docker-compose up

エラーにならず build と 起動ができればOK

/web/html 内に test.php を作成して PDO での MySQL への接続と Redis が使えることを確かめます。

<?php // /web/html/test.php

// MySQL with PDO
$dns = 'mysql:dbname=' . DB_NAME . ';host=db;charset=utf8;';
$options = [
  // カラム型に合わない値がINSERTされようとしたときSQLエラーとする
  PDO::MYSQL_ATTR_INIT_COMMAND => "SET SESSION sql_mode='TRADITIONAL'",
  // SQLエラー発生時にPDOExceptionをスローさせる
  PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
];
try {
  $pdo = new PDO($dns, DB_USER, DB_PASSWORD, $options);
  var_dump($pdo);
} catch (PDOException $e) {
  echo $e->getMessage();
}

// Redis
$redis = new Redis();
// connect の第一引数は docker-compose.yml のイメージ名を指定する
$redis->connect('redis', 6379);
var_dump($redis->ping()); // => true

phpinfo();

localhost:8080/test.php にアクセスして MySQL / Redis への接続・phpinfo の表示がされていれば OK

フロントは別に create-react-app とかして proxy を設定すれば docker 外からアクセス可能なので、APIとして利用することもできます。

おわり。


[参考]

👆ぶっちゃげただの木だけど手首痛くならななくなったので良い買い物だった