🐡

CodecovのSelf Hosted版を(物凄く苦労して)セットアップしました

2024/11/20に公開

こんにちは、バックエンドエンジニアの永田です。

以前、コードカバレッジの可視化ツールであるCodecov を導入した話を投稿しましたが、今回は有料版ではなく Self Hosted 版(OSS 版)をセットアップした話をしようと思います。

インフラ基盤として Google Cloud を使用し、terraform で管理しています。

情報が非常に少なく物凄く苦労したので、誰かの参考になれば幸いです。

codecov_
コンソール画面が表示されカバレッジレポートが正常に処理されていることを確認できた時、今年一番脳汁が出ました。機能開発と並行していたため、作業には 1 ヶ月以上かかりました...

インフラ構成

※ 構成図は特にネットワーク周りなど雑ですが、概要の参考程度に見て頂ければ。

codecov_architecture

単一の GCE インスタンス上で、 docker によって codecov を構成する複数サービスのコンテナを起動しています。

ポートマッピングによって GCE インスタンスへのリクエストを gateway コンテナに送り、そこから各サービスへリクエストが振り分けられます。

ちなみに codecov の各サービスの定義は以下のとおりです。

  • gateway:BFF やロードバランサーの様なもの
  • api:api
  • worker:カバレッジレポートの処理などを行う worker
  • frontend:codecov のコンソール画面
  • redis:キャッシュ
  • postgres:DB
  • timescale:カバレッジの時系列データ専用の DB
  • minio:カバレッジレポート用のファイルストレージ(今回は GCS に外部化)

構成のポイント

アプリケーションの基盤は基本的に GCE

公式の記事でデプロイ戦略が 3 つ紹介されているのですが、最も簡単な、単一のサーバーで docker compose を利用し複数サービスのコンテナを動かす戦略を取りました。

こちらのレポジトリを見ると分かりますが、codecov は 8 つのサービスから構成されています。それぞれを単一のサーバーにデプロイするのが理想なのですが、そうしてしまうとメンテナンスコスト、クラウドの料金が莫大になり、Self Hosted 版を使う意味がなくなってしまいます。

DB についても GCE 内のコンテナとして起動し、外部ディスクを GCE インスタンスに紐づけることでデータが消えない様にしています。Alloy DB や Cloud SQL の料金はとても高いので、使った瞬間 codecov の有料版の料金を超えてしまいます。

カバレッジレポート用のファイルストレージのみ、料金が安かっため GCS に外部化しています。

GCE のスポットインスタンスを Instance Group で管理

GCE は料金を抑えるため、スポットインスタンス(preemptible instance)を利用しています。

「スポットインスタンスが停止した際の新たなインスタンスの起動」と「コスト削減のための、インスタンス起動の営業時間内への限定」のために、Instance Group を利用しています。terraform は以下の通りです。

terraform
resource "google_compute_instance_group_manager" "default" {
  name = "codecov-instance-group"
  zone = "asia-northeast1-b"

  version {
    instance_template = google_compute_instance_template.codecov.self_link
  }

  base_instance_name = "codecov"
}

resource "google_compute_autoscaler" "default" {
  name   = "codecov-autoscaler"
  target = google_compute_instance_group_manager.default.id
  zone   = "asia-northeast1-b"

  autoscaling_policy {
    max_replicas    = 1
    min_replicas    = 0
    cooldown_period = 60

    scaling_schedules {
      name                  = "every-weekday-morning"
      description           = "平日、6時から22時までの間で1台のインスタンスを起動"
      min_required_replicas = 1
      schedule              = "0 6 * * MON-FRI"
      time_zone             = "Asia/Tokyo"
      duration_sec          = 57600
    }
  }
}

HTTPS 化

こちらのissueにもいくつか挙げられていますが、HTTPS 化を行わないと codecov 全体がうまく機能しません。

これは、GitHub が HTTPS に対応していないアプリケーションからのリクエストを拒否するためです。[1] [2]

