はじめに
現在参画しているプロジェクトは、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
参考にした記事
本文中に説明不足なところがあるかと思いますので、こちらの記事も参照いただくとよいと思います。
- docker compose (docker-compose) で複数サービスを起動する
- 【Docker】ローカルPCで同じポート番号をもったコンテナを複数立ち上げる
- dockerのコンテナを複数、同じポートを使って立ち上げたい
- Compose ファイル・リファレンス
試した端末情報
①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\compose
→local-dev-mysql57\mysql57
local-dev-mysql8\compose
→local-dev-mysql8\mysql8
プロジェクト名はnetwork名やimage名のprefixに使用されているので、後々docker compose ps
を実行した時に表示される名前なども「mysql8-api」などのようになり、分かりやすくなります。
2. docker-compose.yml編集
重複しなければよいので、とりあえず片方のcomposeファイルだけ編集します。
2-1. dbをマウントするvolume名の変更
データ保存先は分けないとダメなので、別のvolumeを指定するようにします。
(当然、それぞれのvolumeをcreateする必要あり)
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を変更します。
networks:
app:
ipam:
config:
- - subnet: 192.168.210.0/24
+ - subnet: 192.168.211.0/24
2-3. 各service
に指定しているipv4_address
の値変更
上記でsubnet
を変更するので、各service
で指定しているIPアドレスも変更します。
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」をループバックアドレスに追加する必要があります。詳細は参考にした記事をご確認ください。
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ではない環境の場合はホスト側のポート番号を変えるという地味に面倒な作業で対応しました。
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 stop
とdocker 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