😺

1つのリポジトリから複数のCloudRunにデプロイする構成考えた

2022/06/26に公開

はじめに

「Goで1つのリポジトリで2つのAPIを実装し、そのAPIをそれぞれ別のCloudRunにデプロイするようなことができるのか?」ということが気になり、実際にできるのか試してみました。

やりたいことはできたので、どういう方法で実現したのかについて記録に残します。

なぜこのような構成を考えたのか

「複数のAPIがあり、そのAPI群を任意の単位で分割して複数のCloudRunにデプロイする運用をしたい。しかしアプリケーションのコードは一つのリポジトリで管理したい。」

このような課題に対して、解決方法の1つになるかもしれないと思い、考えてみた次第です。

リポジトリ

実際に実装したリポジトリはこちらに用意してあります。

https://github.com/choimake/multi-deploy-by-cloudbuild

使用した技術

  • Go 1.17.11
  • Docker
  • Cloud Run
  • Cloud Build

要件

以下のような要件があるものとして、構成を考えます。

  • Fizz Buzzを実行するAPIを2つのCloudRun(片方をalpha、もう片方をbetaとする)でデプロイしたい
  • Fizz Buzzはalpha、beta共に同じロジックを利用したい
  • 各APIのレスポンスは、alphaはalpha: {Fizz Buzzの結果}、betaはbeta: {Fizz Buzzの結果}としたい

実現方法

alpha用のエントリーポイント(main.go)とbeta用のエントリーポイントを用意し、そのエントリーポイントをそれぞれ別のCloud Runへデプロイする方法を取りました。

パッケージ構成

具体的に、以下のようなパッケージ構成にしました。

.
|   # Imageに関する処理を置くところ。alphaとbetaそれぞれのものを用意。
├── build
│     ├── alpha
│     │   └── Dockerfile
│     └── beta
│         └── Dockerfile
|
|   # エントリーポイントの置くところ。alphaとbetaそれぞれのものを用意。
├── cmd
│      ├── alpha
│      │   └── main.go
│      └── beta
│          └── main.go
|
|   # デプロイスクリプトを置くところ。alphaとbetaそれぞれのものを用意。
├── deployment
│      ├── alpha
│      │   └── cloudbuild.yaml
│      └── beta
│          └── cloudbuild.yaml
|
|   # アプリケーションの処理を置くところ。alpha、beta双方で使うFizz Buzzのコードを置いている。
└── pkg
    └── fizzbuzz
        └── fizzbuzz.go

コードの内容

cmd

エントリーポイントです。

fuzzbizzの処理を呼び出し、alpha: {Fizz Buzzの結果}orbeta: {Fizz Buzzの結果}というフォーマットで表示する処理を実装しています。

alphaとbetaの違いは表示処理の部分のみです。

package main

import (
	"fmt"
	"log"
	"multi-deploy/pkg/fizzbuzz"
	"net/http"
	"os"
	"strconv"
)

func handler(w http.ResponseWriter, r *http.Request) {
	q := r.URL.Query()
	n := q.Get("n")
	num, _ := strconv.Atoi(n)
	fmt.Fprintf(w, "alpha: %s\n", fizzbuzz.Fizzbuzz(num))
}

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	http.HandleFunc("/fizzbuzz", handler)
	err := http.ListenAndServe(":"+port, nil)
	fmt.Printf("[START] server. port: %s\n", port)
	if err != nil {
		log.Fatal(err)
	}

}

build

Dockerfileは以下になります。

alphaとbetaの違いはRUN go build ~の部分だけです。

FROM golang:1.17.8-bullseye as builder

WORKDIR /app

COPY go.* ./
RUN go mod download

COPY . ./

RUN go build multi-deploy/cmd/alpha && \
    mv alpha server

FROM gcr.io/distroless/base:latest

COPY --from=builder /app/server /server

# start server
CMD ["/server"]

pkg/fizzbuzz

FizzBuzzの実装処理です。alpha、beta共にこの処理を利用しています。

package fizzbuzz

import "strconv"

func Fizzbuzz(number int) string {

	if number%15 == 0 {
		return "Fizz Buzz"
	}
	if number%5 == 0 {
		return "Buzz"
	}
	if number%3 == 0 {
		return "Fizz"
	}
	return strconv.Itoa(number)
}

deployment

CloudBuildの設定ファイルを配置します。

alpha用、beta用それぞれ用意し、alphaにデプロイする際にはalphaの設定を、betaにデプロイする際にはbetaの設定を利用します。

alphaはこちら

steps:
  # Build the container image
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'gcr.io/${PROJECT_ID}/alpha', '-f', 'build/alpha/Dockerfile', '.']
  # Push the container image to Container Registry
  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/${PROJECT_ID}/alpha']
  # Deploy container image to Cloud Run
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: gcloud
    args: [ 'run', 'deploy', 'service-alpha', '--allow-unauthenticated', '--image', 'gcr.io/${PROJECT_ID}/alpha', '--region', 'asia-northeast1' ]

betaはこちらです

steps:
  # Build the container image
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'gcr.io/${PROJECT_ID}/beta', '-f', 'build/beta/Dockerfile', '.']
  # Push the container image to Container Registry
  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/${PROJECT_ID}/beta']
  # Deploy container image to Cloud Run
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: gcloud
    args: [ 'run', 'deploy', 'service-beta', '--allow-unauthenticated', '--image', 'gcr.io/${PROJECT_ID}/beta', '--region', 'asia-northeast1' ]

alphaとbetaの違いは

  • 使用するDockerfile
  • 指定するサービス名

になります。

デプロイ方法

alphaをデプロイしたい時は、alphaの設定でデプロイを実行します。

gcloud builds submit --config=deployment/alpha/cloudbuild.yaml .

betaをデプロイしたい時は、betaの設定でデプロイすればOKです。

gcloud builds submit --config=deployment/alpha/cloudbuild.yaml .

この構成によって何が嬉しいのか

  • デプロイ単位でリポジトリを分ける必要がなくなる
  • 1つのリポジトリに存在する複数の処理を、任意の単位でデプロイできる

おわりに

もしかしたら当たり前にあるテクニックなのかも知れませんが、自分の周りでは見た事なかったので試しに作ってみました。

何かの参考に立てば幸いです。

Discussion