複数のプロジェクトで Docker を使用する場合の個人的ベストプラクティス

zumikiti

November 26, 2021

社内でDockerを利用したプロジェクトが増えてきて、ポートの競合問題やコンテナが多すぎて重いなどの問題があり、「ひとまず現状これがベストかな?」と思える設定に落ち着いたので、それを書く。

概要

注意

DBを共有にするため、プロジェクト毎にDBのバージョンを分けたい場合には対応できない。

そういった場合は、
律儀に、ポート番号が被らないように各プロジェクトで設定するか
ループバックアドレスをプロジェクト毎に割り当てるか (https://qiita.com/hanlio/items/243006a67fb8d535d958)
で対応が可能です。

ディレクトリ構成

.
├── webdev
│   ├── dump/
│   └── docker-compose.yaml
├── project1
│   ├── docker-compose.yaml
│   └── etc...
└── project2
    ├── docker-compose.yaml
    └── etc...

共通コンテナの設定

adwin さんが公開してくれているリポジトリに nginx-proxy を追加いただけ。
https://github.com/adwinying/webdev

docker-compose.yaml

version: '3'
services:
  mysql:
    image: mysql:5.7
    ports:
      - '${MYSQL_PORT:-3306}:3306'
    environment:
      MYSQL_ROOT_PASSWORD: '${DB_PASSWORD:-password}'
      MYSQL_DATABASE: '${DB_DATABASE:-db}'
      MYSQL_USER: '${DB_USERNAME:-sail}'
      MYSQL_PASSWORD: '${DB_PASSWORD:-password}'
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
    volumes:
      - 'webdev-mysql:/var/lib/mysql'
      - './dump:/tmp/dump'
    networks:
      - webdev
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD:-password}"]
      retries: 3
      timeout: 5s


  pgsql:
    image: postgres:13
    ports:
      - '${PGSQL_PORT:-5432}:5432'
    environment:
      PGPASSWORD: '${DB_PASSWORD:-password}'
      POSTGRES_DB: '${DB_DATABASE:-db}'
      POSTGRES_USER: '${DB_USERNAME:-sail}'
      POSTGRES_PASSWORD: '${DB_PASSWORD:-password}'
    volumes:
      - 'webdev-pgsql:/var/lib/postgresql/data'
      - './dump:/tmp/dump'
    networks:
      - webdev
    healthcheck:
      test: ["CMD", "pg_isready", "-q", "-d", "${DB_DATABASE:-db}", "-U", "${DB_USERNAME:-sail}"]
      retries: 3
      timeout: 5s


  redis:
    image: 'redis:alpine'
    ports:
      - '${REDIS_PORT:-6379}:6379'
    volumes:
      - 'webdev-redis:/data'
    networks:
      - webdev
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      retries: 3
      timeout: 5s


  meilisearch:
    image: 'getmeili/meilisearch:latest'
    ports:
      - '${MEILISEARCH_PORT:-7700}:7700'
    volumes:
      - 'webdev-meilisearch:/data.ms'
    networks:
      - webdev


  mailhog:
    image: 'mailhog/mailhog:latest'
    ports:
      - '${MAILHOG_PORT:-1025}:1025'
      - '${MAILHOG_DASHBOARD_PORT:-8025}:8025'
    networks:
      - webdev


  proxy:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    ports:
      - "127.0.0.1:80:80"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
    restart: always
    privileged: true
    networks:
      - webdev


networks:
  webdev:
    name: webdev
    driver: bridge


volumes:
  webdev-mysql:
    driver: local
  webdev-pgsql:
    driver: local
  webdev-redis:
    driver: local
  webdev-meilisearch:
    driver: local

プロジェクト毎の設定

共通コンテナを立ち上げた後、プロジェクト毎では web のコンテナだけ起動すれば良い

docker-compose.yaml

version: '3'

services:
  app:
    image: thecodingmachine/php:7.4-v4-apache
    ports:
      - '80'
    environment:
      PHP_EXTENSIONS: bcmath gd intl pdo_pgsql pgsql
      PHP_INI_MEMORY_LIMIT: 512M
      PHP_INI_DATE__TIMEZONE: Asia/Tokyo
      PHP_INI_MBSTRING__LANGUAGE: Japanese
      APACHE_DOCUMENT_ROOT: /var/www/html/public
      VIRTUAL_HOST: 'laravel.test'
    volumes:
      - '.:/var/www/html'
    networks:
      - webdev

networks:
  webdev:
    external: true
    name: webdev

hosts ファイル

hostsファイルに、 VIRTUAL_HOST の値を追記。

127.0.0.1 laravel.test

おまけ

少しズレるが、docker-compose コマンドが長すぎるので、Taskfile の設定も置いておきます。

使用手順

  1. docker-compose.yaml と同一階層に置く
  2. chmod 755 ./Taskfile で権限を変更する
  3. alias task=./Taskfile などとエイリアスを設定する

これで準備完了です。

task artisan migrate などで実行できるので便利!

Taskfile

#!/bin/bash
# https://github.com/adriancooney/Taskfile#install

function up {
  docker-compose up -d
}

function down {
  docker-compose down
}

function restart {
  docker-compose restart
}

function exec {
  docker-compose exec app "$@"
}

function bash {
  exec bash
}

function php {
  exec /usr/bin/php "$@"
}

function artisan {
  exec /usr/bin/php artisan "$@"
}

function composer {
  exec /usr/local/bin/composer "$@"
}

function test {
  exec vendor/bin/phpunit "$@"
}

function tinker {
  artisan tinker
}

function start {
  echo "start task not implemented"
}

function default {
  help
}

function help {
    echo "$0 <task> <args>"
    echo "Tasks:"
    compgen -A function | cat -n
}

TIMEFORMAT="Task completed in %3lR"
time ${@:-default}