Toye Idowu – BMC Software | Blogs https://s7280.pcdn.co Thu, 02 Dec 2021 13:02:48 +0000 en-US hourly 1 https://s7280.pcdn.co/wp-content/uploads/2016/04/bmc_favicon-300x300-36x36.png Toye Idowu – BMC Software | Blogs https://s7280.pcdn.co 32 32 How Kubernetes Services Work https://s7280.pcdn.co/kubernetes-services/ Fri, 04 Jun 2021 00:00:36 +0000 https://www.bmc.com/blogs/?p=13237 A Kubernetes service is a logical collection of pods in a Kubernetes cluster. We can define a K8s service as an abstract way to load balance across the pods and expose an application deployed on a set of Pods. Moreover, using the inbuilt service mechanism in Kubernetes eliminates the need for implementing a separate service […]]]>

A Kubernetes service is a logical collection of pods in a Kubernetes cluster. We can define a K8s service as an abstract way to load balance across the pods and expose an application deployed on a set of Pods. Moreover, using the inbuilt service mechanism in Kubernetes eliminates the need for implementing a separate service discovery mechanism.

In this article, we will discuss the structure of a Kubernetes service and how to utilize it.

(This article is part of our Kubernetes Guide. Use the right-hand menu to navigate.)

What are Kubernetes services?

A Kubernetes service can be used to easily expose an application deployed on a set of pods using a single endpoint. A service is both a REST object and an abstraction that defines:

  • A set of pods
  • A policy to access them

Pods in a Kubernetes deployment are regularly created and destroyed, causing their IP addresses to change constantly. It will create discoverability issues for the deployed, application making it difficult for the application frontend to identify which pods to connect.

This is where the strengths of Kubernetes services come into play: services keep track of the changes in IP addresses and DNS names of the pods and expose them to the end-user as a single IP or DNS.

Kubernetes services utilize selectors to target a set of pods:

  • For native Kubernetes applications (which use Kubernetes APIs for service discovery), the endpoint API will be updated whenever there are changes to the pods in the service.
  • Non-native applications can use virtual-IP-based bridge or load balancer implementation methods offered by Kubernetes to direct traffic to the backend pods.

Attributes of a Kubernetes service

Here are general attributes of a service:

  • A service is assigned an IP address (“cluster IP”), which the service proxies use.
  • A service can map an incoming port to any targetPort. (By default, the targetPort is set to the same value of the port field, and it can be defined as a string.)
  • The port number assigned to each name can vary in each backend pod. (For example, you can change the port number that pods expose in the next version of your backend software without breaking clients.)
  • Services support TCP (default), UDP, and SCTP for protocols.
  • Services can be defined with or without a selector.
  • Services support a variety of port definitions

Now let’s see how services work.

Defining a Kubernetes service

As mentioned above, we can define Kubernetes services with or without selectors—let’s do both!

Defining a service with a selector

In the following example, we have defined a simple service exposing port 80 in the service while targeting port 8080 in the Pods with the selector label “app=webserver-nginx”.

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: webserver-nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

Kubernetes will automatically assign an IP address (“Cluster IP”) which will then be used by service proxies to route the traffic. The controller for the selector will consistently monitor for Pods matching the defined label.

Some applications will require multiple ports to be exposed via the service. Kubernetes facilitates this using multi-port services where a user can define multiple ports in a single service object. When defining a multi-port service, the main requirement is to provide names for each port exposed so that they are unambiguous. These port names can:

  • Only contain alphanumeric characters and the dash symbol
  • Should start and end with an alphanumeric character.

In this example, we have exposed both ports 80 and 443 to target ports 8080 and 8090 to route HTTP and HTTPS traffic to underlying pods using the selector “app=webserver-nginx-multiport”

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: webserver-nginx-multiport
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 8080
    - name: https
      protocol: TCP
      port: 443
      targetPort: 8090

Defining a service without a selector

When defining a service without a selector, you need to manually map the service to the corresponding IP address and port by adding an endpoints object. The reason is that the endpoint objects are not created automatically like with a selector since Kubernetes does not know to which Pods the service should be connected.

Service:

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

Endpoint:

apiVersion: v1
kind: Endpoints
metadata:
  name: nginx-service
subsets:
  - addresses:
      - ip: 192.10.0.1
    ports:
      - port: 8080

When defining a service and the endpoint, the main consideration is that both the name of the service and the endpoint must be an exact match.

Some use cases for services without selectors include:

  • Connecting to a different service on another Namespace or another cluster
  • Communicating with external services, data migration, testing services, deployments, etc.

Creating a Kubernetes service

Now that we know the basic structure of a Kubernetes service, let’s use a practical example to better understand how to create a service. First, we’ll create a small deployment with four replicas of an apache web server.

apache-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: apache-deployment
  labels:
    app: webserver
spec:
  replicas: 4
  selector:
    matchLabels:
      app: webserver
  template:
    metadata:
      labels:
        app: webserver
    spec:
      containers: 
      - name: apache
        image: bitnami/apache:latest
        ports:
        - containerPort: 80

Create the deployment.

kubectl apply -f apache-deployment.yaml

Result:

apache deployment
Check the status of the deployment.

kubectl get deployment apache-deployment

Result:

Get Deployment
Now we have deployed the application to the apache server.

Next, we will create a service to access our deployed application. There are two methods to do that, either:

  1. Create a YAML manifest for a service
  2. Use the “kubectl expose” command

The expose command allows users to create the service from the command line directly.

We can use the following command to expose the “apache-deployment” with the ClusterIP service type. We will point the service to port 8080 as the “bitnami/apache” image uses port 8080 as the HTTP port.

kubectl expose deployment apache-deployment --name=apache-http-service --type=ClusterIP --port=8080 --target-port=8080

Result:

expose deployment

Check whether the service is created correctly.

kubectl get service apache-http-service

Result:

http service
Now we need to forward the traffic to the service we created, and we can use the “kubectl port-forward” command for that. We will be directing traffic from host port 8090 to service port 8080.

kubectl port-forward service/apache-http-service 8090:8080

Result:

post forward

When we navigate to the “http://localhost:8090“, we will be directed to an Nginx landing page like the following.

local work

We could have also defined a service using a YAML file for the above scenario, as shown below. There we have set the selector as “app=webserver.”

apiVersion: v1
kind: Service
metadata:
  name: apache-http-service
spec:
  selector:
    app: webserver
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080

Types of Kubernetes services

There are four types of Kubernetes services:

kubernates-services

ClusterIP

This is the default type that exposes the service on an internal IP of the cluster. These services are only accessible within the cluster. So, users need to implement port forwarding or a proxy to expose a ClusterIP to a wider ingress of traffic.

NodePort

A NodePort service exposes the service on the IP of each node at a static port. A ClusterIP service is created automatically to route the traffic to the NordPort service. Users can communicate with the service from the outside by requesting <NodeIP>:<NodePort>

LoadBalancer

This is the preferred solution to expose the cluster to the wider internet. The LoadBalancer type of service will create a load balancer (load balancer type depends on the cloud provider) and expose the service externally.

It will also automatically create ClusterIP and NodePort services and route traffic accordingly.

ExternalName

This type of service maps the service to the contents of the externalName field (Ex: app.test.com). It does this by returning a value for the CNAME record.

Service proxy implementations

The kube-proxy process implements a form of virtual IPs for all the service types, excluding the ExternalName type. Using proxying for services enables users to mitigate some DNS resolution issues.

For example, if a DNS record is expired, there might be instances where previous DNS lookups are still cached with the expired record, leading to resolution issues. Similarly, DNS records not getting properly propagated can also lead to resolution issues.

The following three methods can be used by the kube-proxy for routing traffic:

  • Proxy-mode: userspace
  • Proxy-mode: iptables
  • Proxy-mode: ipvs

Proxy-mode: userspace

In this mode, kube-proxy monitors the Kubernetes master, and whenever a service or an endpoint gets created or removed, it allocates or deallocates a random port on the local node.

All the connections to this “proxy port” are proxied to the service and the necessary endpoints.

Proxy-mode: iptables

This mode also monitors the Kubernetes master for services and endpoints. However, it will also install iptable rules to capture traffic to the ClusterIp of the service and port and then redirect the traffic.

Additionally, it will install iptable rules for endpoint objects to select the backend Pod, while the default behavior is to select a random backend. (Pod)

Proxy-mode: ipvs

In this mode, the kube-proxy watches the services and endpoints and then calls the Netlink interface to create appropriate ipvs (IP Virtual Server) rules. This mode will periodically sync the ipvs rules with the services and endpoint to keep everything up to date.

Discovering Kubernetes services

You can use two methods to discover a service—DNS or Environment Variable.

DNS

This is the preferred method for service discovery. Here, the DNS server is added to the Kubernetes cluster that watches the Kubernetes API and creates DNS records for each new service. When the DNS is enabled, cluster-wide all Pods will be able to perform name resolution of services.

Environment Variables

In this method, kubelet adds environment variables to Pods for each active service. When using this method, the desired service must be created before creating the Pods which will use that service. Otherwise, the Pods would not get the necessary environment variables for the desired service.

Headless Services

When load-balancing and single service IP are not required, users can create a headless service by explicitly specifying “none” for the cluster IP field (.spec.clusterIP). These headless services do not have associated Cluster IPs, and no load balancing or proxying is provided for them by the platform. The Kube-proxy also ignores these services.

DNS configuration of these services depends on the selectors defined in the services.

  • Headless service with selectors. The endpoint controller will create the endpoint records in the API, modifying the DNS record to return an A record that points to the necessary Pods.
  • Headless service without selectors. The endpoint controller will not create any endpoint records without having the selectors configured.

Summing up K8s services

With that, we’ve covered all the basics of Kubernetes services. We now know about services, including the different types, service discovery, and service proxy usages. Services are an integral part of Kubernetes that provide means to facilitate communication between pods, external services, and users.

