【2019年4月版】docker push -> Spinnaker -> deploy on GKE

# Spinnakerで`docker push`をトリガーに自動デプロイをしてみます

外部サービスではなく自前クラウドの中にCI環境構築する~~Jenkins Xのような~~SpinnakerをGKE(Google Kubernetes Engine)上に構築し、`docker push`をトリガーにGKEにデプロイするCI環境を構築してみたいと思います。

Spinnakerの構築手順はそれなりにボリュームあるのでこちらのページもご参考にしてください。

- [GKE で Spinnaker を構築する](https://qiita.com/takasp/items/a74c8acdf3a8851b8da7)

## Spinnaker全体像

Spinnakerの動作環境は`Spinnaker`本体と「spinnakerをデプロイする」`Halyard`という2つのモジュールに分かれ、さらにそれぞれ、Spinnaker->GKE, Halyard->GCEと実行するVM環境も異なります。

![deployment.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/99ea8112-e986-9d1d-54db-1e517bbe7a2f.png)

そしてもう一つ、この図の左上の"Your Workstation"のマシンですが、最終的にこのマシンで**ブラウザからSpinnakerを操作します**。**ブラウザからlocalhost:9000にアクセスできる環境**が必須です！！
(自分は調子こいてcloud shellから実施して最後の最後で詰みました。)

## Spinnakerのインストールを実行する環境

OSはGoogle Cloud SDK(gcloudコマンド)が動く環境であればOKです。
そして何より、**ブラウザが動く環境**です。(トラウマ)

# 環境の構築

それでは以下の公式サイトのご案内に従ってインストールを行います。

https://www.spinnaker.io/setup/quickstart/halyard-gke/

## 0.準備

### 0-1. Google Cloud SDK のインストール

こちらのサイトからCloud SDKをダウウンロードしてインストールをお願いします。
https://cloud.google.com/sdk/downloads#interactive

### 0-2. Cloud SDK の初期設定

`gcloud`コマンドにより使用するGoogle Cloud Platformのプロジェクトにログインします。

```
$ gcloud auth login
```
もしくは、ログイン済みの場合でプロジェクトを変更する場合は

```
$ gcloud config set project <プロジェクト名>
```

とします。

## 1. Kubernetes クラスタの作成

以下の画面から Spinnaker を動かしたいクラスタを作成しておきます。

https://console.cloud.google.com/kubernetes/list

また、以下のAPIを有効にします。

- [Identity and Access Management (IAM) API]( https://console.developers.google.com/apis/api/iam.googleapis.com/overview?pli=1)
-  [Cloud Resource Manager API](https://console.developers.google.com/apis/library/cloudresourcemanager.googleapis.com?project=ultimate-hydra-237702&folder&organizationId)

## 2. Halyard用サービスアカウントのセットアップ

これ以降はターミナル、コマンドプロンプトなどを開き、`gcloud`コマンドで作業を行っていきます。

まずHalyardが動くVM用にサービスアカウントをセットアップします。

```
$ GCP_PROJECT=$(gcloud info --format='value(config.project)')
$ HALYARD_SA=halyard-service-account

$ gcloud iam service-accounts create $HALYARD_SA \
    --project=$GCP_PROJECT \
    --display-name $HALYARD_SA

$ HALYARD_SA_EMAIL=$(gcloud iam service-accounts list \
    --project=$GCP_PROJECT \
    --filter="displayName:$HALYARD_SA" \
    --format='value(email)')

$ gcloud projects add-iam-policy-binding $GCP_PROJECT \
    --role roles/iam.serviceAccountKeyAdmin \
    --member serviceAccount:$HALYARD_SA_EMAIL

$ gcloud projects add-iam-policy-binding $GCP_PROJECT \
    --role roles/container.admin \
    --member serviceAccount:$HALYARD_SA_EMAIL
```

ここでは `halyard-service-account` に以下のロールを割り当てています。

- roles/iam.serviceAccountKeyAdmin
- roles/container.admin


## 3.Cloud Storage、Container Registry のサービスアカウント設定

続いて後ほどのSpinnakerで使用するGCSとGCR用のサービスアカウントも設定します。

```
$ GCS_SA=gcs-service-account

$ gcloud iam service-accounts create $GCS_SA \
    --project=$GCP_PROJECT \
    --display-name $GCS_SA

$ GCS_SA_EMAIL=$(gcloud iam service-accounts list \
    --project=$GCP_PROJECT \
    --filter="displayName:$GCS_SA" \
    --format='value(email)')

$ gcloud projects add-iam-policy-binding $GCP_PROJECT \
    --role roles/storage.admin \
    --member serviceAccount:$GCS_SA_EMAIL

$ gcloud projects add-iam-policy-binding $GCP_PROJECT \
    --member serviceAccount:$GCS_SA_EMAIL \
    --role roles/browser
```

ここでは `gcs-service-account` に以下のロールを割り当てています。

- roles/storage.admin
- roles/browser

## 4.Halyard用VMの作成

HalyardをホストするVMの作成を行います。

```
$ HALYARD_HOST=$(echo $USER-halyard-`date +%m%d` | tr '_.' '-')

$ gcloud compute instances create $HALYARD_HOST \
    --project=$GCP_PROJECT \
    --zone=us-central1-f \
    --scopes=cloud-platform \
    --service-account=$HALYARD_SA_EMAIL \
    --image-project=ubuntu-os-cloud \
    --image-family=ubuntu-1404-lts \
    --machine-type=n1-standard-4
```

ここでは`ユーザー名-halyard-月日`のマシン名でVMを作成してます。

## 5.ポート転送付きでSSH

作成したVMに対して、**ポート転送付きで**SSH接続します。

```
$ gcloud compute ssh $HALYARD_HOST \
    --project=$GCP_PROJECT \
    --zone=us-central1-f \
    --ssh-flag="-L 9000:localhost:9000" \
    --ssh-flag="-L 8084:localhost:8084"
```

これ以降はこのVMの中からの操作となります。

## 6. Halyard のインストール

### 6-1. kubectlのインストール

Halyardのツールはkubectlが必要です。以下のコマンドで`kubectl`をインストールします。

```
$ KUBECTL_LATEST=$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)

$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$KUBECTL_LATEST/bin/linux/amd64/kubectl

$ chmod +x kubectl

$ sudo mv kubectl /usr/local/bin/kubectl
```

### 6-2. Halyardのインストール

いよいよHalyardをインストールします。

```
$ curl -O https://raw.githubusercontent.com/spinnaker/halyard/master/install/debian/InstallHalyard.sh

$ sudo bash InstallHalyard.sh

$ . ~/.bashrc
```

## 7. 認証情報のセットアップ

Spinnaker に持たせる各種の認証情報を以下の手順でセットアップします。

### 7-1. Kubernetesの認証情報取得
以下の手順で `~/.kube/config`を生成します。以下の`YOUR_GKE_CLUSTER_NAME`と`YOUR_GKE_CLUSTER_ZONE`は生成したKubernetesクラスタの情報をコピペしてください。

```
$ GKE_CLUSTER_NAME={YOUR_GKE_CLUSTER_NAME}
$ GKE_CLUSTER_ZONE={YOUR_GKE_CLUSTER_ZONE}

$ gcloud config set container/use_client_certificate true

$ gcloud container clusters get-credentials $GKE_CLUSTER_NAME \
    --zone=$GKE_CLUSTER_ZONE
```

### 7-2. Cloud Storage用の認証情報セットアップ

```
$ GCS_SA=gcs-service-account
$ GCS_SA_DEST=~/.gcp/gcp.json

$ mkdir -p $(dirname $GCS_SA_DEST)

$ GCS_SA_EMAIL=$(gcloud iam service-accounts list \
    --filter="displayName:$GCS_SA" \
    --format='value(email)')

$ gcloud iam service-accounts keys create $GCS_SA_DEST \
    --iam-account $GCS_SA_EMAIL
```

## 8. Spinnakerの設定

Halyardに、デプロイするSpinnaker のバージョンを指定します。ここでは**最新バージョン**とします。

```
$ hal config version edit --version $(hal version latest -q)
```
引き続き、以下のように設定をしていきます。
Spinnaker の永続化には CloudStrageを使用します。

```
$ hal config storage gcs edit \
    --project $(gcloud info --format='value(config.project)') \
    --json-path ~/.gcp/gcp.json

$ hal config storage edit --type gcs
```
Container Registryからpullしますよ～

```
hal config provider docker-registry enable

hal config provider docker-registry account add my-gcr-account \
    --address gcr.io \
    --password-file ~/.gcp/gcp.json \
    --username _json_key
```
Kubernetes providerの**v2**を使います。

```
$ hal config provider kubernetes enable

$ hal config provider kubernetes account add my-k8s-account \
    --docker-registries my-gcr-account \
    --context $(kubectl config current-context) \
    --provider-version v2
```

## 9. デプロイ＆接続

以下のコマンドで Halyard にすべての設定を反映させ、GKE に Spinnaker をデプロイさせます。

```
hal config deploy edit \
    --account-name my-k8s-account \
    --type distributed

hal deploy apply
```

デプロイ完了したら以下のコマンドでSpinnaker に接続します。

```
$ hal deploy connect
+ Get current deployment
  Success
+ Connect to Spinnaker deployment.
  Success
Forwarding from 127.0.0.1:8084 -> 8084
Forwarding from [::1]:8084 -> 8084
Forwarding from 127.0.0.1:9000 -> 9000
Forwarding from [::1]:9000 -> 9000
```
上記の`9000ポートの転送しています`メッセージが出たら、ブラウザから`http://localhost:9000`を開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/02cc2fab-a19a-c190-9270-b5ab0e7b7241.png)

はい！Spinnaker の起動いっちょ上がり！

# Spinnaker での設定

以下でデプロイの設定を行います。Spinnakerでは"Application"、および複数のアプリケーションを包括する"Project"の単位で管理が可能です。

ここでは単一の`Application`の登録方法を説明します。

## 0. その前に

以下のSpinnakerの選択画面ではDocker Imageを自動で選択していきますが、自動で選択するためにはあらかじめImageがデプロイされていないとダメです！

ですので、`gcloud`コマンドであらかじめdocker imageを`push`しておきます。

```
$ gcloud docker -- push gcr.io/<プロジェクト名>/<イメージ名>:latest
```

## 1. `Create Application`
画面右上の`Action`メニューから`Create Application`を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/749f6076-480c-9c7a-ed21-4f89cbee1faf.png)

アプリケーション名と通知先のメールアドレスは必須項目です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/b1a7b272-2599-6380-5366-f5a939a69f89.png)

