local docker 環境の説明

本記事は、サムザップ <a href="https://qiita.com/advent-calendar/2020/sumzap1">Advent Calendar 2020 #1</a> の 12/5 の記事です。

スマホゲームの企画・運営事業を行っているサムザップで、エンジニアをしています森本です

サムザップでは、local 環境を docker を用いて構築しているプロジェクトが多いです
その一例として、私の関わっているプロジェクトでの local 環境を紹介したいと思います
使用している docker コンテナは以下等です

- nginx
- php-fpm
- MySQL
- memcache
- Redis
- phpmyadmin

また、DB マイグレーションに

- phinx migration

を使用しています

#フォルダ構成

```

local/
　├ application/
　│　├ mysql/
　│　│　├ 1_initial_mysql.sh
　│　│　└ 2_initial_mysql.sql
　│　└ web/
　│　　　└ initial_web.sh
　├ docker/
　│　├ gatling/
　│　│　└ Dockerfile
　│　├ misc/
　│　│　└ data/
　│　│　　　└ DB実態
　│　├ nginx/
　│　│　├ 鍵回り省略
　│　│　├ Dockerfile
　│　│　├ fastcgi.conf
　│　│　├ nginx.conf
　│　│　└ server.conf
　│　├ php-fpm/
　│　│　├ Dockerfile
　│　│　├ php.ini
　│　│　└ www.conf
　│　└ docker-compose.yml
　├ dump/
　│　└ 移行前のDB,テーブル定義
　├ mysql/
　│　└ custom.cnf
　└ phpmyadmin/
　　　├ conf/
　　　│　└ config.user.inc.php
　　　└ sessions/
　　　　　└ 省略
```


#local/application/
###local/application/mysql/

docker の MySQL image では /docker-entrypoint-initdb.d/ というディレクトリ内に初期化用の SQL やスクリプトを置くことで、最初に image を起動したときにデータの初期化を自動的に行う仕組みがあります

- 1_initial_mysql.sh

```
cd /dump/
zcat 過去DB_table.gz | mysql -uroot -p*****
...
```

phinx 導入前の DB、テーブルを作成しています

- 2_initial_mysql.sql

```
grant all on *.* to user1@'%' identified by '*****';
grant all on *.* to user2@'%' identified by '*****';
...
insert ...
```
mysql ユーザー作成、管理画面初期データ作成　しています

実行順は、ファイル名順のため、ファイル名の頭に「1_」「2_」がついています

###local/application/web/
- initial_web.sh

```

cd .../PhinxMigration
if [ ! -e vendor ]; then
	リンク作成(省略)
	cd .../PhinxMigration
	composer install
else
	until mysqladmin ping -h mysql --silent; do
		echo ""
		echo 'waiting for mysqld to be connectable...'
		echo ""
		sleep 3
	done
	cd .../phinx_migration/
	make migrate ENV=localhost
fi
```

web 起動時

初回起動の場合
(という切り分けができなかったので、composer install に実行時に作成される vender フォルダがない場合)
　　cd .../PhinxMigration
　　composer install 実行

初回起動ではない場合
(vender フォルダがある場合)
　　mysql サーバが立ち上がるまでループ
　　DB マイグレーション同期実行

を実行しています


docker 起動時(=web 起動時) に、毎回、DB マイグレーション同期実行　するようにしています

composer install 実行後、DB マイグレーション同期実行　する方法(else の削除)
は、課題として残っています


#local/docker/
###local/application/nginx/

 - Dockerfile

```
FROM nginx

ADD nginx.conf /etc/nginx/nginx.conf
ADD fastcgi.conf /etc/nginx/fastcgi.conf
ADD server.conf /etc/nginx/conf.d/default.conf
ADD localhost.key /etc/ssl/private/localhost.key
ADD localhost.crt /etc/ssl/certs/localhost.crt
ADD dhparam.pem /etc/nginx/ssl/dhparam.pem
```
nginx イメージに各設定ファイルをaddしています

 - fastcgi.conf

```
fastcgi_param   QUERY_STRING            $query_string;
fastcgi_param   REQUEST_METHOD          $request_method;
...
```

一般的な検索結果サイトから取得したもの
＋
プロジェクトで使用しているものを追加しています


- nginx.conf

```
user			www-data;
pid		/var/run/nginx.pid;

# coreモジュールの設定

http{
    # httpモジュールの設定
}
...
```

一般的な検索結果サイトから取得したもの
＋
ソケット通信に変更しています
user            www-data;
pid     /var/run/nginx.pid;

- server.conf

```
server {
	listen 80;
	...
}
server {
	listen 443 ssl http2;
	...

	location / {
		# other
		try_files $uri $uri/ /index.php?$args;
	}
	location ~ \.php$ {
		fastcgi_pass unix:/var/run/php7-fpm.sock;
		fastcgi_index index.php;
		include      fastcgi.conf;
	}

	ssl_certificate             /etc/ssl/certs/localhost.crt;
	ssl_certificate_key         /etc/ssl/private/localhost.key;
	...
}
server {
	listen 80;
	server_name ~^(?<user>.+)\.local\.jp$;

	root       /var/www/$user/;
	...
}
```

一般的な検索結果サイトから取得したもの
＋
プロジェクトで使用している設定（記述変更、削除しています）
＋
ソケット通信に変更しています
fastcgi_pass unix:/var/run/php7-fpm.sock;


また、ローカルに複数ソースを git clone している人のために