Related reading

]]>
Kubernetes Networking Basics https://www.bmc.com/blogs/kubernetes-networking/ Thu, 27 May 2021 00:00:31 +0000 https://www.bmc.com/blogs/?p=13346 Kubernetes networking is an integral part of managing and making communication easier within a Kubernetes cluster. It manages a wide range of operations, such as: Handling internal container communication Exposing the containers to the internet This article introduces you to key Kubernetes networking concepts. (This article is part of our Kubernetes Guide. Use the right-hand […]]]>

Kubernetes networking is an integral part of managing and making communication easier within a Kubernetes cluster. It manages a wide range of operations, such as:

  • Handling internal container communication
  • Exposing the containers to the internet

This article introduces you to key Kubernetes networking concepts.

(This article is part of our Kubernetes Guide. Use the right-hand menu to navigate.)

Networking in Kubernetes

First, let’s review the basic networking types in a Kubernetes cluster:

  • Container-to-container networking
  • Pod-to-pod networking
  • Pod-to-service networking
  • Internet-to-service networking

Now, let’s take a look at how each type operates to provide connectivity within the cluster.

Kubernetes Clusters

Container-to-container networking

In the most basic configurations, container to container communication within a single pod takes place via the localhost and port numbers. This is possible because the containers in the pod are located in the same network namespace.

A network namespace is a logical networking stack that includes routes, firewall rules, and network devices which provides a complete network stack for processes within the namespace. There can be multiple namespaces on the same virtual machine.

In Kubernetes, there is a hidden container called a pause container that runs on all the pods in Kubernetes. This container keeps the namespace open even if all the other containers in the pod are nonfunctional.

A new networking namespace is assigned to each pod created. Containers within the pod can use this networking namespace via localhost. However, a user must be aware of the port conflicts: If the containers use the same port, networking issues will arise within the containers.

Pod-to-pod networking

Each pod in a Kubernetes node gets assigned a dedicated IP address with a dedicated namespace. Due to an automatic assignment, users do not need to explicitly create links between pods. This allows us to tread pod networking operations such as port allocation, load balancing, and naming similar to a virtual machine or a physical host.

Kubernetes imposes three fundamental requirements on any network.

  1. Pods on a node can communicate with all pods on all nodes without NAT.
  2. Agents on a node (system daemons, kubelet) can communicate with all the pods on that specific node.
  3. Pods in a host network of a node can communicate with all pods on all nodes without NAT (Only for platforms such as Linux, which supports pods running on the host network)

Communication between pods in the same node

Kubernetes creates a virtual ethernet adapter for each pod, and it is connected to the network adaptor of the node.

When a network request is made, the pod connects through the virtual ethernet device associated with the pod and tunnels the traffic to the ethernet device of the node.

In a Kubernetes node, there is a network bridge called cbr0, which facilitates the communication between pods in a node. All the pods are a part of this network bridge. When a network request is made, the bridge checks for the correct destination (pod) and directs the traffic.

Communication between pods in different nodes

When the requested IP address cannot be found within the pod, the network bridge directs the traffic to the default gateway. This would then look for the IP within the cluster level.

Kubernetes keeps a record of all the IP ranges associated with each node. Then an IP address is assigned to the pods within the nodes from the range assigned to the node. When a request is made to an IP address in the cluster, it will:

  1. Look for the IP range for the requested IP.
  2. Then direct it to the specific node and then to the correct pod.

Pod-to-service networking

A service is an abstraction that routes traffic to a set of pods. In other words, a service will map a single IP address to a set of pods.

When a network request is made, the service proxies the request to the necessary pod. This proxy service happens via a process called Kube-proxy that runs inside each node.

The service would get its IP within the cluster when a request first reaches the service IP before being forwarded to the actual IP of the pod. This is an important feature in Kubernetes—it decouples the dependency of networking directly to each pod. The pods can be created and destroyed without worrying about network connectivity. This is because the service will automatically update its endpoints when the pods change with the IP of the pod.

The service would get its IP within the cluster. Any request first reaches the service IP before being forwarded to the actual IP of the Pod. This is an important feature in Kubernetes as it decouples the dependency of networking directly to each Pod. Thus, pods can get created and destroyed without worrying about network connectivity as the service will automatically update its endpoints with the IP of the pod that it targets as the Pods changes.

A service knows which Pods to target using the label selector. The label selector is the core grouping primitive in Kubernetes; via a label selector, the client or user can identify a set of objects.

  • The label selector will look for the specified labels in each Pod and match them with the service accordingly.
  • Without the selector, properly configured services cannot keep track of the Pods and will lead to communication issues within the cluster.

DNS for internal routing in a Kubernetes cluster

Each cluster comes with inbuilt service for DNS resolution.

  • A domain name is assigned to each service in the cluster
  • A DNS name is assigned to the Pods.

(These can be manually configured via the YAML file using the hostname and subdomain fields.)

When a request is made via the domain name, the Kubernetes DNS service will resolve the request and point it to the necessary internal service from the service. The Kube-proxy process will point it to the endpoint pod.

Internet-to-service networking

In the above sections, we have covered the internal networking basics of a Kubernetes cluster. The next step is to expose the containerized application to the internet.

Unlike the previous networking types, exposing the Kubernetes cluster to the internet depends on both the:

  • Underlying cluster infrastructure
  • Network configurations

The most common method used to handle traffic is by using a load balancer. In Kubernetes, we can configure load balancers. When a service is created, users can:

  • Specify a load balancer that will expose the IP address of the load balancer.
  • Direct traffic to the load balancer and communicate with the service through it.

Tools for Kubernetes networking

There are plenty of tools that we can use to configure networking within Kubernetes while adhering to all the guidelines and requirements imposed by the cluster.

  • Cilium is an open-source software for providing and securing network connectivity between application containers. Cilium is L7/HTTP aware and can enforce network policies from L3-L7 using identity-based security models.
  • Flannel is a simple network overlay that meets Kubernetes requirements.
  • Kube-router is a turnkey solution for Kubernetes networking. Kube-router provides a lean and powerful alternative to default Kubernetes network components from a single DaemonSet/Binary.
  • Antrea is a Kubernetes-native open source networking solution that leverages Open vSwitch as the networking data plane.

And here are cloud vendor-specific container network interfaces:

Please refer to the official Kubernetes documentation for the full list of available network tools.

K8s networking optimizes performance

Kubernetes cluster networking can be configured to suit any user requirements to optimize the performance of the containerized application and the cluster.

Related reading

]]>
Kubernetes Deployments Fully Explained https://www.bmc.com/blogs/kubernetes-deployment/ Thu, 20 May 2021 00:00:55 +0000 https://www.bmc.com/blogs/?p=13181 Kubernetes Deployment is the process of providing declarative updates to Pods and ReplicaSets. It allows users to declare the desired state in the manifest (YAML) file, and the controller will change the current state to the declared state. So, let’s look at how to create and use Kubernetes deployments. I’ll walk you through how to […]]]>

Kubernetes Deployment is the process of providing declarative updates to Pods and ReplicaSets. It allows users to declare the desired state in the manifest (YAML) file, and the controller will change the current state to the declared state.

So, let’s look at how to create and use Kubernetes deployments. I’ll walk you through how to utilize Kubernetes deployments to simplify the deployment process and manage, scale, and roll back deployments.

For the purpose of this article, we will be using a locally deployed Kubernetes cluster in a Windows environment utilizing the Windows Subsystem for Linux (WSL).

(This article is part of our Kubernetes Guide. Use the right-hand menu to navigate.)

Creating a Kubernetes deployment

Let’s first create a simple Nginx deployment with four replicas. Like any other Kubernetes configuration, a deployment file will contain:

  • apiVersion (apps/v1)
  • Kind (Deployment)
  • The metadata with a spec section to define the replicas and configurations related to the deployment

nginx-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  # Define the Deployment Name
  name: nginx-deployment
  labels:
    app: webserver
spec:
  # Define the Number of Pods
  replicas: 4
  # Define the Selector
  selector:
    matchLabels:
      app: webserver
  template:
    metadata:
      labels:
        app: webserver
    spec:
      containers: # Container Details
      - name: nginx
        image: nginx:latest # Image
        ports:
        - containerPort: 80

We can create the deployment using the following command. We have added the –record flag to save the command.

kubectl apply -f nginx-deployment.yaml --record

Result:

Nginx Deployment
We have defined the following entries in the metadata and specs sections of the above deployment file.

  • The deployment name and a label (app: webserver).
  • The number of replicas (pods), the selector in which the controller will select the targeted pods. (The label is used to select the necessary pods using the matchLabels field.) The template section contains the actual template for the pod. This section defines the metadata that each pod will have with the specs (container definition). In this instance, we have defined the Nginx image and the container port as 80.

If we check the Kubernetes cluster after some time, we can see that the Pods are deployed with the given template. Additionally, we can retrieve details of the deployment using the describe command.

kubectl get all

Result:

kubect

kubectl describe deployment nginx-deployment

Result:

Deployment Result

Exposing the ReplicaSet

Now we have created a deployment and need to verify if the Nginx web servers were deployed correctly.

The straightforward way to achieve this is to create a service object that exposes the deployment. An important fact to note here is that the way we expose the deployment and the parameters can vary depending on the configurations of the Kubernetes cluster.

kubectl expose deployment nginx-deployment --type=LoadBalancer --name=nginx-web-server

Result:

Load Balancer

kubectl get services

Result:

Services
Then we can navigate to the localhost port 80 to check if we can see the default Nginx server landing page as below.

Welcome

Discovering the Kubernetes deployment details

When managing a Kubernetes cluster, the initial step would be to check for a successful deployment. For this purpose, we can use the kubectl rollout status and kubectl get deployment commands.

  • kubectl rollout status informs the user if the deployment was successful.
  • kubectl get deployment shows the desired and updated number of replicas, the number of replicas running, and their availability. As mentioned previously, we can use the kubectl describe command to a complete picture of the deployment.
kubectl rollout status deployment nginx-deployment
kubectl get deployment nginx-deployment

Result:

Rollout Status
We can fetch information about the ReplicaSets created during deployment using the kubectl get ReplicaSet command.

By default, Kubernetes will automatically append a pod-template-hash value to the ReplicaSet name. However, do not rename the ReplicaSet as it will break the deployment.

