超入門！GCP のCIツール、Cloud Build でリリースサイクル高速化！！

なにかしらのサービスを開発していると、デプロイしてテストして、修正してデプロイしてテストして…と手動で実行することはよくあると思います。
1回だけならそれでもいいと思いますが、それを10回20回、100回行うとなると、非常に多くの時間を本質的ではないことに費やすことになります。

このようなテストを自動で実施する方法として注目されているのがCIです。

本記事は、GCPのCIツールであるCloud Build入門として、Cloud Build とはなにか、Cloud Buildを実際に使ってCloud Buildの理解を深める、導入方法を理解するのが目的になります。
まずはCIについて簡単に説明していきましょう。


＜今流行りのCIについて説明する＞
正式には、「Continuous Integration」の略です。
日本語訳すると「継続的インテグレーション」になります。

CIを簡単に説明すると、「テストやリリース、ビルドの自動化」です。
アジャイル開発が浸透し、細かい修正を何度も実行する機会が増えてきました。
スピードを重視する開発手法では、修正→テスト→リリース の流れを如何に早く行うかが重要になります。
開発の速度を向上させるために、コードの修正を行なうと自動的に今まで行なっていたテストフローを実行してくれる ということがCIでは実現可能になります。

テストやビルドのサイクルを人が実行する場合、個人の端末の環境に左右され、私は動くけど他では動かない、といった事象が発生したり、フローを知っている人がいないとなにもできないといったことも起こり得ます。
CIツールを利用し自動化することで、属人化されたサイクルから脱出することができます。

このCIをクラウドサービスと連携させると、本番環境へのデプロイがさらに簡単になります。
また、デプロイが早く、細かく行えるため、修正に伴うバグの発見が早くなり、必然的にアプリケーションの品質が向上します。
リリースの一部をCIツールに任せることにより、上述した多くのメリットを利用者側が得られるでしょう。

CIツールを導入する方法として、自前で構築する方法やクラウドサービスを利用の2種類があります。
JenkinsやCircleCIという言葉は一度であれば聞いたことはあるのではないでしょうか。

本記事では、これらのツールの中でもGCPに特化したビルドサービスである、Cloud Build を紹介します。

＜GCPのCloud Build サービスについて説明してみる＞
前項でも記載した通り、GCPのCI サービスです。
自動でビルドやテストを実行してくれるサービスとして提供されています。

GCPのサービスのため、他GCPサービスとの親和性も高くCloud Build API を有効化してトリガーを作成するだけで簡単に自動化が実現できます。
フルマネージドのサービスで、1分あたりの料金も$0.003と非常に安く、1 日あたり120分は無料なので、GCPネイティブなサービスのリリース/テストフローの自動化を行う場合に非常に強力なサービスです。

マシンタイプ/仮想CPU/料金
n1-standard-1/1/$0.003/ビルド分
n1-standard-8/8/$0.016/ビルド分
n1-standard-32/32/$0.064/ビルド分
※n1-standard-1 の場合、最初の120分は無料

git のcommit push をトリガーとして、事前に定義した任意のコマンドを実行してくれます。
Cloud Build のトリガーとして設定できるコードホスティングサービスは3つです。

・Cloud Source Repositories
・Git Hub
・Bitbucket

これらのサービスからの任意のブランチ/タグのpush をトリガーとしてCloud Build は動作します。
イメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386394/816f631b-8c39-da70-c646-7521ed616fe1.png)




説明だけではわかりづらいと思うので、実際の設定方法について説明していきます。

＜とっても簡単！Cloud Build を触ってみよう＞
Cloud Build で必要なものは主に以下になります。

・トリガー
・リポジトリ/ブランチ（git 関連）
・ビルド実行用ファイル
　・Dockerfile
　・ビルド構成ファイル（yaml形式 or json形式）

Dockerfile にするか、ビルド構成ファイルにするかは用途によって異なります。
docker のコンテナイメージのみ作成する場合であればDockerfile、そうでない場合はビルド構成ファイルを利用する、と考えていただければOKです。
ただ、ビルド構成ファイルでイメージの作成もできるため、よっぽどのことがなければビルド構成ファイルの利用をお勧めします。



＜構成説明＞
下記のような構成をCloud Build を利用して自動で構築します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386394/402764d5-ebc2-8c3b-33e6-3aeea5b80ed1.png)


デプロイフローについて順番に説明します。
1.任意のブランチからSource Repositories に対してgit push
2.事前にCloud Build のトリガーを作成し、git push を検知してトリガーを実行
3.コンテナイメージをビルドして、Container Registry にpush
4.push したイメージを元にGKE にコンテナをデプロイ

フローを作成する詳細手順について説明していきます。
・Source Repositories でリポジトリ作成
・GKE クラスタ作成
・Cloud Build トリガー作成
・ビルド構成ファイル（yaml形式）作成
・Dockerfile/application ファイル作成
・GKE 設定ファイル作成
・IAM 役割の付与
※手順は2019/01 時点での説明になります。



＜Source Repositories でリポジトリ作成＞
すぐに終わります。
Cloud Console にアクセスし、以下の画像の流れでSource Repositories にアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386394/3220a977-b497-03ff-e1de-421ea02a0b7f.png)

