0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Dockerで(ほぼ)同じ開発環境を複数同時に起動したい

Last updated at Posted at 2024-08-21

はじめに

現在参画しているプロジェクトは、Dockerでローカルの開発環境を構築しています。
そのプロジェクトでDBのバージョンアップを行うことになり、動作確認をしたいため、新旧両バージョンのDBでのローカル開発環境を立ち上げたい!という作業をした時の記録です。

具体的には、以下のcomposeファイルで定義されているような構成の、DBのバージョンを変えたものを二つUPしたいという内容です。

docker-compose.yml
version: '3.3'
services:
  proxy:
    build: ../proxy
    environment:
      TZ: Asia/Tokyo
      DOCKER: 'true'
      DB_HOST: 192.168.210.5
      REDIS_HOST: 192.168.210.7
      REDIS_PORT: 6379
    tty: true
    stdin_open: true
    ports:
      - "127.0.0.1:8080:8080"
    volumes:
      - ../proxy:/app
    networks:
      app:
        ipv4_address: 192.168.210.8
  api:
    build: ../api
    environment:
      TZ: Asia/Tokyo
      DOCKER: 'true'
      DB_HOST: 192.168.210.5
      REDIS_HOST: 192.168.210.7
      REDIS_PORT: 6379
    tty: true
    stdin_open: true
    ports:
      - "127.0.0.1:9292:9292"
    volumes:
      - ../api:/app
    networks:
      app:
        ipv4_address: 192.168.210.3
  web:
    build: ../web
    environment:
      RAILS_ENV: development
      TZ: Asia/Tokyo
      DOCKER: 'true'
      DB_HOST: 192.168.210.5
      REDIS_HOST: 192.168.210.7
      REDIS_PORT: 6379
    tty: true
    stdin_open: true
    ports:
      - "127.0.0.1:3000:3000"
    volumes:
      - ../web:/app
    networks:
      app:
        ipv4_address: 192.168.210.6
  db:
    image: mysql:5.7.26
    environment:
      TZ: Asia/Tokyo
      MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
      MYSQL_USER: root
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    ports:
      - "127.0.0.1:3306:3306"
    volumes:
      - local-dev-mysql:/var/lib/mysql
    networks:
      app:
        ipv4_address: 192.168.210.5
  redis:
    image: redis:latest
    environment:
      TZ: Asia/Tokyo
    ports:
      - "127.0.0.1:6379:6379"
    networks:
      app:
        ipv4_address: 192.168.210.7
networks:
  app:
    ipam:
      config:
        - subnet: 192.168.210.0/24

volumes:
  local-dev-mysql:
    external: true

ここ(↓)を変えたものを2環境使いたい、というネタです。

  db:
-   image: mysql:5.7.26
+   image: mysql:8.0.28

参考にした記事

本文中に説明不足なところがあるかと思いますので、こちらの記事も参照いただくとよいと思います。

試した端末情報

①macOS Ventura 13.6.7 (M2 Mac×colima) ※普段の開発環境

docker -v
Docker version 24.0.4, build 3713ee1eea

docker-compose -v
Docker Compose version 2.20.0

docker compose version
Docker Compose version 2.20.0

②Windows 11 Pro 23H2 (Win11×WSL2×Ubuntu22)

docker -v
Docker version 26.1.3, build b72abbb

docker-compose -v
docker-compose version 1.29.2, build unknown

docker compose version
Docker Compose version v2.27.0

③macOS Sonoma 14.5 (intel Mac×Docker Desktop)

docker -v
Docker version 27.0.3, build 7d4bcd8

docker-compose -v
zsh: command not found: docker-compose

docker compose version
Docker Compose version v2.28.1-desktop.1

④Windows 10 Pro 22H2 (Win10×Docker Desktop)

docker -v
Docker version 27.0.3, build 7d4bcd8

docker-compose -v
Docker Compose version v2.28.1-desktop.1