kubectl get replicaset

Result:

Replicaset
The kubectl get pod command can be used to get only the information about the pods related to the deployment while defining a selector. In this instance, we will be using the “app:webserver” label as the selector.

kubectl get pod --selector=app=webserver

Result:

Web Server

Managing Kubernetes deployments

Now we know how to create a deployment and retrieve information about the said deployment. The next stage is to manage the deployment. What differentiates deployments from a simple ReplicaSet is that deployments enable users to update the pods (pod templates) without causing any interruption to the underlying application.

Performing Rolling Update on a deployment

Let’s assume that we need to change the Nginx server version in our deployment to target our application to a specific server version. We can do this by either:

  • Using the kubectl set image command
  • Changing the deployment configuration file

Using the set image command

The set image command can be used with the container name of the template and the required image name to update the pods.

kubectl set image deployment nginx-deployment nginx=nginx:1.19.10

Result:

Image Deployment
We will get the rollout process if we run the get rollout status command immediately.

kubectl rollout status deployment nginx-deployment

Result:

Rollout Status Deployment

Changing the deployment configuration file

We can use the edit deployment command to edit the configuration file. Navigate the relevant section (container image) and make necessary changes. Kubernetes will start the process of updating the pods the moment we save the new configuration.

kubectl edit deployment nginx-deployment

Deployment Edit View (nginx-deployment):

Deployment Edit View

Deployment strategies

Kubernetes uses two deployment strategies called “Recreate” and “RollingUpdate” to recreate pods. We can define those strategies in .spec.strategy.type field. The RollingUpdate strategy is the default for deployments.

  • Recreate will delete all the existing pods before creating the new pods.
  • RollingUpdate will recreate the pods in a rolling update fashion. Moreover, it will delete and recreate pods gradually without interrupting the application availability. This strategy utilizes the maxUnavailable and maxSurge values to control the rolling update process..
    • maxUnavailable defines the maximum number of pods that can be unavailable in the update process.
    • maxSurge defines the maximum number of pods that can be created.

In our deployment, we haven’t explicitly defined a strategy so that Kubernetes will use the default RollingUpdate strategy. We can use the describe command to verify the current strategy for the deployment.

kubectl describe deployment nginx-deployment | grep Strategy

Result:

Grep Stratergy
From the above output, we can discern that the default configurations for the RollingUpdate strategy are 25% for max unavailable and 25% for the max surge values. We are creating four replicas in our configuration. According to the above configuration in the update process, a single pod will get destroyed while a single pod is created (25% of 4 is 1).

We can view the Events in the deployment using the describe command to gain a better understanding of the update process.

kubectl describe deployment nginx-deployment

Result:

Events
If we look at the current ReplicaSet, we can notice that it has four pods whereas the old ReplicaSet does not contain any pods.

kubectl get replicasets

Result:

Replica sets

Pausing & resuming deployments

Kubernetes deployments provide the ability to pause and resume deployments. This enables users to modify and address issues without triggering a new ReplicaSet rollout.

We can use the “rollout pause deploy” command to pause the deployment.

kubectl rollout pause deploy nginx-deployment

Result:

Pause Deployment
Now, if we update the Nginx image in the paused status, the controller will accept the change, yet it will not trigger the new ReplicaSet rollout. If we look at the rollout status, it will indicate a pending change.

kubectl set image deployment nginx-deployment nginx=nginx:1.20 --record
kubectl rollout status deployment nginx-deployment

Result:

Image Set Deployment
You can simply run the “rollout resume deploy” command to resume the deployment.

kubectl rollout resume deploy nginx-deployment
kubectl rollout status deployment nginx-deployment

Result:

Resume Deployment

Scaling deployments

As the Deployments rely on ReplicaSets to manage the pods, we can scale up or down the number of pods. This scaling can be done either:

  • Manually
  • By configuring an auto-scaling rule

Manual scaling

We can use the scale command with the replica parameter to scale the deployment to the desired number. For instance, we will use the following command to scale up our deployment from 4 pods to 8 pods.

kubectl scale deployment nginx-deployment --replicas=8
kubectl rollout status deployment nginx-deployment

Result:

Scale Depoyment
If we look at the pods associated with this deployment, we can see that it has eight pods now.

kubectl get pod --selector=app=webserver

Result:

Selector App Server

Autoscaling

The best practice for scaling deployments would be to configure an auto-scaling rule so that the pods will scale according to predefined thresholds.

So, let’s go ahead and create an autoscaling rule for our deployment, which will scale according to the CPU load of the node.

kubectl autoscale deployment nginx-deployment --min=5 --max=10 --cpu-percent=70

Result:

Autoscale Deployment
According to the above configuration, if the CPU load is greater than 70%, the deployment will scale until the maximum number of pods is reached (maximum ten pods). On the other hand, it will scale back gradually until there are five pods (minimum five pods) when the load is reduced.

Rolling back a deployment

Kubernetes also supports rolling back deployments to the previous revision. This is a crucial feature enabling users to undo changes in deployment.

For instance, if a critical production bug was deployed to the cluster, we can simply roll back the deployment to the previous revision easily with no downtime until the bug is fixed.

Let’s assume that we have updated our configuration with an incorrect image. (We will be using the caddy webserver in this example.)

kubectl set image deployment nginx-deployment nginx=caddy:latest --record

Result:

Nginx Caddy
This is where the Deployment controller’s history function comes into play. The controller keeps track of any changes to the pod template and keeps them in history. When we specify the record flag in a command, it will be reflected in the history.

kubectl rollout history deployment nginx-deployment

Result:

Rollout History Deployment
We can use the revision number to inform the deployment controller to roll back our deployment to the previous revision.

First, let’s verify if the revision we are going to roll back is the correct deployment. Here, we are trying to roll back to the third revision. Simply specify the revision in the history command to get the details of the indicated revision.

kubectl rollout history deployment nginx-deployment --revision=3

Result:

Revision
After confirming the revision, we can utilize the “kubectl rollout undo” command with the “to-revision” parameter to roll back the deployment.

kubectl rollout undo deployment nginx-deployment --to-revision=3
kubectl rollout status deployment nginx-deployment

Result:

Deployment To Revision
That’s it! Now we have successfully rolled back the deployment.

After the rollback, we won’t be able to see the third revision as we have deployed it as the current configuration. However, we will be able to see a new record with a higher revision number for the newly rolled back deployment.

kubectl rollout history deployment nginx-deployment

Result:

Change Cause

Summing up K8s deployments

In this article, we have only scratched the surface of the capabilities of Kubernetes deployments. Users can create more robust containerized applications to suit any need by combining deployments with all the other Kubernetes features.

Related reading

]]>
How To Use & Manage Kubernetes DaemonSets https://www.bmc.com/blogs/kubernetes-daemonset/ Fri, 07 May 2021 00:00:09 +0000 https://www.bmc.com/blogs/?p=13426 Kubernetes is a leading open-source engine that orchestrates containerized applications. In this article, we will have a look at the DaemonSet feature offered by Kubernetes. We’ll walk you through use cases and how to create, update, communicate with, and delete DaemonSets. (This article is part of our Kubernetes Guide. Use the right-hand menu to navigate.) […]]]>

Kubernetes is a leading open-source engine that orchestrates containerized applications.

In this article, we will have a look at the DaemonSet feature offered by Kubernetes. We’ll walk you through use cases and how to create, update, communicate with, and delete DaemonSets.

(This article is part of our Kubernetes Guide. Use the right-hand menu to navigate.)

What is a Kubernetes DaemonSet?

The DaemonSet feature is used to ensure that some or all of your pods are scheduled and running on every single available node. This essentially runs a copy of the desired pod across all nodes.

  • When a new node is added to a Kubernetes cluster, a new pod will be added to that newly attached node.
  • When a node is removed, the DaemonSet controller ensures that the pod associated with that node is garbage collected. Deleting a DaemonSet will clean up all the pods that DaemonSet has created.

DaemonSets are an integral part of the Kubernetes cluster facilitating administrators to easily configure services (pods) across all or a subset of nodes.

DaemonSet use cases

DaemonSets can improve the performance of a Kubernetes cluster by distributing maintenance tasks and support services via deploying Pods across all nodes. They are well suited for long-running services like monitoring or log collection. Following are some example use cases of DaemonSets:

  • To run a daemon for cluster storage on each node, such as glusterd and ceph.
  • To run a daemon for logs collection on each node, such as Fluentd and logstash.
  • To run a daemon for node monitoring on every note, such as Prometheus Node Exporter, collectd, or Datadog agent.

Depending on the requirement, you can set up multiple DaemonSets for a single type of daemon, with different flags, memory, CPU, etc. that supports multiple configurations and hardware types.

Scheduling DaemonSet pods

By default, the node that a pod runs on is decided by the Kubernetes scheduler. However, DaemonSet pods are created and scheduled by the DaemonSet controller. Using the DaemonSet controller can lead to Inconsistent Pod behavior and issues in Pod priority preemption.

To mitigate these issues, Kubernetes (ScheduleDaemonSetPods) allows users to schedule DaemonSets using the default scheduler instead of the DaemonSet controller. This is done by adding the NodeAffinity term to the DaemonSet pods instead of the .spec.nodeName term. The default scheduler is then used to bind the Pod to the target host.

The following is a sample NodeAffinity configuration:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          # Key Name
          - key: disktype
            operator: In
            # Value
            values:
            - ssd            
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent

Above, we configured NodeAffinity so that a pod will only be created on a node that has the “disktype=ssd” label.

Additionally, DaemonSet pods adhere to taints and tolerations in Kubernetes. The node.kubernetes.io/unschedulable:NoSchedule toleration is automatically added to DaemonSet pods. (For more information about taints and tolerations, please refer to the official Kubernetes documentation.)

How to create a DaemonSet

As for every other component in Kubernetes, DaemonSets are configured using a YAML file. Let’s have a look at the structure of a DaemonSet file.

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: test-daemonset
  namespace: test-daemonset-namespace
  Labels:
    app-type: test-app-type
