Continuous Delivery using Spinnaker on Amazon EKS hero graphic

Continuous Delivery using Spinnaker on Amazon EKS

Jun 30, 2020 by Ryan Cartwright

Note: We are delighted to host this guest post by Irshad Buchh from AWS. The post can also be found on the AWS Open Source Blog.

I work closely with partners, helping them to architect solutions on AWS for their customers. Customers running their microservices-based applications on Amazon Elastic Kubernetes Service (Amazon EKS) are looking for guidance on architecting complete end-to-end Continuous Integration (CI) and Continuous Deployment/Delivery (CD) pipelines using Jenkins and Spinnaker. The benefits of using Jenkins include that it is a very popular CI server with great community support and it has many plugins (Slack, GitHub, Docker, Build Pipeline) available. Spinnaker provides automated release, built-in deployment, and supports blue/green deployment out of the box. This post focuses on Continuous Delivery, and will discuss the installation and configuration of Spinnaker on Amazon EKS.

You can also refer to an earlier post, Build a Deployment Pipeline with Spinnaker on Kubernetesin which Prabhat Sharma explained some of the fundamental concepts of Spinnaker.

Overview of concepts

Amazon EKS runs the Kubernetes management infrastructure across multiple AWS Availability Zones, automatically detects and replaces unhealthy control plane nodes, and provides on-demand upgrades and patching. You simply provision worker nodes and connect them to the provided Amazon EKS endpoint.

In software engineering, continuous integration is the practice of merging all developers’ working copies to a shared mainline several times a day. Grady Booch first proposed the term CI in 1991, though he did not advocate integrating several times a day.

Continuous delivery is a software engineering approach in which teams produce software in short cycles, ensuring that the software can be reliably released at any time and, when releasing the software, doing so manually. This approach aims at building, testing, and releasing software with greater speed and frequency.

Continuous deployment is a strategy for software releases wherein any code commit that passes the automated testing phase is automatically released into the production environment, making changes that are visible to the software’s users.

Prerequisites

In order to implement the instructions laid out in this post, you will need the following:

Architecture

In this post, I will discuss the following architecture for Continuous Delivery:

Continuous Delivery Architecture

Fig 1. Continuous Delivery Architecture

Here are the steps we’ll be following to create the continuous delivery architecture:

Create an AWS Cloud9 environment

Log into the AWS Management Console and search for Cloud9 services in the search bar:

User interface of AWS Management Console

Fig 2. AWS Management Console

Click Cloud9 and create an AWS Cloud9 environment in the us-east-2 region based on Ubuntu Server 18.04 LTS (Halyard is not supported on Amazon Linux yet). Choose the settings as shown in Fig 3 where the platform should be Ubuntu Server 18.04 LTS.

Recommended AWS Cloud9 settings

Fig 3. AWS Cloud9 settings

Configure the AWS Cloud9 environment

Launch the AWS Cloud9 IDE. In a new terminal session, follow the instructions to configure the AWS Cloud9 environment.

1. Install and configure Kubectl

Install kubectland aws-iam-authenticatoron the AWS Cloud9 Ubuntu machine:

curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl

chmod +x ./kubectl

sudo mv ./kubectl /usr/local/bin/kubectl

curl -o aws-iam-authenticator https://amazon-eks.s3-us-west-2.amazonaws.com/1.13.7/2019-06-11/bin/linux/amd64/aws-iam-authenticator

chmod +x ./aws-iam-authenticator

mkdir -p $HOME/bin && cp ./aws-iam-authenticator $HOME/bin/aws-iam-authenticator && export PATH=$HOME/bin:$PATH

echo 'export PATH=$HOME/bin:$PATH' >> ~/.bashrc

aws-iam-authenticator  help

The script verifies that aws-iam-authenticator is working by displaying the help contents of aws-iam-authenticator.

2. Upgrade awscli

aws --version
pip install awscli --upgrade --user

3. Install eksctl

curl --silent --location "https://github.com/weaveworks/eksctl/releases/download/latest_release/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv /tmp/eksctl /usr/local/bin

4. Install Terraform

wget https://releases.hashicorp.com/terraform/0.12.4/terraform_0.12.4_linux_amd64.zip
unzip terraform_0.12.4_linux_amd64.zip
sudo mv terraform /usr/local/bin/
export PATH=$PATH:/usr/local/bin/terraform

5. Install Halyard

curl -O https://raw.githubusercontent.com/spinnaker/halyard/master/install/debian/InstallHalyard.sh
sudo bash InstallHalyard.sh
sudo update-halyard
hal -v

Create Amazon EKS clusters