`test-app-1`という安易な名前で作ってみます。。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/e19cff98-4b1d-b6b9-2f83-f544435b8425.png)

で、`PIPELINES`から行いたい処理を追加していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/d6acd5f3-9ca9-e987-93b9-819919dce712.png)
最初は何もないので`Configure a new Pipeline.`をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/87366292-27ef-f9b1-8c29-7c336aeb5d62.png)
`first-pipeline`とイージーな名前を付けて作成してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/e532ddd1-b5fc-c636-1a0b-a61f7dbe0b57.png)
まず`Automated Triggers`から`Add Trigger`をクリックします。
追加されたトリガーのTypeに`Docker Registry`を選択したところです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/8e652584-775e-0afb-d323-5d89d053dd58.png)
先の手順でサービスの設定がうまくいっていれば`my-gcr-account`が選択できると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/baed3e4c-a658-72b0-35cb-2e6e2d3b37a2.png)

以下、`Organization`にてプロジェクト名を選択、`Image`にてイメージ名を選択、Tagに`latest`と順次設定を行えばOKです。
画面右下の`Save Changes`をクリックして保存されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/658d4eec-1956-4aa2-95ca-2d56c03cd861.png)
トリガーの設定はこれでOKです。

続いてメインの処理を追加します。上に戻って・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/a1e69267-e29f-0d0b-a638-d82cc43c21c4.png)

