Supabase CLI + Docker Compose という構成で Error response from daemon: network と言われたあなたへ

## この記事が役立つかもしれない人
* タイトル通りの状況にある人
* `docker-compose stop` と `docker-compose down` の違いに不安がある人
* Supabase CLI のソースコードに興味がある人

## 状況
次のような Makefile で起動・停止を行なっていました。
ここで重要なのは自前の Docker 環境を `docker compose up` で起動して **`docker compose stop` で停止を行なっている点**です。
```Makefile:Makefile
.PHONY: start supabase-start services-start stop services-stop supabase-stop

# 起動
start: supabase-start
	make services-start

supabase-start:
	supabase start

services-start:
	docker compose up -d

# 停止
stop: services-stop
	make supabase-stop

services-stop:
	docker compose stop

supabase-stop:
	supabase stop
 ```

すると二度目以降の `make start` (`docker compose up`) でエラーが現れます。

```bash
Error response from daemon: network (ここに NETWORK ID が入る) not found
```

## 解決方法
`docker compose stop` を `docker compose down` に直す！

```diff_make:Makefile
.PHONY: start supabase-start services-start stop services-stop supabase-stop

# 起動
start: supabase-start
	make services-start

supabase-start:
	supabase start

services-start:
	docker compose up -d

# 停止
stop: services-stop
	make supabase-stop

services-stop:
-	docker compose stop
+   docker compose down

supabase-stop:
	supabase stop
 ```

## なぜ `docker compose stop` だとエラーが起きるのか？

### Docker Compose の `stop` と `down` の違い
`docker compose stop` は **実行中のコンテナを削除せずに停止** します。名前の通りですね。
停止したコンテナは再起動可能な状態で維持されます。そのため次回 `docker compose up` を実行した際はネットワークとコンテナが再利用されます。

https://docs.docker.com/reference/cli/docker/compose/stop/


一方で `docker compose down` はコンテナを停止して `docker compose up` によって作成された **コンテナとネットワークを削除** します。オプションを付ければボリュームとイメージも消せます。

https://docs.docker.com/reference/cli/docker/compose/down/

Docker Compose 全体のざっくりとした流れとしては以下の通りです。


1. `docker compose up` で実行: コンテナがなければイメージがビルドされてコンテナが作成・起動され、停止・削除されるまで稼働

2. `docker compose down` で削除: 再び `docker compose up` された時は上記と同じように処理が走る

<br />

では 、`docker compose stop` された後に `docker compose up` を行うとどうなるでしょうか？

これは compose.yml が変更されたかどうかによって変わります。
変更されていた場合、`docker compose up` はコンテナを停止して再作成することで変更を拾います。このときボリュームだけは残るため `docker compose down` とは少々動きが異なります。

https://docs.docker.com/reference/cli/docker/compose/up/

### `supabase stop` のコード内容
オープンソースなので Supabase CLI のソースコードを見てみましょう！

https://github.com/supabase/cli


かいつまんで中身を見てみると `supabase stop` は `cli/internal/utils
/docker.go` にある [`DockerRemoveAll`](https://github.com/supabase/cli/blob/29d4cbaddbd66ebbeee60ba41ee5641b911f8d8a/internal/utils/docker.go#L93-L143) 関数を呼び出しているみたいです。


コードを見てみると `down` ではなく `stop` していそうです……

```go
Docker.ContainerStop(ctx, id, container.StopOptions{});
```

……が、読み進めてみるとネットワークを消しとる！！！

```go
	// Remove networks.
	if report, err := Docker.NetworksPrune(ctx, args); err != nil {
		return errors.Errorf("failed to prune networks: %w", err)
	} else if viper.GetBool("DEBUG") {
		fmt.Fprintln(os.Stderr, "Pruned network:", report.NetworksDeleted)
	}
 ```

改めて `docker network ls` を叩いてみても分かります。

```bash
% docker network ls
NETWORK ID     NAME                    DRIVER    SCOPE
acabacebaf48   supabase_network_test   bridge    local
```

```bash
% docker network ls
NETWORK ID     NAME                    DRIVER    SCOPE
3dcc14f257fa   supabase_network_test   bridge    local
```

NETWORK ID がころころ変わっとる！！！

### 具体的なエラー発生のメカニズム
1. `supabase start` 実行時: Supabase のコンテナが多数立ち上がりネットワークが作成される
2.  初回の `docker compose up` 実行時: コンテナが作成されて `supabase start`によって作成されたネットワーク内で起動
3. `docker compose stop` 実行時: コンテナは停止されますが、ネットワークはそのまま残る
4. `supabase stop` 実行時: Supabase CLI によってネットワークが削除されます
5. 再度 `docker compose up` を実行: Docker Compose は前回使用したネットワークを再利用しようとするが、そのネットワークは既に削除されているため network not found エラーが発生する


## まとめ

というわけで `supabase stop` という名前に騙され、同じように `docker compose stop` を設定してしまった私ですが、`supabase stop` がネットワークを消しているなら `docker compose stop` ではいけませんね。

なぜならば `docker compose stop` は　`docker compose up` で作られたときのまま。Supabase CLI によってネットワークが削除されて新しく作られていることを知らない状態で停止しているからです。そのため `docker compose stop` を `docker compose down` に変える必要があったわけです。

<br />

名前や雰囲気で中身を決めつけてはいけないですね。反省です。

---

この記事が役に立ったら 🩷 を頂けると嬉しいです！