spec:
  template:
    metadata:
      labels:
        name: test-daemonset-container
  selector:
    matchLabels:
      name: test-daemonset-container

As you can notice in the above structure, the apiVersion, kind, and metadata are required fields in every Kubernetes manifest. The DaemonSet specific fields come under the spec section—these fields are both mandatory.

  • template. This is the pod definition for the Pod that needs to be deployed across all the nodes. A pod template in a DaemonSet must have its RestartPolicy set to “Always,” and by default it will take “Always” if you havne’t specified a RestartPolicy.
  • selector. The selector for the pods managed by the DaemonSet. This value must be a label specified in the pod template. (In the above example, we have used the name: test-daemonset-container as the selector.) This value is fixed and cannot be changed after the initial creation of the DaemonSet. Changing this value will cause pods created via that DaemonSet to be orphaned. Kubernetes offers two ways to match matchLabels and matchExpressions for creating complex selectors.

Other optional fields

  • template.spec.nodeSelector – This can be used to specify a subset of nodes that will create the Pod matching the specified selector.
  • template.spec.affinity – This field can be configured to set the affinity that would run the pod only on nodes that match the configured affinity.

Creating a DaemonSet

Now let’s go ahead with creating a sample DaemonSet. Here, we will be using a “fluentd-elasticsearch” image that will run on every node in a Kubernetes cluster. Each pod would then collect logs and send the data to ElasticSearch.

daemonset-example.yaml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch-test
  namespace: default # Name Space
  labels:
    k8s-app: fluentd-logging
spec:
  selector: # Selector
    matchLabels: 
      name: fluentd-elasticsearch-test-deamonset
  template: # Pod Template
    metadata:
      labels:
        name: fluentd-elasticsearch-test-deamonset
    spec:
      tolerations: # Tolerations
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers: # Container Details
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

First, let’s create the DaemonSet using the kubectl create command and retrieve the DaemonSet and pod information as follows:

kubectl create -f daemonset-example.yaml

Demonstate Example

kubectl get daemonset

kubectl

kubectl get pod -o wide

Pod Wide

As you can see from the above output, our DaemonSet has been successfully deployed.

Depending on the nodes available on the cluster, it will scale automatically to match the number of nodes or a subset of nodes on the configuration. (Here, the number of nodes will be one as we are running this on a test environment with a single node Kubernetes cluster.)

Updating DaemonSets

When it comes to updating DaemonSets, if a node label is changed, DaemonSet will automatically add new pods to matching nodes while deleting pods from non-matching nodes. We can use the “kubectl apply” command to update a DaemonSet, as shown below.

Apply Demonstate

There are two strategies that can be followed when updating DaemonSets:

  • The default strategy in Kubernetes, this will delete old DaemonSet pods and automatically create new pods when a DaemonSet template is updated.
  • When using this option, new DaemonSet pods are created only after a user manually deletes old DaemonSet pods.

These strategies can be configured using the spec.updateStrategy.type option.

Deleting DaemonSets

Deleting a DaemonSet is a simple task. To do that, simply run the kubectl delete command with the DaemonSet. This would delete the DaemonSet with all the underlying pods it has created.

Delete Demonstate

We can use the cascade=false flag in the kubectl delete command to only delete the DaemonSet without deleting the pods.

Communicating with pods created by DaemonSet

There are multiple methods to communicate with pods created by DaemonSets. Here are some available options:

  • Push. This way, pods can be configured to send information to other services (monitoring service, stats database). However, they do not receive any data.
  • NodeIP & Known Port. Pods are reachable via the node IPs using hostPort. Users can then utilize the known ports and the node IP to communicate with the pods.
  • DNS. In this method, users can configure a headless service with the same pod selector to discover DaemonSet using the endpoints resource.
  • Service.  To select a random node in a DaemonSet, which we can use to create a service with the same pod selector.

DaemonSet summary

In this article, we learned about Kubernetes DaemonSets. These configurations can easily facilitate monitoring, storage, or logging services that can be used to increase the performance and reliability of both the Kubernetes cluster and the containers.

Related reading

]]>
Creating & Using ConfigMaps in Kubernetes https://www.bmc.com/blogs/kubernetes-configmap/ Wed, 05 May 2021 00:00:07 +0000 https://www.bmc.com/blogs/?p=13507 In programming, we use env files or separate configuration files to store settings, configurations, or variables that are required to execute the program. In Kubernetes, we can use ConfigMaps to achieve the same functionality. To understand ConfigMap properly, you should have some knowledge of Kubernetes, pods, and basic Kubernetes cluster management. (This article is part […]]]>

In programming, we use env files or separate configuration files to store settings, configurations, or variables that are required to execute the program. In Kubernetes, we can use ConfigMaps to achieve the same functionality.

To understand ConfigMap properly, you should have some knowledge of Kubernetes, pods, and basic Kubernetes cluster management.

(This article is part of our Kubernetes Guide. Use the right-hand menu to navigate.)

What is a ConfigMap?

A ConfigMap is a Kubernetes API object that can be used to store data as key-value pairs. Kubernetes pods can use the created ConfigMaps as a:

  • Configuration file
  • Environment variable
  • Command-line argument

ConfigMaps provides the ability to make applications portable by decoupling environment-specific configurations from the containers.

Importantly, ConfigMaps are not suitable for storing confidential data. They do not provide any kind of encryption, and all the data in them are visible to anyone who has access to the file. (Kubernetes provides secrets that can be used to store sensitive information.)

Another consideration of ConfigMaps is the size of the file, as we are trying to store application configuration ConfigMap files limited to 1MB. For larger data sets, it’s better to use separate file mounts, databases, or file services.

ConfigMap example

kind: ConfigMap
apiVersion: v1
metadata:
  name: example-configmap
  namespace: default
data:
  # Configuration Values are stored as key-value pairs
  system.data.name: "app-name"
  system.data.url: "https://app-name.com"
  system.data.type_one: "app-type-xxx"
  system.data.value: "3"
  # File like Keys
  system.interface.properties: |
    ui.type=2
    ui.color1=red
    ui.color2=green

In a ConfigMap, the required information can be stored in the data field. We can store values in two ways:

  • As individual key pair properties
  • In a granular format where they are fragments of a configuration format. (File Like Keys)

How to create ConfigMaps

ConfigMaps and pods go hand in hand as ConfigMaps can be used as environment variables and configuration information in a Kubernetes pod.

In this section, we will have a look at how to create ConfigMaps. Here are some notes before we get started:

  • We will be using a windows environment with the windows subsystem for Linux (Ubuntu) as the terminal environment.
  • The Docker desktop will be configured to facilitate a Kubernetes environment.
  • We will be using the official sample files provided by Kubernetes to demonstrate the functionality of ConfigMap.

Creating ConfigMaps from directories

We can use the following command to create ConfigMap directories.

kubectl create configmap

It will look for appropriate files (regular files) within a specific directory that can be used to create a ConfigMap while ignoring any other file types (hidden files, subdirectories, symlinks, etc.)

First, let’s create a directory using this command:

mkdir configmap-example

Command

Then we’ll download the required sample files to the directory. These files will be used to generate the ConfigMap.

wget https://kubernetes.io/examples/configmap/game.properties -O configmap-example/game.properties

wget https://kubernetes.io/examples/configmap/ui.properties -O configmap-example/ui.properties

cmd
Now let’s have a look at the file contents using the following commands.

cat game.properties
cat ui.properties

Cat Game Properties

When creating ConfigMaps using directories, the most important factor is that you have to correctly define the key-value pairs within each file.

After that, let’s create the ConfigMap using the create configmap command.

kubectl create configmap game-config-example --from-file=configmap-example/

ConfigMap

This command will package the files within the specified directory and create a ConfigMap file. We can use the kubectl describe command to view the ConfigMap file.

kubectl describe configmaps game-config-example

Game Config Example

We can get the ConfigMap in YAML format using the following command.

kubectl get configmaps game-config-example -o yaml

YAML

Creating ConfigMaps from files

In the same way we created ConfigMaps using directories, we can also create ConfigMaps using files by using the –from-file parameter to point to a single file in the kubectl create configmap command. So, let’s create a ConfigMap using the game.properties file as shown below.

kubectl create configmap game-config-example-2 --from-file=configmap-example/game.properties

kubect

kubectl describe configmap game-config-example-2

Game Config Example 2

We can define multiple –from-file arguments multiple times to create a single ConfigMap file using several different files.

kubectl create configmap game-config-example-2 --from-file=c

Creating ConfigMaps from an environment file

Kubernetes allows users to create ConfigMaps using env files. We can use the –from-env-file argument when defining an env file. This argument can also be used multiple times to define multiple env files.

When using env files, each line should adhere to the <name>=<value> format. Empty lines and comments will be ignored, while quotation marks will be a part of ConfigMap.

cat configmap-example/game-env-file.properties

game env

kubectl create configmap game-config-env-file-example --from-env-file=configmap-example/game-env-file.properties

kubectl

kubectl get configmap game-config-env-file-example -o yaml

env file

Creating ConfigMap from a file with a predefined key

When creating a ConfigMap, we can use the following format in –from-file argument to define a key name that will overwrite the file name used in the data section.

Key Name

The following example demonstrates how to define a key while creating a ConfigMap.

kubectl create configmap game-config-key-example --from-file=game-key-example-data=configmap-example/game.properties

key example

kubectl get configmap game-config-key-example -o yaml

example data

Creating ConfigMaps from values

Another way to create ConfigMaps is to provide literal values as parameters in the create configmap command. For this, we can use the –from-literal argument to pass each key pair. This is especially handy when we need to create ConfigMaps on the fly.

kubectl create configmap config-example-values --from-literal=example.value=one --from-literal=example-type=2 --from-literal=example.url="http://example.com"

liteurl example

kubectl get configmap config-example-values -o yaml

example values

Utilizing ConfigMaps in pods

Now we have a basic understanding of how to create ConfigMaps. The next step is to use the created ConfigMaps for creating a Pod. In this section, we will create a simple ConfigMap and use it when creating a pod in Kubernetes.