docker compose version
Docker Compose version v2.28.1-desktop.1

想定するディレクトリ構成

PJ_root
│
┝ local-dev-mysql57
│ ┝ proxy
│ │ └ Dockerfile
│ ┝ api
│ │ └ Dockerfile
│ ┝ web
│ │ └ Dockerfile
│ └ compose
│   └ docker-compose.yml
│
└ local-dev-mysql8
  ┝ proxy
  │ └ Dockerfile
  ┝ api
  │ └ Dockerfile
  ┝ web
  │ └ Dockerfile
  └ compose
    └ docker-compose.yml

やったこと

1. composeディレクトリの名前変更

デフォルトだと、カレントディレクトリ名がプロジェクト名として使用されるため(参考)、ディレクトリ名を変更しました。
こうしておくと、docker composeコマンドを実行する時に-p <プロジェクト名>を指定しなくてもよくなるので楽ちんです。

local-dev-mysql57\composelocal-dev-mysql57\mysql57
local-dev-mysql8\composelocal-dev-mysql8\mysql8

プロジェクト名はnetwork名やimage名のprefixに使用されているので、後々docker compose psを実行した時に表示される名前なども「mysql8-api」などのようになり、分かりやすくなります。

2. docker-compose.yml編集

重複しなければよいので、とりあえず片方のcomposeファイルだけ編集します。

2-1. dbをマウントするvolume名の変更

データ保存先は分けないとダメなので、別のvolumeを指定するようにします。
(当然、それぞれのvolumeをcreateする必要あり)

local-dev-mysql8\mysql8\docker-compose.yaml
services:
  db:
    volumes:
-     - local-dev-mysql:/var/lib/mysql
+     - local-dev-mysql8:/var/lib/mysql

volumes:
- local-dev-mysql:
+ local-dev-mysql8:
    external: true

最終的にvolumeは以下のようになります。(上二つはそれぞれのアプリのvolume)

$ docker volume ls
DRIVER    VOLUME NAME
local     9cc6e617e5a98eed5cee86f18d5b6230259fec22ef9da32043d13594e481ff6e
local     dbaa795f95554b76ed0ba0153bdf0847108a980e3d90e0b5330f277f6aef4633
local     local-dev-mysql
local     local-dev-mysql8

2-2. networksで指定しているsubnetの値変更

上記のディレクトリ構成で、local-dev-mysql57とlocal-dev-mysql8に対してそれぞれdocker compose upを実行すると、networkは別々に作成されます。
が、後からupした方は「subnetが既に使われている」というエラーになります。
なので、composeファイルで指定しているsubnetを変更します。

local-dev-mysql8\mysql8\docker-compose.yaml
networks:
  app:
    ipam:
      config:
-       - subnet: 192.168.210.0/24
+       - subnet: 192.168.211.0/24

2-3. 各serviceに指定しているipv4_addressの値変更

上記でsubnetを変更するので、各serviceで指定しているIPアドレスも変更します。

local-dev-mysql8\mysql8\docker-compose.yaml
services:
  proxy:
    networks:
      app:
-       ipv4_address: 192.168.210.8
+       ipv4_address: 192.168.211.8

2-2, 2-3についてはdocker-compose.yaml内で一括置換すると間違えなくてよいです。
vimコマンド :%s/192.168.210/192.168.211/gc

2-4. 各serviceに指定しているportsの値変更

ここが一番厄介だったのですが、、結論から言うとDocker Desktopとそれ以外で振る舞いが違いました。

Docker Desktop(Mac,Win共)を使用した場合、以下のように記載したら「http://127.0.0.2:3000」でブラウザからアクセスできました。

Macの場合は、「127.0.0.2」をループバックアドレスに追加する必要があります。詳細は参考にした記事をご確認ください。

local-dev-mysql8\mysql8\docker-compose.yaml
services:
  web:
    ports:
