Introducción

Buenas, en este post vamos a hacer un despliegue de un clúster de Kubernetes usando una herramienta bastante sencilla llamada Kind. Usaremos únicamente un nodo que mediante contenedores creará los controller y worker

Veremos como podemos escalar nuestro escenario muy fácilmente modificando únicamente un fichero .yaml.

Escenario a usar

Vamos a usar un escenario con vagrant y kvm con un único nodo:

Vagrant.configure("2") do |config|

        config.vm.define :kind do |kind|
          kind.vm.box = "generic/debian10"
          kind.vm.hostname = "kind"
          kind.vm.synced_folder ".", "/vagrant", disabled: true
          kind.vm.provider :libvirt do |libvirt|
            libvirt.uri = 'qemu+unix:///system'
            libvirt.host = "debian"
            libvirt.cpus = 1
            libvirt.memory = 1024
          end
        end

end

Para levantar el escenario:

vagrant up

Instalación de kind

Entramos en nuestra máquina que hemos creado:

vagrant ssh kind

Una vez dentro, antes de instalar kind, debemos de instalar docker, ya que cada nodo del cluster se va ejecutar en un contenedor, para ello:

sudo apt update && sudo apt install docker.io -y

Ahora procedemos a la instalación de kind:

curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.10.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin

Y ya podemos ver su versión:

kind version
kind v0.10.0 go1.15.7 linux/amd64

Despliegue cluster básico kubernetes

Para crear un cluster de kubernetes básico con un único contenedor con el rol de controller y worker ejecutaremos la siguiente instrucción:

sudo kind create cluster

Y podemos comprobarlo:

sudo kind get clusters
kind

sudo kind get nodes
kind-control-plane

Para borrar el cluster:

sudo kind delete cluster

Despliegue cluster más complejos

Sin embargo, queremos crear cluster más complejos, para ello tenemos que crear un fichero config.yaml en el cual especificaremos nuestro cluster, por ejemplo:

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker

Y para crearlo mediante nuestro fichero:

sudo kind create cluster --config=config.yaml

Comprobamos:

sudo kind get nodes
kind-control-plane
kind-worker
kind-worker2

Y también podríamos comprobarlo a través de docker:

sudo docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                       NAMES
c2abbb8d7d3d        kindest/node:v1.20.2   "/usr/local/bin/entr…"   2 minutes ago       Up 2 minutes        127.0.0.1:39921->6443/tcp   kind-control-plane
c04733ee609c        kindest/node:v1.20.2   "/usr/local/bin/entr…"   2 minutes ago       Up 2 minutes                                    kind-worker
7f711e59a193        kindest/node:v1.20.2   "/usr/local/bin/entr…"   2 minutes ago       Up 2 minutes                                    kind-worker2

También podríamos crearlos con alta disponibilidad en los controladores, en el fichero config.yaml:

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: control-plane
- role: control-plane
- role: worker
- role: worker
- role: worker

Y comprobamos:

sudo kind get nodes
kind-worker2
kind-worker
kind-control-plane3
kind-control-plane2
kind-control-plane
kind-external-load-balancer
kind-worker3

Interactuando con el cluster

Para hacer diferentes pruebas, hemos instalado la utilidad de kubectl:

curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

Para que kubectl se sincronice con kind fácilmente, crearemos un clúster nuevo una vez instalado kubectl.

Ahora ya podremos interactuar con nuestro cluster:

sudo kind create cluster --config=config.yaml
sudo kubectl get nodes
NAME                 STATUS   ROLES                  AGE     VERSION
kind-control-plane   Ready    control-plane,master   5m48s   v1.20.2
kind-worker          Ready    <none>                 5m15s   v1.20.2
kind-worker2         Ready    <none>                 5m14s   v1.20.2

Vamos a desplegar un nginx con el siguiente fichero deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: default
  labels:
    app: nginx
spec:
  revisionHistoryLimit: 2
  strategy:
    type: RollingUpdate
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        ports:
        - name: http
          containerPort: 80

Y su servicio NodePort a partir del fichero service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: default
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: http
  selector:
    app: nginx

Hacemos el despliegue de ambos y comprobamos que se han creado correctamente:

kubectl apply -f deployment.yaml 
deployment.apps/nginx created

kubectl create -f service.yaml 
service/nginx created

sudo kubectl get all
NAME                        READY   STATUS    RESTARTS   AGE
pod/nginx-bdc5c7d65-46qqz   1/1     Running   0          69s
pod/nginx-bdc5c7d65-qltfb   1/1     Running   0          69s

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
service/kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP        13m
service/nginx        NodePort    10.96.91.230   <none>        80:30481/TCP   69s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   2/2     2            2           69s

NAME                              DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-bdc5c7d65   2         2         2       69s

Para poder comprobarlo desde la consola, tendremos que obtener la ip del nodo controlador, para ello:

sudo docker inspect -f '' kind-control-plane
172.18.0.3

Y con la ip y el puerto obtenido anteriormente podremos obtener la página generada de nginx:

curl 172.18.0.3:30481
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>