Stupid Simple Kubernetes
Stupid Simple Kubernetes
Stupid Simple Kubernetes
Kubernetes
by Zoltán Czakó
Welcome to Stupid Simple Kubernetes
In software development, the single constant is that everything In this e-book, we will show you how to build a stable, easily
changes fast. Good developers are always prepared for manageable, highly available microservices architecture. In
change: the framework you’re working on today could be the first part, we will introduce Kubernetes, its components and
outdated in a few months. One way to prepare for change is building blocks. Then, we will build a small sample application
to create loosely coupled, independent components that can based on a microservices architecture. We’ll define the
be easily replaced. Kubernetes scripts to create the Deployments, Services,
Ingress Controllers and Persistent Volumes and then deploy
As software and tools change, so do application architectures. this ecosystem in Azure Cloud.
Recently we’ve witnessed an evolution from traditional
monolithic architecture, where all components of the In the second part of this book, we will dive into scalability
application are packed as a single atonomous unit, to and we will define different Kubernetes configuration files for
service-oriented architecture, to today’s microservices Horizontal and Vertical Pod Autoscaling and also for Cluster
architecture. Autoscaling.
Microservices architectures have sprung up because of In the last part of the book, we will present different solutions
changes in tools, programming languages and development for easily handling all the cross-cutting concerns that we
environments. To keep up with new technologies, you need a presented when using Service Meshes. We’ll build our own
way to add new, independent components at any time. These Service Mesh using Envoy proxies and then use Istio to handle
components must be free to use whatever technology they like, all these concerns automatically.
so they can be built using different programming languages
and frameworks, databases or even communication protocols. Ready to get started with Kubernetes? Let’s go.
Chapter 2 Chapter 6
Chapter 3 Chapter 7
Chapter 4 Conclusion
Nodes
As you will see in the next chapter, the beauty of this abstraction
is that we don’t need to know the underlying hardware
structure. We will just use nodes; this way, our infrastructure is
platform independent.
Container
The primary role of deployment is to provide declarative StatefulSet is a new concept in Kubernetes, and it is a resource
updates to both the pod and the ReplicaSet (a set in which the used to manage stateful applications. It manages the
same pod is replicated multiple times). Using the deployment, deployment and scaling of a set of pods and guarantees these
we can specify how many replicas of the same pod should be pods’ ordering and uniqueness. It is similar to deployment;
running at any time. The deployment is like a manager for the the only difference is that the deployment creates a set of
pods; it automatically spins up the number of pods requested, pods with random pod names and the order of the pods
monitors the pods and recreates the pods in case of failure. is not important, while the StatefulSet creates pods with a
Deployments are helpful because you don’t have to create unique naming convention and order. So, if you want to create
and manage each pod separately. three replicas of a pod called example, the StatefulSet will
create pods with the following names: example-0, example-1,
example-2. In this case, the most important benefit is that you
can rely on the name of the pods.
DaemonSets
While deployment is responsible for keeping a set of pods If you want to deploy to multiple environments, like staging,
running, the service is responsible for enabling network dev and prod, it’s a bad practice to bake the configs into the
access to a set of pods. Services provide standardized features application because of environmental differences. Ideally,
across the cluster: load balancing, service discovery between you’ll want to separate configurations to match the deploy
applications and zero-downtime application deployments. environment. This is where ConfigMap comes into play.
Each service has a unique IP address and a DNS hostname. ConfigMaps allow you to decouple configuration artifacts
Applications that consume a service can be manually from image content to keep containerized applications
Now that you’ve got the services running in your cluster, how
do you get external traffic into your cluster? There are three
different service types for handling external traffic: ClusterIP,
NodePort and LoadBalancer. The 4th solution is to add another
layer of abstraction, called Ingress Controller.
ClusterIP
Declaring a service of type LoadBalancer exposes it externally Ingress is not a service but an API object that manages external
using a cloud provider’s load balancer. How the external load access to a cluster’s services. It acts as a reverse proxy and
balancer routes traffic to the Service pods depends on the single entry-point to your cluster that routes the request
cluster provider. With this solution, you don’t have to manage to different services. I usually use NGINX Ingress Controller,
all the IP addresses of every node of the cluster, but you will which takes on reverse proxy while also functioning as SSL. The
have one load balancer per service. The downside is that every best production-ready solution to expose the ingress is to use
service has a separate load balancer and you will be billed per a load balancer.
Deployments,
Services and
Ingresses Explained
In the first chapter, we learned about the basic concepts
used in Kubernetes, its hardware structure, the different
software components like Pods, Deployments, StatefulSets,
Services, Ingresses and Persistent Volumes and saw how to
communicate between services and with the outside world.
NOTE: the scripts are platform agnostic, so you can follow the
tutorial using other types of cloud providers or a local cluster
with K3s. I suggest using K3s because it is very lightweight,
packed in a single binary less than 40MB. What’s more, it’s a
highly available, certified Kubernetes distribution designed for
production workloads in resource-constrained environments.
For more information, you can take a look over its well-written
and easy-to-follow documentation.
Before starting this tutorial, please make sure that you have The Docker file for NodeJS:
FROM node:13.10.1
installed Docker. Kubectl will be installed with Docker. (If not, WORKDIR /usr/src/app
COPY package*.json ./
please install it from here). RUN npm install
# Bundle app source
COPY . .
EXPOSE 3000
The Kubectl commands used throughout this tutorial can be CMD [ “node”, “index.js” ]
found in the Kubectl Cheat Sheet.
Microservices This image comes with Node.js and NPM already installed so
Note the little dot from the end of the Docker command,
it means that we are building our image from the current
directory, so please make sure that you are in the same folder,
where the Dockerfile is located (in this case the root folder of
the repository).
NodeJs backend In each Kubernetes .yml script we have to define the Kubernetes
resource type (Pods, Deployments, Services, etc.) using the
The next step is to define the Kubernetes Deployment script,
kind keyword. In this case, in line 2 we defined that we would
which automatically manages the Pods for us.
like to use the Deployment resource.
MongoDB
The Deployment script for the MongoDB database is quite In this case, we used the official MongoDB image directly from
similar. The only difference is that we have to specify the the DockerHub (line 17). The volume mounts are defined in line
volume mounts (the folder on the node where the data will 24. The last four lines will be explained in the next chapter when
be saved). we will talk about Kubernetes Persistent Volumes.
for Network Access to which we want to refer from this Service. As you can see
in line 8, the selector is app:node-user-service-pod, because
the Pods from the previously defined Deployment are labeled
Now that we have the Pods up and running, we should like this. Another important thing is to define the mapping
define the communication between the containers and with between the container port and the Service port. In this case,
the outside world. For this, we need to define a Service. The the incoming request will use the 3000 port, defined on line 10
relation between a Service and a Deployment is 1-to-1, so for and they will be routed to the port defined in line 11.
each Deployment, we should have a Service. The Deployment
manages the lifecycle of the Pods and it is also responsible for The Kubernetes Service script for the MongoDB pods is very
monitoring them, while the Service is responsible for enabling similar. We just have to update the selector and the ports.
network access to a set of Pods (as we saw in Chapter One).
apiVersion: v1
kind: Service
metadata:
name: user-db-service
apiVersion: v1 spec:
kind: Service clusterIP: None
metadata: selector:
name: node-user-service app: user-db-app
spec: ports:
type: ClusterIP - port: 27017
selector: targetPort: 27017
app: node-user-service-pod
ports:
- port: 3000
targetPort: 3000
External Traffic
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
To communicate with the outside world, we need to define externalTrafficPolicy: Local
type: LoadBalancer
an Ingress Controller and specify the routing rules using an
selector:
Ingress Kubernetes Resource. app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
ports:
- name: http
To configure an NGINX Ingress Controller we will use the script port: 80
targetPort: http
that can be found here. - name: https
port: 443
targetPort: https
The next step is to define the Load Balancer, which will be used
to route external traffic using a public IP address (the cloud
provider provides the load balancer).
Persistent
Volumes Explained
Welcome back to our series, where we introduce you to the
basic concepts of Kubernetes. In the first chapter, we provided
a brief introduction to Persistent Volumes. Here, we’ll dig into
this topic: we will learn how to set up data persistency and will
write Kubernetes scripts to connect our Pods to a Persistent
Volume. In this example, we will use Azure File Storage to store
the data from our MongoDB database, but you can use any
kind of volume to achieve to same results (such as Azure Disk,
GCE Persistent Disk, AWS Elastic Block Store, etc.)
Through this tutorial, we will use Visual Studio Code, but this is
not mandatory.
Persistent Volumes make the consumption of cloud storage much more seamless
and eliminate integration costs. It can also make it much
easier to migrate between clouds and adopt multi-cloud
stateful applications in the container ecosystem. time or manpower (which are closely related) you have to
make some compromises and directly couple your app with a
Every project needs some kind of data persistency, so usually, specific platform or provider, you should try to avoid as many
you need a database to store the data. But in a clean design, direct dependencies as possible. One way of decoupling your
you don’t want to depend on concrete implementations; application from the actual database implementation (there
you want to write an application as reusable and platform are other solutions, but those solutions require more effort) is
There has always been a need to hide the details of storage specific implementation.
environments where applications or users who want to access database with Persistent Volume, or what are the storage
the data need to integrate with a specific storage system. system types which should NOT be used in containers?
which create an unhealthy dependency. Kubernetes is trying Persistent Volumes, but as a starting point, you should have in
to change this by creating an abstraction called Persistent mind scalability and the handling of the loss of node in the
database application can independently re-balance. These can be cloud volumes (like gcePersistentDisk,
awsElasticBlockStore, azureFile or azureDisk), NFS (Network File
Usually, you can and should containerize distributed Systems) or Persistent Volume Claims (a series of abstraction
databases that use redundant storage techniques and to connect to the underlying cloud provided storage volumes).
withstand the loss of a node in the database cluster
(ElasticSearch is a really good example). Based on the way the volumes are provisioned, we can have:
1. Direct access
2. Static provisioning
3. Dynamic provisioning
apiVersion: v1
kind: Secret
metadata:
name: static-persistence-secret
type: Opaque
data:
azurestorageaccountname: “base64StorageAccountName”
azurestorageaccountkey: “base64StorageAccountKey”
In this case, the pod will be directly coupled with the volume, As in any Kubernetes script, on line 2 we specify the type of the
so it will know the storage system (for example, the Pod will be resource -- in this case, Secret. On line 4, we give it a name (we
coupled with the Azure Storage Account). This solution is not called it static because it is manually created by the Admin
cloud-agnostic and it depends on a concrete implementation and not automatically generated). The Opaque type, from
and not an abstraction. So if possible, please avoid this solution. Kubernetes’ point of view, means that the content (data) of
The only advantage is that it is easy and fast. Create the Secret this Secret is unstructured (it can contain arbitrary key-value
in the Pod and specify the Secret and the exact storage type pairs). To learn more about Kubernetes Secrets, see the Secrets
that should be used. design document and Configure Kubernetes Secrets.
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-db-deployment
Kubernetes Storage Class
spec:
selector:
To understand the Static or Dynamic provisioning, first we
matchLabels:
app: user-db-app have to understand the Kubernetes Storage Class.
replicas: 1
template:
metadata:
labels: With StorageClass, administrators can offer Profiles or
app: user-db-app
spec: “classes” regarding the available storage. Different classes
containers:
- name: mongo might map to quality-of-service levels, or backup policies or
image: mongo:3.6.4
command: arbitrary policies determined by the cluster administrators.
- mongod
- “--bind_ip_all”
- “--directoryperdb”
For example, you could have a profile to store data on an
ports:
- containerPort: 27017 HDD named slow-storage or a profile to store data on an SSD
volumeMounts:
- name: data named fast-storage. The kind of storage is determined by
mountPath: /data/db
resources: the Provisioner. For Azure, there are two kinds of provisioners:
limits:
memory: “256Mi” AzureFile and AzureDisk (the difference is that AzureFile
cpu: “500m”
volumes: can be used with ReadWriteMany access mode, while
- name: data
azureFile: AzureDisk supports only ReadWriteOnce access, which can
secretName: static-persistence-secret
shareName: user-mongo-db
be a disadvantage when you want to use multiple pods
readOnly: false
simultaneously). You can learn more about the different types
of StorageClasses here.
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: azurefilestorage
provisioner: kubernetes.io/azure-file
parameters:
storageAccount: storageaccountname
reclaimPolicy: Retain
allowVolumeExpansion: true
This means that the Admin will create the Persistent Volume
to specify the type of storage that can be used by the Pods,
In this case, there is NO PersistentVolume and Secret created
the size of the storage, and the access mode. The Developer
manually, so Kubernetes will try to generate them. The
will create a Persistent Volume Claim asking for a piece of
StorageClass is mandatory and we will use the one created
volume, access permission and the type of storage. This way
earlier.
there is a clear separation between “Dev” and “Ops.” Devs
are responsible for asking for the necessary volume (PVC)
The script for the PersistentVolumeClaim can be found below:
and Ops are responsible for preparing and provisioning the
requested volume (PV).
apiVersion: v1
kind: PersistentVolumeClaim
The difference between Static and Dynamic provisioning is metadata:
name: persistent-volume-claim-mongo
that if there isn’t a PersistentVolume and a Secret created spec:
accessModes:
manually by the Admin, Kubernetes will try to automatically - ReadWriteMany
resources:
create these resources. requests:
storage: 1Gi
storageClassName: azurefilestorage
apiVersion: v1
kind: PersistentVolume
metadata:
name: static-persistent-volume-mongo In this tutorial, we learned how to persist data and state
labels:
storage: azurefile using Volumes. We presented three different ways of setting
spec:
up your system, Direct Access, Dynamic Provisioning and
capacity:
storage: 1Gi Static Provisioning and discussed the advantages and
accessModes:
- ReadWriteMany disadvantages of each.
storageClassName: azurefilestorage
azureFile:
secretName: static-persistence-secret
shareName: user-mongo-db In the next chapter, we will talk about CI/CD pipelines to
readOnly: false
automate the deployment of Microservices.
Create an
Azure Infrastructure
for Microservices
In the first chapter, we learned about the basic concepts used
in Kubernetes and its hardware structure. We talked about the
different software components, including Pods, Deployments,
StatefulSets and Services and how to communicate between
services and with the outside world.
Through this tutorial, we will use Visual Studio Code, but this is
not mandatory.
Production Ready
Azure Infrastructure for
Microservices
To have a fast setup, I’ve created an ARM Template, which will Based on this information, you will have to update the ARM
automatically spin up all the Azure resources needed for this Template to use your Service Principal. For this, please copy
tutorial. You can read more about ARM Templates here. the appId from the returned JSON to the clientId in the ARM
Template. Also, copy the password and paste it into the ARM
We will run all the scripts in the VS Code Terminal. Template’s secret field.
The first step is to log in to your Azure account from the VS In the next step, you should create a new Resource Group
Code Terminal. For this run az login. This will open a new tab called “StupidSimpleKubernetes” in your Azure Portal and
in your default browser, where you can enter your credentials. import the ARM template to it.
After the ARM Template Deployment is done, we should have the following Azure resources:
In the right menu, search for the correct Service Principal (use the Z from the returned JSON object — see the Service Principal image
above).
After this step, our Kubernetes Service will be able to pull the right Docker images from the Azure Container Registry. We will store all
our custom Docker images in this Azure Container Registry.
We are almost ready! In the last step, we will set up the NGNIX Ingress Controller and add a RecordSet to our DNS. This assigns a hu-
man-readable hostname to our services instead of using the IP:PORT of the Load Balancer.
This will create a new public IP, which you can see in the Azure Portal:
Stupid Simple
Scalability
This post will define and explain software scalability in employee can handle only one client per minute. You decide to
Kubernetes and look at different scalability types. Then we hire two more employees. With this, you’ve solved the problem
will present three autoscaling methods in Kubernetes: HPA for a while.
(Horizontal Pod Autoscaler), VPA (Vertical Pod Autoscaler), and
CA (Cluster Autoscaler). After some time, near the coffee shop, the city opens a fun
park, so more and more tourists are coming and drinking
their coffee in your famous coffee shop. So you decide to hire
Scalability Explained more people, but even with more employees, the waiting time
is almost the same. The problem is that your coffee machine
can make three coffees per minute, so now your employees
To understand the different concepts in software scalability,
are waiting for the coffee machine. The solution is to buy a new
let’s take a real-life example.
coffee machine. Another problem is that the clients tend to
buy coffee from employees that they already know. As a result,
Suppose you’ve just opened a coffee shop, you bought a
some employees have a lot of work, and others are idle. This
simple coffee machine, which can make three coffees per
is when you decide you need to hire another employee who
minute, and you hired an employee who serves the clients.
will greet the clients and redirect them to the employee who is
free or has fewer orders to prepare.
At first, you have a few clients: everything is going well, and
all the people are happy about the coffee and the service
Analyzing your income and expenses, you realize that you
because they don’t have to wait too long to get their delicious
have many more clients during the summer than in the winter,
coffee. As time goes by, your coffee shop becomes famous in
so you decide to hire seasonal workers. Now you have three
town, and more and more people are buying their coffee from
employees working full-time and the other employees are
you. But there is a problem. You have only one employee and
working for you only during the summer. This way, you can
too many clients, so the waiting time gets considerably higher
increase your income and decrease expenses. Furthermore,
and people are starting to complain about your service. The
you can rent some coffee machines during the summer and
coffee machine could make three coffees per minute, but the
give them back during the winter to minimize the costs. This
Autoscaling (HPA) API for each pod. Using these metrics, it calculates the actual
resource utilization values based on the mean values of all the
pods and compares them to the metrics defined in the HPA
definition. To calculate the desired number of replicas, HPA
uses the following formula:
desiredReplicas = ceil[currentReplicas*(currentMet-
ricValue/desiredMetricValue)]
spec:
containers:
- name: php-apache
image: k8s.gcr.io/hpa-example
Horizontal scaling or scaling out means that the number of ports:
running pods dynamically increases or decreases as your - containerPort: 80
application usage changes. To know exactly when to increase resources:
or decrease the number of replicas, Kubernetes uses triggers limits:
based on the observed metrics (average CPU utilization, cpu: 500m
average memory utilization, or custom metrics defined by requests:
the user). HPA, a Kubernetes resource, runs in a loop (the loop cpu: 200m
Suppose that the CPU usage has increased to 210 percent; this
means that we will have nrReplicas = ceil[ 1 * ( 210 / 50 )] =
ceil[4.2] = 5 replicas.
Autoscaling (VPA) that the cluster resources are efficiently used). VPA won’t add
more replicas of a Pod, but it increases the memory or CPU
limits. This is useful when adding more replicas won’t help your
solution. For example, sometimes you can’t scale a database
(read Chapter Three, Persistent Volumes Explained) just by
adding more Pods. Still, you can make the database handle
more connections by increasing the memory or CPU. You can
use the VPA when your application serves heavyweight re-
quests, which requires higher resources.
HPA and VPA are incompatible. Do not use both together for
the same set of pods. HPA uses the resource request and limits
to trigger scaling, and in the meantime, VPA modifies those
limits, so it will be a mess unless you configure the HPA to use
either custom or external metrics. Read more about VPA and
HPA here.
Stupid Simple
Service Mesh -
What, When, Why
Recently microservices-based applications became very
popular and with the rise of microservices, the concept of
Service Mesh also became a very hot topic. Unfortunately,
there are only a few articles about this concept and most of
them are hard to digest.
API Gateway vs. Service 1. Ingress Controller: allows a single IP port to access all services
Mesh from the cluster, so its main responsibilities are path mapping,
routing and simple load balancing, like a reverse proxy
As best practices suggest, proxy and service should be Ingress and Egress
in separate containers, so each container has a single
responsibility. In the world of Kubernetes, the container of
the proxy is implemented as a sidecar. This means that each
service has a sidecar containing the proxy. A single Pod will
contain two containers: the service and the sidecar. Another
implementation is to use one proxy for multiple pods. In this
case, the proxy can be implemented as a Deamonset. The
Simple definitions:
most common solution is using sidecars. Personally, I prefer
sidecars over Deamonsets, because they keep the logic of the
proxy as simple as possible.
• Any traffic sent to the server (service) is called ingress.
• Any traffic sent from the server (service) is called egress.
before starting with these higher-level solutions, it’s a good service using Service Discovery. By intercepting the inbound
idea to understand the low-level functioning. and outbound traffic, Envoy can implement service discovery,
circuit breaker, rate limiting, etc.
--- match:
admin: path: “/”
access_log_path: “/tmp/admin_access.log” route:
address: cluster: “base”
socket_address: http_filters:
address: “127.0.0.1” -
port_value: 9901 name: “envoy.router”
static_resources: config: {}
listeners:
- clusters:
name: “http_listener” -
address: name: “base”
socket_address: connect_timeout: “0.25s”
address: “0.0.0.0” type: “strict_dns”
port_value: 80 lb_policy: “ROUND_ROBIN”
filter_chains: hosts:
filters: -
- socket_address:
name: “envoy.http_connection_manager” address: “service_1_envoy”
config: port_value: 8786
stat_prefix: “ingress” -
codec_type: “AUTO” socket_address:
generate_request_id: true address: “service_2_envoy”
route_config: port_value: 8789
name: “local_route” -
virtual_hosts: name: “nodejs”
- connect_timeout: “0.25s”
name: “http-route” type: “strict_dns”
domains: lb_policy: “ROUND_ROBIN”
- “*” hosts:
routes: -
- socket_address:
match: address: “service_4_envoy”
prefix: “/nestjs” port_value: 8792
route: -
prefix_rewrite: “/” name: “nestjs”
cluster: “nestjs” connect_timeout: “0.25s”
- type: “strict_dns”
match: lb_policy: “ROUND_ROBIN”
prefix: “/nodejs” hosts:
route: -
prefix_rewrite: “/” socket_address:
cluster: “nodejs” address: “service_5_envoy”
- port_value: 8793
This diagram did not include all configuration files for all the
services, but it is enough to understand the basics. You can
find this code in my Stupid Simple Service Mesh repository.
As you can see, between lines 10-15 we defined the Listener for
our Envoy proxy. Because we are working in Docker, the host is
0.0.0.0.
In the next chapter, we will look at how to use Service Mesh with Kubernetes and will create an example project that can be used as
a starting point in any project using microservices.
Stupid Simple
Service Mesh
in Kubernetes
To understand the estimate, let’s understand what we need
Stupid Simple Service to do in order to have a functional rating microservice. The
Mesh in Kubernetes CRUD (Create, Read, Update, Delete) part is easy -- just simple
coding. But adding this new project to our microservices-based
application is not trivial. First, we have to implement
authentication and authorization, then we need some kind of
We covered the what, when and why of Service Mesh in an
tracing to understand what is happening in our application.
earlier chapter. Now I’d like to talk about why they are critical
Because the network is not reliable (unstable connections can
in Kubernetes.
result in data loss), we have to think about solutions for retries,
circuit breakers, timeouts, etc.
To understand the importance of using service meshes when
working with microservices-based applications, let’s start with
We also need to think about deployment strategies. Maybe we
a story.
want to use shadow deployments to test our code in production
without impacting the users. Maybe we want to add A/B testing
Suppose that you are working on a big microservices-based
capabilities or canary deployments. So even if we create just a
banking application, where any mistake can have serious
simple microservice, there are lots of cross-cutting concerns
impacts. One day the development team receives a feature
that we have to keep in mind.
request to add a rating functionality to the application. The
solution is obvious: create a new microservice that can handle
Sometimes it is much easier to add a new functionality to an
user ratings. Now comes the hard part. The team must come
existing service, than create a new service and add it to our
up with a reasonable time estimate to add this new service.
infrastructure. It can take a lot of time to deploy a new service,
to add authentication and authorization, to configure tracing,
The team estimates that the rating system can be finished in 4
to create CI/CD pipelines, to implement retry mechanisms
sprints. The manager is angry. He cannot understand why it is
and more. But adding the new feature to an existing service
so hard to add a simple rating functionality to the app.
will make the service too big. It will also break the rule of single
responsibility, and like many existing microservices projects, it
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: http-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts: - “*”
Traffic Management
metadata:
name: service2
spec:
Traffic splitting is a technique used to test your new version of In canary deployments, newer versions of services
a service by letting only a small part (a subset) of users to are incrementally rolled out to users to minimize the risk and
interact with the new service. This way, if there is a bug in the impact of any bugs introduced by the newer version.
new service, only a small subset of end users will be affected.
This can be achieved by gradually decreasing the weight of
This can be achieved by modifying our virtual service the old version while increasing the weight of the new version.
as follows:
apiVersion: networking.istio.io/v1alpha3
A/B Testing
kind: VirtualService
metadata: This technique is used when we have two or more different
name: service2
spec: user interfaces and we would like to test which one offers a
hosts:
- service2 better user experience. We deploy all the different versions
http:
- route: and we collect metrics about the user interaction. A/B testing
- destination:
host: service2
can be configured using a load balancer based on consistent
subset: v1 hashing or by using subsets.
weight: 90
- destination:
host: service2
subset: v2
weight: 10
The most important part to notice is the spec -> template ->
metadata -> version: v2. The other service has the version:
v1 tag.
retries:
attempts: 5
perTryTimeout: 10s
With this configuration, our service2 will have five retry attempts
in case of failure and it will wait 10 seconds before returning a
timeout.
Become a
Microservices Master
You’ve made it through our Stupid Simple Kubernetes e-book. Congratulations! You are well on your way to becoming
a microservices master.
There are many more resources available to further your learning Microservices, including the Microservices.io website. Similarly,
there are many Kubernetes resources out there. One of our favorites is The Illustrated Children’s Guide to Kubernetes video.
I strongly encourage you to get hands on and continue your learning. The SUSE & Rancher Community is a great place to start – and
is welcoming to learners at all levels. Whether you are interested in an introductory Kubernetes class or ready to go deeper with a
mutli-week class on K3s, they’ve got it all. Join the free community today!
Zoltán Czakó
SUSE puts the “open” back in open source, giving customers the agility to tackle
innovation challenges today and the freedom to evolve their strategy and solutions
tomorrow. The company employs more than 2,000 people globally. SUSE is listed on
the Frankfurt Stock Exchange.