ちょっと話題の記事

Spinnakerを使ってEKSへの継続的デリバリー環境を構築する

2019.04.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

みなさんKubernetesクラスタへのデプロイはどのように実施していますか??

小規模環境であれば kubectlを利用した手動デプロイ、もう少し規模が大きい場合は、CodePipeline、CodeBuildなどを利用した自動デプロイにて実施するケースが多いのではないでしょうか。

そんな中、最近のk8s界隈では 俺たちはSpinnakerでデプロイしているぜ!!という声をちらほら聞くようになりました。

ということで今回は、Spinnaker環境の構築方法と、何かできるのかを簡単に紹介したいと思います。

Spinnakerとは

Spinnakerは、Netflix社が開発したマルチクラウド環境への継続的デリバリーツールです。 大雑把に説明すると、CodePipelineの機能、CodeDelpoy(マルチクラウド)の機能、管理対象リソースのViewがあるイメージです。 その他、Pipelineに対しImmutable Infrastructureを強制できたり、カナリアリリースなど高度なデプロイを実現することも可能です。

デプロイ先としてAWS、Azure、GCP、OpenStackなど様々なクラウドプロバイダーを選択することができます。詳細は公式ドキュメントを参照してください。

AWSにデプロイする場合、デプロイ対象となるリソースに応じて以下のいずれか、もしくは複数のプロバイダーを有効にします。

  • EC2・・・ provider aws enable
  • ECS・・・ provider ecs enable
  • EKS・・・ provider kubernetes enable

今回はEKSをデプロイ対象とした継続的デリバリー環境を構築していきます。

構成イメージ

  1. EKSクラスタ構築
  2. Spinnaker環境構築 on EC2(Ubuntu16.04)
  3. アプリケーション登録
  4. EKSデプロイ用Pipeline作成
  5. Pipeline起動

Spinnakerはk8sクラスタ上に構築することもできますが、今回はEC2(Ubuntu16.04)上に構築します。Spinnakerでは簡単なPipelineを作成しEKSクラスタにPodをデプロイするところまで確認しようと思います。

目次

EKSクラスタ構築

まずはEKSクラスタを構築します。今回はeksctlを利用しサクッと構築していきます。

$ eksctl create cluster --name=k8s-cluster --nodes=2 --node-type=t2.medium

2つのWorkerノードをクラスタ化した状態からスタートします。 kubectlでの実行結果は以下のようになります。

$ kubectl get nodes
NAME                                               STATUS   ROLES    AGE   VERSION
ip-192-168-12-64.ap-northeast-1.compute.internal   Ready    <none>   2m    v1.11.5
ip-192-168-64-59.ap-northeast-1.compute.internal   Ready    <none>   2m    v1.11.5

$ kubectl get all
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.100.0.1   <none>        443/TCP   8m

PipelineのトリガーとなるECRを作成します。

$ aws ecr create-repository --repository-name spinnaker-test-app
{
    "repository": {
        "repositoryArn": "arn:aws:ecr:ap-northeast-1:XXXXXXXXXXXX:repository/spinnaker-test-app",
        "registryId": "XXXXXXXXXXXX",
        "repositoryName": "spinnaker-test-app",
        "repositoryUri": "XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/spinnaker-test-app",
        "createdAt": 1555259004.0
    }
}

NginxのイメージをPushしておきます。

$ $(aws ecr get-login --no-include-email --region ap-northeast-1)
$ docker pull nginx:1.12
$ docker tag nginx:1.12 XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/spinnaker-test-app:1.12
$ docker push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/spinnaker-test-app:1.12

Spinnaker環境構築 on EC2(Ubuntu16.04)

Ubuntu16.04 (ami-06c43a7df16e8213c)、インスタンスサイズm5.xlargeのマシンを準備します。IAMロールとしては、AmazonEC2ContainerRegistryReadOnlyAmazonS3FullAccessの権限があればOKです。

Ubuntuに接続し以下を実施します。

Halyardインストール

Spinnakerを管理するためのライブラリであるHalyardをインストールします。

$ curl -O https://raw.githubusercontent.com/spinnaker/halyard/master/install/linux/InstallHalyard.sh
$ sudo bash InstallHalyard.sh
$ hal -v
1.19.0-20190412012808