Source Repositories のページにリダイレクトされたらOKです。
右上「リポジトリを追加」を選択しましょう。
追加を選ぶと詳細画面に遷移します。
Source Repositories では外部のホスティングサービスとのミラーリングが可能ですが、今回は単体のリポジトリを作成します。
「新しいリポジトリを作成」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386394/a6b00626-9fad-ed84-8a91-e5e0980ef930.png)

「新しいリポジトリを作成」を選択すると、リポジトリ名とどのプロジェクトに作成するか、を選択します。任意の名前、プロジェクトを選択してください。

さらに遷移すると「リポジトリにコードを追加」と記載された画面に遷移します。
「リポジトリにコードを push するオプションを選択:」では、「ローカル Git リポジトリへのリポジトリのクローンを作成する」をオプションとして選択し、認証の方法を「Google Cloud SDK」に設定します。

画面にも記載されていますが、その後リポジトリのclone を実行するため、下記のコマンドをclone したいマシン上で順番に実行します。

―――――――――――――――――――――――――――――――
$ gcloud init
$ gcloud source repos clone REPO_NAME --project=PROJECT_NAME
$ cd REPO_NAME
$ git push -u origin master
―――――――――――――――――――――――――――――――
これでリポジトリ作成は完了です。

＜GKE クラスタ作成＞
今回はCUI 上から作成します。
下記コマンドをローカルマシンにて実行してください。

―――――――――――――――――――――――――――――――
$ gcloud container clusters create [CLUSTER_NAME] --num-nodes=1 --zone=asia-northeast1-c --preemptible
―――――――――――――――――――――――――――――――
これでGKE クラスタの作成は完了です。


＜Cloud Build トリガー作成＞
Cloud Build を動作させるためのトリガーを作成します。
下記画像の順番でアクセスしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386394/d1914f3f-f702-5633-762e-4ab4f22c4356.png)


「トリガー」の画面から、「トリガーの作成」を選択し、ソースを選択する画面で「Cloud Source Repositories」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386394/f396b6f4-29d0-9444-8ae6-987b76c5b1b9.png)

その後、続行を選択すると、リポジトリの選択画面に遷移します。
さきほど作成したリポジトリを選択してください。

同様に続行を選択すると、トリガーの設定画面に遷移します。
今回は下記の内容で設定しました。

・名前：任意
・トリガータイプ：ブランチ
・ブランチ（正規表現）：任意のブランチ
・ビルド設定：cloudbuild.yaml
※他はデフォルトのままです。
これでトリガーの作成は完了です。

＜ビルド構成ファイル（yaml形式）作成＞
さきほどトリガーの作成時に、ビルド設定をcloudbuild.yaml に設定しました。
Cloud Build では、この設定ファイルを元に任意のコマンドを実行します。

今回は下記のようなステップでコマンドを実行するよう設定しました。

1.docker build
2.Container Registry に対してdocker push
3.任意のクラスタに対して接続
4.GKE に対してapply
―――――――――――――――――――――――――――――――
steps:
- name: 'gcr.io/cloud-builders/docker'
  args: [ 'build', '-t', 'gcr.io/$PROJECT_ID/IMAGE_NAME:TAG_NAME', '.' ]
  id: docker build
- name: 'gcr.io/cloud-builders/docker'
  args: [ 'push' ,'gcr.io/$PROJECT_ID/IMAGE_NAME:TAG_NAME' ]
  id: docker push
- name: 'gcr.io/cloud-builders/gcloud'
  args: [ 'container', 'clusters', 'get-credentials', 'CLUSTER_NAME', '--zone', 'asia-northeast1-c', '--project', '$PROJECT_ID' ]
  id: gcloud container clusters get-credentials
- name: 'gcr.io/cloud-builders/kubectl'
  args: [ 'apply', '-f', 'apps-gcp.yaml' ]
  id: kubectl apply
―――――――――――――――――――――――――――――――

IMAGE_NAME、TAG_NAME はそれぞれ任意の値に変更してください。
CLUSTER_NAME は、先ほど作成したクラスタの名前に変更してください。

ビルド構成ファイルの作成は以上です。

＜GKE 設定ファイル作成＞
GKE にデプロイするためのDeployment とService の設定ファイルを作成します。
―――――――――――――――――――――――――――――――
apiVersion: apps/v1
kind: Deployment
metadata:
 name: NAME
spec:
 selector:
   matchLabels:
     app: NAME
 replicas: 1
 template:
   metadata:
     labels:
       app: NAME
   spec:
     containers:
     - name: NAME
       image: gcr.io/ca-tkg-test/IMAGE_NAME:TAG_NAME
       resources:
         requests:
           cpu: 100m
           memory: 100Mi
       ports:
       - containerPort: 8080
---
kind: Service
apiVersion: v1
metadata:
 name: NAME
spec:
 type: LoadBalancer
 selector:
   app: NAME
 ports:
 - name: http
   port: 8080
   targetPort: 8080
―――――――――――――――――――――――――――――――