As the first step, let’s create a file named “app-basic.properties” and include two key-value pairs.

app-basic.properties

system.type="TESTING CONFIGMAP"
system.number=12345

We will create a ConfigMap named “app-basic-configmap” using the above file and the –from-file option.

kubectl create configmap app-basic-configmap --from-file=configmap-example/app-basic.properties

basic properties

kubectl get configmap app-basic-configmap -o yaml

basic configmap

Finally, let’s create a Pod referencing the newly created ConfigMap. We will be using the following YAML file to create the Pod.

example-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: configmap-example-pod
spec:
  containers:
    - name: configmap-example-busybox
      image: k8s.gcr.io/busybox
      command: [ "/bin/sh", "-c", "env" ]
      envFrom:
        # Load the Complete ConfigMap
        - configMapRef:
            name: app-basic-configmap
  restartPolicy: Never

As you can see from the above example, We are going to load the complete ConfigMap we created to the Kubernetes Pod.

kubectl create -f example-pod.yaml
kubectl get pods

example pod

kubectl logs configmap-example-pod | grep system.number

kubectl logs

The above result indicates that the ConfigMap “app-basic-configmap” was successfully loaded when creating the Kubernetes Pod.

Mapping keys from ConfigMaps to pods

Another way we can use ConfigMaps is to directly map values from ConfigMaps to the specific environmental variables in the Pod.

In this section, we will create two simple configmap files manually and load and map the values directly to the Kubernetes Pod. There, we will define the ConfigMaps as YAML files and then use the kubectl create command to generate the ConfigMaps.

application-defaults.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: application-configs
  namespace: default
data:
  app.value: "45000"
  app.type: test-application
  app.ui: web

application-logs.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: application-log-configs
  namespace: default
data:
  log_level: WARNING
  log_type: TEXT
kubectl create -f application-defaults.yaml
kubectl create -f application-logs.yaml

application default

example-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: configmap-example-pod
spec:
  containers:
    - name: configmap-example-busybox
      image: k8s.gcr.io/busybox
      command: [ "/bin/sh", "-c", "env" ]
      env:
        - name: APPLICATION_TYPE
          valueFrom:
            configMapKeyRef:
              name: application-configs
              key: app.type
        - name: APPLICATION_UI_TYPE
          valueFrom:
            configMapKeyRef:
              name: application-configs
              key: app.ui
        - name: LOG_LEVEL
          valueFrom:
            configMapKeyRef:
              name: application-log-configs
              key: log_level
  restartPolicy: Never

In this configuration, we are mapping environmental variables to values within each ConfigMap.

The following is the basic structure for mapping a value. In the environment section in the YAML file, we define a variable name and  reference the ConfigMap via the “configMapKeyRef” element using the “valueFrom.” Here we will provide:

  • The ConfigMap name
  • The key where the value should be mapped from

Config Map Key Reference

Next, we will create the Pod using the kubectl create command as shown below.

kubectl create -f example-pod.yaml
kubectl get pods

pod creation

After successfully creating the Pod, we can explore the environment variables as shown below.

kubectl logs configmap-example-pod | grep APPLICATION_TYPE
kubectl logs configmap-example-pod | grep APPLICATION_UI_TYPE
kubectl logs configmap-example-pod | grep LOG_LEVEL

application type

The above results indicate that the values were correctly mapped to environment variables with custom names within the Kubernetes pod.

ConfigMap defined environment variables in pod commands

Another way we can utilize ConfigMap defined environmental variables is by using them in Pod Commands. This can be done for both the command and args elements in a YAML file using the $(VARIABLE_NAME) Kubernetes substitution syntax.

The following code block demonstrates how to use these environment variables in the command element using example-pod.yaml as the base.

apiVersion: v1
kind: Pod
metadata:
  name: configmap-example-pod
spec:
  containers:
    - name: configmap-example-busybox
      image: k8s.gcr.io/busybox
      command: [ "/bin/echo", "Application Type $(APPLICATION_TYPE) - $(APPLICATION_UI_TYPE)" ]
      env:
        - name: APPLICATION_TYPE
          valueFrom:
            configMapKeyRef:
              name: application-configs
              key: app.type
        - name: APPLICATION_UI_TYPE
          valueFrom:
            configMapKeyRef:
              name: application-configs
              key: app.ui
        - name: LOG_LEVEL
          valueFrom:
            configMapKeyRef:
              name: application-log-configs
              key: log_level
  restartPolicy: Never

In this instance, the environmental variables are identified at the execution of the command (at the container start), and they will be directly displayed in the terminal.

Adding ConfigMap data to a volume

Users can consume ConfigMaps by mounting the ConfigMap data into a Kubernetes volume. In the following example, we are mounting the “application-log-config” ConfigMap data to a volume called “config-volume” mounted in “/etc/config” in the container. Then we have configured a command that would list all the files within the /etc/config directory.

apiVersion: v1
kind: Pod
metadata:
  name: configmap-example-volume-pod
spec:
  containers:
    - name: configmap-volume-example-busybox
      image: k8s.gcr.io/busybox
      command: [ "/bin/sh", "-c", "ls /etc/config/" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: application-log-configs
  restartPolicy: Never

Mounted ConfigMaps are automatically updated. Kubelt will periodically check if the mounted ConfigMap is up to date and update the mount accordingly. However, this auto-update mechanism does not apply to volumes mapped as a SubPath volume.

That concludes this tutorial. Explore more Kubernetes topics with the right-hand menu.

ConfigMaps are essential to K8s clusters

In this article, we have learned about Kubernetes ConfigMaps, including multiple ways that can be used to create ConfigMaps and how to utilize ConfigMaps in a Kubernetes Pod. ConfigMaps are an essential part of any Kubernetes cluster, providing a robust method to store simple and frequently accessed application or container data.

Related reading

]]>
3 Kubernetes Patterns for Cloud Native Applications https://www.bmc.com/blogs/kubernetes-patterns/ Tue, 07 Jul 2020 00:00:10 +0000 https://www.bmc.com/blogs/?p=17941 Modern cloud native applications are designed to be scalable, elastic, reliable, and predictable. To achieve these characteristics, certain principles can help guide admins or architects when running applications in Kubernetes. In this article, we are going to cover three important patterns to consider when running a cloud native application on Kubernetes. At the end of […]]]>

Modern cloud native applications are designed to be scalable, elastic, reliable, and predictable. To achieve these characteristics, certain principles can help guide admins or architects when running applications in Kubernetes.

In this article, we are going to cover three important patterns to consider when running a cloud native application on Kubernetes. At the end of this post you should have a good understanding of what to look for when architecting a containerized application that is going to run inside of a K8s cluster.

Kubernetes Patterns

(This article is part of our Kubernetes Guide. Use the right-hand menu to navigate.)

Foundational Pattern

The foundational pattern is fundamental to running any container-based application in a Kubernetes cluster and for it to be considered cloud native.

There are five areas to focus on when working with the foundational pattern:

  • Predictable demand
  • Declarative deployment
  • Health probe
  • Managed lifecycle
  • Automated placement

These concepts cover most of what you would need to understand to run your application in Kubernetes with this pattern.

Predictable demands

Understanding applications resources and runtime dependency is key to running any application on Kubernetes. To be able to predict the demand of the application we need to know:

  • The runtime dependency (e.g., persistent volume or ConfigMap)
  • The application resource profile which covers setting compressible resources (CPU) and incompressible resources (memory)

Declarative deployment

Automating application deployment is another critical part of running a cloud native app on Kubernetes. This principle is only possible with the use of the deployment workload to provide declarative updates for pods and replicasets. Similarly, for a deployment to do its job correctly, it expects the containerized applications to be good cloud-native citizens.

At the very core of a deployment is the ability to start and stop a set of pods predictably. For this to work as expected, the containers themselves usually listen and honor lifecycle events such as sigterm and also provide health-check endpoints which indicate whether they started successfully.

Health probe

A cloud native Kubernetes application must be observable. Health probe concept focuses more on how the running application should communicate its state to the cluster. Using a combination of process health check, liveness probe, and readiness probe, you can quickly determine if application is healthy and how to control traffic.

In the case where the liveness probe fails, the container is completely terminated but with the readiness probe failure, the container is removed from the service.

Managed lifecycle

Container based applications running in k8s should be able to react to certain lifecycle events emitted by the cluster. Understanding how to take advantage of process signals like sigterm and sigkill (force kill after 30 seconds), poststart, and prestop hooks is important.

  • Poststart hook is a blocking call that executes when a container gets created. Pod status is pending until poststart hook is completed and if poststart hook fails, the container process gets terminated.
  • Prestop is a blocking call sent to a container before termination and it is particularly useful for shutting down a container gracefully based on events emitted by the cluster.

Automated placement

Understanding how container-based applications will be distributed on a Kubernetes node is key to performance, reliability, and automation. The job of a scheduler is to retrieve each newly created pod definition from the API server and assign it to a node. However, it is not as simple as that—we must make sure that node capacity will allow pod placements based on container resource profile.

Things to consider when dealing with automated placements are:

  • Available node resources
  • Container resource demands
  • Placement policies
  • Node affinity, pod affinity and anti-affinity
  • Taints and tolerance

Behavioral Pattern

The concepts in the behavioral pattern are focused around the pod management primitives and their behaviors. It is very important to know how you want to run your application in a pod in a cluster depending on the use case.

For example, you can run an application in a bare pod or as a daemonset which runs a single pod in every node in the cluster.

The concepts covered under the behavioral pattern are:

  • Batch job
  • Periodic job
  • Daemon service
  • Stateful service
  • Self-awareness

Batch job

This is used to run short-lived pods reliably until completion. This is particularly useful when you don’t want a long running pod, but instead want to simply run a task that runs to completion and terminate the pod. Unlike other pod primitives, batch jobs will not restart pods once they run to completion.

Periodic job

This is used to execute a unit of work to be triggered by an event or at a certain time. Periodic jobs are deployed using the cronjob primitive where you can think of cronjobs as one line of a unix crontab. The difference between Kubernetes cronjob and Unix cron is that Kubernetes cronjob is highly available and allows both time and event based execution. This approach is useful when applications need to run a specific task like file transfer or polling another service.