HTTPS 化の方法としては、GCE インスタンスの startup script で let's encrypt から証明書を取得し、その証明書をボリュームマッピングで gateway コンテナに渡すことで実現しています。

最初は Google Cloud のマネージドの証明を利用することを考えましたが、そちらは Google Cloud のロードバランサに紐づける前提でしか利用できない様だったので諦めています。(ロードバランサが gateway コンテナと合わせて二重になってしまう。)

startup script
# Install Certbot
sudo apt-get install -y certbot

# SSL証明書の取得
# 月曜の場合はLet's EncryptからSSL証明書を取得し、GCSにアップロードする。そうでない場合は、GCSからSSL証明書をダウンロードする。
#(サーバーは毎日6時に起動するので、UTCとの差分を考慮して条件文では日曜日で判定している)
echo "start setup SSL certificate"
if [ "$(date +%u)" -eq 7 ]; then
    sudo certbot certonly --standalone -d codecov.example.com --non-interactive --agree-tos -m mail_address@example.com
    # 証明書を.pem形式から.crt形式に変更
    sudo sh -c 'cat /etc/letsencrypt/live/codecov.example.com/fullchain.pem /etc/letsencrypt/live/codecov.example.com/privkey.pem > /etc/letsencrypt/live/codecov.example.com/cert.crt'
    sudo gsutil cp /etc/letsencrypt/live/codecov.example.com/cert.crt gs://bucket-name/cert.crt
    echo "SSL certificate obtained from let's encrypt."
else
    sudo mkdir -p /etc/letsencrypt/live/codecov.example.com
    sudo gsutil cp gs://bucket-name/cert.crt /etc/letsencrypt/live/codecov.example.com/cert.crt
    echo "SSL certificate obtained from GCS."
fi

結局コストはどのくらい?

Google Cloud の料金計算ツールの数字ですが、料金は$16.63/ monthほどになります。[3]

GCE のスポットインスタンスを利用し更に営業時間内のみの起動のみにしたこと、DB のマネージドサービスを利用せずに永続化ディスクで補っていることがかなり効いています。

有料版の codecov の料金はこちらのページの通りで、一人当たり$4~12 / monthかかります。大幅に安く済ませられていることが分かります 🎉

https://cloud.google.com/products/calculator?hl=ja&dl=CjhDaVJsTlRrMVpXSXpaQzFpTlRKaExUUmlOekF0T1dVME9TMHdOVEZtTVdKa1pqRmpabU1RQVE9PRAIGiQxQTlDRTI0Ni1CMzA1LTRCOTctODY0Ny1FMDY0NTcxRkJCMzQ

終わりに

実際には書ききれなかった細かい詰まりポイントが無数にあり、何度も心が折れそうになりましたが、何とか運用に乗せることができました。

ただここまで書いておいてなんですが、セットアップと保守にコストがかかるので、料金を安くできるとはいえ codecov の導入を検討しているすべての組織に Self Hosted 版がお勧めできるとは限りません。

terraform や docker-compose.yml、startup script の内容などをすべて公開できたらもっと良かったなと思っており、今後個人のレポジトリに対しても codecov の Self Hosted 版をセットアップして、それを公開したいなと考えています。

これからセットアップに挑戦しようとされている方の幸運を祈ります。この記事が何らか参考になれば幸いです。

脚注
  1. codecov を GitHub と連携するには GitHub APP を作成し、webhook エンドポイントとして Self Hosted 版 codecov の API エンドポイントを登録する必要があります。 ↩︎

  2. 後で気づいたのですが、GitHub APP の設定画面で HTTPS 対応していないアプリケーションからのリクエストを許可することもできる様です。その場合 HTTPS 化は不要かもしれません。 ↩︎

  3. GCS の料金は非常に安価なため考慮していません。またドメインについては、すでに取得済みのドメインのサブドメインを利用したため料金はかかりませんでした。 ↩︎

Discussion