この記事は 一休.com Advent Calendar 2024 の 24 日目の記事です。
一休の RESZAIKOチーム で働いているmatsumuranです。
昨年の記事 ではCloud Runを利用したデモ環境の紹介をしましたが、デモ環境を増やすためには手動でGoogle Cloudやリポジトリ内の設定を操作する必要がありました。今年は昨年の心残りを解決しようと思います。
デモ環境を簡単に作りたい
開発中のデモ環境は簡単に作成、更新、破棄できると嬉しいものです。
Advent Calendar 6 日目の記事 では Kubernetes を使ってデモ環境を作る方法を紹介しましたが、
一休では Google Cloud の Cloud Run を利用して提供しているサービスもあります。
Cloud Run は完全にゼロの状態からスケールするので使用していない時間は課金されず、常に使用している訳ではないデモ環境と相性がいいです。
本記事では、Cloud Load Balancing と Cloud Run を使用したデモ環境の作成方法について紹介します。
やりたいこと
- IDを指定すると、新規デモ環境が自動で作成される
- 不要になったデモ環境のIDを指定すると、自動で削除される
各環境の ID
デモ環境を並列にいくつも作りたいので、自由な ID を設定できるようにします。
ID 名は demo-xxxxx
のような形式にして、 https://demo-xxxxx.ikyu-demo.example.com/
のように、ドメインで環境を分ける事にします。
GitHub Actions によるデプロイ
通常のデプロイを GitHub Actions で行っているプロジェクトであれば、デモ環境の構築も GitHub Actions でやるようにすれば構成が楽になります。
という訳で、Google Cloud を操作できる gcloud
のコマンドを駆使して環境の構築、破棄をどんどん行うスクリプトを作成します。
一度 action を定義すれば、特定の PR のタイミングで実行する事も可能ですし、外部から API で呼び出すこともできます。
以下のような workflow_call
を定義した Workflow を定義します。
name: api-server.demo.deploy
on:
workflow_call:
demo-id:
required: true
type: string
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Dockerの設定
run: gcloud auth configure-docker asia-northeast1-docker.pkg.dev --quiet
- name: DockerをビルドしてArtifact RegistryにPush
uses: docker/build-push-action@v6
with:
file: ./Dockerfile
push: true
- name: Cloud Runにデプロイ
run: |
gcloud run services replace settings/api-server-demo.yaml
- ...以下省略
Cloud Run のデプロイ
今回は省略しますが、前提として、 Docker でビルドしたイメージを Artifact Registry に push できているものとします。
Cloud Run は構成を yaml で記述できるので、以下のようにデモ環境用の設定を作成します。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: api-server-demo-<demo-id>
labels:
cloud.googleapis.com/location: asia-northeast1
spec:
template:
metadata:
name: api-server-demo-<demo-id>-v<Version>
annotations:
run.googleapis.com/vpc-access-egress: all-traffic
autoscaling.knative.dev/minScale: "0"
spec:
containers:
- image: asia-northeast1-docker.pkg.dev/demo/test/api-server-demo-<demo-id>:V<Version>
name: api-server
args:
- "yarn"
- "server:demo"
ports:
- name: http1
containerPort: 80
api-server-demo-<demo-id>:V<Version>
というイメージを使って、 api-server-demo-<demo-id>
という名前のサービスを作る事になります。
<demo-id>
や <Version>
等のデプロイ毎に変わる値については、デプロイ時に sed で強制的に書き換えています。
以下のコマンドでサービスを作成できます。
gcloud run services replace api-server-demo.yaml
replace
を使う事で、サービスの作成と更新の両方に対応します。
新規作成時にはサービスはデフォルトで認証ユーザしかアクセスできないようになっているので、認証を入れない場合は以下のコマンドで未認証の呼び出しを許可するようにしてください。
gcloud run services add-iam-policy-binding api-server-demo-${demo-id} \
--member="allUsers" \
--role="roles/run.invoker"
Cloud Load Balancing によるルーティング
1 つのサーバで全てをやりくりするならこれで大丈夫ですが、
demo-xxxxx.demo-ikyu.example.com
等のドメインと各デモ環境の対応や、パスによって接続先を振り分けするために CLB のグローバル外部アプリケーション ロードバランサを使ってルーティングを行います。
ロードバランサは大まかにいって以下の 3 層に分かれます。
- 外部からのアクセスを受け付けるターゲットプロキシ
- Cloud Run 等のサービスへ繋がるバックエンド
- ドメインやパスなどから接続先のバックエンドを振り分けるルーティングルールとなる URL マップ
ここでは、作成済みのロードバランサにデモ環境毎の要素を追加する方法について説明します。
ターゲットプロキシ
ターゲットプロキシ を作成すると IP を割り振ってくれて、外部からの HTTPS リクエストを受け付けます。
DNSで *.demo-ikyu.example.com
がこの IP を指すようにすれば、以降はデモ環境毎の設定をする必要なくターゲットプロキシが利用できます。
Google マネージドの証明書 を利用している場合は自動で証明書を作成してくれますが、ワイルドカードの証明書が利用できませんし、発行まで数分の時間がかかります。
ロードバランサで証明書を設定する場合は、Certificate Manager を使えばワイルドカードの証明書を設定できるのでそちらを利用してください。
バックエンド
LB から Cloud Run に接続するためには、Cloud Run のサービス毎に以下の 2 つのリソースを作成する必要があります。
公式の手順 に従って作成していきます。
VPC ネットワークについては既にある物を利用する事にします。
- サーバレス NEG の作成
- バックエンドサービスの作成
NEG の作成
作成した api-server-demo-xxxxx
という名前の Cloud Run サービスに接続する NEG を作成するためのコマンドです。
NEG の名前は neg-api-server-demo-xxxxx
にします。
gcloud compute network-endpoint-groups create neg-api-server-demo-xxxxx \
--region=asia-northeast1 \
--network-endpoint-type=serverless \
--cloud-run-service=api-server-demo-xxxxx
バックエンドサービスの作成
次に LB のバックエンドサービスを作成します。
backend-api-server-demo-xxxxx
という名前にします。
gcloud compute backend-services create backend-api-server-demo-xxxxx \
--load-balancing-scheme=EXTERNAL_MANAGED \
--protocol=HTTP \
--region=asia-northeast1
先程作成した NEG を紐付けます。
gcloud compute backend-services add-backend backend-api-server-demo-xxxxx \
--region=northeast1 \
--network-endpoint-group=neg-api-server-demo-xxxxx \
--network-endpoint-group-region=northeast1
URL マップの作成
HTTP リクエストを条件に応じてバックエンドサービスに振り分けるために、URL マップ を作成します。
gcloud compute url-maps create demo-url-map \
--default-service=demo-frontend
コンソールから LB を作成した場合は自動で紐つきますが、gcloud で作成した場合はターゲットプロキシと紐付ける必要があります。
gcloud compute target-https-proxies update target-proxy-demo \
--url-map=demo-url-map
URL マップはホストルールとパスマッチャーの 2 種類の要素があります。
今回は、以下のようなケースを想定してパスマッチャーを作ります。
- APIサーバへのリクエストは
/api/*
に集約して、バックエンドサーバに振り分ける - それ以外のパスへのリクエストはフロントエンドサーバに振り分ける
https://demo-xxxxx.ikyu-demo.example.com/
に来たアクセスの内、 /api/*
を api-server-demo-xxxxx
に、それ以外を react-server-demo-xxxxx
に振り分けるようにします。
パスマッチャーの作成
パスマッチャーを作成します。
デフォルトでは backend-react-server-demo-xxxxx
というバックエンドサービス、 /api/*
にアクセスが来たときは backend-api-server-demo-xxxxx
というバックエンドサービスにリクエストを振り分けます。
gcloud compute url-maps add-path-matcher demo-url-map \
--path-matcher-name demo-xxxxx \
--default-service=backend-react-server-demo-xxxxx
--path-rules="/api/*=backend-api-server-demo-xxxxx"
ホストルールの作成
アクセスが来たときのホスト名( demo-xxxxx.ikyu-demo.example.com
) に応じて処理を行います。
今回は、先程作成した demo-url-map
を使うように設定します。
gcloud compute url-maps add-host-rule demo-xxxxx \
--hosts=[demo-xxxxx.ikyu-demo.example.com] --path-matcher-name=demo-url-map
アクセス元の制限等
以上でデモ環境が作成でき、指定した URL でアクセスできるようになりました。
ただし、特に制御を入れていないので全世界からアクセスできてしまいます。
接続元 IP 等を制限したい場合は、 Cloud Armor 等で適宜制御を追加してください。
削除について
環境を削除する場合、今回追加したそれぞれの要素を削除していけば大丈夫です。
# ホストルールの削除
gcloud compute url-maps remove-host-rule demo-xxxxx \
--host=demo-xxxxx.ikyu-demo.example.com
# バックエンドサービスの削除
gcloud compute backend-services delete backend-api-server-demo-xxxxx \
--region=asia-northeast1
# NEGの削除
gcloud compute network-endpoint-groups delete neg-api-server-demo-xxxxx \
--region=asia-northeast1
# Cloud Runの削除
gcloud run services delete api-server-demo-xxxxx \
--region=asia-northeast1
感想
EKSのようにファイル1つで全ての設定が完了せずコマンドでいろいろ操作する必要はあるものの、環境IDを決めておけば一括で操作できるようにはなっています。
現在のプロジェクトでは monorepo を採用しているので、フロントエンドサーバとバックエンドサーバのバージョンが異なる事などを気にしなくていいですし、
DB を Prisma で構成していてスキーマを開発リポジトリ内で管理しているので、デモ用の DB の構築が非常に楽でした。
monorepo 自体には色々メリットデメリットがあると思いますが、今回のケースでは上手くかみ合って非常に良い開発体験でした。
おわりに
一休では、エンジニアを募集しています。
カジュアル面談も実施しているので、お気軽にご応募ください。