Getting Started With Kubernetes - Sample Chapter
Getting Started With Kubernetes - Sample Chapter
P U B L I S H I N G
pl
C o m m u n i t y
$ 34.99 US
22.99 UK
Sa
m
Jonathan Baier
ee
D i s t i l l e d
E x p e r i e n c e
Jonathan Baier
a passion for technology since an early age. When he was 14 years old, he was so
interested in the family computer (an IBM PCjr) that he poured through the several
hundred pages of BASIC and DOS manuals. Then, he taught himself to code a very
poorly-written version of Tic-Tac-Toe. During his teen years, he started a computer
support business. Since then, he has dabbled in entrepreneurship several times
throughout his life. He now enjoys working for Cloud Technology Partners,
a cloud-focused professional service and application development firm
headquartered in Boston.
He has over a decade of experience delivering technology strategies and solutions for
both public and private sector businesses of all sizes. He has a breadth of experience
working with a wide variety of technologies and with stakeholders from all levels
of management.
Working in the areas of architecture, containerization, and cloud security, he has
created strategic roadmaps to guide and help mature the overall IT capabilities of
various enterprises. Furthermore, he has helped organizations of various sizes build
and implement their cloud strategy and solve the many challenges that arise when
"designs on paper" meet reality.
Preface
This book is a guide to getting started with Kubernetes and overall container
management. We will walk you through the features and functions of Kubernetes
and show how it fits into an overall operations strategy. You'll learn what hurdles
lurk in moving container off the developer's laptop and managing them at a larger
scale. You'll also see how Kubernetes is the perfect tool to help you face these
challenges with confidence.
Preface
Chapter 6, Monitoring and Logging, teaches you how to use and customize built-in
and third-party monitoring tools on your Kubernetes cluster. We will look at
built-in logging and monitoring, the Google Cloud Logging service, and Sysdig.
Chapter 7, OCI, CNCF, CoreOS, and Tectonic, discovers how open standards benefit
the entire container ecosystem. We'll look at a few of the prominent standards
organizations and cover CoreOS and Tectonic. Also, we will explore their
advantages as a host OS and enterprise platform.
Chapter 8, Towards Production-Ready, shows some of the helpful tools and third-party
projects available and where you can go to get more help.
Updates and
Gradual Rollouts
This chapter will expand upon the core concepts, which show the reader how to
roll out updates and test new features of their application with minimal disruption
to uptime. It will cover the basics of doing application updates, gradual rollouts,
and A/B testing. In addition, we will look at scaling the Kubernetes cluster itself.
This chapter will discuss the following topics:
Application scaling
Rolling updates
A/B testing
Example set up
Before we start exploring the various capabilities built into Kubernetes for scaling
and updates, we will need a new example environment. We are going to use a
variation of our previous container image with a blue background (refer to
Figure 4.2 for a comparison). We have the following code:
apiVersion: v1
kind: ReplicationController
metadata:
name: node-js-scale
labels:
name: node-js-scale
spec:
replicas: 1
[ 83 ]
Scaling up
Over time, as you run your applications in the Kubernetes cluster, you will find that
some applications need more resources, whereas others can manage with fewer
resources. Instead of removing the entire RC (and associated pods), we want a
more seamless way to scale our application up and down.
[ 84 ]
Chapter 4
If all goes well, you'll simply see the word scaled on the output of your
terminal window.
Optionally, you can specify the --current-replicas flag as a
verification step. The scaling will only occur if the actual number of
replicas currently running matches this count.
After listing our pods once again, we should now see three pods running with a
name similar to node-js-scale-XXXXX, where the Xs are a random string.
You can also use the scale command to reduce the number of replicas. In either
case, the scale command adds or removes the necessary pod replicas, and the
service automatically updates and balances across new or remaining replicas.
Smooth updates
The scaling of our application up and down as our resource demands change is
useful for many production scenarios, but what about simple application updates?
Any production system will have code updates, patches, and feature additions.
These could be occurring monthly, weekly, or even daily. Making sure that we
have a reliable way to push out these changes without interruption to our users
is a paramount consideration.
Once again, we benefit from the years of experience the Kubernetes system is
built on. There is a built-in support for rolling updates with the 1.0 version. The
rolling-update command allows us to update entire RCs or just the underlying
Docker image used by each replica. We can also specify an update interval, which
will allow us to update one pod at a time and wait until proceeding to the next.
Let's take our scaling example and perform a rolling update to the 0.2 version of our
container image. We will use an update interval of 2 minutes, so we can watch the
process as it happens in the following way:
$ kubectl rolling-update node-js-scale --image=jonbaier/pod-scaling:0.2
--update-period="2m"
[ 85 ]
You should see some text about creating a new RC named node-js-scale-XXXXX,
where the Xs will be a random string of numbers and letters. In addition, you will see
the beginning of a loop that is starting one replica of the new version and removing
one from the existing RC. This process will continue until the new RC has the full
count of replicas running.
If we want to follow along in real time, we can open another terminal window and
use the get pods command, along with a label filter, to see what's happening.
$ kubectl get pods -l name=node-js-scale
This command will filter for pods with node-js-scale in the name. If you run this
after issuing the rolling-update command, you should see several pods running as
it creates new versions and removes the old ones one by one.
The full output of the previous rolling-update command should look something
like Figure 4.1, as follows:
As we can see here, Kubernetes is first creating a new RC named node-js-scale10ea08ff9a118ac6a93f85547ed28f6. K8s then loops through one by one. Creating
a new pod in the new controller and removing one from the old. This continues until
the new controller has the full replica count and the old one is at zero. After this, the
old controller is deleted and the new one is renamed to the original controller name.
[ 86 ]
Chapter 4
If you run a get pods command now, you'll note that the pods still all have a longer
name. Alternatively, we could have specified the name of a new controller in the
command, and Kubernetes will create a new RC and pods using that name. Once
again, the controller of the old name simply disappears after updating is complete.
I recommend specifying a new name for the updated controller to avoid confusion
in your pod naming down the line. The same update command with this method
would look like this:
$ kubectl rolling-update node-js-scale node-js-scale-v2.0
--image=jonbaier/pod-scaling:0.2 --update-period="2m"
Using the static external IP address from the service we created in the first section,
we can open the service in a browser. We should see our standard container
information page. However, you'll note that the title now says Pod Scaling v0.2
and the background is light yellow.
It's worth noting that during the entire update process, we've only been looking at
pods and RCs. We didn't do anything with our service, but the service is still running
fine and now directing to the new version of our pods. This is because our service is
using label selectors for membership. Because both our old and new replicas use the
same labels, the service has no problem using the new pods to service requests. The
updates are done on the pods one by one, so it's seamless for the users of the service.
[ 87 ]
[ 88 ]
Chapter 4
This will create a service that will point to our pods running both version 0.2 and 0.3
of the application. Next, we will create the two RCs which create two replicas of the
application. One set will have version 0.2 of the application, and the other will have
version 0.3, as shown here:
apiVersion: v1
kind: ReplicationController
metadata:
name: node-js-scale-a
labels:
name: node-js-scale-a
version: "0.2"
service: node-js-scale-ab
spec:
replicas: 2
selector:
name: node-js-scale-a
version: "0.2"
service: node-js-scale-ab
template:
metadata:
labels:
name: node-js-scale-a
version: "0.2"
service: node-js-scale-ab
spec:
containers:
- name: node-js-scale
image: jonbaier/pod-scaling:0.2
ports:
- containerPort: 80
livenessProbe:
# An HTTP health check
httpGet:
path: /
port: 80
initialDelaySeconds: 30
timeoutSeconds: 5
readinessProbe:
# An HTTP health check
httpGet:
path: /
port: 80
initialDelaySeconds: 30
timeoutSeconds: 1
[ 89 ]
Chapter 4
Note that we have the same service label, so these replicas will also be added
to the service pool based on this selector. We also have livenessProbe and
readinessProbe defined to make sure that our new version is working as
expected. Again, use the create command to spin up the controller:
$ kubectl create -f pod-A-controller.yaml
$ kubectl create -f pod-B-controller.yaml
Now we have a service balancing to both versions of our app. In a true A/B test, we
would now want to start collecting metrics on the visit to each version. Again, we
have the sessionAffinity set to ClientIP, so all requests will go to the same pod.
Some users will see v0.2, and some will see v0.3.
Because we have sessionAffinity turned on, your test will likely
show the same version every time. This is expected, and you would
need to attempt a connection from multiple IP addresses to see both user
experiences with each version.
Since the versions are each on their own pod, one can easily separate logging and
even add a logging container to the pod definition for a sidecar logging pattern. For
brevity, we will not cover that setup in this book, but we will look at some of the
logging tools in Chapter 6, Monitoring and Logging.
We can start to see how this process would be useful for a canary release or a manual
blue-green deployment. We can also see how easy it is to launch a new version and
slowly transition over to the new release.
Let's look at a basic transition quickly. It's really as simple as a few scale commands,
which are as follows:
$ kubectl scale --replicas=3 rc/node-js-scale-b
$ kubectl scale --replicas=1 rc/node-js-scale-a
$ kubectl scale --replicas=4 rc/node-js-scale-b
$ kubectl scale --replicas=0 rc/node-js-scale-a
Use the get pods command combined with l filter in between scale
commands to watch the transition as it happens.
[ 91 ]
Now we have fully transitioned over to version 0.3 (node-js-scale-b). All users
will now see the version 0.3 of the site. We have four replicas of version 0.3 and 0
of 0.2. If you run a get rc command, you will notice that we still have a RC for 0.2
(node-js-scale-a). As a final cleanup, we can remove that controller completely
as follows:
$ kubectl delete rc/node-js-scale-a
In the newly released version 1.1, K8s has a new "Horizontal Pod
Autoscaler" construct which allows you to automatically scale pods based
on CPU utilization.
Bear in mind that changing this after the cluster is started will have no
effect. You would need to tear down the cluster and create it once again.
Thus, this section will show you how to add nodes to an existing cluster
without rebuilding it.
[ 92 ]
Chapter 4
On the side panel under Compute and then Compute Engine, select Instance
templates. You should see a template titled kuberenetes-minion-template. Note
that the name could vary slightly if you've customized your cluster naming settings.
Click on that template to see the details. Refer to the following screenshot:
You'll see a number of settings, but the meat of the template is under Custom
metadata. Here, you will see a number of environment variables and also a startup
script that is run after a new machine instance is created. These are the core
components that allow us to create new machines and have them automatically
added to the available cluster nodes.
[ 93 ]
Because the template for new machines is already created, it is very simple to scale
out our cluster in GCE. Simply go to the Instance groups located right above the
Instance templates link on the side panel. Again, you should see a group titled
kubernetes-minion-group or something similar. Click on that group to see the
details, as shown in the following screenshot:
[ 94 ]
Chapter 4
You'll see a page with a CPU metrics graph and four instances listed here. By default,
the cluster creates four nodes. We can modify this group by clicking the Edit group
button at the top of the page.
[ 95 ]
[ 96 ]
Chapter 4
We can scale this group up easily by clicking Edit. Then, change the Desired, Min,
and Max values to 5 and click on Save. In a few minutes, you'll have the fifth node
available. You can once again check this using the get nodes command.
Scaling down is the same process, but remember that we discussed the same
considerations in the previous Scaling the cluster on GCE section. Workloads
could get abandoned or at the very least unexpectedly restarted.
[ 97 ]
Scaling manually
For other providers, creating new minions may not be an automated process.
Depending on your provider, you'll need to perform various manual steps. It can
be helpful to look at the provider-specific scripts under the cluster directory.
Summary
We should now be a bit more comfortable with the basics of application scaling in
Kubernetes. We also looked at the built-in functions in order to roll updates as well
a manual process for testing and slowly integrating updates. Finally, we took a look
at scaling the nodes of our underlying cluster and increasing overall capacity for our
Kubernetes resources.
[ 98 ]
www.PacktPub.com
Stay Connected: