Spinnaker on EKS

みんなのウェディングのインフラエンジニア横山です。
今回は、既存VPCを流用したEKS環境の構築に引き続き、SpinnakerをEKS上にデプロイする手法について書きます。

Spinnakerについて

Spinnakerとは、Netflixが開発した継続的デリバリー(CD)を実現するためのツールです。
Spinnakerがどういったものかについては、この記事の主題ではないので詳しく説明致しません。
以下の公式ドキュメントを確認いただければと思います。
https://www.spinnaker.io/
日本語情報ですと以下のメルカリさんの記事が大変参考になります。
https://tech.mercari.com/entry/2017/08/21/092743

今回、SpinnakerのEKS上へのデプロイを行うにあたり、ネット上にまとまった情報が少なく大変苦労しました。 私のような苦労をする人が少なくなるよう、以下にデプロイ手順をまとめておきたいと思います。

Spinnakerデプロイ手順

この手順は以下のドキュメントを参考にしています。
各ドキュメントの様々な箇所に情報が分散しているので、それをまとめていった形となります。

https://www.spinnaker.io/setup/
https://aws.amazon.com/jp/blogs/opensource/spinnaker-on-aws/

前提条件

halコマンド実行環境をCloud9に用意

Spinnakerのデプロイにはhalというコマンドを使います。
halコマンドを使ってSpinnakerをデプロイすると、Spinnakerの設定ファイルがローカルに作成されます(~/.hal配下)。
Spinnakerの設定変更を自分しか行わないのであれば、個人PCでhalコマンドを実行しても良いですが、
多くのケースではインフラチームなどの複数人でSpinnakerを運用していくことになるかと思います。

そういったケースの場合は、チームで設定ファイルを共有するために、Cloud9を利用することをおすすめします。
https://ap-northeast-1.console.aws.amazon.com/cloud9/home

Cloud9は複数人で同一の環境を共有することができるので、Cloud9上でhalコマンドを実行することで、設定ファイルを複数人で共有することができます。
https://docs.aws.amazon.com/ja_jp/cloud9/latest/user-guide/share-environment.html

※Cloud9環境の作成は、EKSクラスターを作成したIAMユーザーと同一ユーザか、
以下の手順で設定した、kuberntesクラスターへのアクセス権限を持つIAMユーザで行なってください。
https://aws.amazon.com/jp/premiumsupport/knowledge-center/amazon-eks-cluster-access/

以降ではCloud9上で実行する想定で説明していきますが、ローカル環境でも手順はほぼ変わらないかと思います。

halコマンドのインストール

kubectlのインストール

aws eks --region region update-kubeconfig --name cluster_name
  • kubectlの動作確認を行う。
kubectl get pods

サービスアカウントの準備

  • 以下のコマンドを順次実行していく。
CONTEXT=aws
kubectl create namespace spinnaker
kubectl apply -f https://d3079gxvs8ayeg.cloudfront.net/templates/spinnaker-service-account.yaml 
kubectl apply -f https://d3079gxvs8ayeg.cloudfront.net/templates/spinnaker-cluster-role-binding.yaml 
TOKEN=$(kubectl get secret --context $CONTEXT \
   $(kubectl get serviceaccount spinnaker-service-account \
       --context $CONTEXT \
       -n spinnaker \
       -o jsonpath='{.secrets[0].name}') \
   -n spinnaker \
   -o jsonpath='{.data.token}' | base64 --decode)
kubectl config set-credentials ${CONTEXT}-token-user --token $TOKEN
kubectl config set-context $CONTEXT --user ${CONTEXT}-token-user

やっていることは以下の通りです。

Spinanker用のnamespace(spinnaker)を作成
Spinakerが利用するサービスアカウントを作成し、クラスタロールをバインド。
作成したサービスアカウントの認証情報をkubeconfigに設定し、コンテキストを作成

Spinnakerのデプロイ準備

  • kuberntes cloudプロバイダーを有効にして、EKSクラスターを追加する。
    アカウント名は、本番・ステージング環境といったように複数のkuberntes cloudプロバイダーを設定した際に、個々のプロバイダーを識別するために利用されます。
    お好きな名前でつけていただいて大丈夫です。
hal config provider kubernetes enable
hal config provider kubernetes account add <アカウント名> --provider-version v2 --context $CONTEXT
hal config features edit --artifacts true
  • Spinnakerのデプロイ先となるEKSクラスターを指定する。
hal config deploy edit --type distributed --account-name <アカウント名>
  • Spinnakerの永続ストレージとしてS3を使うように設定する。
    永続ストレージには作成したデプロイパイプラインの情報などSpinnakerの設定が保存されます。
    事前にバケットを作成しておき、ワーカーノードのIAMロールには該当バケットへの読み書きアクセス権限をつけておきます。
hal config storage s3 edit --region ap-northeast-1 --bucket バケット名
hal config storage edit --type s3

Spinnakerのデプロイ

  • 利用可能なバージョンを確認する。
hal version list
  • 使用するバージョンを設定してデプロイする。
hal config version edit --version <バージョン名>
hal deploy apply
  • 接続確認する。
hal deploy connect

サービスの外部公開

このままだと、コンソール画面にhal deploy connectを使わずにアクセスできません。
そこで、デプロイされたkuberntes Serviceの設定変更などをすることで外部から接続できるようにしていきます。

  • kubectl editコマンドでKubernetes Serviceの設定を変更する。
kubectl edit svc spin-deck -n spinnaker
kubectl edit svc spin-gate -n spinnaker

