Kubernetes For Java Developers
Kubernetes For Java Developers
m
pl
im
en
ts
of
Kubernetes for
Java Developers
Orchestrate Multi-Container
Applications with Ease
Arun Gupta
Kubernetes for Java
Developers
Orchestrate Multicontainer
Applications with Ease
Arun Gupta
Editors: Nan Barber and Brian Foster Interior Designer: David Futato
Production Editor: Melanie Yarbrough Cover Designer: Karen Montgomery
Copyeditor: Rachel Monaghan Illustrator: Rebecca Demarest
Proofreader: Amanda Kersey
The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Kubernetes for
Java Developers, the cover image, and related trade dress are trademarks of O’Reilly
Media, Inc.
While the publisher and the author have used good faith efforts to ensure that the
information and instructions contained in this work are accurate, the publisher and
the author disclaim all responsibility for errors or omissions, including without limi‐
tation responsibility for damages resulting from the use of or reliance on this work.
Use of the information and instructions contained in this work is at your own risk. If
any code samples or other technology this work contains or describes is subject to
open source licenses or the intellectual property rights of others, it is your responsi‐
bility to ensure that your use thereof complies with such licenses and/or rights.
978-1-491-97326-4
[LSI]
Table of Contents
Foreword. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v
Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii
1. Kubernetes Concepts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Pods 1
Replication Controllers 4
Replica Sets 5
Deployments 7
Services 8
Jobs 10
Volumes 12
Architecture 14
3. Advanced Concepts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Persistent Volume 43
Stateful Sets 48
Horizontal Pod Autoscaling 51
Daemon Sets 52
iii
Checking the Health of a Pod 53
Namespaces 54
Rolling Updates 56
Exposing a Service 58
4. Administration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Cluster Details 59
Application Logs 62
Debugging Applications 63
Application Performance Monitoring 66
5. Conclusion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
iv | Table of Contents
Foreword
v
Preface
vii
Chapter 1 explains them from the developer and operations per‐
spective. Chapter 2 explains how to create a single-node local devel‐
opment cluster and how to get started with a multinode cluster. It
also covers a simple Java application communicating with a database
running on Kubernetes. Chapter 3 gets into more advanced con‐
cepts like stateful containers, scaling, performing health checks and
rolling updates of an application, and sharing resources across the
cluster. Chapter 4 details administrative aspects of Kubernetes. The
examples in this book use the Java programming language, but the
concepts are applicable for anybody interested in getting started
with Kubernetes.
Acknowledgments
I would like to express gratitude to the people who made writing
this book a fun experience. First and foremost, many thanks to
O’Reilly for providing an opportunity to write it. The team provided
excellent support throughout the editing, reviewing, proofreading,
and publishing processes. At O’Reilly, Brian Foster believed in the
idea and helped launch the project. Nan Barber was thorough and
timely with her editing, which made the book fluent and consistent.
Thanks also to the rest of the O’Reilly team, some of whom we may
not have interacted with directly, but who helped in many other
ways. Paul Bakker (@pbakker) and Roland Huss (@ro14nd) did an
excellent technical review of the book, which ensured that the book
stayed true to its purpose and explained the concepts in the simplest
possible ways. A vast amount of information in this book is the
result of delivering the “Kubernetes for Java Developers” presenta‐
tion all around the world. A huge thanks goes to all the workshop
attendees whose questions helped clarify my thoughts. Last but not
least, I seek forgiveness from all those who have helped us over the
past few months and whose names I have failed to mention.
viii | Preface
CHAPTER 1
Kubernetes Concepts
Pods
A pod is the smallest deployable unit that can be created, scheduled,
and managed. It’s a logical collection of containers that belong to an
application. Pods are created in a namespace. All containers in a pod
share the namespace, volumes, and networking stack. This allows
1
containers in the pod to “find” each other and communicate using
localhost.
Each resource in Kubernetes can be defined using a configuration
file. For example, a WildFly pod can be defined with the configura‐
tion file shown in Example 1-1.
Pods | 3
Replication Controllers
A replication controller (RC) ensures that a specified number of pod
“replicas” are running at any one time. Unlike manually created
pods, the pods maintained by a replication controller are automati‐
cally replaced if they fail, get deleted, or are terminated. A replica‐
tion controller ensures the recreation of a pod when the worker
node fails or reboots. It also allows for both upscaling and downscal‐
ing the number of replicas.
A replication controller creating two instances of a WildFly pod can
be defined as shown in Example 1-2.
Replica Sets
Replica sets are the next-generation replication controllers. Just like a
replication controller, a replica set ensures that a specified number
of pod replicas are running at any one time. The only difference
between a replication controller and a replica set is the selector sup‐
port.
For replication controllers, matching pods must satisfy all of the
specified label constraints. The supported operators are =, ==, and !
=. The first two operators are synonyms and represent equality. The
last operator represents inequality.
For replica sets, filtering is done according to a set of values. The
supported operators are in, notin, and exists (only for the key).
For example, a replication controller can select pods such as envi
ronment = dev. A replica set can select pods such as environment
in ["dev", "test"].
Replica Sets | 5
A replica set creating two instances of a WildFly pod can be defined
as shown in Example 1-3.
The key differences between Examples 1-2 and 1-3 are as follows:
Deployments
Deployments provide declarative updates for pods and replica sets.
You can easily achieve the following functionality using deployment:
A WildFly replica set with three replicas can be defined using the
configuration file shown in Example 1-4.
Deployments | 7
spec:
containers:
- name: wildfly
image: jboss/wildfly:10.1.0.Final
ports:
- containerPort: 8080
Services
A pod is ephemeral. Each pod is assigned a unique IP address. If a
pod that belongs to a replication controller dies, then it is recreated
and may be given a different IP address. Further, additional pods
may be created using replication controllers. This makes it difficult
for an application server such as WildFly to access a database such
as Couchbase using its IP address.
A service is an abstraction that defines a logical set of pods and a
policy by which to access them. The IP address assigned to a service
does not change over time, and thus can be relied upon by other
pods. Typically, the pods belonging to a service are defined by a label
selector. This is similar to how pods belong to a replication control‐
ler.
This abstraction of selecting pods using labels enables a loose cou‐
pling. The number of pods in the replication controller may scale up
or down, but the application server can continue to access the data‐
base using the service.
Multiple resources, such as a service and a replication controller,
may be defined in the same configuration file. In this case, each
resource definition in the configuration file needs to be separated by
---.
Multiple resources are created in the order they are specified in the
file.
In this configuration file:
The service selects any pods that contain the label app:
wildfly-rc-pod. The replication controller attaches those labels
to the pod.
Services | 9
tainer using targetPort. By default, targetPort is the same as
port.
A service may expose multiple ports. In this case, each port
must be given a unique name:
ports:
- name: web
port: 8080
Jobs
A job creates one or more pods and ensures that a specified number
of them successfully complete. When the specified number of pods
has successfully completed, the job itself is complete. The job will
start a new pod if the pod fails or is deleted due to hardware failure.
This is different from a replication controller or a deployment,
which ensure that a certain number of pods are always running. If a
pod in a replication controller or deployment terminates, it is restar‐
ted. This makes replication controllers and deployments both long-
running processes, which is well suited for an application server
such as WildFly. But a job is completed only when the specified
number of pods successfully completes, which is well suited for tasks
that need to run only once. For example, a job may convert one
image format to another. Restarting this pod in a replication con‐
troller would not only cause redundant work but may even be harm‐
ful in certain cases.
There are two main types of jobs:
Nonparallel jobs
Job specification consists of a single pod. The job completes
when the pod successfully terminates.
Parallel jobs
A predefined number of pods successfully completes. Alterna‐
tively, a work queue pattern can be implemented where pods can
Jobs are defined in their own API group using the path
batch/v1.
This job uses the base image of ubuntu. Usually, this will be a
custom image that will perform the run-once task.
Jobs | 11
OnFailure means the pod is restarted if the container in the pod
exits with a failure. More details about these policies are avail‐
able at the Kubernetes website.
Kubernetes 1.4 introduced a new alpha resource called Scheduled
Job. This resource was renamed to CronJob starting in version 1.5.
CronJob allows you to manage time-based jobs. There are two pri‐
mary use cases:
Volumes
Pods are ephemeral and work well for a stateless container. They are
restarted automatically when they die, but any data stored in their
filesystem is lost with them. Stateful containers, such as Couchbase,
require data to be persisted outside the lifetime of a container run‐
ning inside a pod. This is where volumes help.
A volume is a directory that is accessible to the containers in a pod.
The directory, the medium that backs it, and the contents within it
are determined by the particular volume type used. A volume out‐
lives any containers that run within the pod, and the data is pre‐
served across container restarts.
Multiple types of volumes are supported. Some of the commonly
used volume types are shown in Table 1-1.
Volumes | 13
volumes defines the volumes accessible to the pod.
Architecture
The key components of the Kubernetes architecture are shown in
Figure 1-1.
Master nodes
A master node is a central control plane that provides a unified view
of the cluster. You can easily create a Kubernetes cluster with a single
master node for development. Alternatively, you could create a
Kubernetes cluster with high availability with multiple master
nodes. Let’s look at the key components in the master node:
kubectl
This is a command-line tool that send commands to the master
node to create, read, update, and delete resources. For example,
it can request to create a pod by passing the pod configuration
file, or it can query more details about the replicas running for a
replica set. It reads container manifests as YAML or JSON files
that describe each resource. A typical way to provide this mani‐
fest is using the configuration file as shown in the previous sec‐
tions. This process is explained more in “Running Your First
Java Application” on page 25.
API server
Each command from kubectl is translated into a REST API and
issued to the API server running inside the master node. The
API server processes REST operations, validates them, and per‐
sists the state in a distributed watchable storage. This is imple‐
mented using etcd for Kubernetes.
Scheduler
The scheduler works with the API server to schedule pods to
the nodes. The scheduler has information about resources avail‐
able on the worker nodes, as well as the ones requested by the
pods. It uses this information to decide which node will be
selected to deploy a specific pod.
Controller manager
The controller manager is a daemon that watches the state of
the cluster using the API server for different controllers and
Architecture | 15
reconciles the actual state with the desired one (e.g., the number
of pods to run for a replica set). Some other controllers that
come with Kubernetes are the namespace controller and the
horizontal pod autoscaler.
etcd
This is a simple, distributed, watchable, and consistent key/
value store. It stores the persistent state of all REST API objects
—for example, how many pods are deployed on each worker
node, labels assigned to each pod (which can then be used to
include the pods in a service), and namespaces for different
resources. For reliability, etcd is typically run in a cluster.
Worker nodes
A worker node runs tasks as delegated by the master. Each worker
node can run multiple pods:
Kubelet
This is a service running on each node that manages containers
and is managed by the master. It receives REST API calls from
the master and manages the resources on that node. Kubelet
ensures that the containers defined in the API call are created
and started.
Kubelet is a Kubernetes-internal concept and generally does not
require direct manipulation.
Proxy
This runs on each node, acting as a network proxy and load bal‐
ancer for a service on a worker node. Client requests coming
through an external load balancer will be redirected to the con‐
tainers running in a pod through this proxy.
Docker
Docker Engine is the container runtime running on each node.
It understands the Docker image format and knows how to run
Docker containers. Alternatively, Kubernetes may be config‐
uired to use rkt as the container runtime. More details about
that are available in the guide to running Kubernetes with rkt.
17
cluster and a highly available cluster using Kops on AWS is also
explained.
Start cluster
Download the Minikube binary as follows:
curl -Lo minikube \
https://storage.googleapis.com/minikube/releases/v0.18.0/
minikube-darwin-amd64 \
&& chmod +x minikube
The example starts by downloading the ISO base image and creating
the VirtualBox VM. Then it generates the SSL certificates that allow
a secure connection to the VM. Next, all the needed components—
such as the API server, Docker engine, and etcd—are started. All
the configuration information is stored in the kubeconfig file. The
default location of this file is ~/.kube/config. Finally, the kubectl CLI
is configured to connect to this cluster using the configuration
information.
As of this writing, Minikube starts a Kubernetes 1.6.0 cluster. For a
complete list of Kubernetes versions, use the command minikube
get-k8s-versions. You’ll see the following output:
The following Kubernetes versions are available:
- v1.6.0
- v1.6.0-rc.1
- v1.6.0-beta.4
- v1.6.0-beta.3
- v1.6.0-beta.2
- v1.6.0-alpha.1
- v1.6.0-alpha.0
- v1.5.3
- v1.5.2
- v1.5.1
- v1.4.5
- v1.4.3
- v1.4.2
- v1.4.1
- v1.4.0
- v1.3.7
- v1.3.6
- v1.3.5
- v1.3.4
- v1.3.3
- v1.3.0
You can start a different version of Kubernetes cluster as follows:
minikube start --kubernetes-version=<version>
For more details about the cluster, use the command kubectl
cluster-info, which gives the following output:
Kubernetes master is running at https://192.168.99.100:8443
KubeDNS is running at https://192.168.99.100:8443/api/v1/proxy/
namespaces/kube-system/services/kube-dns
kubernetes-dashboard is running at https://192.168.99.100:8443/
api/v1/proxy/namespaces/kube-system/services/kubernetes-
dashboard
To view the complete list of commands for Minikube, use the com‐
mand minikube --help.
Kubernetes dashboard
The Kubernetes dashboard is a general-purpose, web-based UI for
Kubernetes clusters. It provides an overview of applications running
You can find a list of all the nodes in the cluster using kubectl get
nodes command; you’ll see the following output:
NAME STATUS AGE VERSION
ip-172-20-109-249.compute.internal Ready,master 7m v1.5.2
ip-172-20-123-1.compute.internal Ready,node 6m v1.5.2
ip-172-20-32-140.compute.internal Ready,master 7m v1.5.2
ip-172-20-61-111.compute.internal Ready,node 6m v1.5.2
ip-172-20-82-253.compute.internal Ready,master 7m v1.5.2
ip-172-20-82-57.compute.internal Ready,node 6m v1.5.2
By default, a cluster created using Kops does not have the UI dash‐
board. But you can include it as an add-on:
kubectl create -f https://raw.githubusercontent.com/kubernetes/
kops/master/addons/kubernetes-dashboard/v1.5.0.yaml
deployment "kubernetes-dashboard" created
service "kubernetes-dashboard" created
The URL for the dashboard will be derived based upon the domain
name used for starting the Kubernetes cluster. The Kubernetes dash‐
board is now available at https://api.kubernetes.arungupta.me/ui. To
obtain the login credentials for the dashboard, use the command
kubectl config view. The dashboard by itself looks like
Figure 2-2.
RESTARTS AGE
0 25s
The first run of the pod requires the Docker image to be downloa‐
ded on the node where the pod is created. This is indicated by the
status ContainerCreating. Adding the -w switch watches for any
change in the object’s state, and the output is updated accordingly.
Check logs from the pod using the pod’s name:
kubectl logs hello-java-888248798-8ingx
openjdk version "1.8.0_102"
OpenJDK Runtime Environment (build 1.8.0_102-8u102-b14.1-1~bpo
8+1-b14)
OpenJDK 64-Bit Server VM (build 25.102-b14, mixed mode)
The output shows the JDK version, as expected.
If you wait a few seconds to watch the output of the kubectl get
-w pods command, you should see the following:
NAME READY STATUS RESTARTS AGE
hello-java 0/1 Completed 0 9m
hello-java-xxx 0/1 Completed 0 5s
hello-java-xxx 0/1 Completed 1 6s
hello-java-xxx 0/1 CrashLoopBackOff 1 7s
You can then delete this pod using the command kubectl delete
pod hello-java. Now, if you check the list of pods using the
kubectl get pods command, an empty list will be returned.
--port defines the port number that this container exposes. This
only exposes the port within the Kubernetes cluster though, not out‐
side.
Get the list of deployments like so:
SubObjectPath
-------------
Normal ScalingReplicaSet Scaled up replica
set hello-wildfly-135927814 to 1
A single replica of WildFly pod is created as part of this deployment.
http://localhost:8001/api/v1/proxy/namespaces/default/<resource-
type>/<resource-name>
http://localhost:8001/api/v1/proxy/namespaces/default/services/
hello-wildfly-service/index.html
The link shows the main page of WildFly as shown in Figure 2-3.
Checking the list of pods using the command kubectl get rc/
wildfly-rc now shows:
NAME DESIRED CURRENT READY AGE
wildfly-rc 4 4 4 3m
New pods created by this command have the labels app: wildfly-
rc-pod. This is the selector label on the service as well. So the
number of pods in that service has now increased from two to four.
Resources created by this configuration file can be deleted as fol‐
lows:
kubectl delete -f wildfly-service.yml
In this example:
-w watches for changes in the requested object. The status of the pod
is ContainerCreating and then Running. The first run of this com‐
mand involves downloading the Docker image from the Docker
hub, so it may take some time for the pod to start, depending upon
your internet connectivity.
Check logs for the pod using the command kubectl logs
couchbase-rc-8r6j1:
Starting Couchbase Server -- Web UI available at http://<ip>:8091
* Trying 127.0.0.1...
% Total % Received % Xferd Average Speed Time Time
Dload Upload Total Spent
0 0 0 0 0 0 0 0 --:--:-- --:--:--
> POST /pools/default HTTP/1.1
> User-Agent: curl/7.40.0-DEV
> Host: 127.0.0.1:8091
. . .
<
{ [286 bytes data]
100 325 100 286 100 39 140 19 0:00:02 0:00:02
* Connection #0 to host 127.0.0.1 left intact
{"newBaseUri":"http://127.0.0.1:8091/"}{
"requestID": "9f109317-5764-4d75-bce1-2ec7b1f502cc",
"signature": null,
"results": [
],
"status": "success",
In this example:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.4.0.RELEASE)
. . .
Java developers are already familiar with how to use Maven to create
archives (e.g., JAR or WAR). This plugin extends the functionality of
Maven to use the known targets for Kubernetes.
The plugin coordinates are shown in Example 2-6.
The complete set of goals for this plugin is listed at the plugin’s web‐
site.
A zero-config setup allows you to use the plugin with opinionated
defaults. This is possible because of several generators that provide
reasonable defaults for the commonly used build types, like a plain
Java build or a Spring Boot application. If the build type is identified
as a certain type it makes reasonable defaults, like the base image,
which ports to expose, and the startup command. They can be con‐
figured, but offer only a few options.
For example, adding the plugin definition shown in Example 2-7 to
your pom.xml file will generate Kubernetes resource configuration
files in the target/classes/META-INF/fabric8/kubernetes directory
before the build target is invoked. This ensures that the Kubernetes
resources are packaged in the Docker image built using the build
target.
Persistent Volume
Stateful containers, such as Couchbase, need to store data outside
the container. This allows the data to be preserved independent of
container and pod restarts. To accomplish this, Kubernetes provides
volumes, which are essentially directories accessible to the pod. The
lifecycle of a volume is tied to the pod that created it. Pods can store
data on this volume and preserve data across container restarts. But
the volume ceases to exist along with the pod. Moreover, pods are
ephemeral and so may be rescheduled on a different host. This
means the data cannot be stored on a host as well.
43
Kubernetes persistent volumes solve this problem by providing per‐
sistent, cluster-scoped storage for applications that require long-
lived data.
Creating and using a persistent volume is a three-step process:
Provision
The administrator provisions a networked storage solution in
the cluster, such as AWS ElasticBlockStore (EBS) volumes. This
is called a persistent volume (PV).
Request storage
The user requests storage for pods by using claims. Claims spec‐
ify levels of resources (CPU and memory), sizes and access
modes (e.g., can be mounted once read/write or many times
write-only). This is called PersistentVolumeClaim (PVC).
Use claim
Claims are mounted as volumes and used in pods for storage.
For an AWS Elastic Block Storage to be used as a persistent volume:
Persistent Volume | 45
Example 3-2. Kubernetes persistent volume claim
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: couchbase-pvc
labels:
type: amazonEBS
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
AGE
3m
NAME CAPACITY
pv/pvc-9a765e86-311b-11e7-be2d-08002724bd66 3Gi
NAME STATUS
pvc/couchbase-pvc Bound
VOLUME CAPACITY
pvc-9a765e86-311b-11e7-be2d-08002724bd66 3Gi
In this example:
Persistent Volume | 47
Stateful Sets
Typically, pods are stateless. So if one of them is unhealthy or super‐
seded by a newer version, then Kubernetes disposes of it. If it is part
of a replication controller, then another pod will be started. This
notion of treating pods as “cattle” work for stateless applications.
Stateful pods, like Couchbase, have a stronger notion of identity.
Such pods are called “pets,” as they need to be managed more care‐
fully and are typically long-lived entities with persistent storage.
Kubernetes 1.3 introduced the pet set as an alpha resource to define
stateful pods. Kubernetes 1.5 renamed the pet set to stateful set and
also made it a beta resource. Different API versions, such as alpha
and beta, imply different levels of stability and support.
A stateful set ensures that a specified number of “pets” with unique
identities are running at any given time. Each pet is a stateful pod.
The identity of a pod is composed of:
1. Create n nodes.
2. Pick any node, and add other n–1 nodes to it to create a homo‐
geneous cluster.
3. When a new node starts, it can join the cluster by talking to any
node in the cluster.
A stateful set requires that there be 0..N–1 pods. Each pod has a
deterministic name in the format <statefulset-name>-<ordinal>,
and a unique identity. The identity of a pod sticks to it, regardless of
which node it is (re)scheduled on.
Stateful Sets | 49
The StatefulSet value defines this resource to be of the type
stateful set.
Daemon Sets
A daemon set ensures that a copy of the pod runs on a selected set of
nodes. By default, all nodes in the cluster are selected, but you can
specify criteria to select a limited number of nodes instead.
Pods defined in the daemon set are created on a node when it’s
added to the cluster, and removed when it’s removed from the
cluster.
Common use cases for a daemon set include running a log daemon
such as logstash, an exporter for machine metrics such as prom/
node-exporter, a monitoring agent such as New Relic agent, or a
cluster storage daemon such as glusterd.
You can define a configuration to run a Prometheus monitoring
agent pod on all nodes of the cluster using Example 3-6.
More details about daemon sets are available at the Kubernetes web‐
site.
Table 3-1. Handlers used by the probe to check the health of a pod
Handler Diagnostic Success criteria
exec Executes a command inside the container Command exits with status
code 0
tcpSocket Runs a TCP check against the container’s IP Port is open and connection can
address on a specified port be established
httpGet Performs an HTTP GET against the Status code is between 200 and
container’s IP address on a specified port 399
and path
The first diagnostic is run after the time specified here, 30 sec‐
onds in our case.
The probe is marked failed if the diagnostic times out after the
time specified here, 1 second in our case.
Often a live container may be performing some background task.
The container may not be ready to receive a request in this case, or
may not be able to respond within a specified time. For example, a
Couchbase cluster may be getting rebalanced. In this case, the con‐
tainer is still relevant and does not need to be killed. But it may not
be ready to process requests. So the liveness probe may succeed but
the readiness probe may fail.
More details about health-checking a pod are at the Kubernetes
website.
Namespaces
All resources in a Kubernetes cluster are created in a default name‐
space. A pod will run with unbounded CPU and memory requests/
limits. A Kubernetes namespace allows you to partition created
resources into a logically named group. Each namespace provides:
Namespaces | 55
This configuration file requests 20 cores of CPU, 10 GB of memory
across all pods, and a total of 10 pods, 20 replication controllers, and
5 services in the default namespace.
You can view the allocated quota using the kubectl describe
quota command:
Name: quota
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 20
memory 0 1Gi
pods 0 10
replicationcontrollers 0 20
services 1 5
Some of the common resources that are supported by the quota sys‐
tem are shown in Table 3-2.
Rolling Updates
A rolling update is a method of deploying a new version of the
application with zero downtime. You achieve this by updating pods
one by one instead of updating all the pods at once.
Kubernetes allows rolling updates of replication controllers and
deployments.
This command changes the Docker image of the existing pods of the
replication controller webapp-rc to the new image at arungupta/
wildfly-app:2, one at a time.
Example 3-10 shows a rolling update of a deployment with a new
Docker image.
This command changes the Docker image of the existing pods of the
deployment webapp-deployment to the new image at arungupta/
wildfly-app:2, one at a time.
You can check the deployment history using the command kubectl
rollout history deployment webapp-deployment.
Rolling Updates | 57
More details about rolling deployment are available at the Kuber‐
netes website.
Exposing a Service
A service may need to be exposed outside of your cluster or on the
public internet. You can define this behavior using the type prop‐
erty. This property can take three values:
ClusterIP
This is the default and means that the service will be reachable
only from inside the cluster.
NodePort
This value exposes the service on a port on each node of the
cluster (the same port on each node):
spec:
type: NodePort
ports:
- name: web
port: 8080
nodePort: 30001
The nodePort value must be within the fixed range 30000–
32767.
This allows you to set up your own custom load balancer.
LoadBalancer
This option is valid only on cloud providers that support exter‐
nal load balancers. It builds upon the NodePort type. The cloud
provider exposes an external load balancer that forwards the
request from the load balancer to each node and the exposed
port:
spec:
. . .
type: LoadBalancer
This chapter explains how to get more details about the Kubernetes
cluster. It introduces the Kubernetes dashboard and basic CLI com‐
mands, discusses application logs and other means of debugging the
application, and covers monitoring an application’s performance
using add-on components of Heapster, InfluxDB, and Grafana.
The Kubernetes administration guide provides a comprehensive set
of docs on Kubernetes administration.
Cluster Details
Once the cluster is up and running, often you’ll want to get more
details about it. You can obtain these details using kubectl. In addi‐
tion, you can use the Kubernetes dashboard, a general-purpose,
web-based UI, to view this information as well. It can be used to
manage the cluster and applications running in the cluster.
The dashboard is accessible at the URI http://<kubernetes-
master>/ui. This URI is redirected to this URI:
http://<kubernetes-master>:8443/api/v1/proxy/namespaces/kube-
system/services/kubernetes-dashboard
59
dashboard for a cluster installed using Kops. “Running Kubernetes
Locally via Minikube” explains how to enable the dashboard for a
cluster started using Minikube.
Figure 4-1 shows a view of dashboard with a Couchbase cluster and
a WildFly replication controller.
It shows all the nodes and namespaces in the cluster. Once you
choose a namespace, you’ll see different resources within that name‐
space, such as deployments, replica sets, replication controllers, and
daemon sets. You can create and manage each resource by upload‐
ing the resource configuration file.
The information in the dashboard is also accessible via the kubectl
commands.
The kubectl cluster-info command displays the addresses of the
master and services with the label kubernetes.io/cluster-
service=true. The output from the Minikube install is shown in
Example 4-1.
60 | Chapter 4: Administration
The output shows the URI of the master, the DNS service, and the
dashboard.
Example 4-2 shows similar output from a Kubernetes cluster run‐
ning on AWS.
This output does not have the dashboard URL because that compo‐
nent has not been installed yet.
As the output states, complete details about the cluster can be
obtained with the kubectl cluster-info dump command.
More details about the client (i.e., kubectl CLI) and the server (i.e.,
Kubernetes API server) can be obtained with the kubectl version
command. The output looks like the following:
Client Version: version.Info{Major:"1", Minor:"6", GitVersion:
"v1.6.2", GitCommit:"477efc3cbe6a7effca06bd1452fa356e2201e
1ee", GitTreeState:"clean", BuildDate:"2017-04-19T20:33:11
Z", GoVersion:"go1.7.5", Compiler:"gc", Platform:"darwin/
amd64"}
Server Version: version.Info{Major:"1", Minor:"6", GitVersion:
"v1.6.0", GitCommit:"fff5156092b56e6bd60fff75aad4dc9de6b6ef
37", GitTreeState:"dirty", BuildDate:"2017-04-07T20:46:46Z",
GoVersion:"go1.7.3", Compiler:"gc", Platform:"linux/amd64"}
The output prints two lines, one each for the client and server. The
value of the Major and Minor attributes defines the Kubernetes API
server used by each one. Both use version 1.4 in our case. Other
detailed information about the binary requesting and serving the
Kubernetes API is displayed as well.
The kubectl get nodes command provides basic information—
name, status, and age—about each node in the cluster. kubectl
describe nodes provides detailed information about each node in
the cluster. This include pods running on a node; CPU and memory
requests and limits for each pod; labels, events, and conditions for
each node in the cluster.
Cluster Details | 61
The kubectl top command displays resource consumption for
nodes or pods. For nodes, it shows how many cores and memory are
allocated to each node. It shows percent utilization for both of them
as well.
Application Logs
Accessing application logs is typically the first step to debugging any
errors. These logs provide valuable information about what might
have gone wrong. Kubernetes provides integrated support for log‐
ging during development and production.
The kubectl logs command prints standard output and standard
error output from the container(s) in a pod. If there is only one con‐
tainer in the pod, the container name is optional. If the pod consists
of multiple containers, the container name must be specified—for
example, kubectl logs <pod-name> <container-name>.
Some other relevant options for the command are:
You can view the complete set of options using kubectl logs --
help.
This command is typically useful during early development stages,
when there is only a handful of pods. An application typically con‐
sists of multiple replication controllers, each of which may create
multiple pods. Existing pods may be terminated and new pods may
be created by Kubernetes, based upon your application. Viewing
application logs across multiple pods and containers using this com‐
mand may not be the most efficient approach.
Kubernetes supports cluster-level logging that allows you to collect,
manage, and query the logs of an application composed of multiple
pods. Cluster-level logging allows you to collect logs that persist
beyond the lifetime of the pod’s container images or the lifetime of
the pod or even cluster.
62 | Chapter 4: Administration
A typical usage is to manage these logs using ElasticSearch and
Kibana. The logs can also be ingested in Google Cloud Logging.
Additional logfiles from the container, specific to the application,
can be sent to the cluster’s ElasticSearch or Google Cloud Logging
service.
Debugging Applications
As explained in the previous section, debugging an application typi‐
cally requires looking at application logs. If that approach does not
work, you need to start getting more details about the resources.
The kubectl get command is used to display basic information
about one or more resources. Some of the common resource names
are pods (aka pod), replicasets (aka rs), services (aka svc), and
deployments (aka deploy). For example, kubectl get pods will
display the list of pods as follows:
NAME READY STATUS RESTARTS AGE
couchbase-master-rc-o9ri3 1/1 Running 0 1h
couchbase-worker-rc-i49rt 1/1 Running 0 1h
couchbase-worker-rc-pjdkh 1/1 Running 0 1h
couchbase-worker-rc-qlshi 1/1 Running 0 1h
wildfly-rc-rlu6o 1/1 Running 0 1h
wildfly-rc-uc79a 1/1 Running 1 1h
kubectl --help shows the complete list of resource names that can
be used with this command.
By default, basic details about each resource are shown. To display
only the name for each resource, use the -o name option. To see a
complete JSON or YAML representation of the resource, use the -o
json and -o yaml options, respectively.
You can use -w to watch for state changes of a resource. This is par‐
ticularly useful when you’re creating pods using replication control‐
lers. It allows you to see the pod going through different stages.
With multiple applications deployed in the cluster, it’s likely that the
pods created by each application will have specific labels. You can
use the -l option to query resources, using the selector (label query)
to filter on.
The kubectl describe command can be used to get more details
about a specific resource or a group of resources. For example, the
kubectl get svc command shows the list of all services:
Debugging Applications | 63
Name: couchbase-master-service
Namespace: default
Labels: app=couchbase-master-service
Selector: app=couchbase-master-pod
Type: LoadBalancer
IP: 10.0.0.235
Port: <unset> 8091/TCP
NodePort: <unset> 31854/TCP
Endpoints: 172.17.0.4:8091
Session Affinity: None
No events.
Name: kubernetes
Namespace: default
Labels: component=apiserver
provider=kubernetes
Selector: <none>
Type: ClusterIP
IP: 10.0.0.1
Port: https 443/TCP
Endpoints: 10.0.2.15:8443
Session Affinity: ClientIP
You can use the kubectl get events command to see all events in
the cluster. These events provide a high-level view of what is hap‐
pening in the cluster. To obtain events from a specific namespace,
you can use the --namespace=<namespace> option.
kubectl attach can be used to attach to a process that is already
running inside an existing container. This is possible only if the con‐
tainer’s specification has the stdin and tty attributes set to true, as
shown in Example 4-3.
64 | Chapter 4: Administration
containers:
- name: wildfly
image: jboss/wildfly
stdin: true
tty: true
ports:
- containerPort: 8080
Debugging Applications | 65
Application Performance Monitoring
You can monitor the performance of an application in a Kubernetes
cluster at multiple levels: whole cluster, services, pods, and contain‐
ers. Figure 4-2 shows how this information is collected.
66 | Chapter 4: Administration
performance requirements. It exposes an easy-to-use API to
write and fetch time series data. Heapster in Kubernetes is set
up to use InfluxDB as the storage backend by default on most
Kubernetes clusters. Other storage backends, such as Google
Cloud Monitoring, are supported as well.
Grafana
Grafana is an open source metric analytics and visualization
suite. It is most commonly used for visualizing time series data
for infrastructure and application analytics. It is available out of
the box in a Kubernetes cluster. The Grafana container serves
Grafana’s UI, which provides an easy-to-configure dashboard
interface for visualizing application performance in a Kuber‐
netes cluster.
The default dashboard for Kubernetes contains an example dash‐
board that monitors resource usage of the cluster and the pods
within it. This dashboard can easily be customized and expanded.
If you are using a Kubernetes cluster on AWS, then Heapster,
InfluxDB, and Grafana are already available. If you’re using Mini‐
kube or Kops, then these add-ons need to be enabled.
You can obtain complete details about different endpoints in the
cluster using the kubectl cluster-info command. The output
looks as shown in Example 4-2.
Access the Grafana endpoint URI in a browser. Use kubectl config
view to get the login name and password.
The cluster dashboard is shown in Figure 4-3.
68 | Chapter 4: Administration
CHAPTER 5
Conclusion
69
teams can then create a production-ready cluster on a cloud pro‐
vider and use the same configuration files to deploy the application.
Docker’s container donation to the Cloud Native Computing Foun‐
dation only enables a closer collaboration between the two projects.
Kubernetes already supports different container formats. The Open
Container Initiative is working on creating open industry standards
around container formats and runtime. Projects like CRI-O will
enable standardized support for containers in Kubernetes.
Even though not a strict requirement, containers simplify microser‐
vices deployment. There are some common tenets behind both: the
single responsibility principle, isolation, explicitly published inter‐
face, service discovery, and ability to scale. All of these aspects are
embraced by Kubernetes as well.
There is a lot of excitement and an equal amount of work happening
in this space. This is not just hype—containers provide the real and
credible benefits of simplicity and portability. Kubernetes orchestra‐
tion simplifies the plumbing needed to get those containers up and
running at all times.
If you have yet to explore the world of container orchestration, let
me just say, “Toto, we’re not in Kansas anymore!”
70 | Chapter 5: Conclusion
About the Author
Arun Gupta is a Principal Open Source Technologist at Amazon
Web Services. He has built and led developer communities for 10+
years at Sun, Oracle, Red Hat, and Couchbase. He has deep expertise
in leading cross-functional teams to develop and execute strategy,
content, marketing campaigns, and programs. Prior to that he led
engineering teams at Sun and is a founding member of the Java EE
team. Gupta has authored more than 2,000 blog posts on technol‐
ogy. He has extensive speaking experience in more than 40 countries
on myriad topics and has been a JavaOne Rock Star for four years in
a row. Gupta also founded the Devoxx4Kids chapter in the US and
continues to promote technology education among children. An
author of several books on technology, an avid runner, a globe trot‐
ter, a Java Champion, a JUG leader, a NetBeans Dream Team mem‐
ber, and a Docker Captain, he is easily accessible at @arungupta.