In this post, we will provide a brief introduction to the container orchestrator Kubernetes (K8s). We recommend having basic knowledge of Docker to gain an overall understanding of containers, and because this post will use Docker as the container system.
- What is Kubernetes?
- Basic concepts
- Cluster
- Pod
- Service
Installation
- Common steps
- Initializing the cluster
- Adding workers
- Testing
- Deleting resources
What is Kubernetes?
According to the Kubernetes documentation:
Kubernetes is an open-source platform for automating the deployment, scaling and management of containerized applications.
To expand on this definition, Kubernetes is a system for controlling the lifecycle of containers using various methods that enable a high level of availability and scalability, among other features.
Basic concepts
Cluster
A cluster is a group of computers. In our case, this will be a Kubernetes cluster, and each computer will have one of two roles:
- Master: there is only one in the group, and it is responsible for distributing the workload among the other nodes, maintaining the desired operating state, and scaling or updating applications.
- Worker: the other nodes that are not the master. These run applications using containers. The minimum recommended number of workers is 3.
Communication between the master and the workers takes place through the Kubernetes API, via the master (although end users can also interact with the API). Workers are connected to the master through the kubelet process.
A Kubernetes cluster can be deployed on a physical machine or a virtual machine. It is also possible to use Minikube, a lightweight implementation of Kubernetes that creates a virtual machine locally with a single worker.
Pod
This is the smallest unit of execution in Kubernetes. It represents processes running in the cluster. A Pod contains one or more containers (Docker containers, for example) and manages application resources, the IP address and various options that determine how the containers work.
Service
This is an abstraction that defines a set of pods running a microservice, such as the frontend.
Pods are finite: they are “born” and “die”, but cannot be “resurrected”. They are created and deleted throughout the execution of the Deployment. Each pod has its own IP address, so the IP addresses of pods running at one point in time will differ from those running at another. This poses a problem, since we want a fixed IP address when accessing pods. The concept of a service exists to solve this problem.
Installation
As mentioned earlier, we need a server acting as the master and another as a worker, so we will need at least 2 VPS servers. When initializing them, select the Docker image; in this case, it will run on Ubuntu 18.04. To avoid problems, the servers must have at least two processors, although you can force them to run with fewer, but performance may not meet expectations.
Common steps
The following dependencies and Kubernetes itself must be installed on every machine in the cluster, regardless of its role.
- Disable swap:
# swapon -s && swapoff -aTo disable the swap partition permanently, open the /etc/fstab file (with vim, for example) and comment out the line corresponding to the swap partition, as shown in the following image:
- Start the Docker service and enable it at startup:
# systemctl enable docker.service && systemctl start docker.service- Update the system:
# apt update && apt upgrade -y && apt dist-upgrade -y- Dependencies (in case they are not already installed):
# apt install -y apt-transport-https- Import the Kubernetes repository key:
# curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add- Add the repository:
# curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | \ gpg --dearmor -o /etc/apt/sources.list.d/kubernetes.apt.keyring.gpg
# echo "deb [signed-by=/etc/apt/sources.list.d/kubernetes.apt.keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.32/deb/ /" > /etc/apt/sources.list.d/kubernetes.list- Install Kubernetes:
# apt update && apt install -y kubeadm kubelet kubectlInitializing the cluster
Now we will initialize the cluster on the node acting as the master. To do this, run the following commands only on the master:
# kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address DIRECCION_IP_MASTERWhere DIRECCION_IP_MASTER is the public IP address of our master VPS.
If we get the following error due to the number of processors:
([ERROR NumCPU]: the number of available CPUs 1 is less than the required 2)we can still run it, although performance will naturally be lower, by adding the following option to the previous command:
--ignore-preflighterrors=NumCPU.If everything has gone well, we should get a message like this (it may take several minutes to run all the commands):
We must copy the command starting with “kubeadm join …” (at the end of the message), as this will allow us to add nodes to our cluster.
- Configure the cluster: we must create a new configuration for the cluster in the $HOME/.kube directory. To do this, we can copy the default Kubernetes configuration using the following commands:
# mkdir -p $HOME/.kube
# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# chown $(id -u):$(id -g) $HOME/.kube/configDeploy flannel to manage container IP addresses, since Kubernetes assumes that each pod has its own unique IP address:
# kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/main/Documentation/kube-flannel.ymlTo check the active nodes and the pods and their status, run the following two commands, respectively:
# kubectl get nodes
# kubectl get pods --all-namespacesBefore adding nodes, we must add the firewall rules. In my case, I have decided to allow all TCP traffic between the worker and the master using the following configuration, where the IP address shown belongs to the worker:
Adding workers
To add a new node to the cluster, we need the “kubectl join …” command mentioned earlier, as it contains the key for adding a node:
# kubeadm join 85.208.20.82:6443 --token *** --discovery-token-ca-cert-hash sha256: ***Where the asterisks represent the specific keys.
After several minutes, we should see the following message, confirming that everything has gone as expected:
We can check from the master that the node has been added to the cluster by running this again
# kubectl get nodesTesting
Now that we have at least one node, we can check whether it works correctly. To do this, we will deploy a simple nginx web page.
- Create the directory on the worker where our web server will be hosted:
# mkdir -p nginx/
# cd nginx/- We must create a YAML file with the configuration we want, for example:
apiVersion: apps/v1 # Use apps/v1beta2 for versions earlier than 1.9.0
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # tells the controller to run 2 pods
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9 # image and version to use
ports:
- containerPort: 80 # port it runs on; the default for an HTTP server is 80And save it in a file with the .yaml extension, for example nginx.yaml.
- Create a new resource from the YAML:
# kubectl create -f nginx.yamlWe will receive the following message:
deployment.apps/nginx-deployment createdWe can view the deployments and their status with the following command:
# kubectl get deploymentswhich will return:
We can also get more information about a specific resource by running:
# kubectl describe deployment DESPLIEGUEwhere DESPLIEGUE in our case is nginxdeployment:
- After the deployment, two more pods have been created (since we set replicas: 2), which we can easily check with the command shown earlier:
# kubectl get podsAnd, naturally, get more information about each pod with:
# kubectl describe pod PODwhere POD is the name obtained from the previous command.
Finally, we need to create a service, otherwise we will not see the output of our HTTP server.
- Create a YAML file with the following
content in nginx-svc.yaml: https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/service/networking/nginx-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
labels:
run: nginx-svc
spec:
type: NodePort
ports:
- port: 80
protocol: TCP
selector:
app: nginx- Create the service as before with:
# kubectl create -f nginx-svc.yamlView the list of services with:
# kubectl get serviceAs shown in the list, the port we must use to access the web server is not 80, but 31890 (in my case), so when entering it in a web browser's address bar, we must use http://IP:PUERTO, giving the following result:
Deleting resources
To delete different types of resources, pods or services, we can use the “kubectl delete” command if we know the resource identifier:
- Services:
# kubectl delete svc/SERVICIO- Pods:
# kubectl delete pod/POD- Deployments:
# kubectl delete deployment/DEPLOYMENTAuthor: David Población.