The software industry is rapidly seeing the value of using containers as a way to ease development, deployment, and environment orchestration for app developers. That’s because containers effectively manage environmental differences, allow for improved scalability, and provide predictability that supports Continuous Delivery (CD) of features. In addition to the technical advantages, containers have been shown to dramatically reduce the cost model of complex environments.
Large-scale and highly-elastic applications that are built in containers definitely have their benefits, but managing the environment can be daunting. This is where an orchestration tool like Kubernetes really shines.
Kubernetes is a platform-agnostic container orchestration tool created by Google and heavily supported by the open source community as a project of the Cloud Native Computing Foundation. It allows you to spin up a number of container instances and manage them for scaling and fault tolerance. It also handles a wide range of management activities that would otherwise require separate solutions or custom code, including request routing, container discovery, health checking, and rolling updates.
Kenzan is a services company that specializes in building applications at scale. We’ve seen cloud technology evolve over the last decade, designing microservice-based applications around the Netflix OSS stack, and more recently implementing projects using the flexibility of container technology. While each implementation is unique, we’ve found the combination of microservices, Kubernetes, and Continuous Delivery pipelines to be very powerful.
Crossword Puzzles, Kubernetes, and CI/CD
This article is the first in a series of four blog posts. Our goal is to show how easy it is to set up a fully-containerized application stack in Kubernetes with a simple CI/CD pipeline to manage the deployments.
We’ll describe the setup and deployment of an application we created especially for this series. It’s called the Kr8sswordz Puzzle, and working with it will help you link together some key Kubernetes and CI/CD concepts. The application will start simple enough, then as we progress we will introduce components that demonstrate a full application stack, as well as a CI/CD pipeline to help manage that stack, all running as containers on Kubernetes. Check out the architecture diagram below to see what you’ll be building.
The completed application will show the power and ease with which Kubernetes manages both apps and infrastructure, creating a sandbox where you can build, deploy, and spin up many instances under load.
Get Kubernetes up and Running
The first step in building our Kr8sswordz Puzzle application is to set up Kubernetes and get comfortable with running containers in a pod. We’ll install several tools explained along the way: Docker, Minikube, and Kubectl.
To complete these exercises, you’ll need a computer running an up-to-date version of Linux or macOS. Your computer should have 16 GB of RAM.
Exercise 1: Install Docker
Docker is one of the most widely-used container technologies and works directly with Kubernetes. In this exercise we’ll install Docker and then try out a few commands.
Install Docker on Linux
To quickly install Docker on Ubuntu 16.04 or higher, open a terminal and enter the following commands (see the Linux installation instructions for other distributions):
sudo apt-get updatecurl -fsSL https://get.docker.com/ | sh
After installation, create a Docker group so you can run Docker commands as a non-root user (you’ll need to log out and then log back in after running this command):
sudo usermod -aG docker $USER
When you’re all done, make sure Docker is running:
sudo service docker start
Install Docker on macOS
Download Docker for Mac (stable) and follow the installation instructions. To launch Docker, double-click the Docker icon in the Applications folder. Once it’s running, you’ll see a whale icon in the menu bar.
Try Some Docker Commands
You can test out Docker by opening a terminal window and entering the following commands:
# Display the Docker versiondocker version# Pull and run the Hello-World image from Docker Hubdocker run hello-world# Pull and run the Busybox image from Docker Hubdocker run busybox echo "hello, you've run busybox"# View a list of containers that have rundocker ps -a
Exercise 2: Install Minikube and Kubectl
Minikube is a single-node Kubernetes cluster that makes it easy to run Kubernetes locally on your computer. We will use Minikube as the primary Kubernetes cluster to run our application on. Kubectl is a command line interface (CLI) for Kubernetes and the way we will interface with our cluster.
In this exercise we’ll quickly install both Minikube and kubectl. (For all the details, check out Running Kubernetes Locally via Minikube.)
Install Virtual Box
Download and install the latest version of VirtualBox for your operating system. VirtualBox lets Minikube run a Kubernetes node on a virtual machine (VM).
Head over to the Minikube releases page and install the latest version of Minikube using the recommended method for your operating system. This will set up our Kubernetes node.
On Linux, install Minikube using the following command. For example, for v0.18.0:
curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.18.0/minikube- linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
On macOS, install Minikube using the following command. For example, for v0.18.0:
curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.18.0/minikube- darwin-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
The last piece of the puzzle is to install kubectl so we can talk to our Kubernetes node.
On Linux, install kubectl using the following command:
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/
On macOS, install kubectl using the following command:
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/
Exercise 3: Install Prerequisites
In the next exercises, we’re going to use Minikube to start a local Kubernetes cluster and deploy some pods. You can manually enter each of the commands in the exercises, but to make things a little easier we’ve created a tutorial script that will walk you through the steps (and save you some typing). Let’s get the interactive tutorial going.
To use the tutorial, you need to install NodeJS and npm. (You can skip this if you want to enter all the commands manually—but really, who loves typing that much?)
On Linux, follow the NodeJS installation steps for your distribution. To quickly install NodeJS and npm on Ubuntu 16.04 or higher, open a terminal and enter the following commands:
curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash -sudo apt-get install -y nodejs
On macOS,download the NodeJS installer, and then double-click the .pkg file to install NodeJS and npm.
Fork the Git Repo
Now it’s time to make your own copy of the Kubernetes CI/CD repository on Github.
1. Install Git on your computer if you don’t have it already.
On Linux, use the following command:
sudo apt-get install git
On macOS, download and run the macOS installer for Git. To install, first double-click the .dmg file to open the disk image. Right-click the .pkg file and click Open, and then click Open again to start the installation.
2. Fork Kenzan’s Kubernetes CI/CD repository on Github. This has all the containers and other goodies for our Kr8sswordz Puzzle application, and you’ll want to fork it as you’ll later be modifying some of the code.
a. Sign up if you don’t yet have an account on Github.
b. On the Kubernetes CI/CD repository on Github, click the Fork button in the upper right and follow the instructions.
c. Make sure you’re in your home directory, and then clone your newly forked repository with the following terminal command:
git clone https://github.com/YOURUSERNAME/kubernetes-ci-cd
Clear out Minikube
Let’s get rid of the leftovers from any previous experiments you might have conducted with Minikube. Enter the following terminal command:
minikube delete; sudo rm -rf ~/.minikube; sudo rm -rf ~/.kube
Next, change directories to the cloned repository and install the tutorial script:
cd ~/kubernetes-ci-cdnpm install
Once that operation completes, go ahead and start the script:
npm run part1
Exercise 4: Run a Test Pod
In this exercise we’ll test out Minikube by running a pod based on a public image on DockerHub.
You don’t have to actually type the commands below—just press Enter at each step and the script will enter the command for you!
1. Start up the Kubernetes cluster with Minikube, giving it some extra resources.
minikube start --memory 8000 --cpus 2 --kubernetes-version v1.6.0
2. Enable the Minikube add-ons Heapster and Ingress.
minikube addons enable heapster; minikube addons enable ingress
In a second terminal, you can inspect the pods in the cluster. You should see the add-ons heapster, influxdb-grafana, and nginx-ingress-controller. Enter the command:
kubectl get pods --all-namespaces
3. Wait 20 seconds, and then view the Minikube Dashboard, a web UI for managing deployments. You may have to refresh the web browser if you don’t see the dashboard right away.
sleep 20; minikube service kubernetes-dashboard --namespace kube-system
4. Deploy the public nginx image from DockerHub into a container in a pod. Nginx is an open source web server. The nginx image is automatically downloaded from Docker Hub if it’s not available locally.
kubectl run nginx --image nginx --port 80
After running the command, you should be able to see the new deployment in the Minikube Dashboard with the Heapster graphs. (If you don’t see the graphs, just wait a few minutes.)
5. Create a service for deployment. This will expose the nginx pod so you can access it with a web browser.
kubectl expose deployment nginx --type NodePort --port 80
6. Launch a web browser to test the service. The nginx welcome page displays, which means the service is up and running. Nice work!
minikube service nginx
Exercise 5: Create a Local Image Registry
In the previous exercise, we ran a public image from Docker Hub. While Docker Hub is great for public images, setting up a private image repository on the site involves some security key overhead that we don’t want to deal with. Instead, we’ll set up our own local image registry. We’ll then build, push, and run a sample Hello-Kenzan app from the local registry. (Later, we’ll use the registry to store the container images for our Kr8sswordz Puzzle app.)
The interactive tutorial should still be running—just press Enter to run each step below.
7. Set up the cluster registry by applying a .yml manifest file.
kubectl apply -f manifests/registry.yml
8. Wait for the registry to finish deploying. Note that this may take several minutes.
kubectl rollout status deployments/registry
9. View the registry user interface in a web browser. Right now it’s empty, but you’re about to change that.
minikube service registry-ui
10 . Let’s make a change to an HTML file in the cloned project. Running the command below will open the file /applications/hello-kenzan/index.htmlin the nanotext editor.
Change some text inside one of the <p> tags. For example, change “Hello from Kenzan!” to “Hello from Me!”. When you’re done, press Ctrl+X to close the file. You’ll be prompted to save your changes — enter Y to save changes and Enter to write to the specified file.
11. Now let’s build an image, giving it a special name that points to our local cluster registry.
docker build -t 127.0.0.1:30400/hello-kenzan:latest -f applications/hello-kenzan/Dockerfile applications/hello-kenzan
12. We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a container that listens on 127.0.0.1:30400 and forwards to our cluster.
docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400"
13. With our proxy container up and running, we can now push our image to the local repository.
docker push 127.0.0.1:30400/hello-kenzan:latest
Refresh the browser window with the registry, UI and you’ll see the image has appeared.
14. The proxy’s work is done, so you can go ahead and stop it.
docker stop socat-registry;
15. With the image in our cluster registry, the last thing to do is apply the manifest to create and deploy the hello-kenzan service based on the image.
kubectl apply -f applications/hello-kenzan/k8s/deployment.yaml
16. Launch a web browser and view the service.
minikube service hello-kenzan
Notice the change you made to the index.html file. That change was baked into the image when you built it and then was pushed to the registry. Pretty cool!
If you’re done working in Minikube for now, you can go ahead and stop the cluster by entering the following command:
So far, we’ve installed Docker, Minikube, and Kubectl. To build out our Kr8sswordz Puzzle stack, we’ve run our image repository as a pod in Minikube, and we were able to test building and pushing to it with our Hello-Kenzan app.
Stay tuned for Part 2 of the series, where we will continue to build out our infrastructure by adding in a CI/CD component: Jenkins running in its own pod. Using a Jenkins 2.0 Pipeline script, we will build, push, and deploy our Hello-Kenzan app, giving us the infrastructure for continuous deployment that will later be used with our Kr8sswordz Puzzle app. Though it might seem mind-bending to deploy containers from a Jenkins container within Kubernetes, Part 2 will show how easy it is to manage deployments this way.
Want to learn more about Kubernetes? Get unlimited access to the new Kubernetes Fundamentals training course for one year for $199. Sign up now!