Daemon service

In general daemons are programs that run as processes without interaction. Since Kubernetes is a distributed system and applications running on it are also distributed by nature, daemonset can be used to provide insight into the cluster or application running on it, e.g., running fluentd daemonset on every node to collect cluster logs.

Stateful service

This concept is for applications that are not stateless. Unlike a typical 12 factor application where application can be terminated and expected to be restarted with any issue, a stateful application is the opposite. It is mostly for applications that need to store state. By using statefulset workload, you can control persistent identity, networking, storage, and ordinality, which impacts how application is scaled up and down.

Self-awareness

In some cases, applications running in Kubernetes need to know certain information about themselves, this is what the self-awareness concept solves with downward API. It provides a simple way for introspection and metadata injection into applications running in Kubernetes. Downward API allows passing metadata about the pod to the containers and the cluster through environment variables (e.g., POD_IP) or files.

The ability for an application to be aware of its own surroundings is powerful when you think about how distributed Kubernetes is by nature.

Structural Pattern

This pattern is one of the most important patterns to understand when running any distributed cloud native application on Kubernetes. The main objective of the structural pattern is to help understand how to organize containers in a pod to solve different use cases.

The core of this pattern is based on a single responsibility model where containers should only perform one task. If it needs to do more than one single task, there should be a second container to perform the second task.

To implement this pattern, there are four areas to focus on depending on the use case:

  • Init containers
  • Sidecar
  • Adapter
  • Ambassador

Init containers

Separating initialization related tasks from application startup is the main focus of init containers. For example, the ability to perform database schema setup before starting application.

This concept allows for running two sets of containers in a single pod—the init containers and the application containers. The only difference is that application containers run in parallel while init containers run sequentially. The benefit of this is that you can be assured that the initialization completes successfully before the application starts up.

There is also no readiness check for init containers, which is important to know.

Sidecar

Unlike init containers whose job is only to initialize the application containers during startup, sidecars containers allow us to extend the functionality of an existing container without changing the container. This pattern allows single-purpose containers to cooperate closely together in a distributed system like Kubernetes.

An example of this concept is a pod with two containers where one is an http server and another container pulls down the file the http container is serving, maybe from s3, storage bucket, or git. The behavior of the http container is now enhanced by the other container.

Adapter

This is a variation of the sidecar mentioned above and it is used to solve situations where all containers running in an application pod need to be exposed in a unified way.

For example, we have a pod with three containers where two containers work together as the application and the last container, the adapter, parses and formats the logs of the two application containers in a unified way for a third party tool to consume. The main containers could be written in two languages, but their logs are still presented the same way that other tools can understand.

Ambassador

This is another variation of the sidecar concept. There are times where you need your containerized application running in a pod to communicate with external services outside of the pod. This is where the Ambassador concept comes into play. It acts as a proxy and removes the responsibility of the main application container contacting an external service directly.

For example, a situation where an application has to query an external datastore or cache. In this case a request hits the main application container that sends the request to the ambassador container that forwards the request to the external source.

Useful Kubernetes patterns

The patterns and considerations mentioned above are good patterns to think about when architecting and running distributed cloud native applications in Kubernetes to achieve scalability, elasticity, reliability, and predictability.

Additional resources

For more on Kubernetes, explore these resources:

 

]]>
What is Kubernetes (K8s)? A Kubernetes Basics Tutorial https://www.bmc.com/blogs/what-is-kubernetes/ Wed, 06 May 2020 00:00:35 +0000 https://www.bmc.com/blogs/?p=13151 In this post, we’re going to explain Kubernetes, also known as K8s. In this introduction, we’ll cover: What Kubernetes is What it can’t do The problems it solves K8s architectural components Installation Alternative options This article assumes you are new to Kubernetes and want to get a solid understanding of its concepts and building blocks. (This […]]]>

In this post, we’re going to explain Kubernetes, also known as K8s. In this introduction, we’ll cover:

  • What Kubernetes is
  • What it can’t do
  • The problems it solves
  • K8s architectural components
  • Installation
  • Alternative options

This article assumes you are new to Kubernetes and want to get a solid understanding of its concepts and building blocks.

(This article is part of our Kubernetes Guide. Use the right-hand menu to navigate.)

What is Kubernetes?

To begin to understand the usefulness of Kubernetes, we have to first understand two concepts: immutable infrastructure and containers.

  • Immutable infrastructure is a practice where servers, once deployed, are never modified. If something needs to be changed, you never do so directly on the server. Instead, you’ll build a new server from a base image, that have all your needed changes baked in. This way we can simply replace the old server with the new one without any additional modification.
  • Containers offer a way to package code, runtime, system tools, system libraries, and configs altogether. This shipment is a lightweight, standalone executable. This way, your application will behave the same every time no matter where it runs (e.g, Ubuntu, Windows, etc.). Containerization is not a new concept, but it has gained immense popularity with the rise of microservices and Docker.

Armed with those concepts, we can now define Kubernetes as a container or microservice platform that orchestrates computing, networking, and storage infrastructure workloads. Because it doesn’t limit the types of apps you can deploy (any language works), Kubernetes extends how we scale containerized applications so that we can enjoy all the benefits of a truly immutable infrastructure. The general rule of thumb for K8S: if your app fits in a container, Kubernetes will deploy it.

By the way, if you’re wondering where the name “Kubernetes” came from, it is a Greek word, meaning helmsman or pilot. The abbreviation K8s is derived by replacing the eight letters of “ubernete” with the digit 8.

The Kubernetes Project was open-sourced by Google in 2014 after using it to run production workloads at scale for more than a decade. Kubernetes provides the ability to run dynamically scaling, containerised applications, and utilising an API for management. Kubernetes is a vendor-agnostic container management tool, minifying cloud computing costs whilst simplifying the running of resilient and scalable applications.

Kubernetes has become the standard for running containerised applications in the cloud, with the main Cloud Providers (AWS, Azure, GCE, IBM and Oracle) now offering managed Kubernetes services.

Kubernetes basic terms and definitions

To begin understanding how to use K8S, we must understand the objects in the API. Basic K8S objects and several higher-level abstractions are known as controllers. These are the building block of your application lifecycle.

Basic objects include:

  • Pod. A group of one or more containers.
  • Service. An abstraction that defines a logical set of pods as well as the policy for accessing them.
  • Volume. An abstraction that lets us persist data. (This is necessary because containers are ephemeral—meaning data is deleted when the container is deleted.)
  • Namespace. A segment of the cluster dedicated to a certain purpose, for example a certain project or team of devs.

Controllers, or higher-level abstractions, include:

  • ReplicaSet (RS). Ensures the desired amount of pod is what’s running.
  • Deployment. Offers declarative updates for pods an RS.
  • StatefulSet. A workload API object that manages stateful applications, such as databases.
  • DaemonSet. Ensures that all or some worker nodes run a copy of a pod. This is useful for daemon applications like Fluentd.
  • Job. Creates one or more pods, runs a certain task(s) to completion, then deletes the pod(s).

Micro Service

A specific part of a previously monolithic application. A traditional micro-service based architecture would have multiple services making up one, or more, end products. Micro services are typically shared between applications and makes the task of Continuous Integration and Continuous Delivery easier to manage. Explore the difference between monolithic and microservices architecture.

Images

Typically a docker container image – an executable image containing everything you need to run your application; application code, libraries, a runtime, environment variables and configuration files. At runtime, a container image becomes a container which runs everything that is packaged into that image.

Pods

A single or group of containers that share storage and network with a Kubernetes configuration, telling those containers how to behave. Pods share IP and port address space and can communicate with each other over localhost networking. Each pod is assigned an IP address on which it can be accessed by other pods within a cluster. Applications within a pod have access to shared volumes – helpful for when you need data to persist beyond the lifetime of a pod. Learn more about Kubernetes Pods.

Namespaces

Namespaces are a way to create multiple virtual Kubernetes clusters within a single cluster. Namespaces are normally used for wide scale deployments where there are many users, teams and projects.

Replica Set

A Kubernetes replica set ensures that the specified number of pods in a replica set are running at all times. If one pod dies or crashes, the replica set configuration will ensure a new one is created in its place. You would normally use a Deployment to manage this in place of a Replica Set. Learn more about Kubernetes ReplicaSets.

Deployments

A way to define the desired state of pods or a replica set. Deployments are used to define HA policies to your containers by defining policies around how many of each container must be running at any one time.

Services

Coupling of a set of pods to a policy by which to access them. Services are used to expose containerised applications to origins from outside the cluster. Learn more about Kubernetes Services.

Nodes

A (normally) Virtual host(s) on which containers/pods are run.

Kubernetes architecture and components

A K8S cluster is made of a master node, which exposes the API, schedules deployments, and generally manages the cluster. Multiple worker nodes can be responsible for container runtime, like Docker or rkt, along with an agent that communicates with the master.

Master components

These master components comprise a master node:

  • Kube-apiserver. Exposes the API.
  • Etcd. Key value stores all cluster data. (Can be run on the same server as a master node or on a dedicated cluster.)
  • Kube-scheduler. Schedules new pods on worker nodes.
  • Kube-controller-manager. Runs the controllers.
  • Cloud-controller-manager. Talks to cloud providers.

Node components

  • Kubelet. Agent that ensures containers in a pod are running.
  • Kube-proxy. Keeps network rules and perform forwarding.
  • Container runtime. Runs containers.

What benefits does Kubernetes offer?

Out of the box, K8S provides several key features that allow us to run immutable infrastructure. Containers can be killed, replaced, and self-heal automatically, and the new container gets access to those support volumessecretsconfigurations, etc., that make it function.

