A Quick Guide to Writing YAML for Kubernettes

Written by asadfaizi | Published 2022/01/18
Tech Story Tags: cloud-computing | kubernetes | k8s | devops | gitops | containers | mesh | yaml

TLDRvia the TL;DR App

What is YAML?

YAML’s official definition is a “human-friendly, data serialization standard for all programming languages.” YAML’s main advantage over other similar formats like JSON or XML is its human readability. YAML was specifically designed to be easily readable and editable by humans. This makes it ideal for dual human-machine use cases such as log files, configuration files, inter-process messages, and in this case, also for Kubernetes config and definition files. Read more about the rules of YAML syntax here.

In YAML, you only need to know 2 types of structures: lists and maps.

A YAML map is how you define key-value pairs, which is an intuitive and convenient method of creating configurations, such as in Kubernetes (A sample Kubernetes config showing a map is below).

Here, ‘apiVersion’ and ‘kind’ are the keys, and ‘v2.4’ and ‘pod’ are the respective values assigned to these keys. The 3-dashes (—) are used to denote the start of a new YAML file.

apiVersion: v2.4
kind: pod

A YAML list is simply a sequence of objects treated as a unit. For example:

containers:
- name: webserver1
  image: nginx:1.6
  ports:
   - containerPort:80
- name: database-server
  image: mysql-3.2
  ports:
   - containerPort:3306
- name: rss-reader
  image: rss-php-nginx:2.8
  ports:
   - containerPort:86

In the example above, we have a list of 3 items defined in our ‘containers’ key. Each of these 3 items is differently colored for better differentiation. And each item in the list contains a map containing 3 sub-objects: ‘name’, ‘image’, and ‘ports’.

Let’s now take a look at real-world examples of how to create or define Kubernetes objects using YAML. If you first need to re-familiarize yourself with some Kubernetes objects, go back and read this introductory article.

How to create a Kubernetes Pod using YAML

To create a Kubernetes pod with YAML, you first create an empty file, assign it the necessary access permissions, and then define the necessary key-value pairs. The important ones are the apiVersion, the kind (pod), name, and the containers within the pod.

For instance, below is the YAML code to create a pod named mywebapp1 that has 2 containers: One is a web server and the other is a database server. It is also assigned to a specific volume named websvr-storage:

Filename: /k8s/pods/pod1.YAML

apiVersion: v1
kind: Pod
metadata:
  name: mywebapp1
  labels:
    role: webserver-role
    app: nginx
spec:
  containers:
  - name: webserver1
    image: nginx:1.6
    ports:
     - containerPort:80
  - name: database-server
    image: mysql-3.2
    ports:
     - containerPort:3306
volumes:
  - name: websvr-storage
    emptyDir: {}

As you may have guessed, an important key-value here is kind: Pod. You can define many more parameters and values for a pod. For example, you can specify extra parameters to assign CPU resources, configure quality-of-service for a pod, configure service accounts, configure pod initialization, assign a pod to a specific node, and many more tasks as listed in the official Kubernetes documentation.

How to create a Kubernetes Deployment using YAML

Remember that in the case of deployment, we are creating a set of resources to be managed as a unit. And also keep in mind that one of the reasons to use Kubernetes is for redundancy of our resources, mainly achieved via replicas and replica sets. Therefore, one of the most common (though not mandatory) specifications in the deployment YAML file is the number of replicas we want, and this is nested under ‘spec’, as detailed in the sample code below. The mandatory specifications to be included when defining our deployment via YAML are apiVersion, kind, metadata, and spec.

Filename: /k8s/deployments/deployment1.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment1
  labels:
	app: nginx
spec:
  replicas: 3
  selector:
    matchlabels:
      app: nginx
template:
  metadata:
    labels:
      app: nginx
  spec:
    containers:
    - name: webserver1
	  image: nginx:1.6
	  ports:
 	  - containerPort:80
    - name: database-server
	  image: mysql-3.2
	  ports:
 	  - containerPort:3306

  • We have specified that in our desired state, this deployment should always have 3 replicas.
  • Because deployments are sets of objects, we must specify what objects are to be created by this deployment. This is done under the template: specification. And to ensure we are creating only the correct pods in this deployment, we use the .selector.match labels: specification. In this case, only those pods that match our desired label (which is app:nginx) will be included in this deployment.
  • We have also specified that we want 2 pods to be created in this deployment. These pods are webserver1 and database-server. And their respective specs are also included here, just as they were when creating the individual pods.
  • And finally, to actually create the deployment, use the kubectl command:

kubectl create -f /k8s/deployments/deployment1.yaml

How to create a Kubernetes Service using YAML

Now that we have defined our pods and the deployment to create those pods, we need a way of consistently being able to access our pod-set even if the pods themselves are recreated or lost. And this should be transparent to any application or other pods trying to access this pod-set.

For example, when a user searches from our website’s frontend using HTML, that search request is directed to a set of pods where our database is defined. If the ‘database’ pod goes down and has to be recreated, the frontend should be completely unaware of this. The request should still be acknowledged and fulfilled as usual. And this is achieved by means of Kubernetes services. A service is an abstract way to expose an application running on a set of Pods as a network service.

Let’s take a look at a sample service definition in Kubernetes YAML:

apiVersion: v1
kind: Service
metadata:
  name: nginx-service  
  labels:
    app: nginx
spec:
  ports:
  - nodePort: 30500
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: NodePort

Note the following:

  • Our service name is ‘nginx-service’. We specify that this is a service using the kind: Service specification
  • We have defined a selector that has the app: nginx label. Using this, the service will be able to match and identify the pods in our Nginx deployment, since the deployment and the pods also have the exact same label. This is how all incoming requests to this Nginx service will be automatically routed to the Nginx deployment.
  • This Kubernetes service is of type NodePort (30500) and it points to our Nginx deployment. Using this NodePort, you will be able to access the Nginx service on all Kubernetes nodes via port 30500.

Just as with deployments and nodes, there are many more specifications you can define for services. Read more about these in the official Kubernetes documentation.

Is YAML for Kubernetes really easy?

Even though YAML was invented to be more human-readable than other formats like JSON if you need to create tens of YAML manifest files to deploy, manage and upgrade your Kubernetes applications, the friendliness of YAML decreases significantly. Kubernetes requires the manual creation of a large number of YAML manifest and config files. In addition to that, Kubernetes uses YAML’s more advanced features, like how to work with blobs of text or with a more complex “array in a hash in an array” type of structure.

As developers, you will manually create Config files, and YAML or JSON manifests for each Docker container keeping into account syntax and all attributes. With time, developers end up with a huge wall of small YAML files that define all of the resources in their environment. Oftentimes, developers’ artifacts grow exponentially and become extremely difficult to manage.

This is a complexity that development teams should handle along with product development, and with time it becomes a burden. This is why you need to choose the right tools that make you focus more on your development and spend less time managing your infrastructure.

How CloudPlex addresses your pain

With CloudPlex, developers no longer need to write the manifest files, nor search for valid parameters and supported values. Developers just configure services using a visual interface, in a single view. The platform performs validation and generates all related manifest and config files, which can also be downloaded and used on any K8s cluster.
The screenshot is a visual interface used by the developer to create the same application as above. As you can see, the developer can create the application simply by dragging and dropping containers from a palette to the canvass and configuring the containers visually in the Config Panel:

First published here


Written by asadfaizi | Founder and CEO @ CloudPlex.io | Entrepreneur | Technologist | Mad Cloud Scientist
Published by HackerNoon on 2022/01/18