変更箇所は以下の通りです。各Serviceに対して同様に行なっていきます。

・3つのannotationsを追加
・nameを追加、httpsにする。
・443に変更
・ClusterIPからLoadBalancerに変更

# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
kind: Service
metadata:
  annotations:  # 以下の3つのannotationsを追加
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:{region}:{user id}:certificate/{id}
    service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https"
  creationTimestamp: 2017-06-01T00:57:34Z
  name: spin-deck
  namespace: spinnaker
  resourceVersion: "6038615"
  selfLink: /api/v1/namespaces/spinnaker/services/spin-deck
  uid: 4c1fb82f-4165-11e7-888f-42020a8a0a12
spec:
  clusterIP: 10.127.244.30
  ports:
  - name: https                         # nameを追加、httpsにする。
    port: 443                           # 443に変更
    protocol: TCP
    targetPort: 9000
  selector:
    load-balancer-spin-deck: "true"
  sessionAffinity: None
  type: LoadBalancer                   # ClusterIPからLoadBalancerに変更

status:
  loadBalancer: {}

参考資料: https://aws.amazon.com/jp/premiumsupport/knowledge-center/terminate-https-traffic-eks-acm/

  • カスタムプロファイルに以下の設定を行う。
    ~/.hal/default/profiles/gate-local.ymlというファイルを作成します。
server:
  tomcat:
    protocolHeader: X-Forwarded-Proto
    remoteIpHeader: X-Forwarded-For
    internalProxies: .*

参考資料: https://www.spinnaker.io/setup/security/authentication/oauth/#network-architecture-and-ssl-termination

  • --override-base-urlを設定してCORS対応する。
hal config security api edit --override-base-url https://<spin-gateサーバのドメイン名>
hal config security ui edit --override-base-url https://<spin-deckサーバのドメイン名>
  • 設定変更をデプロイする
hal deploy apply
  • Route53にspin-gateサーバ,spin-deckサーバのドメイン名を追加する。
    名前解決先は各Serviceのエンドポイントを設定します。
kubectl get svc

GoogleOAuth認証の設定

  • 以下を参考にクライアントIDとクライアントシークレットを発行する。

https://www.spinnaker.io/setup/security/authentication/oauth/providers/google/

  • oauth2を追加する。
    オプション(–pre-established-redirect-uri)も指定しておく必要があります。
hal config security authn oauth2 edit --provider google 
--client-id $CLIENT_ID 
--client-secret $CLIENT_SECRET 
--user-info-requirements hd=<組織ドメイン名>
--pre-established-redirect-uri=https://<spin-gateサーバのドメイン名>/login

参考資料: https://www.spinnaker.io/setup/security/authentication/oauth/#network-architecture-and-ssl-termination
参考資料: https://github.com/spinnaker/spinnaker/issues/2414#issuecomment-507231606

  • 設定変更をデプロイする
hal deploy apply

クラスターの追加

単一のSpinnakerからステージング、本番の両方のクラスターにデプロイしたいという場合、kuberntes cloudプロバイダーの追加を行う必要があります。

  • サービスアカウントの作成と設定
CONTEXT=aws-production
kubectl create namespace spinnaker
kubectl apply -f https://d3079gxvs8ayeg.cloudfront.net/templates/spinnaker-service-account.yaml 
kubectl apply -f https://d3079gxvs8ayeg.cloudfront.net/templates/spinnaker-cluster-role-binding.yaml 
TOKEN=$(kubectl get secret --context $CONTEXT \
   $(kubectl get serviceaccount spinnaker-service-account \
       --context $CONTEXT \
       -n spinnaker \
       -o jsonpath='{.secrets[0].name}') \
   -n spinnaker \
   -o jsonpath='{.data.token}' | base64 --decode)
kubectl config set-credentials ${CONTEXT}-token-user --token $TOKEN
kubectl config set-context $CONTEXT --user ${CONTEXT}-token-user
  • kuberntes cloudプロバイダーの追加
hal config provider kubernetes account add <アカウント名> --provider-version v2 --context $CONTEXT
  • 設定変更をデプロイする
hal deploy apply

ECR追加

デプロイパイプラインでECR上のDockerイメージを利用したり、ECRへのDockerイメージPushをトリガーにしてデプロイを実行したい場合に設定が必要です。

  • 以下を実行してECRを追加する。
    事前にワーカーノードのIAMロールにECRへのアクセス権限をつけておきます。
hal config provider docker-registry enable
hal config provider docker-registry account add my-ecr-registry \
 --address <レジストリアドレス(例:012345678910.dkr.ecr.us-east-1.amazonaws.com)>\
 --username AWS \
 --password-command "aws --region ap-northeast-1 ecr get-authorization-token --output text --query 'authorizationData[].authorizationToken' | base64 -d | sed 's/^AWS://'"

参考資料: https://www.spinnaker.io/setup/install/providers/docker-registry/#amazon-elastic-container-registry-ecr

GitHubアーティファクト

GitHub上のマニフェストファイルを利用してデプロイを実行する場合に設定が必要です。

echo "取得したトークン" >token.txt
hal config features edit --artifacts true
hal config artifact github enable
hal config artifact github account add my-github-artifact-account \
    --token-file token.txt
rm token.txt

参考資料: https://www.spinnaker.io/setup/artifacts/github/

GitHubWebHook

GitHub上のマニフェストファイルなどの変更をトリガーに、デプロイを実行したい場合に設定が必要です。

まとめ

以上、SpinnakerをEKS上に構築する手法についてまとめました。
お読みいただきありがとうございました。