これから始めるDevOps Cloud Buildでパイプラインを構築する

# はじめに
本記事はGCP環境にてCloud Buildでパイプラインを構築し、GCEの仮想マシンインスタンスに静的コンテンツをデプロイする方法について解説しています。

## DevOps
[DevOps](https://ja.wikipedia.org/wiki/DevOps)は価値を提供することを目的に、迅速にデプロイを行い品質を担保するための仕組みであり、文化です。

開発 (Development) と運用 (Operations) を組み合わせて、技術的要素だけではなく、体制を整備し、サイロ化を作り込まないことが重要です。

DevOpsを組織に導入することで、俗人化されていたデプロイ作業をパイプラインに置き換えて、誰でもビルド・デプロイできる仕組みを提供します。

本記事ではDevOpsの真髄となるCI/CDの自動化を実現する手段として、GCPの[Cloud Build](https://cloud.google.com/build)について学びます。

### 何故、パイプラインを構築するのか？
DevOpsにおいて、Cloud Buildなど自動化ツールを導入することは目的はありません。

As-Is/To-Beを基に、DevOpsの必要性について理解しましょう。

- As-Is
    - ソースの変更を反映させる場合、手動のデプロイ作業が必要になるため、オペレーションミスのリスクや、デプロイに時間がかかる。
    - 少人数の組織の場合、デプロイ作業が俗人化して作業のサイロ化を生みやすい。
- To-Be
    - ソースコードの変更を反映させる場合、自動でデプロイ作業を行い、冪等性を確保し品質向上や、迅速にデプロイを行う。
    - Gitにpushするなど、何らかのコンテキストをトリガーにすることで誰でもデプロイを行うことができ、作業のサイロ化を発生させない。

上記、運用に関わる課題を解決するための**手段**がパイプラインの構築であり、ベネフィットはデプロイ自動化による**工数削減及び品質向上**になります。

### パイプラインの構築
クラウドサービスにおいて、パイプラインを構築するためには以下の様な仕組みが必要です。

- パイプライン
	- Gitなどのバージョン管理システムにソースコードをプッシュすると、パイプラインのトリガーが起動し、ソースコードの変更を検出
- ビルド・テスト
	- 必要に応じて、アプリケーションのビルドの実施
	- ソースコードに対する静的テストや動的テストの実施
- デプロイ
	- Gitなどのバージョン管理システムで指定したmainブランチなどから、最新のソースコードを取得し、仮想マシンやコンテナなどの実行環境にデプロイする
	- 必要に応じてコマンドによる命令の実行
	- デプロイ終了後の完了通知を行うための仕組み

本記事で紹介する[Cloud Build](https://cloud.google.com/build)は、パイプラインからデプロイまで、一気通貫でデプロイすることができます。ちなみに1日120分までは無料枠として利用することができます。

なお、本記事の内容をAWS環境で実行する場合は、[AWS CodePipeline](https://aws.amazon.com/jp/codepipeline/)と、[AWS CodeDeploy](https://aws.amazon.com/jp/codedeploy/)の組み合わせが必要です。

補足として[Google Cloud Deploy](https://cloud.google.com/blog/ja/products/devops-sre/google-cloud-deploy-automates-deploys-to-gke)は、GKEに対するマネージド型の継続的デリバリーサービスになります。現在は、GKEのみサポートしています。

:::note
パイプラインの仕組みを理解し、デプロイを実現する手段として、クラウドサービスの仕様が要件を満たしているか確認することが重要です。
:::

## Cloud Build
Cloud Buildでパイプラインを構築し、GCEの仮想マシンインスタンスにデプロイするための方法について以下に記載します。

本記事では以下の構成でCloud Buildを軸に、パイプラインを構築します。また、ソースコードの脆弱性を保護するために、Snykを利用しています。

![DevOps.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/9b479cf4-1c6e-c421-0283-a18361c84547.png)

ソースコードをGitHubにプッシュすると、Cloud Buildのトリガーがソースコードの変更を検知し、最新の`index.html`ファイルをデプロイ先のサーバに配備します。デプロイ後、Slackに通知を行います。

※本記事ではテストについては対象外としています。

### パイプラインの構築
前提条件：
デプロイ先である仮想マシンインスタンスのVPCネットワークのファイアウォール設定は、トラフィックの送信元を識別するためのソースフィルタについて、Cloud Buildから仮想マシンインスタンス宛のSSHのトラフィックが許可されている必要があります。

Cloud Buildで必要な作業は以下になります。

- Cloud Buildの設定
    - トリガーの作成
    - Cloud Build　APIの有効化
    - サービスアカウント権限の設定（IAM）
- cloudbuild.yamlファイルの作成

#### Cloud Buildの設定
Cloud Build画面のトリガーペインより、「トリガーを作成」を選択し、名前など必要な項目を入力します。また、ソースからリポジトリを選択します。リポジトリ選択は初回のみ、認証を行います。

![スクリーンショット 2022-01-19 22.43.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/55f895b0-ed82-0f33-d2d5-cd4aa9603be4.png)

保存をクリックして、設定を保存します。

![スクリーンショット 2022-01-18 1.41.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/7f227c31-41bc-e225-4edc-a68954e6da58.png)

Cloud Build画面の設定ペインより、「APIを表示」をクリックします。

![スクリーンショット 2022-01-10 21.14.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/6ec91ebb-4a14-afa6-2cda-5b0ccb488443.png)


Cloud Build API画面に遷移後、Cloud Build APIを有効にするため、「有効にする」をクリックします。

![スクリーンショット 2022-01-10 21.15.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/ba203b66-de07-6068-a8b2-e1fa510e3566.png)

Cloud Build画面の設定ペインより、サービスアカウント権限の「Compute Engine」について、ステータスを「有効にする」に変更します。

![スクリーンショット 2022-01-10 21.24.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/3e2c28c8-8131-6025-25d7-b643de0a4200.png)

画面の様なポップアップが表示されるので、「すべてのサービスアカウントにアクセス権を付与」をクリックします。

![スクリーンショット 2022-01-10 21.25.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/651ae0ab-be0d-195b-d1cd-13149b4c8d81.png)

サービスアカウント権限の「Compute Engine」と、「Service Accounts」のステータスが有効になったことが確認できます。合わせてIAMのCloud Buildで使用するサービスアカウントに、ロールが追加されたことが確認できます。

![スクリーンショット 2022-01-10 21.57.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/6dcb956c-a723-c020-73fa-b80bc854cf87.png)

#### cloudbuild.yamlファイルの作成
Cloud Buildにてデプロイ実行時のタスクを制御するための命令は、`cloudbuild.yaml`ファイルに記述します。`cloudbuild.yaml`ファイルは、リポジトリ直下に配備します。

Cloud Buildに実行させるアクションは`steps`に記述します。

以下の場合、最初のステップでcloud-sdkのイメージをビルドし、ビルドされたコンテナからgcloudコマンドのscpを用いて、GCEの仮想マシンの`/var/www/html`ディレクトリに`index.html`ファイルをコピーします。

次のステップで、Slackで指定したワークスペースのtestという名前のチャンネルに、curlコマンドを用いて、メッセージを通知します。

- cloudbuild.yaml

```yaml
steps:
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: gcloud
    args: ['compute', 'scp', '--project', 'unique-sentinel-XXXXXX', '--zone', 'us-west1-a', 'index.html', '＜ユーザー名＞@＜ホスト名＞:/var/www/html', '--port', '＜指定したポート番号＞']

  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: bash
    args:
      - '-c'
      - |
        curl -X POST --data-urlencode "payload={\"channel\": \"#test\", \"username\": \"webhookbot\", \"text\": \"Deploy Done\", \"attachments\": [{\"color\": \"#36a64f\", \"title\": \"Deploy notification\"}]}" https://hooks.slack.com/services/XXXXXXXXXXX/XXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX
```

:::note
デプロイ時にgcloudのscpを使うメリットは、コードの中でSSH秘密鍵などのクレデンシャル情報を持つ必要がないため、セキュアな運用が実現できます。
:::

- [gcloud コマンドライン ツールを使用したファイルの転送](https://cloud.google.com/compute/docs/instances/transfer-files?hl=ja#transfergcloud)

>`gcloud` コマンドライン ツールには SCP ファイル転送ユーティリティが備わっています。このユーティリティは初回接続時に SSH 認証鍵ペアを作成します。秘密鍵はローカル デバイスに保存され、対応する公開鍵はプロジェクト メタデータまたは VM インスタンス メタデータにコピーされます。

### デプロイ検証
ローカル環境でソースコードを変更後、Gitで`commit`及び`push`を実行すると、Cloud Buildによる自動デプロイが行われます。

デプロイ終了後、Slackのtestチャンネルに通知が行われます。通知によりデプロイ完了が確認できます。

![スクリーンショット 2022-01-18 1.31.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/6ddb7749-24e1-c8a1-ccdf-a782ec412d0f.png)

また、Cloud Build画面のダッシュポードペインより、ビルド成功と表示され、サーバでも`index.html`が反映されたことが確認できます。

![スクリーンショット 2022-01-18 1.39.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/c307c434-76d6-ea80-3081-454804bfc82b.png)

### ロギング
ビルド時のログは、[Cloud Logging](https://cloud.google.com/logging/)のLogs Explorerからも確認できます。

Cloud Buildのログは、ログバケットの`_Default`に保存されます。

デフォルト設定で使用し続ける場合は、基本的に料金は無料ですが、デフォルトの保持期間30日を超える場合は、課金が発生するため、注意が必要です。

### Snyk
SnykはDevSecOpsを実現するためのソリューションとして、**コードを保護**することを目的としています。

Snyk及びDevSecOpsについては、以前書いた[SnykではじめるDevSecOps](https://qiita.com/Brutus/items/f3aed88abdeaeb9e048a)を参照。

Snykのスキャンはオンデマンドでも実行することができますが、CI/CDにも対応しているため、パイプラインに組み込むことができます。

本記事ではSnykのCI/CDの組み込み方法や、ソースコードをスキャンするための簡単な使い方について記載しています。

#### Snyk Code
Snykを使用するためには、GitHubとSnykを連携します。

Projectsに保護したいリポジトリを登録したタイミングで、自動的にスキャンが行われます。
また、Snykは各リポジトリ毎に、自動スキャンを行ないます。各リポジトリ毎の設定のSettingsタブから、スキャンスケジュールの設定が確認ができます。

![スクリーンショット 2022-01-20 0.56.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/437f01a3-1a59-7da1-f18e-9841b35a63be.png)

デフォルトは`Test weekly`になっているので、週次でスキャンが行われてレポートがメールで通知されます。日時でスキャンを行いたい場合は、`Test daily`を選択します。

:::note
スキャンされた脆弱性に対して、自動でPull Requestも行ってくれるので、Snykは開発者の負担を軽減します。
:::

#### CI/CDへの組み込み
SnykのCI/CDへの組み込みは以下、4パターン存在します。

- ネイティブプラグインの使用
- パイプラインスクリプトから、npmを使用してSnyk CLIをインストール
- パイプラインスクリプトから、npmを使用できない場合、CLIバイナリをインストール
- パイプラインから、SnykのDockerイメージをダウンロードし、コンテナのデプロイ

:::note
環境に応じてCI/CDにSnykのスキャンを組み込むことで、スキャンで問題が検出された場合は、デプロイを行わないなど、DevOpsにセキュリティを融合できます。
:::

# おわりに
GCEの仮想マシンインスタンスについても無料で利用することができます。詳細については以前書いた[これから始めるGCP（GCE）　安全に無料枠を使い倒せ](https://qiita.com/Brutus/items/22dfd31a681b67837a74)を参照。

DevOpsはこれからも重要なスキルです。GCPの無料枠を最大限に活用し、DevOpsについて学びましょう。

## 参考
### DevOps
- [How to begin your DevOps journey](https://about.gitlab.com/blog/2022/01/13/how-to-begin-your-devops-journey/)
- [What is DevOps? REALLY understand it](https://dev.to/techworld_with_nana/what-is-devops-really-understand-it-29j7)
- [What don't people understand about DevOps (yet)?](https://www.protocol.com/braintrust/what-people-misunderstand-about-devops?rebelltitem=2#rebelltitem2)

### Cloud Build
- [Cloud Build の料金](https://cloud.google.com/build/pricing)
- [ビルド構成の概要](https://cloud.google.com/build/docs/build-config?hl=ja)
- [ビルドエラーのトラブルシューティング](https://cloud.google.com/build/docs/troubleshooting?hl=ja&_ga=2.247842503.-1142788752.1641568212)

### Cloud Logging
- [Cloud Logging の料金概要](https://cloud.google.com/stackdriver/pricing#logging-pricing-summary)
- [ログの保持期間](https://cloud.google.com/logging/quotas#logs_retention_periods)

### その他
- [gcloud compute ssh](https://cloud.google.com/sdk/gcloud/reference/compute/ssh)
- [gcloud compute scp](https://cloud.google.com/sdk/gcloud/reference/compute/scp)
- [Snyk CI/CD Integration: good practices](https://docs.snyk.io/getting-started/snyk-cicd-integration-good-practices)
- [snyk-cicd-integration-examples](https://github.com/snyk-labs/snyk-cicd-integration-examples)