To make a complete environment, I will create three AWS EKS clusters including one for production, one for UAT, and one for Spinnaker installation. Inside the AWS Cloud9 IDE, run the following commands to create these Amazon EKS clusters. (You can choose your preferred regions; for this post I shall use us-east-2 to provision the Amazon EKS cluster for Spinnaker deployment and us-east-1 region to provision the UAT and production Amazon EKS clusters.

1. Create the Production Amazon EKS cluster

eksctl create cluster --name=eks-prod --nodes=3 --region=us-east-1 \
  --write-kubeconfig=false

Detailed output of the eksctl command

Fig 4. eksctl

2. Create the UAT Amazon EKS cluster

eksctl create cluster --name=eks-uat --nodes=3 --region=us-east-1 \
  --write-kubeconfig=false

3. Create the Spinnaker Amazon EKS cluster

eksctl create cluster --name=eks-spinnaker --nodes=2 --region=us-east-2 \
 --write-kubeconfig=false

eksctl is a simple CLI tool for creating clusters on Amazon EKS which creates the following components of the Amazon EKS cluster architecture:

Amazon EKS cluster architecture

Fig 5. Amazon EKS cluster

Install and configure Spinnaker

This section will walk you through the process of installing and configuring Spinnaker for use with Amazon EKS. I prefer to use Armory Spinnaker because:

1. Retrieve Amazon EKS cluster kubectl contexts

aws eks update-kubeconfig --name eks-spinnaker --region us-east-2 \ 
 --alias eks-spinnaker

aws eks update-kubeconfig --name eks-uat --region us-east-1 \ 
 --alias eks-uat

aws eks update-kubeconfig --name eks-prod --region us-east-1 \ 
 --alias eks-prod

2. Check halyard version

hal -v

3. Create and configure a Docker registry

hal config provider docker-registry enable 

hal config provider docker-registry account add ibuchh-docker \ 
 --address index.docker.io --username ibuchh --password

This command will prompt you to enter your docker account password.

4. Add and configure a GitHub account

hal config artifact github enable

hal config artifact github account add spinnaker-github --username ibuchh \
  --password --token

This command will prompt you to enter your GitHub token that you can get from the GitHub account setting.

5. Add and configure Kubernetes accounts

Production Amazon EKS account:

Set the Kubernetes provider as enabled:

hal config provider kubernetes enable

kubectl config use-context eks-prod

A context element in a kubeconfig file is used to group access parameters under a convenient name. Each context has three parameters: cluster, namespace, and user. By default, the kubectl command line tool uses parameters from the current context to communicate with the cluster.

CONTEXT=$(kubectl config current-context)

We will create service accounts for the three Amazon EKS clusters. See the Kubernetes documentation for more details on service accounts.

kubectl apply --context $CONTEXT \
    -f https://spinnaker.io/downloads/kubernetes/service-account.yml

Extract the secret token of the spinnaker-service-account:

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)

Set the user entry in kubeconfig:

kubectl config set-credentials ${CONTEXT}-token-user --token $TOKEN

kubectl config set-context $CONTEXT --user ${CONTEXT}-token-user

Add eks-prod cluster as a Kubernetes provider.

hal config provider kubernetes account add eks-prod --provider-version v2 \
 --docker-registries ibuchh-docker --context $CONTEXT

UAT Amazon EKS account:

kubectl config use-context eks-uat 

CONTEXT=$(kubectl config current-context) 

kubectl apply --context $CONTEXT \
    -f https://spinnaker.io/downloads/kubernetes/service-account.yml

Extract the secret token of the spinnaker-service-account:

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)

Set the service account entry in kubeconfig file:

kubectl config set-credentials ${CONTEXT}-token-user --token $TOKEN

kubectl config set-context $CONTEXT --user ${CONTEXT}-token-user

Add eks-uat cluster as a Kubernetes provider.

hal config provider kubernetes account add eks-uat --provider-version v2 \
 --docker-registries ibuchh-docker --context $CONTEXT

Spinnaker Amazon EKS account:

kubectl config use-context eks-spinnaker 

CONTEXT=$(kubectl config current-context)

kubectl apply --context $CONTEXT \
    -f https://spinnaker.io/downloads/kubernetes/service-account.yml

Extract the secret token of the spinnaker-service-account:

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)

Set the service account entry in the Kubeconfig file:

kubectl config set-credentials ${CONTEXT}-token-user --token $TOKEN

kubectl config set-context $CONTEXT --user ${CONTEXT}-token-user

Add eks-spinnaker cluster as a Kubernetes provider.

hal config provider kubernetes account add eks-spinnaker --provider-version v2 \
 --docker-registries ibuchh-docker  --context $CONTEXT

6. Enable artifact support

hal config features edit --artifacts true

7. Configure Spinnaker to install in Kubernetes

For our environment we will use a distributed Spinnaker installation onto the Kubernetes cluster. This installation model has Halyard deploy each of the Spinnaker microservices separately. A distributed installation helps to limit update-related downtime, making it recommended for use in production environments.

hal config deploy edit --type distributed --account-name eks-spinnaker