These key K8S features make your containerized application scale efficiently:

  • Horizontal scaling.Scale your application as needed from command line or UI.
  • Automated rollouts and rollbacks.Roll out changes that monitor the health of your application—ensuring all instances don’t fail or go down simultaneously. If something goes wrong, K8S automatically rolls back the change.
  • Service discovery and load balancing.Containers get their own IP so you can put a set of containers behind a single DNS name for load balancing.
  • Storage orchestration.Automatically mount local or public cloud or a network storage.
  • Secret and configuration management.Create and update secrets and configs without rebuilding your image.
  • Self-healing.The platform heals many problems: restarting failed containers, replacing and rescheduling containers as nodes die, killing containers that don’t respond to your user-defined health check, and waiting to advertise containers to clients until they’re ready.
  • Batch execution.Manage your batch and Continuous Integration workloads and replace failed containers.
  • Automatic binpacking.Automatically schedules containers based on resource requirements and other constraints.

What won’t Kubernetes do?

Kubernetes can do a lot of cool, useful things. But it’s just as important to consider what Kubernetes isn’t capable of:

  • It does not replace tools like Jenkins—so it will not build your application for you.
  • It is not middleware—so it will not perform tasks that a middleware performs, such as message bus or caching, to name a few.
  • It does not care which logging solution is used. Have your app log to stdout, then you can collect the logs with whatever you want.
  • It does not care about your config language (e.g., JSON).

K8s is not opinionated with these things simply to allow us to build our app the way we want, expose any type of information and collect that information however we want.

Kubernetes competitors

Of course, Kubernetes isn’t the only tool on the market. There are a variety, including:

  • Docker Compose—good for staging but not production-ready.
  • Nomad—allows for cluster management and scheduling but it does not solve secret and config management, service discover, and monitoring needs.
  • Titus—Netflix’s open-source orchestration platform doesn’t have enough people using it in production.

Overall, Kubernetes offers the best out-of-the-box features along with countless third-party add-ons to easily extend its functionality.

Getting Started with Kubernetes

Typically, you would install Kubernetes on either on premise hardware or one of the major cloud providers. Many cloud providers and third parties are now offering Managed Kubernetes services however, for a testing/learning experience this is both costly and not required. The easiest and quickest way to get started with Kubernetes in an isolated development/test environment is minikube.

How to install Kubernetes

Installing K8S locally is simple and straightforward. You need two things to get up and running: Kubectl and Minikube.

  • Kubectl is a CLI tool that makes it possible to interact with the cluster.
  • Minikube is a binary that deploys a cluster locally on your development machine.

With these, you can start deploying your containerized apps to a cluster locally within just a few minutes. For a production-grade cluster that is highly available, you can use tools such as:

  • Kops
  • EKS, which is an AWS managed service
  • GKE, provided by Google

Minikube allows you to run a single-node cluster inside a Virtual Machine (typically running inside VirtaulBox). Follow the official Kubernetes documentation to install minikube on your machine. https://kubernetes.io/docs/setup/minikube/.

With minikube installed you are now ready to run a virtualised single-node cluster on your local machine. You can start your minikube cluster with;

$ minikube start

Interacting with Kubernetes clusters is mostly done via the kubectl CLI or the Kubernetes Dashboard. The kubectl CLI also supports bash autocompletion which saves a lot of typing (and memory). Install the kubectl CLI on your machine by using the official installation instructions https://kubernetes.io/docs/tasks/tools/install-kubectl/.

To interact with your Kubernetes clusters you will need to set your kubectl CLI context. A Kubernetes context is a group of access parameters that defines which users have access to namespaces within a cluster. When starting minikube the context is automatically switched to minikube by default. There are a number of kubectl CLI commands used to define which Kubernetes cluster the commands execute against.

$ kubectl config get-context
$ kubectl config set-context <context-name>

$ Kubectl config delete-context <context-name>

Deploying your first containerised application to Minikube

So far you should have a local single-node Kubernetes cluster running on your local machine. The rest of this tutorial is going to outline the steps required to deploy a simple Hello World containerised application, inside a pod, with an exposed endpoint on the minikube node IP address. Create the Kubernetes deployment with;

$ kubectl run hello-minikube --image=k8s.gcr.io/

echoserver:1.4 --port=8080

We can see that our deployment was successful so we can view the deployment with;

$ kubectl get deployments

Our deployment should have created a Kubernetes Pod. We can view the pods running in our cluster with;

$ kubectl get pods

Before we can hit our Hello World application with a HTTP request from an origin from outside our cluster (i.e. our development machine) we need to expose the pod as a Kubernetes service. By default, pods are only accessible on their internal IP address which has no access from outside the cluster.

$ kubectl expose deployment hello-minikube --

type=NodePort

Exposing a deployment creates a Kubernetes service. We can view the service with:

$ kubectl get services

When using a cloud provider you would normally set —type=loadbalancer to allocate the service with either a private or public IP address outside of the ClusterIP range. minikube doesn’t support load balancers, being a local development/testing environment and therefore —type=NodePort uses the minikube host IP for the service endpoint. To find out the URL used to access your containerised application type;

$ minikube service hello-minikube -—url

Curl the response from your terminal to test that our exposed service is reaching our pod.

$ curl http://<minikube-ip>:<port>

Now we have made a HTTP request to our pod via the Kubernetes service, we can confirm that everything is working as expected. Checking the the pod logs we should see our HTTP request.

$ kubectl logs hello-minikube-c8b6b4fdc-sz67z

To conclude, we are now running a simple containerised application inside a single-node Kubernetes cluster, with an exposed endpoint via a Kubernetes service.

Minikube for learning

Minikube is great for getting to grips with Kubernetes and learning the concepts of container orchestration at scale, but you wouldn’t want to run your production workloads from your local machine. Following the above you should now have a functioning Kubernetes pod, service and deployment running a simple Hello World application.

From here, if you are looking to start using Kubernetes for your containerized applications, you would be best positioned looking into building a Kubernetes Cluster or comparing the many Managed Kubernetes offerings from the popular cloud providers.

Additional resources

For more on Kubernetes, explore these resources:

]]>
AWS CloudFormation Basics https://www.bmc.com/blogs/aws-cloudformation/ Fri, 24 Apr 2020 00:00:14 +0000 https://www.bmc.com/blogs/?p=17112 In the cloud native era, infrastructure as code (IaC) is a critical part of ensuring consistency and reusability. Most public providers have a version of IaC they offer; for AWS, it is CloudFormation. CloudFormation helps you model your resources by describing it in a template that can be deployed as a stack on AWS. With […]]]>

In the cloud native era, infrastructure as code (IaC) is a critical part of ensuring consistency and reusability. Most public providers have a version of IaC they offer; for AWS, it is CloudFormation.

CloudFormation helps you model your resources by describing it in a template that can be deployed as a stack on AWS. With CloudFormation, you can go from creating resources from the console to automating complex architecture on demand. Let’s get started with these basics of AWS CloudFormation.

(This tutorial is part of our AWS Guide. Use the right-hand menu to navigate.)

The benefits of using CloudFormation

CloudFormation offers a variety of benefits, including:

  • Improved automation. The simplicity of the template allows you to declare what you want your resources to look like. This eliminates the need to rely on other scripting tools to create the resources.
  • Quick infrastructure replication. You can quickly replicate your infrastructure without affecting other resources that your template previously created. The template can be used to create as many stacks as needed.
  • Infrastructure consistency. The declarative way of defining templates allows for consistency—you can be assured that stacks created with the template will be identical.
  • Easy-to-read template. If you are in the web application or microservice space, you have used yaml or JSON at some point. They are both widely used, therefore making it easy to understand or find resources on it.

How does CloudFormation work?

There are three concepts you need to be aware of when using CloudFormation, and these concepts are fundamental to how it works:

  • Template
  • Stack
  • Change Set

Let’s look at each.

Template

A template is a declarative way of defining your resources as a yaml or json file. This template can then be used to deploy the resources either using the console or CLI.

This demo.yaml template shows an example of a yaml template file that creates an EC2 instance and Elastic IP and attaches the IP to the instance.

AWSTemplateFormatVersion: "2010-09-09"

Description: A demo template

Resources:

MyEC2Instance:

Type: "AWS::EC2::Instance"

Properties:

ImageId: "ami-0f7919c33c90f5b58"

InstanceType: t2.nano

KeyName: testkey

MyEIP:

Type: AWS::EC2::EIP

Properties:

InstanceId: !Ref MyEC2Instance

Stack

When you deploy a template like the example we had above, it creates both resources (EIP and EC2) as a stack. These resources are created as a unit; therefore, any update or deletion of resources will be applied to the stack.

You can use a single template to create multiple stacks as long as there are no naming conflicts.

Change Set

When a stack needs to be updated, you can simply run an update on the stack and let AWS take care of replacing the necessary resources. Change Set takes that further and gives you the ability to see the impact of the changes you are applying before they are actually applied. In the terraform world this would be equivalent to terraform plan.

A basic CloudFormation example

To demonstrate how CloudFormation works, we will deploy the demo.yaml template. There are two ways to deploy the template, from the console or CLI. For this demo we will use AWS CLI which allows us to trigger CloudFormation API actions.

(This example assumes you have an AWS account, networking setup, access keys and AWS CLI installed.)

Create a stack

To create a new stack, run:

aws cloudformation create-stack --stack-name  demo-stack --template-body file://demo.yaml

After running this command, you should see an output that looks like this:

{    
"StackId": "arn:aws:cloudformation:us-east-2:<ACCOUNT>:stack/demo-stack/a2ade760-7ccc-11ea-bcf5-06d398e7edd6"
}

If there are no errors with the deployment, you should see the stack creation as complete in the AWS console.

Updating a stack

Let’s say you want to update the stack to use a different instance type. You can simply update the template, removing t2.nano and adding t2.micro. With that change we can then run the update-stack API action to deploy that change. This is also a good time to use a change set to check the impact of our changes.

Run:

aws cloudformation create-change-set --stack-name demo-stack --change-set-name demo-changeSet --template-body file://demo.yaml

In the AWS console we can see the changeset we just created:

Click on the change set name and you should see what will happen if you apply this change set. The image below shows the one for demo-changeSet.

As we can see, both the EC2 and ElasticIP will be modified. Also, it looks like the EC2 instance will be replaced. In our case, we are fine to replace the EC2 instance so we can go ahead and apply the changeset.