NAMEは任意の値に変更してください。
これでGKE のファイル作成も完了です。

＜Dockerfile / Application ファイル作成＞
最後にDocker イメージをビルドするためのDockerfileとアプリケーションファイルを作成します。
今回はGKE クイックスタートから下記ファイルを使用します。
https://cloud.google.com/kubernetes-engine/docs/quickstart?hl=ja#code_review

―――――――――――――――――――――――――――――――
FROM golang:1.8-alpine
ADD . /go/src/hello-app
RUN go install hello-app
{1}
FROM alpine:latest
COPY --from=0 /go/bin/hello-app .
ENV PORT 8080
CMD ["./hello-app"]
―――――――――――――――――――――――――――――――
―――――――――――――――――――――――――――――――
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 listening on port %s", port)
        log.Fatal(http.ListenAndServe(":"+port, server))
}
 
func hello(w http.ResponseWriter, r *http.Request) {
        log.Printf("Serving request: %s", r.URL.Path)
        host, _ := os.Hostname()
        fmt.Fprintf(w, "Hello, world!\n")
        fmt.Fprintf(w, "Version: 1.0.0\n")
        fmt.Fprintf(w, "Hostname: %s\n", host)
}
―――――――――――――――――――――――――――――――
これで必要なファイルはすべて揃いました。

＜IAM 役割の付与＞
ここまで準備ができたらあとはCloud Build を動かすだけ！と思いきや、IAMの設定が必要になります。
Cloud Build APIを有効化した際に、自動的に有効にしたプロジェクトにサービスアカウントが作成されます。
このサービスアカウントは、Cloud Build がビルドを実行する際に使用するGoogle アカウントになります。
そのため、このサービスアカウントに対して適切な役割が付与されていない場合、Cloud Build がビルドを実行する際にpermission エラーが発生します。

まずはIAMの設定を確認しましょう。
「IAMと管理」、「IAM」でIAMの設定画面に遷移。
Cloud Build が使用するサービスアカウントは、@以降が “cloudbuild.gserviceaccount.com” となっています。
検索すると下記画像にある通り、「Cloud Build サービス アカウント」の役割が付与されています。
この役割の権限をみてみると、GCS に対する権限とPub/Sub に対する権限しかもっていません。（Container Registry はGCSの権限が必要、Pub/Sub はCloud Build のログ保存先として使用されるためだと思います。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386394/2ebb71c5-5c8a-e5af-9b2b-a95a40f672bf.png)

今回はGKE に対してリクエストを行うため、このサービスアカウントに対して、「Kubernetes Engine 管理者」を付与します。
これでIAM 役割の付与も完了です。


＜Cloud Build を動かしてみる＞
ここまでが完了したらあとは動作確認のみです。
Cloud Build は任意のブランチに対するgit push で動作します。
今回はdevelop ブランチを作成し、そのブランチへのpush をトリガーに設定しました。

それでは実際に動かしてみましょう。
さきほど作成したファイルすべてを、作成したSource Repositories のdevelop ブランチに対してpush します。

それをトリガーとしてCloud Build が動き出します。
「Cloud Build」、「履歴」からトリガーの実行結果がわかります。

下記画像の緑色はビルド成功、赤いマークはビルドが失敗したことを意味します。
ビルドの途中でエラーが発生した場合、そのステップで実行は終わりますので、ビルドIDを選択してログを確認しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386394/f634b587-9204-a9cb-52d0-88377ed22846.png)

ビルド詳細でログが見れます。
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386394/2fe14f26-48be-386e-05de-d16be5cd7088.png)

それでは最後にGKE 上に無事デプロイができているか確認します。
「Kubernetes Engine」、「ワークロード」の順番に遷移。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386394/0a537655-db85-17c1-6cbf-b24b2be1033a.png)

podが配置されていることが確認できした。
続いて、サービスの確認です。
「Kubernetes Engine」、「ワークロード」の順番に遷移します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386394/0afb2c3d-aad8-5374-ff4b-9306aabc2394.png)

こちらも作成できています。
「エンドポイント」の欄にHTTPロードバランサの外部IPとポート番号が書いてあるため、アクセステストをします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386394/3e64da25-4cac-f0be-376d-b2095929ab2d.png)

GKE 上で提供されているHello world を返すWeb サイトにアクセスできました。

これで動作検証は完了です。
無事、Cloud Build を利用してGKE 上にアプリケーションをデプロイすることができました。


＜まとめ＞
いかがだったでしょうか。
本記事ではCloud Build を紹介し、実際にCloud Build を使用してイメージ作成とプッシュ、作成したイメージをGKE にデプロイする一連の流れを紹介しました。

実際に構築された方は、その簡単さに驚かれたのではないでしょうか。
Cloud Build を利用することで、人に依存しない高速なリリースプロセスを構築することが可能です。

GCP ネイティブなアプリケーションを作成する場合、他GCPサービスと親和性の高いCloud Build を利用することで、非常に簡単に自動化が実現できます。

フルマネージドサービスで管理がいらないのも魅力です。
GCP上にあるアプリケーションのリリースサイクルを是非Cloud Build を使って高速化しましょう。