docker-compose v2.2.1でlinksオプションが効かず躓いた話

# はじめに

この記事は[and factory.inc Advent Calendar 2021](https://qiita.com/advent-calendar/2021/andfactory)の11日目の記事です。
昨日は@ichikawa7ssさんの[実機デバッグしたときにクラッシュログを端末から取得する](https://qiita.com/ichikawa7ss/items/9d53301c67449831a94e)でした。

ごくごく最近にM1 Macを使用することになり、開発で使用しているDockerを動かすべくあれこれしていました。
M1 MacでDockerを動かす際に起こるエラーやその対処、そもそもなんでM1だと動かないの？という話については[こちら](https://zenn.dev/suzuki_hoge/books/2021-12-m1-docker-5ac3fe0b1c05de)の記事が大変参考になります。
というか参考にしました。とても助かりました、ありがとうございます。

この記事ではそんな環境構築の中、M1に全く関係がないdocker-composeのバグで躓いた話をします。

# 結論

ググりにくい・ググっても全然解決法が出てこない問題にブチ当たったらとりあえず公式のissueも確認してみた方が良い

# 何が起きたか

## Dockerの構成

Docker Composeを使って以下のような構成のサービスを作っています。

```yaml
# docker-compose.yml
services:
  app:
    build:
      context: .
      dockerfile: ./docker/app/Dockerfile
    environment:
      - DB_HOST=db
    volumes:
      - $GOPATH/src:/go/src
    command: bash -c "/wait-for-it.sh db:3306"
    network_mode: "bridge"
    links:
      - db
  db:
    image: mysql:5.7
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
    volumes:
      - ./docker/mysql/init:/docker-entrypoint-initdb.d
      - ./docker/mysql/data:/var/lib/mysql
      - ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
      - ./db:/db
    network_mode: "bridge"
```

appコンテナとdbコンテナを連携するような構成で、appで動いているサービスから、dbコンテナで動いているDB(MySQL)内のデータを参照するようになっています。
appコンテナは[wait-for-it.sh](https://docs.docker.com/compose/startup-order/)を使ってdbコンテナの起動を待ってから実行されます。

## dbコンテナにアクセスできない(というかコンテナ名を使用した通信ができない)

2021/12/04時点で最新版であったDocker Desktop 4.3.0を何も考えずMacに導入し、M1にまつわるいろいろなエラーに対応しながらなんとか各コンテナが立ち上がるところまで持っていけたのですが、サービスを動かしてみるとdbコンテナからデータが取れずエラーになってしまいました。

appコンテナのログを確認すると以下のようなログが出ていました。

```sh
wait-for-it.sh: waiting 15 seconds for db:3306
wait-for-it.sh: timeout occurred after waiting 15 seconds for db:3306
2021/12/09 15:29:51 driver: bad connection
```

`docker-compose.yml`内で`links`を使ってコンテナ名を指定しているので、コンテナ名を使って通信できるようになるはずなのですが、どうもdbコンテナとの連携がうまく行ってない様子…。

## 疎通確認

M1対応のためにいろいろ設定をいじっていたのでもはや問題が起きてても何が原因なのか分からんと思いつつ、とりあえずDockerコマンドでネットワークを確認してみました。
`docker network ls`でネットワークIDを確認し、さらに詳細を確認。

```sh
% docker network inspect <ネットワークID>
[
    {
        "Name": "bridge",
        ...
        "Containers": {
            "<appのコンテナID>": {
                "Name": "app",
                ...
                "IPv4Address": "172.17.0.6/16",
                "IPv6Address": ""
            },
            "dbのコンテナID": {
                "Name": "db",
                ...
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            },
        },
    }
    ...
]
```

同じネットワークにはちゃんと入っている。

コンテナに割り振られているIPアドレスが分かったので、とりあえずそのアドレス宛にpingを送ってみると疎通ができました。

```sh
% docker exec -it app /bin/bash
root@app# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.192 ms
```

しかし宛先を「db」に変えるとpingが届かない。

```sh
root@app# ping db
/bin/ping: db: Name or service not known
```

名前解決できてないだと…。

# 解決

「M1 Macで怪しいエラーを出しながらもコンテナが動いている」という状況だったので、もしかしてその関係で何か起きてるのか…？と怪しんでいたのですが、`Name or service not known`を見てどうもDockerの設定がおかしそうだな！？と思ったので解決方法をググってみました。
が、「docker links between containers not working」とかでググっても「MySQLのホストはコンテナ名を指定しないとダメだよ」という記事や`link`という単語が範囲広すぎて全然違う記事が出てきたりして解決に至らない。
([ググって解決しづらかったこと Advent Calendar 2021](https://qiita.com/advent-calendar/2021/gseach)を見て対応力をつけます。。)


数時間ほど右往左往してたところで以下のissueを発見。
[Connecting to wrong database: docker-compose v2 is not respecting links any more - ambiguous "db" hostname](https://github.com/drud/ddev/issues/3369)

どうやらdocker-compose v2.1.1〜v2.2.1では`links`を使用したコンテナ連携がうまく動かないようです。
手元のdocker-composeのバージョンを確認してみると見事にv2.2.1でした。

```sh
% docker-compose -v
Docker Compose version v2.2.1
```

issue内で言及されている通り、Docker Desktopの設定から`Use Docker Compose V2`のチェックを外し、各コンテナを再起動したところ、ちゃんとdbコンテナにアクセスできるようになりました。

![スクリーンショット 2021-12-14 12.40.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491167/431a961c-d43c-b552-ca3d-b9ccf043b831.png)

pingも「db」指定で通る。

```sh
root@app# ping db
PING db (172.17.0.3) 56(84) bytes of data.
64 bytes from db (172.17.0.3): icmp_seq=1 ttl=64 time=0.198 ms
```

## 最後に

上記issueの人がこの問題をdocker-composeのissueにちゃんと上げてくれていました。
[Critical: compose v2.1.1+ loses links affinity for hostname named in links directive](https://github.com/docker/compose/issues/8935)

issue内で「links」で検索すると上の方に出てきたので脱力してしまいました…。早くこっちから検索すれば良かった。
すでに修正がマージされているのでdocker-composeのv2.2.2(2021/12/03リリース)では直っているようです。タイムリーなバグにハマってしまった。

そもそもdocker-compose v2.2.1〜2は2021/12/10時点で他のissueでも問題が上がっており、[完全に壊れている](https://github.com/drud/ddev/issues/3369#issuecomment-981859037)とまで言われているのでまだ使わない方が良いのかもですね。
何も考えずにDocker Desktopを入れた時にdocker-composeも一緒にインストールされたはずなので、まずその時点からダメだったという感じでもありますが…。

また、今回の対応で[linksオプションはすでに非推奨](https://stackoverflow.com/questions/39173670/docker-are-docker-links-deprecated)になっていることを改めて知りました。`links`の設定のまま粘らず、これを機に`networks`オプションに変更して大丈夫かチームメンバに持ちかけたいなと思います。

同じくタイムリーなバグにハマってる人の助けになることを願います。