例
test.local.jp
にアクセスすると
/var/www/test/
以下のソースを見に行くようにしています

###local/application/php-fpm/

- Dockerfile

```
FROM php:7.4-fpm

ADD php.ini /usr/local/etc/php/conf.d/php.ini
ADD www.conf /usr/local/etc/php-fpm.d/zzz-www.conf

RUN apt-get update && apt-get install -y libmcrypt-dev mariadb-client bc zlib1g-dev libmemcached-dev procps curl unzip git libonig-dev \
  && docker-php-ext-install pdo_mysql mysqli mbstring opcache bcmath

RUN pecl install memcached-3.1.3 \
    && docker-php-ext-enable memcached

RUN mkdir -p /usr/src/php/ext/redis \
    && curl -L https://github.com/phpredis/phpredis/archive/5.1.1.tar.gz | tar xvz -C /usr/src/php/ext/redis --strip 1 \
    && echo 'redis' >> /usr/src/php-available-exts \
    && docker-php-ext-install redis

RUN pecl install timecop-beta \
    && docker-php-ext-enable timecop

RUN pecl install apcu \
  && docker-php-ext-enable apcu

# install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
```
ソケット通信の設定ファイルは、「zzz-」をつける必要があります
<a href="https://yoshinorin.net/2017/03/06/php-official-docker-image-trap/">PHPの公式DockerイメージでUNIXソケット通信しようとして罠にハマるの巻</a>
ADD www\.conf /usr/local/etc/php-fpm.d/zzz-www\.conf

- www\.conf

ソケット回りの設定等

```
[www]
listen = /var/run/php7-fpm.sock
listen.owner = www-data
listen.group = www-data
request_terminate_timeout = 30s
```


###local/application/docker-compose.yml

```
version: '3.7'

volumes:
  php_sockert:

services:
  memcached:
    image: memcached
    container_name: memcached

  redis:
    image: redis
    container_name: redis

  mysql:
    image: mysql:5.7.31
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci --max_allowed_packet=32M
    environment:
      MYSQL_ROOT_PASSWORD: ********
      MYSQL_DATABASE: mysql_database
      MYSQL_USER: user
      MYSQL_PASSWORD: ********
      TZ: "Asia/Tokyo"
    ports:
      - "3306:3306"
    volumes:
      - ../application/mysql/:/docker-entrypoint-initdb.d/
      - ../dump/:/dump/
      - ../mysql/:/etc/mysql/conf.d/
      - ./misc/data:/var/lib/mysql
    container_name: mysql

  nginx:
    build: ./nginx
    ports:
      - "80:80"
      - "443:443"
    environment:
      TZ: "Asia/Tokyo"
    volumes:
      - ../../local/:/var/www/local
      # local複数環境用     - ../../test/:/var/www/test
      - php_sockert:/var/run
    depends_on:
      - web
    container_name: nginx

  web:
    build: ./php-fpm
    tty: true
    privileged: true
    ulimits:
      core: -1
    volumes:
      - ../application/web/initial_web.sh:/tmp/initial_web.sh
      - ../../local/:/var/www/local
      # local複数環境用     - ../../test/:/var/www/test
      - php_sockert:/var/run
    depends_on:
      - mysql
      - memcached
      - redis
      - rabbitmq
    environment:
      DATABASE_HOST: 'mysql'
      DATABASE_NAME: 'mysql_database'
      DATABASE_USER: 'user'
      DATABASE_PASSWORD: '********'
      TZ: "Asia/Tokyo"
    command: bash -c "bash /tmp/initial_web.sh && php-fpm"
    container_name: web

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOST=mysql
      - PMA_USER=root
      - PMA_PASSWORD=********
    links:
      - mysql
    ports:
      - 8080:80
    volumes:
      - ../phpmyadmin/sessions:/sessions
      - ../phpmyadmin/conf/config.user.inc.php:/etc/phpmyadmin/config.user.inc.php
```

image: memcached
docker hub から落としてくるイメージです

image: mysql:5.7.31
等「:」でバージョン指定可能です

nginx:
　　build: ./nginx
のように記述すると、./nginx/Dockerfile を読みにいきます
Dockerfile 内で image を指定したり
command を指定したりしています

container_name: memcached
etc/hosts に上記名称が追加されます

volumes:
　　-  ./misc/data:/var/lib/mysql
ホストの /misc/data 以下と
ゲストの /var/lib/mysql 以下が共有されます

mysql 上記データをホストとゲストを共有していないと、docker の mysql を落とすとデータが削除されます

volumes:
　php_sockert:

　nginx:
　　volumes:
　　　- php_sockert:/var/run

　web:
　　volumes:
　　　- php_sockert:/var/run
　
nginx と web の /var/run が共有されます
ソケットで使用しています


command:
　イメージが作られた時点で、記述内容が実行されます
ports:
　ホストのポートとゲストのポートが結びつきます

nginx:depends_on:
　　-  web
nginx コンテナからwebコンテナへ通信するため web 起動してから、nginx 起動するように設定

#最後に
私の関わっているプロジェクトでの local 環境を紹介いたしました

今後は

- 本文中に記述した問題の改修
- jenkins 導入

などを改修、導入できればと思っています!!

明日は @shirai_suguru です。お楽しみに!!

サムザップのアドベントカレンダーは人数の関係上2つあります。
こちらもよろしくお願いいたします！
<a href="https://qiita.com/advent-calendar/2020/sumzap2">サムザップ #2 Advent Calendar 2020 - Qiita</a>