Mercari Advent Calendar 2017 の17日目は SET(Software Engineer in Test)チームの @masudak がお送りします。
Spinnakerの登場
みなさんの会社では、どうやってサービスのデプロイを行っていますでしょうか。手で温かみのある配布しているという方もいるかもしれませんし、scp/rsyncでデプロイ、シンボリックリンクを駆使してデプロイ、botを使ってデプロイなど、色々な方法があるでしょう。
@deeeetが
tech.mercari.com
に書いたように弊社ではマイクロサービスのデプロイを少しずつSpinnakerに寄せています。
RED/BLACKデプロイや、承認フローの追加、カオスモンキーなど数多くのマイクロサービスを、共通の基盤を使ってコントロールすることができるようになります。
この記事ではSpinnakerの構築を可能な限り分かりやすく、ハンズオン形式で覚えられるようかなり平易な内容で書いてみました。
環境はGCPですが、それ以外の環境でも極力自力でできるよう必要な概念を説明するようにしています。
また本文中では、Kubernetesをk8sと省略しています。ご了承ください。
是非実際手を動かして覚えて頂き、活用した結果をコミュニティに還元して頂ければと思います。
では、行きます。
インスタンスを用意
まず、 Ubuntu 14.04
のインスタンスを一台用意してください。Dockerイメージもあるのですが、gcloudツールを別途入れたりしないといけなくて面倒なので、普通に Ubuntu 14.04
を使うことをオススメします。
その際、サービスアカウントには Allow full access to all Cloud APIs
を選択してください。
もちろん、
https://www.spinnaker.io/setup/install/halyard/
に従い、Dockerイメージなども使うことは可能ですので、その場合は上記ドキュメントをご参照ください。また、Macで動かすこともできるのですが、8〜9GB求められたという噂も聞いたので、その辺もお気をつけください。
必要なコマンドのインストール
インスタンス作ったら、SSHし、以下を叩きます。
$ curl -O https://raw.githubusercontent.com/spinnaker/halyard/master/install/stable/InstallHalyard.sh $ sudo bash InstallHalyard.sh
以下を聞かれるので、自動補完したければそのままデフォルトのとおり進めてください。
Would you like to configure halyard to use bash auto-completion? [default=Y]: Where is your bash RC? [default=/home/USER_NAME/.bashrc]:
インストールされました。
$ hal -v 0.38.0-20171207201947
読み直します。
$ . ~/.bashrc
GCSの設定
では、Spinnaker構築していきましょう。
https://www.spinnaker.io/setup/install/environment/
にあるとおり、
- Local installations of Debian packages.
- Distributed installations via a remote bootstrapping process.
- Local git installations from github.
という3つの構築方法があります。ここでは、せっかくなのでGKEを使って、 Distributed installations
する方法を書いてみたいと思います。
Note: We recommend having at least 4 cores and 8 GiB of RAM free in the cluster you are deploying to.
と書かれているので、適当にクラスタを作っとおいてください。
次からは以下のドキュメントに従います。
https://www.spinnaker.io/setup/providers/kubernetes/
$ gcloud iam service-accounts create spinnaker-account \ --display-name spinnaker-account
以下で有効にしていいかと聞かれるので、そうしましょう。
API [iam.googleapis.com] not enabled on project [YOUR_PROJECT]. Would you like to enable and retry? (Y/n)? y
成功したら、以下のように叩いてアカウントができたか確認しましょう。この際自分が作ったアカウントの EMAIL
をメモしておいてください。
$ gcloud iam service-accounts list NAME EMAIL spinnaker-account spinnaker-account@YOUR_PROJECT.iam.gserviceaccount.com
そして、そのサービスアカウントに storage.admin
の権限を付与します。
$ gcloud projects add-iam-policy-binding "YOUR_PROJECT" \ --role roles/storage.admin --member serviceAccount:"上記のEMAILアドレス"
以下のように聞かれるので、Yを押しましょう。
API [cloudresourcemanager.googleapis.com] not enabled on project [YOUR_PROJECT]. Would you like to enable and retry? (Y/n)?
サービスアカウントJSONを作成します。
$ gcloud iam service-accounts keys create ~/.gcp/gcs_account.json --iam-account "上記のEMAILアドレス"
Spinnakerのセットアップ
では以下のコマンドを叩いて、どのバージョンを使えるか確認しましょう。
$ hal version list + Get current deployment Success + Get Spinnaker version Success + Get released versions Success + You are on version "", and the following are available: - 1.4.2 (Dragons): Changelog: https://gist.github.com/spinnaker-release/c791562094c040e936776b501b42c7a6 Published: Tue Oct 03 17:28:52 UTC 2017 (Requires Halyard >= 0.34.0) - 1.5.0 (Atypical): Changelog: https://gist.github.com/spinnaker-release/d3d2ca93ebcc0fce546323723dee65ea Published: Wed Nov 08 18:52:38 UTC 2017 (Requires Halyard >= 0.34.0) - 1.5.1 (Atypical): Changelog: https://gist.github.com/spinnaker-release/e884c78db5dead1a72c3f6b52c05738b Published: Thu Nov 30 21:50:14 UTC 2017 (Requires Halyard >= 0.34.0)
最新版の 1.5.1
を使ってみたいと思います。
$ hal config version edit --version 1.5.1
以下のようなメッセージが出ますが、まだデプロイできないので、落ち着きましょう。
Deploy this version of Spinnaker with hal deploy apply
.
パーシステントストレージの設定
https://www.spinnaker.io/setup/storage/
こちらのページにあるように、Spinnakerは保存された設定やパイプラインの情報をパーシステントストレージに保存します。
- Azure Storage
- Google Cloud Storage
- Minio
- Redis
- S3
から選べるわけですが、ここでは無難にGCSにしましょう。
GSCの場合はドキュメントは以下になります。
https://www.spinnaker.io/setup/storage/gcs/
では、パーシステントストレージを有効にしていきます。まず設定を編集します。
$ hal config storage gcs edit --project "自分のプロジェクト名" \ --json-path ~/.gcp/gcs_account.json
ドキュメントでは以下のように bucket-location
を指定するよう書かれているのですが、
$ hal config storage gcs edit --project "自分のプロジェクト名" \ --bucket-location "asia.gcr.io" \ --json-path ~/.gcp/gcs_account.json
asia.gcr.io
にしても、 jp
にしても、
com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
エラーが返ってきてしまいダメでした。
うまくいったら、有効化します。
$ hal config storage edit --type gcs
クラウドプロバイダーの設定
In Spinnaker, a Cloud Provider is an interface to a set of virtual resources that Spinnaker has control over. Typically, this is a IaaS provider, like AWS, or GCP, but it can also be a PaaS, like App Engine, or a container orchestrator, like Kubernetes.
https://www.spinnaker.io/setup/providers/
とあるように、クラウドプロバイダーはIaaSなどのコントロール対象の環境を抽象化したインターフェイスになります。
そのため、このクラウドプロバイダーを必要な環境に合わせて設定する必要があります。
2017/12/12時点で使えるプロバイダーは以下です。
- App Engine
- Amazon Web Services
- Azure
- DC/OS
- Docker v2 Registry (Note: This only acts as a source of images, and does not include support for deploying Docker images)
- Google Compute Engine
- Kubernetes
- Openstack
- Oracle
今回はデプロイ先をGKEのKubernetesに、イメージのソースをDocker RegistryとしてのGCRにしてみましょう。
ちなみに、ドキュメントに
Keep in mind that every Provider can have as many accounts added as desired – this will allow you to keep your environments (e.g. staging vs. prod) separate, as well as restrict access to sets of resources using Spinnaker’s Authorization mechanisms.
とあるように、これから作るアカウントはDEV/本番を意識した上で作成してください。
https://www.spinnaker.io/setup/providers/docker-registry/#adding-an-account
に書いてあるとおりですが、サービスアカウントJSONを使って、GCRに登録をしていきます。
$ hal config provider docker-registry enable
以下のようにメッセージが出ているとおり、まだアカウントがないのでこれから作ります。
- WARNING Provider dockerRegistry is enabled, but no accounts have been configured.
以下でアカウントを作ります。
$ hal config provider docker-registry account add masudak-gcr-account \ --address asia.gcr.io \ --password-file ~/.gcp/gcs_account.json \ --username _json_key
アカウントができたことを確認しましょう。WARNINGも出てますが、気にせず進めます。
$ hal config provider docker-registry account list + Get current deployment Success + Get the dockerRegistry provider Success Problems in default.provider.dockerRegistry.masudak-gcr-account: - WARNING Your docker registry has no repositories specified, and the registry's catalog is empty. Spinnaker will not be able to deploy any images until some are pushed to this registry. ? Manually specify some repositories for this docker registry to index. + Accounts for dockerRegistry: - masudak-gcr-account
では、レジストリのアカウントもできたので、クラウドプロバイダーのアカウントも作っていきます。
まず kubectl
コマンドを使えるようにします。
$ sudo curl -L https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl -o /usr/local/bin/kubectl $ sudo chmod 755 /usr/local/bin/kubectl
$ cat <<EOF > ~/switch_cluster.sh # !/bin/sh gcloud container clusters get-credentials masudak-cluster --project=[YOUR PROJECT] --zone=asia-east1-a EOF $ chmod 755 ~/switch_cluster.sh
$ ./switch_cluster.sh
以下を叩いてコンテクストが取得できることを確認してください。
$ kubectl config current-context
k8sをプロバイダーとして有効化。
$ hal config provider kubernetes enable
k8s用のアカウントを作ります。
$ hal config provider kubernetes account add masudak-k8s-account \ --docker-registries [上記で作った自分のGCRアカウント] \ --context $(kubectl config current-context)
作ったアカウントをセットします。
$ hal config deploy edit \ --account-name masudak-k8s-account \ --type distributed
ちなみにパイプラインの処理時にSlack通知をしたい場合は、以下を設定してください。もちろんマストではないので、やりたい人だけ。
$ hal config notification slack enable
https://www.spinnaker.io/setup/features/notifications/#slack
を読むと、
$ hal config notification slack edit --bot-name $SPINNAKER_BOT --token $TOKEN_FROM_SLACK
とありますが、これでは動きません(変数になっている部分は、自分の環境に合わせて書き換えてください)。
以下のようにして、 --token
の引数省略します。対話式になるので、そこで初めてトークンをいれましょう。画面にはトークン表示されないですが、入力していれば進めて大丈夫です。
$ hal config notification slack edit --bot-name $SPINNAKER_BOT --token
やっとここまで来ました。では、デプロイしてみましょう。5分ちょっとかかるでしょうが、待ちましょう。
$ hal deploy apply
以下のメッセージが出れば大丈夫です。
+ Run hal deploy connect
to connect to Spinnaker.
以下のコマンドを叩いてください。
$ hal deploy connect
以下のメッセージが出ると思います。これでSpinnakerのためにこちらからアクセスすべきポートが、ローカルのポートにマッピングされます。
Forwarding from 127.0.0.1:9000 -> 9000 Forwarding from 127.0.0.1:8084 -> 8084
とはいえ、インスタンス内のポートですので、ブラウザからアクセスするために、以下を自分のPCなりで叩いてください。
$ gcloud compute ssh [作ったインスタンス名] --project [プロジェクト名] --zone [ゾーン] --ssh-flag="-L" --ssh-flag="9000:localhost:9000" --ssh-flag="-L" --ssh-flag="8084:localhost:8084"
こうすると、自分のPCにトンネルされます。もちろん、自分でSSHトンネルを貼っても構いません。
https://www.spinnaker.io/reference/architecture/
にもありますが、9000ポートで動いている Deck
と、その Deck
からブラウザ経由でアクセスされる Gate
の2つをともにトンネルしなければなりません。 Deck
だけトンネルすると、ブラウザ経由で繋ぎに行けないので、それを忘れないようにしてください。
Macであれば、以下でリッスンできてるか確認できますね。
$ lsof -i -P | grep "LISTEN"|egrep "9000|8084" ssh 4430 masudak 6u IPv6 0x57758a6751d 0t0 TCP localhost:9000 (LISTEN) ssh 4430 masudak 7u IPv4 0x57758a677d3 0t0 TCP localhost:9000 (LISTEN) ssh 4430 masudak 8u IPv6 0x57758a678fc 0t0 TCP localhost:8084 (LISTEN) ssh 4430 masudak 9u IPv4 0x57758a678cf 0t0 TCP localhost:8084 (LISTEN)
あとは、 http://localhost:9000/ にアクセスしましょう。
ベースとなるイメージの作成
のちのち必要になるので、適当にDockerfileを持ってきて、イメージをGCRにあげておきましょう。
https://github.com/nginxinc/docker-nginx/tree/master/mainline/alpine
などをローカルに持ってきて、イメージを作ります。
$ docker build -t asia.gcr.io/[プロジェクト名]/nginx:latest .
以下でイメージができたか確認しましょう。
$ docker images|grep nginx
pushしておきます。
$ gcloud docker -- push "asia.gcr.io/[プロジェクト名]/nginx:latest"
https://console.cloud.google.com/gcr
にアクセスしてイメージがpushされたことを確認しておきましょう。
GUIの操作
http://localhost:9000/#/applications
にアクセスして、まずアプリケーションを作成しましょう。右上の Actions
から Create Application
します。
必須となっている項目を埋めて、Createします。
たとえば、分かりやすくnginxでも動かしてみましょう。
http://localhost:9000/#/applications/nginx/clusters
にリダイレクトされたら、次に右上の LOAD BALANCERS
からLBの設定をします。
Create Load Balancer
で、
- Account: ↑で作ったk8sのアカウント
- Namespace: とりあえずdefault
- Stack: dev
- Name: nginx
- Type: LoadBalancer
でCreateしてください。 Type: LoadBalancer
なので、Ingressを使わず、サービスにグローバルIPをもたせます。
次に、左上にある PIPELINES
を選び、パイプラインを作ります。
Pipiline Name
は適当にnginxとかにして、進みましょう。
パイプラインの設定画面になるので、まず Automated Triggers
の項目で、 Add Triggers
します。
- Type: Docker Registry
- Registry Name: masudak-gcr-account
- Organization: YOUR PROJECT
- Image: [YOUR PROJECT]/nginx
- Tag: ^.*$
- Trigger Enabled: チェック入れる
ちなみに、ここで何もImageなどが現れない場合は、以下の Google Cloud Resource Manager API
が有効になっているか確認してください。
https://console.developers.google.com/apis/library/cloudresourcemanager.googleapis.com/
上述したSlackの設定をしていれば、ここでnotificationの設定をしておきましょう。
Notifications
の項目から、 Slack
を選び、通知したいチャンネルを入力してください。その際そのチャンネルに、対象のボットをちゃんとinviteしておいてください。
ちなみにチャンネル名の接頭辞として #
は別にいれなくても大丈夫です。
そしたら、設定をSaveし、次にまた画面上部に戻り、次に Add stage
をクリックして、デプロイの設定をしましょう。
Type: Deploy
を選択し、 Add Server Group
で
- Account: masudak-k8s-account
- Namespace: default
- Stack: dev
- Container:
asia.gcr.io/[YOUR PROJECT]/nginx:^.*$
- Strategy: Red/Black
- Deployment: チェック入れる
- Load Balancers: nginx-dev
Containers
の項目に行き、
Name: nginx
にして、Addしましょう。
そして、 Save Changes
します。
そしたら、
http://localhost:9000/#/applications/nginx/executions
にアクセスして、右側にある Start Manual Excution
してみましょう。
あとは Load Balancers
の画面に戻り、 nginx-dev
の項目から、 Ingress
のIPを探してください。そのGIPがグローバルからアクセスできる値になります。 Cluster IP
は単にクラスタ内のIPですので、そちらではないので、ご注意を。
人間による承認
ここまでで、イメージがプッシュされたら、適当なGKEクラスタにデプロイされるところまでは見てきました。最後に「人間による承認」たとえば、プロデューサーによる承認フローの追加を想定して、設定してみたいと思います。
PIPELINES
の画面に行き、上記で設定したパイプラインを選び、 Configure
を選択してください。
PIPELINEにはConfigurationとDeployが既に設定されていると思いますので、Deployをクリックし、 Add stage
してください。
そして、以下の設定をします。
- Type: Manual Judgement
- Stage Name: Judgement by producer
- Depends On: Deploy
- Instrunctions: 「問題なければ承認お願いします」みたいななんでもいいので、分かりやすいメッセージ
- If stage fails:
halt the entire pipeline
そして、あとは Start Manual Execution
なり、イメージをプッシュするなりしてください。
Configuration -> Deployとパイプラインが進み、しばらくすると Status: RUNNING
のまま止まっているかと思います。
そしたら、 Details
をクリックし、 Judgement by Producer
をクリックしてください。
Continue
するか Stop
するか選べますので、 Continue
をしましょう。
印象まとめ
ここまで書いた内容以外にも色々ありますが、自分が構築してみた印象として、
- PROS
- PIPELINEによってCDのフローを定義できるので、承認フロー含めたデプロイを一つのツールで完結できる
- また、誰が行ったなどのログが残る
- カオスモンキーなどの機能も使うことで、マイクロサービスの要件として必要な項目を一つのツールでテストしやすい
- CONS
- WebUIで設定をしないといけない。よって、設定が消えると復元が極めて困難(GCSにデータはあるので、もしかしたら何か復旧することが可能なのかもしれない)
- ドキュメントを見ても躓くところがある、またドキュメントをまず理解するのがなかなか簡単ではない
- k8s deploymentのバージョン管理とは別の管理システムを持つため、相性がよくない
- k8s ingressに対応してない。今回のように
Type: LoadBalancer
の場合はよいが、ingressを使う場合はType: nodeType
にしつつ、別途自分でapplyしてingressを作る必要がある - エラーが発生した場合に、Spinnaker自体もマイクロサービスなので、慣れていないとトラブルシューティングがしにくい
と言った感じで、正直まだ人類には早いのではないかという印象もあります。
終わりに
ということで、長丁場でしたが、概念や用語も踏まえてここまで可能な限り丁寧に説明していきました。
k8sの概念のみならず、クラウドプロバイダーなどのSpinnakerの概念も出てきて大変だったかと思います。
とは言え、ここまで一つ一つやっていけば、全体像もかなり見えやすくなるでしょう。
あとは、DEV/本番の使い分けや、カオスモンキーなどの新しい機能など、色々是非試していただいて、日本の大事な情報源として、色々発表して頂ければと思います。
弊社では、マイクロサービスや自動化が好きなエンジニアを常に募集しています。優秀な人が多い上に、色々新しい技術も使え、刺激に溢れていますので、興味ある方は是非 @masudak までご連絡ください。メンションでもなんでも構いません。
明日18日目の執筆担当は @Hiraku です。引き続きお楽しみください。ではでは!