Github ActionのServicesとDocker Composeで立ち上げたコンテナのネットワーク共有について

## 背景

あるプロジェクトでは、**バックエンドAPI（Go）** と **フロント（スマホアプリ、ブラウザアプリ）** という構成で運用されていました。しかし、運用中にデータベース（DB）のレコード追加や編集が必要になる場面が増え、**管理画面の必要性** が高まっていました。

管理画面の開発には以下の要件がありました：

1. **学習コストの低い言語** で実装したい
2. **Goでの実装は不要**
3. **PHPプログラマーのリソースを活用** する

その結果、管理画面を別リポジトリでPHPを用いて作成することになりました。また、以下のような運用面での工夫が求められました。

- 管理画面とAPIは**別コンテナ**として運用
- DBは共通のため、管理を**API側に集約**

ローカル環境では、各サービスのDockerコンテナ群を起動し、**ネットワークを共有する構成** でDBアクセスを実現しました。

![docker_network_cira_internal-1.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187496/85c51a1e-8c7a-e7e6-8732-0fa80904d1ef.png)

しかし、**GitHub Actions上でのテスト** では、DBコンテナが不足しており、DBに依存するテストを実行できないという課題が発生しました。
そこで、GitHub Actions上でのみDBのコンテナを別構築するということにしました。

![docker_network_cira_internal-2.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187496/7c1fb993-def3-5eee-8f0c-52628e748747.png)

この記事では、**GitHub Actions上でDocker ComposeのサービスとGitHub Actionsの`services`機能を使い、DBコンテナを接続する方法** を解説します。


### 解決方法：GitHub Actionsでのネットワーク共有

GitHub Actionsでは、`services` を利用することで、DBコンテナを簡単に追加できます。ただし、Docker Composeで定義したサービス群との接続には**ネットワーク設定の工夫**が必要です。

## Docker Composeのネットワーク構成

まず、Docker Composeでのネットワークを確認します。以下の例では、APIと管理画面、そして共通のDBを立ち上げています。

```api-compose.yml
services:
  api:
    build:
      context: ./api
    networks:
      - api-external-network
  db:
    build:
      context: ./db
    networks:
      - api-external-network
networks:
  api-external-network:
    driver: bridge
    external: true
```
```admin-compose.yml
services:
  admin:
    build:
      context: ./admin
    networks:
      - shared_network
networks:
  shared_network:
    driver: bridge
    external: true
    name: "${NETWORK_NAME}"
```
ここでは、shared_network というネットワークを作成し、api と admin サービスがこのネットワークを共有しています。

### ローカル用の.env
ローカル用の.envに、バックエンド用のネットワーク名を付け加えることによって、API側のDBと接続できるようにします。
```.env
NETWORK_NAME=api-external-network
```

上記の設定を行うことでローカルは解決しました。

## GitHub Actionsの設定
GitHub Actionsでは、servicesでDBコンテナを指定し、Docker Composeで立ち上げたサービス群とネットワークを共有する必要があります。以下はその設定例です。

```yml
jobs:
  ci:
    runs-on: ubuntu-latest
    services:
      # CI用のDBを立ち上げる
      db:
        image: mysql:8.0.23
        ports:
          - 3306:3306
        env:
          MYSQL_ALLOW_EMPTY_PASSWORD: yes
          BIND-ADDRESS: 0.0.0.0
          MYSQL_USER: app
          MYSQL_PASSWORD: password
          MYSQL_DATABASE: app
        options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
    steps:
      # リポジトリを指定したディレクトリにチェックアウト
      - uses: actions/checkout@v4

      # テスト用の.envファイルを利用
      - name: Copy Env FIle
        run: cp src/.env.testing src/.env

      # GitHub Actionsのネットワークを取得
      - name: Get GitHub network name
        id: get_network
        run: |
          network=$(docker network ls --filter name=github -q --format "{{.Name}}")
          echo "NETWORK_NAME=$network" >> $GITHUB_ENV

      # Dockerのイメージをビルドして立ち上げる
      - name: Docker Compose Build and Up
        run: docker compose up -d

      # （割愛）別リポジトリからDB情報を取得してGA上のDBへスキーマ情報を流す
        
      # PHPUnitを実行
      - name: Laravel PHPUnit Testing
        run: docker compose exec -T php ./vendor/bin/phpunit


```

## 解説
```
network=$(docker network ls --filter name=github -q --format "{{.Name}}")
```

`docker network ls`でネットワーク一覧を取得でき、プレフィックスには**github**と付くため、それで検索ができます。そして、取得したネットワーク名を環境変数に設定して、docker compose時にそれを設定するという流れになります。

## まとめ
こういった需要があるか微妙なところですが（笑）
ただやろうと思って調べても中々情報がなかったので、記事にしてみました。
是非ご活用ください！