Get Started with Spinnaker on Kubernetes

In the previous installment of the series, we introduced Spinnaker as the multicloud deployment tool. We will explore how to setup Spinnaker on the Kubernetes open source container orchestration engine and deploy your first application through it.
In this tutorial, I will walk you through how to setup and configure Spinnaker on Minikube. Once it is up and running, we will deploy and scale a containerized application running in Kubernetes.
Spinnaker is usually installed in a VM running Ubuntu 14.04 LTS. Thanks to the Helm community, it is now available as a Chart to install with just one command.
Install and Configure Minikube
Spinnaker is architected as a cloud-native, microservices application. It comes with a set of containers that are resource intensive. Typical Minikube installation doesn’t provide enough power for Spinnaker to run locally. We will customize Minikube configuration to make it powerful enough to host Spinnaker.
Alternatively, you can install Spinnaker on a Kubernetes cluster where the Nodes have at least 4GB RAM. Google Kubernetes Engine or Azure Container Service for Managed Kubernetes are ideal candidates for this configuration. Since Minikube is free and simple, we are using that to configure Spinnaker. This configuration is not recommended for production use.
Run the following commands to install Minikube on macOS.
1 2 3 4 5 |
$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.24.1/minikube-darwin-amd64 $ chmod +x ./minikube $ sudo mv ./minikube /usr/local/bin/ |
We also need the latest version of Kubectl to manage the Kubernetes cluster. The following steps will install it.
1 2 3 4 5 |
$ curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt` /bin/darwin/amd64/kubectl $ chmod +x ./kubectl $ sudo mv ./kubectl /usr/local/bin/kubectl |
With the prerequisites in place, let’s start Minikube.
Firstly, we need to make sure that Minikube VM is configured with at least 4GB RAM and 4 CPU cores. We do this with the below commands.
1 2 3 4 5 6 7 |
$ minikube config set memory 4096 These changes will take effect upon a minikube delete and then a minikube start $ minikube config set cpus 4 These changes will take effect upon a minikube delete and then a minikube start |
If you don’t want to persistent the configuration, you can also launch Minikube with the following parameters:
1 2 3 4 5 6 7 8 9 10 11 12 |
$ minikube start --memory 4096 --cpus 4 Starting local Kubernetes v1.8.0 cluster... Starting VM... Downloading Minikube ISO 140.01 MB / 140.01 MB [============================================] 100.00% 0s Getting VM IP address... Moving files into cluster... Downloading localkube binary 148.25 MB / 148.25 MB [============================================] 100.00% 0s 0 B / 65 B [----------------------------------------------------------] 0.00% 65 B / 65 B [======================================================] 100.00% 0s |
1 2 3 4 5 6 |
Setting up certs... Connecting to cluster... Setting up kubeconfig... Starting cluster components... Kubectl is now configured to use the cluster. Loading cached images from config file. |
Wait for the single node Kubernetes cluster to start, and the verify the installation. If this is the first time you are launching Minikube, it will download the ISO file before starting the cluster.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ kubectl version Client Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.0", GitCommit:"925c127ec6b946659ad0fd596fa959be43f0cc05", GitTreeState:"clean", BuildDate:"2017-12-15T21:07:38Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"darwin/amd64"} Server Version: version.Info{Major:"1", Minor:"8", GitVersion:"v1.8.0", GitCommit:"0b9efaeb34a2fc51ff8e4d34ad9bc6375459c4a4", GitTreeState:"clean", BuildDate:"2017-11-29T22:43:34Z", GoVersion:"go1.9.1", Compiler:"gc", Platform:"linux/amd64"} $ kubectl get cs NAME STATUS MESSAGE ERROR scheduler Healthy ok controller-manager Healthy ok etcd-0 Healthy {"health": "true"} |
Install Helm
Helm makes installing applications in Kubernetes extremely easy. Each application is packaged as a Chart, a deployable unit of Helm. Before installing Spinnaker Chart, we need to set up Helm on Kubernetes.
Download the latest release of Helm binary and move it to the bin folder
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ wget https://storage.googleapis.com/kubernetes-helm/helm-v2.7.2-darwin-amd64.tar.gz --2018-01-03 10:55:06-- https://storage.googleapis.com/kubernetes-helm/helm-v2.7.2-darwin-amd64.tar.gz Resolving storage.googleapis.com (storage.googleapis.com)... 172.217.31.208 Connecting to storage.googleapis.com (storage.googleapis.com)|172.217.31.208|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 12091997 (12M) [application/x-tar] Saving to: 'helm-v2.7.2-darwin-amd64.tar.gz' |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
helm-v2.7.2-darwin- 100%[===================>] 11.53M 3.10MB/s in 3.8s 2018-01-03 10:55:11 (3.01 MB/s) - 'helm-v2.7.2-darwin-amd64.tar.gz' saved [12091997/12091997] $ tar -zxvf helm-v2.7.2-darwin-amd64.tar.gz x darwin-amd64/ x darwin-amd64/README.md x darwin-amd64/LICENSE x darwin-amd64/helm |
1 2 3 |
$ chmod +x ./darwin-amd64/helm $ mv ./darwin-amd64/helm /usr/local/bin/ |
We will now install Helm and verify it.
1 2 3 4 5 6 7 8 9 10 11 12 |
$ helm init Creating /Users/janakiramm/.helm Creating /Users/janakiramm/.helm/repository Creating /Users/janakiramm/.helm/repository/cache Creating /Users/janakiramm/.helm/repository/local Creating /Users/janakiramm/.helm/plugins Creating /Users/janakiramm/.helm/starters Creating /Users/janakiramm/.helm/cache/archive Creating /Users/janakiramm/.helm/repository/repositories.yaml Adding stable repo with URL: https://kubernetes-charts.storage.googleapis.com Adding local repo with URL: http://127.0.0.1:8879/charts $HELM_HOME has been configured at /Users/janakiramm/.helm. |
Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.
Happy Helming!
1 2 3 4 5 |
$ helm version Client: &version.Version{SemVer:"v2.7.2", GitCommit:"8478fb4fc723885b155c924d1c8c410b7a9444e6", GitTreeState:"clean"} Server: &version.Version{SemVer:"v2.7.2", GitCommit:"8478fb4fc723885b155c924d1c8c410b7a9444e6", GitTreeState:"clean"} |
The above output confirms that Helm and Tiller, the server-side component of Helm are properly installed. Tiller runs as a Kubernetes Pod and Service within the kube-system namespace.
Installing Spinnaker
With Minikube and Helm up and running, it’s time for us to install Spinnaker. Since it is available as a Helm Chart, we will get this done through a couple of steps.
Before we deploy Spinnaker, we need a configuration file in YAML format, which will provide the initial set of configuration values. Grab this file from the Github Spinnaker Helm Chart repository.
1 2 3 4 5 6 7 |
$ curl -Lo values.yaml https://raw.githubusercontent.com/kubernetes/charts/master/stable/spinnaker/values.yaml % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 2950 100 2950 0 0 2950 0 0:00:01 --:--:-- 0:00:01 10535 |
It’s time to install Spinnaker. Run the below command to deploy it in Kubernetes cluster.
1 |
$ helm install -n kubelive stable/spinnaker -f values.yaml --timeout 300 --version 0.3.5 --namespace spinnaker |
The -f parameter points the installation to the default configuration saved in values.yaml. The –timeout parameter will force Helm to wait for at least five minutes before aborting with a timeout error. This tutorial is tested with version 0.3.5 which is mentioned by –version switch. Finally, we are installing the Helm Chart in a dedicated namespace called spinnaker configured through the –namespace switch.
After a few minutes, we should see the following output, which confirms the installation of Spinnaker.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
NAME: kubelive LAST DEPLOYED: Wed Jan 3 11:26:12 2018 NAMESPACE: spinnaker STATUS: DEPLOYED RESOURCES: ….. NOTES: You will need to create 2 port forwarding tunnels in order to access the Spinnaker UI: export DECK_POD=$(kubectl get pods --namespace spinnaker -l "component=deck,app=kubelive-spinnaker" -o jsonpath="{.items[0].metadata.name}") kubectl port-forward --namespace spinnaker $DECK_POD 9000 Visit the Spinnaker UI by opening your browser to: http://127.0.0.1:9000 For more info on the Kubernetes integration for Spinnaker, visit: http://www.spinnaker.io/docs/kubernetes-source-to-prod |
In case you see a timeout error, delete the chart with helm del –purge kubelive command and run the install command again.
All the assets related to Spinnaker are deployed in the spinnaker namespace of the Kubernetes cluster. We can verify it with the below command.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
$ kubectl get pod --namespace=spinnaker NAME READY STATUS RESTARTS AGE kubelive-jenkins-67bb8f6b96-w5rdp 1/1 Running 0 53m kubelive-minio-5946fc9bcc-fcvv8 1/1 Running 0 53m kubelive-redis-7bb9d95468-kt2vq 1/1 Running 1 53m kubelive-spinnaker-clouddriver-6cd89c9bd5-8rwln 1/1 Running 1 53m kubelive-spinnaker-deck-7846d6497-bjg7b 1/1 Running 0 53m kubelive-spinnaker-echo-6fd649469d-2pxzd 1/1 Running 1 53m kubelive-spinnaker-front50-85dd9fd58c-ktj6j 1/1 Running 1 53m kubelive-spinnaker-gate-5868d9f8ff-hjpvg 1/1 Running 0 53m kubelive-spinnaker-igor-fdbdcc9c8-hldsk 1/1 Running 0 53m kubelive-spinnaker-orca-dd79c8bc7-xmwc7 1/1 Running 0 53m kubelive-spinnaker-rosco-7b9f77b5bb-drxhs 1/1 Running 0 53m |
Before we access the Spinnaker dashboard from the browser, we need to enable port forwarding by running the below commands. This exposes the Pod that runs the Spinnaker web UI to the host.
1 2 3 |
$ export DECK_POD=$(kubectl get pods --namespace spinnaker -l "component=deck,app=kubelive-spinnaker" -o jsonpath="{.items[0].metadata.name}") $ kubectl port-forward --namespace spinnaker $DECK_POD 9000 |
Spinnaker can now be accessed from the browser by visiting http://localhost:9000.
Deploying and Scaling a Containerized Application through Spinnaker
Let’s get familiar with Spinnaker concepts and terminology by deploying a simple Nginx web server.
Start by creating an application by clicking on Create Application under the Actions menu on the right top corner. An “application” here is a logical collection of various resources such as Load Balancers, Security Groups, Server Groups, and Clusters.
Let’s create a Load Balancer through which the application can be accessed. Click on the Load Balancer on the top menu bar, and then click on the Create Load Balancer button.
When creating a new Load Balancer, type prod as the stack name, 80 for Target Port, and choose NodePort as Type. Click on Create button when done.
Under Clusters, click on Create Server Group.
When creating a new Server Group, type prod as the stack name. Choose nginx:latest as the container from the dropdown. Choose nginx-prod as the Load Balancer, which we created in the previous step. Type 10 as capacity.
Under the Container setting, select Probes to create Readiness Probe and Liveness Probe with defaults. Finally, click on the Create button.
Wait for the instances under the Server Group to become available. The red colored blocks indicate that the instances are not ready yet.
Switch to the terminal, and run the following command to get the NodePort of the Service.
1 2 3 4 5 6 7 |
$ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 50m nginx-prod NodePort 10.99.164.47 <none> 80:31728/TCP 18m |
The Load Balancer created in Spinnaker is translated to a NodePort Service in Kubernetes. We now access this directly through the Minikube command.
1 2 3 |
$ minikube service nginx-prod Opening kubernetes service default/nginx-prod in default browser... |
Running kubectl get pods shows that there are 10 Pods created from Nginx container.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
$ kubectl get pods NAME READY STATUS RESTARTS AGE nginx-prod-v000-6m642 1/1 Running 0 9m nginx-prod-v000-9kxtv 1/1 Running 0 9m nginx-prod-v000-bpzw4 1/1 Running 0 9m nginx-prod-v000-f87gn 1/1 Running 0 9m nginx-prod-v000-h629g 1/1 Running 0 9m nginx-prod-v000-hkhjc 1/1 Running 0 9m nginx-prod-v000-jhnv2 1/1 Running 0 9m nginx-prod-v000-jmkgx 1/1 Running 0 9m nginx-prod-v000-s59pm 1/1 Running 0 9m nginx-prod-v000-ssz85 1/1 Running 0 9m |
Expanding the Server Group in Spinnaker dashboard confirms the same.
This tutorial covered all the steps involved in getting Spinnaker up and running in a development environment. In the next part of the Spinnaker series, we will build an end-to-end CI/CD pipeline for Blue/Green deployments through Spinnaker. Stay tuned!
Additional editions of this series on learning Spinnaker will be found here.