book-of-kubernetes / examples

Examples for The Book of Kubernetes
MIT License
178 stars 80 forks source link

The Book of Kubernetes

This repository provides examples for The Book of Kubernetes by Alan Hohn, published by No Starch Press. The examples for each chapter are self-contained in a directory for each chapter.

The examples make extensive use of virtual machines, both to enable running a complete cluster and to isolate experimentation into a temporary environment. The examples support both Vagrant and Amazon Web Services (AWS).

Getting Started

Start by following the instructions in the setup directory's README.md file. Then you'll be ready to use the README.md file in each chapter's folder to run examples for that chapter.

Automated Configuration

The examples use Ansible to provide automated configuration of the virtual machines once they're started. The setup instructions will help you get Ansible installed. All of the chapters have a base playbook.yaml file that provides essential configuration to run the chapter's examples. Some of the chapters also provide an extra.yaml playbook that can be used to skip some of the less exciting installation and configuration. Instructions for using the playbooks are found in each chapter's README.md file.

The book itself will walk you through everything you need to know about installing, configuring, and using container runtimes and Kubernetes. However, the Ansible roles in the setup/roles directory are also an excellent resource to understand the setup of container runtimes and Kubernetes. You're welcome to reuse this Ansible automation in your own work, consistent with the license found in the LICENSE file. Of course, specific design choices I made to keep this content easy to use as examples for a book will not be suitable for production use, so be sure to modify accordingly and test thoroughly.

High Availability

One difference between Vagrant and AWS is load balancing to provide a high-availability solution for the API server and ingress. In Vagrant, these examples use kube-vip. In AWS, they use an Elastic Load Balancer (specifically a network load balancer). Here I provide some background in case it's helpful.

For the Vagrant solution, I started with Keepalived, an excellent library for sharing an IP address between two or more servers. It is a great fit for a shared IP on bare metal servers as it doesn't require any special network configuration or a separate set of load balancing servers. However, after some playing with kube-vip, I became convinced that it represents a better solution for Kubernetes high availability outside of cloud environments, as it provides similar functionality and can be easily integrated into the cluster itself.

Unfortunately, what works well in bare metal and Vagrant does not work as well in AWS. What keepalived and kube-vip both require is for the underlying network to be OK with a server suddenly ARPing an additional IP address, and AWS Virtual Private Cloud (VPC) is definitely not OK with that, thank you very much. There is a clever workaround that watches Keepalived to follow the shared IP and configures AWS to add that IP to the current master, but I did not feel that the added complexity of that solution lends itself to being reliable enough for the examples for a book.

Additionally, the right way to deploy a cluster to a cloud environment is to take advantage of the available features. In the case of AWS, this means deploying an Elastic Load Balancer (ELB). I was initially concerned about the complexity of this approach and the risk of exposing a lab cluster to the outside Internet, so I started with a separate EC2 instance to carry the 172.31.1.10 IP address and run HAProxy to load balance traffic across the cluster's API server instances. That was not a real high availability solution, as HAProxy and its AWS instance are single points of failure, so I was never satisfied with it.

Ultimately, I was able to get a network load balancer going with an address solely on the private 172.31/16 network I'm using for the examples. This required only minimal additions to the aws-instances Ansible role, which is good, because that is already the most complex in the whole set of roles used for these examples, not least because I have to create and remove resources without interfering with the rest of someone's AWS account, as well as automate SSH access to these temporary instances without leaving a bunch of cruft in $HOME/.ssh. Solving this with Ansible is also good because I didn't want to introduce a whole 'nother tool like Terraform that readers would have to install and configure.

The only remaining evidence of this churn is the existence of keepalived and haproxy roles in setup/roles. I decided to leave them there in case they are useful to someone, but they are not used in the playbook files in the chapters.

So long story short, as I said above, the Vagrant cluster uses kube-vip, while the AWS cluster uses a network load balancer. In both cases, the Kubernetes cluster setup is largely identical, which was one of my purposes in offering two ways to deploy the same cluster. If you're deploying a real production cluster, you can use the kube-vip and AWS load balancer setup for your own purposes, though you'll have to make some changes to make a cluster available publicly.

Better yet, use a Kubernetes provider that will set up your cloud provider for you properly. There are many good options, including Elastic Kubernetes Service (EKS), Google Kubernetes Engine (GKE), and Azure Kubernetes Service (AKS), as well as cloud-agnostic Kubernetes distributions like Rancher Kubernetes Engine (RKE), Tanzu Kubernetes Grid (TKG), and Red Hat OpenShift.