-     - "127.0.0.1:3000:3000"
+     - "127.0.0.2:3000:3000"

当然、composeファイルを変更していない方の環境は「http://127.0.0.1:3000」でアクセスできます。

 
Win×WSL2×Ubuntu22環境の場合、docker compose psで確認すると問題なく起動しているのですが、「http://127.0.0.2:3000」でブラウザからアクセスできませんでした。
WSLに接続したコンソールからcurlコマンドを実行したところ、応答は返ってくるので、どちらかというと「Win×WSL2」の問題な気がしています。 (が、解決はしていない。。)

$ curl -v http://127.0.0.2:3000
*   Trying 127.0.0.2:3000...
* Connected to 127.0.0.2 (127.0.0.2) port 3000 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.2:3000
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Found
< X-Frame-Options: SAMEORIGIN
< X-Xss-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< Location: http://127.0.0.2:3000/sessions/new
< Content-Type: text/html; charset=utf-8
< Cache-Control: no-cache
< X-Request-Id: 72837b30-b40c-4f03-a32f-9d23503f947d
< X-Runtime: 0.994378
< Server: WEBrick/1.4.2 (Ruby/2.6.3/2019-04-16)
< Date: Fri, 09 Aug 2024 00:53:10 GMT
< Content-Length: 100
< Connection: Keep-Alive
<
* Connection #0 to host 127.0.0.2 left intact
<html><body>You are being <a href="http://127.0.0.2:3000/sessions/new">redirected</a>.</body></html>

 
Mac×colima環境もdocker compose psで確認すると問題なく起動しているのですが、ブラウザからのアクセスはできず、curlコマンドもエラーになりました。
127.0.0.2はループバックアドレスに追加済です。

% docker compose ps
NAME           IMAGE        COMMAND                  SERVICE   CREATED       STATUS       PORTS
mysql8-web-1   mysql8-web   "bash -c 'rm -f /app…"   web       2 weeks ago   Up 2 weeks   127.0.0.2:3000->3000/tcp

% curl -v http://127.0.0.2:3000
*   Trying 127.0.0.2:3000...
* connect to 127.0.0.2 port 3000 failed: Connection refused
* Failed to connect to 127.0.0.2 port 3000 after 0 ms: Couldn't connect to server
* Closing connection
curl: (7) Failed to connect to 127.0.0.2 port 3000 after 0 ms: Couldn't connect to server

 
というわけで、Docker Desktopではない環境の場合はホスト側のポート番号を変えるという地味に面倒な作業で対応しました。

local-dev-mysql8\mysql8\docker-compose.yaml
services:
  web:
    ports:
-     - "127.0.0.1:3000:3000"
+     - "127.0.0.1:13000:3000"

 
Compose ファイル・リファレンスを見ると、portsは「ホスト側:コンテナ側」のポート割り当てとのことなので、WSLが挟まるとWindowsのブラウザからうまくアクセスできない、というのは何となく分かるのですが、Mac×colimaの時の動きがよく分からないです。
逆に言うと、Docker Desktopはどういう処理をしているのか?という疑問でもあるわけですが。。

さいごに

これをやるまではdocker-compose.ymlに書いてある内容はほとんど理解しておらず、機械的にdocker compose stopdocker compose up -dで環境を切り替えていました。しかし、面倒くさい!となり、いろいろと調べた結果やりたかったことが実現できた上にcomposeファイルの中身の理解も進んで、やってみてよかったなぁと思いました。謎は残ってはいますが。。

 
変更したcomposeファイルを置いておきます。
誰かの役に立ったらうれしいです。