8. Configure Spinnaker to use AWS S3

You will need your AWS account access key and secret access key.

export YOUR_ACCESS_KEY_ID=<access-key>

hal config storage s3 edit --access-key-id $YOUR_ACCESS_KEY_ID \
 --secret-access-key --region us-east-2

Enter your AWS account secret access key at the prompt.

hal config storage edit --type s3

9. Choose the Spinnaker version

To identify the latest version of Spinnaker to install, run the following to get a list of available versions:

hal version list

At the time of writing, 1.15.0 is the latest Spinnaker version:

export VERSION=1.15.0

hal config version edit --version $VERSION

Now we are finally ready to install Spinnaker on the eks-spinnaker Amazon EKS cluster.

hal deploy apply

10. Verify the Spinnaker installation

kubectl -n spinnaker get svc

Spinnaker Microservices

Fig 6. Spinnaker Microservices

11. Expose Spinnaker using Elastic Loadbalancer

I shall expose the Spinnaker API (Gate) and the Spinnaker UI (Deck) via Load Balancers by running the following commands to create the spin-gate-public and spin-deck-public services:

export NAMESPACE=spinnaker

kubectl -n ${NAMESPACE} expose service spin-gate --type LoadBalancer \
  --port 80 --target-port 8084 --name spin-gate-public 

kubectl -n ${NAMESPACE} expose service spin-deck --type LoadBalancer \
  --port 80 --target-port 9000 --name spin-deck-public  

export API_URL=$(kubectl -n $NAMESPACE get svc spin-gate-public \
 -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') 

export UI_URL=$(kubectl -n $NAMESPACE get svc spin-deck-public  \ 
 -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') 

hal config security api edit --override-base-url http://${API_URL} 

hal config security ui edit --override-base-url http://${UI_URL}

hal deploy apply

12. Re-verify the Spinnaker installation

kubectl -n spinnaker get svc

Spinnaker UI endpoints

Fig 7. Spinnaker UI endpoints

13. Log in to Spinnaker console

Using a browser, log in to the Spinnaker UI using the spin-deck-public services endpoint as shown above.

Spinnaker Console

Fig 8. Spinnaker Console

Cleanup

To remove the three Amazon EKS clusters, run the following commands inside the AWS Cloud9 IDE:

eksctl delete cluster --name=eks-uat --region=us-east-1

eksctl delete cluster --name=eks-prod --region=us-east-1

eksctl delete cluster --name=eks-spinnaker --region=us-east-2

Conclusion

In this post, I have outlined the detailed instructions needed to install and configure a Continuous Delivery platform using Spinnaker (Halyard) on Amazon EKS. Spinnaker can integrate with Jenkins to architect complete Continuous Integration (CI) and Continuous Deployment/Delivery (CD) pipelines. To learn more, see the Spinnaker documentation.

Check out the companion blog Continuous Integration using Jenkins and HashiCorp Terraform with Spinnaker on Amazon EKS.

If you have questions or suggestions, please join the Spinnaker Slack and tag Irshad (AWS) or contact our friends at Armory.

Irshad A Buchh is a Partner Solutions Architect at Amazon Web Services and he is helping partners and customers in architecting enterprise applications in AWS cloud. For about 25 years, he specialized on the distributed systems and service oriented architecture (SOA) starting with operating systems and virtualization technologies. Lately he has been advising AWS Public Sector partners in their transitioning into AWS cloud with a focus on Containers, Microservices, DevOps and security. He has been a regular speaker at various conferences including AWS reInvent, OpenWorld, KubeCon, IEEE Metrocon and he is passionate about Serverless, DevOps, Amazon ECS, Amazon EKS, and AWS Fargate.

Recently Published Posts

Introducing Pipelines-as-Code Plugin for Open Source Spinnaker

Jul 21, 2023

Easily Scale and Automate with Version Control in Git Developers choose best-of-breed version control systems like GitHub for a reason: they need the ability to collaborate and improve code together.  But a broken Spinnaker deployment pipeline can often be the last thing standing in the way of getting your application to market.  Until now. Armory’s […]

Read more

What is FedRAMP and Why It Matters

Jun 8, 2023

What’s FedRAMP? Federal Risk and Authorization Management Program (FedRAMP) is a government-wide program that provides a standardized approach to security assessment, authorization, and continuous monitoring for cloud products and services. FedRAMP is important since it’s the gold standard for assessing cloud service providers (CSP) within the government. Under this program, authorized FedRAMP cloud service providers […]

Read more

New Spinnaker Operator Updates Now available for the Spinnaker Community

Mar 15, 2023

Stay up-to-date with the latest Kubernetes release with Spinnaker. The Armory crew has worked diligently the past several weeks to release a new stable version of OSS Operator (1.3.0). This is the first release in just over 18 months and is now available for the open source community.  What Changed? The Spinnaker Operator is the […]

Read more