Cloud BuildとArtifact RegistryでCI/CD基盤の構築
目的
この記事では、GCPの教科書II【コンテナ開発編】の3章のCloud Buildをベースに構築していきます。
具体的には、以下の2つの方法を試します。
- Cloud BuildとGCR、GKEによるCI/CD基盤構築
- Cloud BuildとArtifact Registry、GKEによるCI/CD基盤構築
Cloud BuildとGCR、GKEによるCI/CD基盤構築
この章では、まず3.5節の方法でCI/CD基盤構築を実現していきます。
CSRリポジトリの作成
まずは、CSRのリポジトリを作成します。リポジトリ名は、myrepository
とします。
gcloud source repos create myrepository
Created [myrepository].
コンテナの準備
続いて、アプリケーションのファイルとDockerfileを作成します。
これはGCP公式ドキュメントのコードとなります。
HTTPリクエストを行うと、「Hello world!」が返ってきます。
以下はmain.go
です。
package main
import(
"fmt"
"log"
"net/http"
"os"
)
func main() {
port := "8080"
if fromEnv := os.Getenv("PORT"); fromEnv != "" {
port = fromEnv
}
server := http.NewServeMux()
server.HandleFunc("/", hello)
log.Printf("Server listinig on port %s", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), server))
}
func hello(w http.ResponseWriter, r *http.Request) {
log.Printf("Serving request: %s", r.URL.Path)
host, _ := os.Hostname()
fmt.Fprintln(w, "Hello, World!")
fmt.Fprintf(w, "Version: 1.0.0\n")
fmt.Fprintf(w, "Hostname: %s\n", host)
}
Dockerfileは以下です。
FROM golang:1.8-alpine
ADD . /go/src/hello-world
RUN go install hello-world
FROM alpine:latest
COPY /go/bin/hello-world .
ENV PORT 8080
CMD ["./hello-world"]
GKEのクラスタとマニフェストファイルの作成
以下をk8s-sample.yaml
として作成します。
NAME, PROJECT_ID, IMAGE_NAME, TAG_NAMEは自身の環境にあった設定へ変更してください。
apiVersion: apps/v1
kind: Deployment
metadata:
name: <NAME>
spec:
replicas: 1
selector:
matchLabels:
app: <NAME>
template:
metadata:
labels:
app: <NAME>
spec:
containers:
- name: <NAME>
image: <NAME>:latest
ports:
- containerPort: 8080
image: gcr.io/<PROJECT_ID>/<IMAGE_NAME>/<TAG_NAME>:latest
resources:
requests:
memory: "128Mi"
cpu: "500m"
---
kind: Service
apiVersion: v1
metadata:
name: <NAME>
spec:
type: LoadBalancer
selector:
app: <NAME>
ports:
- name: http
port: 8080
targetPort: 8080
GKEのクラスタを作成します。
gcloud container clusters create <CLUSTER_NAME> --num-nodes=3 --preemptible
少々時間がかかります。
Creating cluster <CLUSTER_NAME> in <zones>... Cluster is being configured...
Cluster is being health-checked (master is healthy)...
done.
Created [https://container.googleapis.com/v1/projects/<PROJECT_ID>/zones/<zones>/clusters/<CLUSTER_NAME>].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/<zones>/<CLUSTER_NAME>?project=<PROJECT_ID>
kubeconfig entry generated for <CLUSTER_NAME>.
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS
<CLUSTER_NAME> <zones> 1.27.2-gke.1200 xxx.xxx.xxx.xxx e2-medium 1.27.2-gke.1200 3 RUNNING
Cloud Build
Cloud Buildの構成ファイルを作成します。
substitutions:
_CLOUDSDK_COMPUTE_ZONE: ゾーンを指定
_CLOUDSDK_CONTAINER_CLUSTER: クラスタ名を指定
_PROJECT_ID: プロジェクト名を指定
_IMAGE_NAME: イメージ名を指定
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gcr.io/${_PROJECT_ID}/${_IMAGE_NAME}:latest', '.']
id: docker build
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'gcr.io/${_PROJECT_ID}/${_IMAGE_NAME}:latest']
id: docker push
- name: 'gcr.io/cloud-builders/gcloud'
args: ['container', 'clusters', 'get-credentials', '${_CLOUDSDK_CONTAINER_CLUSTER}', '--zone','${_CLOUDSDK_COMPUTE_ZONE}','--project', '${_PROJECT_ID}']
id: gcloud container clusters get-credentials
- name: 'gcr.io/cloud-builders/kubectl'
args: ['apply', '-f', 'k8s-sample.yaml']
env:
- 'CLOUDSDK_COMPUTE_ZONE=${_CLOUDSDK_COMPUTE_ZONE}'
- 'CLOUDSDK_CONTAINER_CLUSTER=${_CLOUDSDK_CONTAINER_CLUSTER}'
id: kubectl apply
続いて、Cloud Buildのトリガーを作成します。
Cloud Build>トリガーで作成します。
Cloud Buildを実行する
git add .
git commit -m "cloud build test"
git push origin master
続いて、Cloud Buildの画面でビルド状況を確認します。
403エラーが出た場合は、Cloud Buildが使用するサービスアカウントに「Kubernetes Engine開発者」の役割を付与してください。
Cloud Build>設定>サービスアカウント権限、でステータスを有効にできます。
アプリケーションへリクエスト
Cloud Buildでのビルドが完了したら、作成したアプリケーションへリクエストを実行します。
kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
k8s-sample LoadBalancer xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx 8080:32652/TCP 2m36s
kubernetes ClusterIP xxx.xxx.xxx.xxx <none> 443/TCP 47m
上記のk8s-sampleのEXTERNAL-IPのIPアドレスに対して、ポート8080で開きます。
すると、「Hello, World!」が表示されます。
ここで、次のためにサービスを削除しておきます。
kubectl delete -f k8s-sample.yaml
deployment.apps "k8s-sample" deleted
service "k8s-sample" deleted
Cloud BuildとArtifact Registry、GKEによるCI/CD基盤構築
続いて、GCRからArtifact Registryに変更していきます。
Container Registryは2023年5月15日から非推奨になっており、Artifact Registryに置き換えていきます。
Artifact Registryのリポジトリを作成
gcloud artifacts repositories create cloud-build-sample --repository-format=docker --location=<REGION> --description="Docker repository"
Create request issued for: [cloud-build-sample]
Waiting for operation [projects/<PROJECT_ID>/locations/<REGION>/operations/610418cb-8ec6-4788-aae4-db99be7f4f93] to complete...done.
Created repository [cloud-build-sample].
作成後は以下のコマンドで一覧が確認できます。
gcloud artifacts repositories list
Listing items under project <PROJECT_ID>, across all locations.
ARTIFACT_REGISTRY
REPOSITORY FORMAT MODE DESCRIPTION LOCATION LABELS ENCRYPTION CREATE_TIME UPDATE_TIME SIZE (MB)
cloud-build-sample DOCKER STANDARD_REPOSITORY Docker repository <REGION> Google-managed key 2023-07-30T14:40:03 2023-07-30T14:40:03 0
Artifact Registryへのリクエストの認証
以下の<REGION>には、自身の環境での設定を入れてください。
例えば、us-east1
などです。
gcloud auth configure-docker <REGION>-docker.pkg.dev
cloudbuild.yamlの修正
cloudbuild.yamlを以下のように修正します。
substitutions:
_CLOUDSDK_COMPUTE_REGION: リージョン
_CLOUDSDK_COMPUTE_ZONE: ゾーン
_CLOUDSDK_CONTAINER_CLUSTER: クラスタ名
_PROJECT_ID: プロジェクト名
_DIRECTORY: ディレクトリ名
_IMAGE_NAME: イメージ名
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', '${_CLOUDSDK_COMPUTE_REGION}-docker.pkg.dev/${_PROJECT_ID}/${_DIRECTORY}/${_IMAGE_NAME}:latest', '.']
id: docker build
- name: 'gcr.io/cloud-builders/docker'
args: ['push', '${_CLOUDSDK_COMPUTE_REGION}-docker.pkg.dev/${_PROJECT_ID}/${_DIRECTORY}/${_IMAGE_NAME}:latest']
id: docker push
- name: 'gcr.io/cloud-builders/gcloud'
args: ['container', 'clusters', 'get-credentials', '${_CLOUDSDK_CONTAINER_CLUSTER}', '--zone','${_CLOUDSDK_COMPUTE_ZONE}','--project', '${_PROJECT_ID}']
id: gcloud container clusters get-credentials
- name: 'gcr.io/cloud-builders/kubectl'
args: ['apply', '-f', 'k8s-sample.yaml']
env:
- 'CLOUDSDK_COMPUTE_ZONE=${_CLOUDSDK_COMPUTE_ZONE}'
- 'CLOUDSDK_CONTAINER_CLUSTER=${_CLOUDSDK_CONTAINER_CLUSTER}'
id: kubectl apply
Artifact Registry にイメージを保存するさまざまな方法の例は以下に記載されています。
name
フィールドで参照するビルダーイメージの例は以下に記載されています。
name
フィールドでは、タスクを実行するコンテナイメージを指すように指定する必要があります。
私の場合、name
フィールドに当初${_CLOUDSDK_COMPUTE_REGION}-docker.pkg.dev/cloud-builders/docker
のように指定していて、ビルダーイメージをうまく読み込めず、
権限周りのエラーが出ました。
例えば、以下のようなエラーがでていました。
Step #2 - "gcloud container clusters get-credentials": Using default tag: latest
Step #2 - "gcloud container clusters get-credentials": Error response from daemon: Head "https://<zone>-docker.pkg.dev/v2/cloud-builders/gcloud/manifests/latest": denied: Permission "artifactregistry.repositories.downloadArtifacts" denied on resource "projects/cloud-builders/locations/<zone>/repositories/gcloud" (or it may not exist)
ERROR: failed to pull because we ran out of retries.
ERROR
ERROR: build step 2 "<zone>-docker.pkg.dev/cloud-builders/gcloud" failed: error pulling build step 2 "<zone>-docker.pkg.dev/cloud-builders/gcloud": generic::unknown: retry budget exhausted (10 attempts): step exited with non-zero status: 1
Cloud Buildの実行
pushを行うことで、Cloud Buildのトリガーを起動します。
git add .
git commit -m "cloud build test"
git push origin master
Cloud Buildの画面でビルドが完了したことを確認します。
また、Artifact Registryの画面でイメージが作成されたか確認します。
アプリケーションへリクエスト
前回と同様、Cloud Buildでのビルドが完了したら、作成したアプリケーションへリクエストを実行します。
kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
k8s-sample LoadBalancer xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx 8080:32652/TCP 2m36s
kubernetes ClusterIP xxx.xxx.xxx.xxx <none> 443/TCP 47m
上記のk8s-sampleのEXTERNAL-IPのIPアドレスに対して、ポート8080で開きます。
すると、「Hello, World!」が表示されます。
ここで、次のためにサービスを削除しておきます。
kubectl delete -f k8s-sample.yaml
deployment.apps "k8s-sample" deleted
service "k8s-sample" deleted
これで該当のリポジトリへpushすると、Cloud Buildが起動し、Artifact Registryへイメージがpushされ、GKEへデプロイされるCI/CD基盤が構築できました。
まとめ
この記事では、以下の2つの方法を試しました。
- Cloud BuildとGCR、GKEによるCI/CD基盤構築
- Cloud BuildとArtifact Registry、GKEによるCI/CD基盤構築
また、Cloud Buildのドキュメントが参考になるかと思います。
Discussion