docker-compose.yml 修正案1
version: '3.3'
services:
  proxy:
    build: ../proxy
    environment:
      TZ: Asia/Tokyo
      DOCKER: 'true'
      DB_HOST: 192.168.211.5
      REDIS_HOST: 192.168.211.7
      REDIS_PORT: 6379
    tty: true
    stdin_open: true
    ports:
      - "127.0.0.2:8080:8080"
    volumes:
      - ../proxy:/app
    networks:
      app:
        ipv4_address: 192.168.211.8
  api:
    build: ../api
    environment:
      TZ: Asia/Tokyo
      DOCKER: 'true'
      DB_HOST: 192.168.211.5
      REDIS_HOST: 192.168.211.7
      REDIS_PORT: 6379
    tty: true
    stdin_open: true
    ports:
      - "127.0.0.2:9292:9292"
    volumes:
      - ../api:/app
    networks:
      app:
        ipv4_address: 192.168.211.3
  web:
    build: ../web
    environment:
      RAILS_ENV: development
      TZ: Asia/Tokyo
      DOCKER: 'true'
      DB_HOST: 192.168.211.5
      REDIS_HOST: 192.168.211.7
      REDIS_PORT: 6379
    tty: true
    stdin_open: true
    ports:
      - "127.0.0.2:3000:3000"
    volumes:
      - ../web:/app
    networks:
      app:
        ipv4_address: 192.168.211.6
  db:
    image: mysql:8.0.28
    environment:
      TZ: Asia/Tokyo
      MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
      MYSQL_USER: root
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    ports:
      - "127.0.0.2:3306:3306"
    volumes:
      - local-dev-mysql8:/var/lib/mysql
    networks:
      app:
        ipv4_address: 192.168.211.5
  redis:
    image: redis:latest
    environment:
      TZ: Asia/Tokyo
    ports:
      - "127.0.0.2:6379:6379"
    networks:
      app:
        ipv4_address: 192.168.211.7
networks:
  app:
    ipam:
      config:
        - subnet: 192.168.211.0/24

volumes:
  local-dev-mysql8:
    external: true
docker-compose.yml 修正案2
version: '3.3'
services:
  proxy:
    build: ../proxy
    environment:
      TZ: Asia/Tokyo
      DOCKER: 'true'
      DB_HOST: 192.168.211.5
      REDIS_HOST: 192.168.211.7
      REDIS_PORT: 6379
    tty: true
    stdin_open: true
    ports:
      - "127.0.0.1:18080:8080"
    volumes:
      - ../proxy:/app
    networks:
      app:
        ipv4_address: 192.168.211.8
  api:
    build: ../api
    environment:
      TZ: Asia/Tokyo
      DOCKER: 'true'
      DB_HOST: 192.168.211.5
      REDIS_HOST: 192.168.211.7
      REDIS_PORT: 6379
    tty: true
    stdin_open: true
    ports:
      - "127.0.0.1:19292:9292"
    volumes:
      - ../api:/app
    networks:
      app:
        ipv4_address: 192.168.211.3
  web:
    build: ../web
    environment:
      RAILS_ENV: development
      TZ: Asia/Tokyo
      DOCKER: 'true'
      DB_HOST: 192.168.211.5
      REDIS_HOST: 192.168.211.7
      REDIS_PORT: 6379
    tty: true
    stdin_open: true
    ports:
      - "127.0.0.1:13000:3000"
    volumes:
      - ../web:/app
    networks:
      app:
        ipv4_address: 192.168.211.6
  db:
    image: mysql:8.0.28
    environment:
      TZ: Asia/Tokyo
      MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
      MYSQL_USER: root
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    ports:
      - "127.0.0.1:13306:3306"
    volumes:
      - local-dev-mysql8:/var/lib/mysql
    networks:
      app:
        ipv4_address: 192.168.211.5
  redis:
    image: redis:latest
    environment:
      TZ: Asia/Tokyo
    ports:
      - "127.0.0.1:16379:6379"
    networks:
      app:
        ipv4_address: 192.168.211.7
networks:
  app:
    ipam:
      config:
        - subnet: 192.168.211.0/24

volumes:
  local-dev-mysql8:
    external: true
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?