AWS CLIのインストール

AWS CLIをインストールします。

$ sudo apt-get install python
$ sudo apt install python-pip
$ sudo pip install awscli
$ aws --version
aws-cli/1.16.140 Python/2.7.12 Linux/4.4.0-1067-aws botocore/1.12.130

kubectlインストール

EKSクラスタに対し各種コマンドを実行するためkubectlをインストールします。

$ curl -o kubectl https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-07-26/bin/linux/amd64/kubectl
$ chmod +x ./kubectl
$ mkdir $HOME/bin && cp ./kubectl $HOME/bin/kubectl && export PATH=$HOME/bin:$PATH
$ echo 'export PATH=$HOME/bin:$PATH' >> ~/.bashrc
$ kubectl version --short --client
Client Version: v1.10.3

aws-iam-authenticatorインストール

EKSクラスタに接続するため aws-iam-authenticatorをインストールします。

$ curl -o aws-iam-authenticator https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-07-26/bin/linux/amd64/aws-iam-authenticator
$ chmod +x ./aws-iam-authenticator
$ sudo cp ./aws-iam-authenticator /bin/

ConfigMap作成(ローカルマシンで実施)

Spinnaker環境からEKSへの接続を許可するための設定をConfigMapに追加します。この作業はeksctlコマンドを実行したマシンで実施してください。

ConfigMap(aws-auth)を取得します。

$ kubectl get configmap aws-auth -n kube-system -o yaml > aws-auth.yaml

Spinnaker環境から接続できるように設定を追記します。ec2-private-dnsは、今回作成したEC2のプライベートDNS名に置き換えてください。

aws-auth.yaml

apiVersion: v1
data:
  mapRoles: |
    - groups:
      - system:bootstrappers
      - system:nodes
      rolearn: arn:aws:iam::XXXXXXXXXXXX:role/eksctl-k8s-cluster-nodegroup-0-NodeInstanceRole-1760PVA81PZH6
      username: system:node:{{EC2PrivateDNSName}}
    - rolearn: arn:aws:iam::XXXXXXXXXXXX:role/SpinnakerRole
      username: <ec2-private-dns>
      groups:
      - system:masters
kind: ConfigMap
metadata:
  creationTimestamp: "2019-04-14T15:26:31Z"
  name: aws-auth
  namespace: kube-system
  resourceVersion: "595"
  selfLink: /api/v1/namespaces/kube-system/configmaps/aws-auth
  uid: ade8c1d0-5ec9-11e9-b4b2-0edc1fad6e02

設定を反映します。

$ kubectl apply -f aws-auth.yaml
configmap/aws-auth configured

Configファイル作成

Spinnaker環境からEKSクラスタへの接続するための設定を追加します。 Spinnaker環境にてconfigファイルを作成します。endpoint-urlbase64-encoded-ca-certcluster-nameは、今回作成したEKSクラスタの値に変更してください。

~/.kube/config

apiVersion: v1
clusters:
- cluster:
    server: <endpoint-url>
    certificate-authority-data: <base64-encoded-ca-cert>
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: aws
  name: aws
current-context: aws
kind: Config
preferences: {}
users:
- name: aws
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      command: aws-iam-authenticator
      args:
        - "token"
        - "-i"
        - "<cluster-name>"
        # - "-r"
        # - "<role-arn>"
      # env:
        # - name: AWS_PROFILE
        #   value: "<aws-profile>"

EKSクラスタ情報が取得できることを確認しておきましょう。

$ kubectl get all
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.100.0.1   <none>        443/TCP   24m

Halyardの設定

halコマンドを利用し、クラウドプロバイダーの設定、アカウント登録をおこないます。${AWS_ACCOUNT}は任意の値に変更してください。

$ hal config provider kubernetes enable
$ hal config provider kubernetes account add ${AWS_ACCOUNT} --provider-version v2 --context $(kubectl config current-context)
$ hal config features edit --artifacts true

バックアップストレージの設定

Spinnakerに登録するアプリケーションのメタ情報やPipelineのメタ情報をバックアップするためのストレージを追加します。バックアップストレージはS3を利用します。