`Add Stage`をクリックします。そしてTypeにて`Deploy(Manifest)`を選択した状態です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/186b96fd-de3d-b386-a540-deaf4c935324.png)

画面下の方に・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/7f3ca95d-4970-d845-4f19-45c2dadeda84.png)

どーん！と広大なテキストエリアが広がっておりますので、ここに**ymlをベタ貼り**いたします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/1f79f978-5902-44b4-bb27-172f70728352.png)
右下の`Save Changes`で保存されます。
ちなみにある程度の書式チェックはしてくれるようです。賢い！

ymlが複数ある場合にも同様に`Add Stage`でタスクをガンガン追加していけます。
設定の手順は以上です。

# Spinnakerから手動でパイプライン実行

上記の設定後はコンソールなどから`gcloud docker push`してパイプラインが動くと思いますが、手動でトリガーする場合は以下の手順になります。

Spinnaker画面、ヘッダーの`PIPELINES`をクリックすると先ほど登録したパイプラインが表示されているはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/240d9c35-9712-7c21-46a2-c590f71a8c8f.png)
実行したいパイプライン(ここでは`first-pipeline`)の行の右端にある`Start Manual Execution`をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/06cee8dd-22ae-9761-c5f3-7dd16d6eddbe.png)
確認が出るので`Run`をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/396118fb-c2d2-677c-8e5b-d5989473e1d1.png)

このように詳しく進捗状況を教えてくれます。

# Spinnaker 悪くないかも

他社のクラウドサービス系はリポジトリをグローバルに出さないとフックできないですが、Spinnakerは自前K8s内にCIを構築できるのでソースコードを完全に外に出さないで済みます。
お蔭で構成がかなりアレで慣れないと構築するの大変ですが、いったん構築してしまえば使うのは割と簡単です。
GUIもよくできてます。

Spinnaker 悪くないかも、でした！