To apply the change set, we can run:

aws cloudformation execute-change-set --stack-name demo-stack --change-set-name demo-changeSet

In the AWS console, we can see the changes being applied.

Deleting a stack

To delete the stack, you can run the delete-stack API action. In the demo example, run:

aws cloudformation delete-stack --stack-name demo-stack

In the console, you can see the stack being deleted.

]]>
What is a Service Mesh? https://www.bmc.com/blogs/service-mesh/ Tue, 21 Apr 2020 00:00:14 +0000 https://www.bmc.com/blogs/?p=17047 Organizations are using microservice architecture to build scalable network applications thanks to the resurrection of containers. In a typical microservice architecture, the application consists of multiple microservices that communicate using remote procedure calls (RPC) over the network, with each service performing a specific business task. This allows each of the services to be built using […]]]>

Organizations are using microservice architecture to build scalable network applications thanks to the resurrection of containers. In a typical microservice architecture, the application consists of multiple microservices that communicate using remote procedure calls (RPC) over the network, with each service performing a specific business task. This allows each of the services to be built using whatever programming language fits the task, a backend datastore that fits the data type, and independent deployment (each service has an independent lifecycle).

One of the biggest benefits you get when using this pattern is that you can have different developers working on different services simultaneously. In the case where one service goes down, the impact is limited to that service, not the others.

Of course, microservices as a pattern does come with some disadvantages, especially when you run a large ecosystem of services. The bigger the ecosystem, the more difficult it is to get insight into all the moving pieces and to manage the network communications between all the services.

This is where service mesh comes in.

What is a service mesh?

A service mesh is a dedicated infrastructure that handles all service-to-service network communication needs within the ecosystem. It provides visibility, resiliency, traffic, and security control of these services with little or no change to your existing code. This is a big win for developers, who no longer have to build networking concerns into their code.

Advantages of using a service mesh

Using a service mesh offers plenty of benefits, including:

  • Observability. Typically, teams have different tools for keeping track of logging, tracing, metrics, and things like security control. With a service mesh, you get all these benefits, eliminating the need for other tools.
  • Resiliency. Service mesh offers resiliency features like circuit breaking, latency-aware load balancing, eventually consistent service discovery, retries, timeout, and deadlines.
  • Traffic control. A service mesh gives granular control of network traffic to determine where your request is routed.
  • Security. Service mesh provides certificate authority that generates a per service certificate for TLS communication between services.
  • Delay and fault injection. Service mesh allows you to inject failure and latency to simulate what would happen in a real situation. The benefit is that you can rest assured that you know how your services will behave in case of an issue.
  • Less code for Devs and Ops. Service mesh also reduces the amount of code devs must write. Ops don’t have to involve the devs about things like service retries and timeouts. A dedicated layer of infrastructure that takes care of this sits between the devs and ops, allowing a uniform and yet highly customizable way of handling service-to-service communication while allowing the code to stay relatively light.

Service mesh architecture

A typical service mesh architecture is made up of two network planes.

  • The Data Plane (proxy) is responsible for moving application request traffic between all the services. This plane is responsible for things like health checking, load balancing, authentication, authorization, etc.
  • The Control Plane provides policy and configuration for all the services in the mesh. It does not touch or care about the network packet, its main job is to configure the data plane.

Popular service mesh projects

Several technologies offer service mesh technologies. The most popular ones are:

]]>
Introduction to Kubernetes Helm Charts https://www.bmc.com/blogs/kubernetes-helm-charts/ Fri, 10 Apr 2020 00:00:54 +0000 https://www.bmc.com/blogs/?p=16937 In this post we are going to discuss a tool used with Kubernetes called Helm. Part of our multi-part Kubernetes Guide, this article will: Explore Helm charts Determine when and why to use Helm and Helm Charts Provide instructions for getting started To explore other K8s topics, use the navigation menu on the right-hand side. (This […]]]>

In this post we are going to discuss a tool used with Kubernetes called Helm. Part of our multi-part Kubernetes Guide, this article will:

  • Explore Helm charts
  • Determine when and why to use Helm and Helm Charts
  • Provide instructions for getting started

To explore other K8s topics, use the navigation menu on the right-hand side.

(This article is part of our Kubernetes Guide. Use the right-hand menu to navigate.)

What is Helm?

In simple terms, Helm is a package manager for Kubernetes. Helm is the K8s equivalent of yum or apt. Helm deploys charts, which you can think of as a packaged application. It is a collection of all your versioned, pre-configured application resources which can be deployed as one unit. You can then deploy another version of the chart with a different set of configuration.

Helm helps in three key ways:

  • Improves productivity
  • Reduces the complexity of deployments of microservices
  • Enables the adaptation of cloud native applications

Why use Helm?

Writing and maintaining Kubernetes YAML manifests for all the required Kubernetes objects can be a time consuming and tedious task. For the simplest of deployments, you would need at least 3 YAML manifests with duplicated and hardcoded values. Helm simplifies this process and creates a single package that can be advertised to your cluster.

Helm is a client/server application and, until recently, has relied on Tiller (the helm server) to be deployed in your cluster. This gets installed when installing/initializing helm on your client machine. Tiller simply receives requests from the client and installs the package into your cluster. Helm can be easily compared to RPM of DEB packages in Linux, providing a convenient way for developers to package and ship an application to their end users to install.

Once you have Helm installed and configured (details below), you are able to install production-ready applications from software vendors, such as MongoDB, MySQL and others, into your Kubernetes cluster with one very simple helm install command. Additionally, removing installed applications in your cluster is as easy as installing them.

What are Helm charts?

Helm Charts are simply Kubernetes YAML manifests combined into a single package that can be advertised to your Kubernetes clusters. Once packaged, installing a Helm Chart into your cluster is as easy as running a single helm install, which really simplifies the deployment of containerized applications.

Describing Helm

Helm has two parts to it:

  • The client (CLI), which lives on your local workstation.
  • The server (Tiller), which lives on the Kubernetes cluster to execute what’s needed.

The idea is that you use the CLI to push the resources you need and tiller will make sure that state is in fact the case by creating/updating/deleting resources from the chart. To fully grasp helm, there are 3 concepts we need to get familiar with:

  • Chart: A package of pre-configured Kubernetes resources.
  • Release: A specific instance of a chart which has been deployed to the cluster using Helm.
  • Repository: A group of published charts which can be made available to others.

Benefits of Helm

Developers like Helm charts for many reasons:

Boosts productivity

Software engineers are good at writing software, and their time is best spent doing just that. Using Helm allows software to deploy their test environments at the click of a button.

An example of this might be that, in order to test a new feature, an engineer needs a SQL database. Instead of going through the process of installing the software locally, creating the databases and tables required, the engineer can simply run a single Helm Install command to create and prepare the database ready for testing.

Reduces duplication & complexity

Once the chart is built once, it can be used over and over again and by anyone. The fact that you can use the same chart for any environment reduces complexity of creating something for dev, test and prod. You can simply tune you chart and make sure it is ready to apply to any environment. And you get the benefit of using a production ready chart in dev.

Smooths the K8S learning curve

It’s no secret that the learning curve for Kubernetes and containers is long for your average developer. Helm simplifies that learning curve: developers do not require a full, detailed understanding of the function of each Kubernetes object in order to start developing and deploying container applications.

Helm easily integrates into CI/CD pipelines and allows software engineers to focus on writing code—not deploying applications.

Simplifies deployments

Helm Charts make it easy to set overridable defaults in the values.yaml file, allowing software vendors or administrators of charts to define a base setting. Developers and users of charts can override these settings when installing their chart to suit their needs. If the default installation is required, then no override is required.

Deploying applications to Kubernetes is not a straightforward process, with different objects being tightly coupled. This required specific knowledge of these objects and what their functions are in order to be able to successfully deploy. Helm takes the complexity out of that doing much of the hard work for you.

Describing a Helm chart

Helm has a certain structure when you create a new chart. To create, run “helm create YOUR-CHART-NAME”. Once this is created, the directory structure should look like:

YOUR-CHART-NAME/
 |
 |- .helmignore 
 | 
 |- Chart.yaml 
 | 
 |- values.yaml 
 | 
 |- charts/ 
 |
 |- templates/
  • .helmignore: This holds all the files to ignore when packaging the chart. Similar to .gitignore, if you are familiar with git.
  • Chart.yaml: This is where you put all the information about the chart you are packaging. So, for example, your version number, etc. This is where you will put all those details.
  • Values.yaml: This is where you define all the values you want to inject into your templates. If you are familiar with terraform, think of this as helms variable.tf file.
  • Charts: This is where you store other charts that your chart depends on. You might be calling another chart that your chart need to function properly.
  • Templates: This folder is where you put the actual manifest you are deploying with the chart. For example you might be deploying an nginx deployment that needs a service, configmap and secrets. You will have your deployment.yaml, service.yaml, config.yaml and secrets.yaml all in the template dir. They will all get their values from values.yaml from above.

Installing Helm and configuring Helm Charts

Ready to use Helm? Installing and configuring Helm for your K8S cluster is a very quick and straight forward process—there are multiple versions of Helm that can be installed (v1/v2 and most recently v3), all of which can be configured to your organization’s needs. Check out the getting started page for instructions on downloading and installing Helm.

Beginning your first Helm chart is as simple as installing some charts from the stable repository, which is available on GitHub. The Helm stable repository is a collection of curated applications ready to be deployed into your cluster.

Helm users can write their own charts or can obtain charts from the stable repository:

If you want to write your own Helm Charts for your applications, Helm provides a simple Developer’s Guide for getting started.

Helm simplifies software deployment

In summary, Helm takes a lot of the complexity out of deploying software and your own applications to Kubernetes. It can be installed in a matter of minutes and you can be deploying charts from the stable repository in no time. Writing your own charts is also a straightforward process, though does require understanding of Kubernetes objects. Helm can empower your developers to work more efficiently giving them the tools they need to test their code locally.

Additional resources

For more on Kubernetes, explore these resources:

]]>