$ hal config storage s3 edit \
    --region ap-northeast-1
$ hal config storage edit --type s3
$ aws s3 ls | grep spin
2019-04-14 15:59:41 spin-0ee562b8-f76f-4e45-a667-93c5cb68eaa5

ECRの登録

SpinnakerからECRを参照できるよう設定を追加します。

$ export REGION=ap-northeast-1
$ export ADDRESS=https://XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com
$ hal config provider docker-registry enable

$ hal config provider docker-registry account add spinnaker-registry \
 --address $ADDRESS \
 --username AWS \
 --password-command "aws --region $REGION ecr get-authorization-token --output text --query 'authorizationData[].authorizationToken' | base64 -d | sed 's/^AWS://'"

Spinnakerをデプロイ

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.11.12 (Cobra Kai):
   Changelog: https://gist.github.com/spinnaker-release/29a01fa17afe7c603e510e202a914161
   Published: Fri Apr 05 14:55:40 UTC 2019
   (Requires Halyard >= 1.11)
 - 1.12.9 (Unbreakable):
   Changelog: https://gist.github.com/spinnaker-release/7fa9145349d6beb2f22163977a94629e
   Published: Fri Apr 05 14:11:44 UTC 2019
   (Requires Halyard >= 1.11)
 - 1.13.3 (BirdBox):
   Changelog: https://gist.github.com/spinnaker-release/aba784ce73cfe97ec502e12ee0f532f3
   Published: Tue Apr 09 14:11:45 UTC 2019
   (Requires Halyard >= 1.17)

使用したいバージョンを設定しデプロイします。

$ hal config version edit --version 1.13.3
$ sudo hal deploy apply

Spinnakerへの接続

ローカルマシンで新しいターミナルを起動しSSLで接続します。9000番ポートはWebUI、8084番ポートはApiに対するアクセスになります。

$ ssh -i XX.pem -L 9000:localhost:9000 -L 8084:localhost:8084 ubuntu@XXXXXXXXXX

Spinnakerに接続します。

アプリケーション登録

新規アプリケーションを登録します。

もし、アプーションの作成画面が表示されず、Error fetching applications. Check that your gate endpoint is accessibleのようなエラーメッセージが表示される場合は、Redisを再起動してください。

$ sudo systemctl enable redis-server && sudo systemctl start redis-server 
$ sudo systemctl restart spinnaker

NameOwner Emailに任意の値を設定し、Createをクリックします。

Pipeline構築

ECRへのPushをトリガーにEKSクラスタにPodをデプロイするPipelineを構築します。

Pipeline Nameに任意の名前を入力します。

Automated TriggerAdd Triggerをクリックします。

先ほど設定したECRのイメージを指定します。

画面上部に戻り、Add stageをクリックします。

TypeをDeploy(Manifest)とし、manifest sourceをTextで入力します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
        - image: XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/spinnaker-test-app
          name: sample-app
          ports:
            - containerPort: 80

ImageTagはECRをトリガーした部分から引き継がれるため上記で設定する必要はありません。また、今回はmanifestファイルをTextで入力しましたが、GitHubなどからアーティファクトとして取り込むことも可能です。

Save ChangeをクリックしPipelineを保存します。

これで準備が整いました。

Pipeline起動

最後にPipelineの起動を確認してみましょう! 新しいイメージをECRにPushします。

docker pull nginx:1.13
docker tag nginx:1.13 XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/spinnaker-test-app:1.13
docker push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/spinnaker-test-app:1.13

しばらく待つとPipelineが起動します。

デプロイ完了後はClustersから起動しているPodの状況を確認することができます。

さいごに

SpinnakerによりEKSへの継続的デリバリー環境を構築しました。今回は簡易なPipelineの作成/実行のみ確認しましたが、Spinnakerを利用すれば手動承認やカナリアリリースなど高度なデプロイをPipelineに組み込むことができます。それらについてはまた次のブログで紹介しようと思います!

ハマりポイント(というか情報量が少なく概念を理解するのが難しい)はいくつかありましたが、なかなか面白いツールでした!

参考