Instalar Cluster de Kubernetes con vSphere CSI

En esta guía revisaremos la instalación y configuración de un cluster Kubernetes sobre Ubuntu 20.04 utilizando containerd, calico, realizando la integración vía vSphere CSI (Container Storage Interface) para proveer los volúmenes persistentes para los contenedores que funcionarán en el cluster. Ademas utilizaremos MetalLB como balanceador de carga para acceder a nuestros servicios.

Introducción

Si ya estas aquí, es posible que estés iniciando o ya sepas que es Kubernetes (k8’s), para que sirve o cual es la función principal. Aun así siempre es bueno revisar la documentación oficial para saber las nuevas versiones, características y soporte de kubernetes, containerd, calico, MetalLB y los drivers CSI, donde en este caso, vamos a utilizar vSphere CSI para aprovechar las bondades de esta integración.

Entonces para la instalación del cluster vamos a utilizar 4 maquinas virtuales, con la instalación por defecto de la imagen de Ubuntu server 20.04.2. Importante señalar que esto es para una ambiente de laboratorio, aun así si quisieras pasar a producción siempre debe tener al menos 3 nodos master para conseguir la alta disponibilidad necesaria para la gestión de kubernetes.

Servidores

Para esta guia, utilizaremos los siguientes requerimientos y maquinas:

NombreCPURAMDiscoHW VersionAvanzadasIP
masterprd4vcpu8G30gbVersion 15 o superiordisk.EnableUUID = TRUE40.40.40.206
workerprd012vcpu4G30gbVersión 15 o superiordisk.EnableUUID = TRUE40.40.40.204
workerprd022vcpu4G30gbVersión 15 o superiordisk.EnableUUID = TRUE40.40.40.203
workerprd032vcpu4G30gbVersión 15 o superiordisk.EnableUUID = TRUE40.40.40.202

Para los nombres siempre utiliza dns o en su defecto agregarlos en la tabla host de cada servidor, para esta guía yo utilizo mi dns interno para la gestión de nombres. Con respecto a la versión del hw virtual, es necesario que debe ser desde la versión 15 que equivale a la versión de vSphere 6.7 U2 o una versión superior, en este caso lo estaremos configurando con la versión de hw 18 ya que tengo instalado vSphere 7U2 y por último muy importante, cada maquina virtual debe ser configurada con el parámetro avanzado disk.EnableUUID ya que son los requerimientos necesarios para utilizar vSphere CSI. Ademas deben tener acceso a internet.

Instalación Cluster Kubernetes

Validamos en TODOS los servidores se encuentren completamente actualizados despues de la instalacion

sudo apt update
sudo apt -y upgrade && sudo reboot

Nos conectamos nuevamente vía SSH con nuestros servidores y nos aseguramos que respondan por dns

ahora pasaremos a la instalación de algunos pauetes necesarios y la configuracion del repositorio para apt y posterior una actualizacion de los repositorios de apt

sudo apt -y install curl apt-transport-https
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt update

Ahora pasaremos a instalar los paquetes importantes para la configuración y administración de kubernetes,

sudo apt -y install vim git curl wget kubelet kubeadm kubectl containerd
sudo apt-mark hold kubelet kubeadm kubectl containerd

sudo apt-mark hold es para que los paquetes no se remuevan o actualicen de versión automáticamente.

Deshabilitar Swap

Como requerimiento para el cluster de kubernetes es necesario deshabilitar swap, por tanto con los siguientes comandos lo realizaremos

sudo swapoff -a
sudo nano /etc/fstab

Con el primer comando se deshabilita swap y en el segundo comenta la linea en fstab para que al reinicio no se active nuevamente por tanto quedaria asi

Configuración ContainerD

Ahora es necesario configurar algunos módulos necesarios para el funcionamiento de ContainerD

cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF

Con el comando anterior estamos generando el archivo containerd.conf en la ruta para que cargue los modulos overlay y br_netfilter, luego de eso activaremos los cambios con los siguientes comandos:

sudo modprobe overlay
sudo modprobe br_netfilter

Y podemos validar la configuracion con el comando

lsmod | grep br_netfilter

Ahora de acuerdo a las necesidades de ContainerD realizaremos algunas configuraciones necesarias que involucran parámetros de kernel para el buen funcionamiento

cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

Y con el siguiente comando aplicamos los cambios

sudo sysctl --system

Por ultimo realizamos la configuracion y final de containerd

sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
sudo systemctl restart containerd

Con el primero comando se genera la carpeta para luego con el segundo comando dejar el archivo de configuracion en la ruta y finalmente reiniciamos los servicios y nos aseguramos que se inicien al booteo.

Configuración Nodo Master

En esta etapa SOLO realizaremos los comandos en el nodo MASTER para comenzar con la configuración necesaria. Por tanto con el siguiente comando en el nodo master vamos a inicializar kubernetes

sudo kubeadm init

Este comando puede tomar algún tiempo, por tanto alcanzas para ir a preparar un café. Cuando termine la ejecución nos mostrara lo siguiente:

Es importante señalar que ahora la aplicacion nos esta solicitado realizar los siguientes pasos:

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 40.40.40.206:6443 --token u31dsc.dbotgztbrid0f6h0 \
        --discovery-token-ca-cert-hash sha256:efecb019f0351590c1a3b30e61a1ac06b65c617b61bfcf63daae2bf7de010540

La primera parte genera una carpeta oculta en el home del usuario para almacenar el archivo de configuración de kubernetes y con el cual nos podemos conectar y el export es para dejarlo como variable de entorno el archivo de configuracion y sea posible conectarnos fácilmente. Y por ultimo y muy importante es el comando kubeadm join el cual sirve para agregar los nodos worker al master.

Para dejar persistente esta configuración debemos realizar lo siguiente:

nano .bashrc

Y agregamos al final del archivo

export KUBECONFIG=$HOME/.kube/config

Así cada vez que ingresemos al servidor por ssh tendremos configurada la variable de entorno para conectarnos.

Configuración Nodos Worker

En esta etapa los comando se deben ejecutar solo en los nodos worker por tanto como vimos anteriormente debemos ejecutar el comando que nos muestra por pantalla que es único por cada cluster en mi caso:

sudo kubeadm join 40.40.40.206:6443 --token u31dsc.dbotgztbrid0f6h0 \
        --discovery-token-ca-cert-hash 

Y al ejecutarlo en cada uno de los nodos worker veras el siguiente resultado:

Revisión Configuración Cluster

Ahora volvemos a la sesión de ssh del nodo master o nos reconectamos al nodo master y ejecutamos el siguiente comando

kubectl get nodes -o wide

Con el cual veremos si los nodos workers fueron agregados al cluster y su estado:

Como vemos en la imagen anterior, tenemos toda la información del cluster, la única diferencia es que en el estado de los nodos aparece “NotReady”, nos aparece éste estado ya que no hemos configurado la red del cluster kubernetes donde utilizaremos en este caso Project Calico.

Configuración Red Cluster Calico

Para instalar calico en nuestro cluster de kubernetes, solo debemos ejecutar el siguiente comando en nuestro nodo MASTER

kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml

Luego, revisamos nuevamente nuestro cluster con el comando para validar el estado

kubectl get nodes -o wide

Y ya tenemos el estado en “Ready”.

Configuración Balanceador MetalLB

Para instalar MetalLB en nuestro cluster de kubernetes, solo debemos ejecutar los siguientes comandos en nuestro nodo MASTER

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.6/manifests/namespace.yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.6/manifests/metallb.yaml

El primer comando generara el namespace de MetalLB y el segundo todos los requerimientos para el funcionamiento

Luego generaremos una contraseña random para el cifrados de las comunicaciones

kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"

Y por ultimo debemos configurar el rango de direcciones IP que va a utilizar MetalLB para asignar y poder acceder a los servicios desde la red. Para ello debemos utilizar la siguiente configuracion

cat <<EOF | kubectl create -f -
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: address-pool-1
      protocol: layer2
      addresses:
      - 40.40.40.190-40.40.40.200
EOF

Como vemos en el comando anterior, en mi caso estaré usando un rango de 10 direcciones IP de mi red. Si quieres puedes agregar toda la red /24, pero debe asegurarte que las direcciones IP estén disponibles. Luego lo Ejecutar en tu servidor MASTER

Configuración vSphere CSI

Para iniciar la configuración de vSphere CSI, hay que crear dos archivos con la configuración necesaria para la conexión hacia vCenter:

csi-vsphere.conf

[Global]

cluster-id = "kubernetes"
#[NetPermissions "A"]
#ips = "*"
#permissions = "READ_WRITE"
#rootsquash = false

#[NetPermissions "B"]
#ips = "10.20.20.0/24"
#permissions = "READ_ONLY"
#rootsquash = true

[VirtualCenter "vcenter.24xsiempre.cl"]

insecure-flag = "true"
user = "[email protected]"
password = "PASSWORD"
port = "443"
datacenters = "24xSiempre"

# Opcional cuando configures con VSAN File Services
#targetvSANFileShareDatastoreURLs = "ds:///vmfs/volumes/vsan:52635b9067079319-95a7473222c4c9cd/" 

vsphere.conf

[Global]

cluster-id = "kubernetes"

[VirtualCenter "vcenter.24xsiempre.cl"]

insecure-flag = "true"
user = "[email protected]"
password = "PASSWORD"
port = "443"
datacenters = "24xSiempre"

Ahora te preguntaras por que estamos generando dos archivos con el mismo contenido pero de distinto nombre? es netamente para el primero utilizarlo como “secret” o almacenar los datos de autenticación como tambien si quieres agregar otras configuraciones, como por ejemplo para VSAN y el segundo archivo es para la creación del “configmap” para almacenar estas variables y disponibilizarlas al cluster. Por tanto creamos estos archivos en el servidor MASTER

nano csi-vsphere.conf
nano vsphere.conf

Guardas los archivos y los ejecutaremos en el server MASTER

kubectl create secret generic vsphere-config-secret --from-file=csi-vsphere.conf --namespace=kube-system

kubectl create configmap cloud-config --from-file=vsphere.conf --namespace=kube-system

Ahora que tenemos configurada las credenciales y variables, realizaremos la configuración del CSI para en un inicio conseguir el “ProviderID”, primero debemos dejar los nodos en “Taint” para ello ejecutaremos en el MASTER

kubectl taint nodes --all 'node.cloudprovider.kubernetes.io/uninitialized=true:NoSchedule'

Y luego ejecutar lo siguiente para configurar

kubectl apply -f https://raw.githubusercontent.com/kubernetes/cloud-provider-vsphere/master/manifests/controller-manager/cloud-controller-manager-roles.yaml

kubectl apply -f https://raw.githubusercontent.com/kubernetes/cloud-provider-vsphere/master/manifests/controller-manager/cloud-controller-manager-role-bindings.yaml

kubectl apply -f https://github.com/kubernetes/cloud-provider-vsphere/raw/master/manifests/controller-manager/vsphere-cloud-controller-manager-ds.yaml

Y validaremos si se genera la configuracion y obtenemos el “ProviderID”, con el comando

kubectl describe nodes | grep "ProviderID"

Ahora instalaremos el driver CSI version 2.1.1 con lo siguiente:

kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/vsphere-csi-driver/v2.1.1/manifests/v2.1.1/vsphere-7.0u1/vanilla/rbac/vsphere-csi-controller-rbac.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/vsphere-csi-driver/v2.1.1/manifests/v2.1.1/vsphere-7.0u1/vanilla/deploy/vsphere-csi-node-ds.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/vsphere-csi-driver/v2.1.1/manifests/v2.1.1/vsphere-7.0u1/vanilla/deploy/vsphere-csi-controller-deployment.yaml
kubectl get CSINode

Ya que tenemos nuestro driver instalado debemos crear el Storage Class para utilizar nuestros datastore de vSphere y generar los volúmenes o First Class Disk, antes de esto hay que generar un Storage Policy Name en vCenter asociado al datastore que utilizaremos para albergar los volúmenes persistentes

Y luego generamos el Storage Class

cat << EOF | kubectl apply -f -
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: csi-sc-vmc
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: csi.vsphere.vmware.com
parameters:
  StoragePolicyName: "Contenedores"
  datastoreURL: "ds:///vmfs/volumes/60634600-6fcc5d36-bd83-dcfe07e145f9/"
EOF

En datastoreURL debes ingresar la direccion que se encuentra en el resumen del datastore en vCenter

Y tendrás el resultado

Ahora revisaremos que el Storage Class este correcto y crearemos un disco de prueba

kubectl get sc

Ahora creamos un disco de 5 gigas

cat << EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pruebasc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: csi-sc-vmc
EOF

Al ejecutar lo anterior, podremos ver la creación del disco en vCenter

Y ya con esto tienes un cluster kubernetes utilizando como almacenamiento de los volúmenes persistentes la plataforma de vSphere, para luego respaldarlo con Kasten, que en un próximo post revisaremos como respaldar múltiples cluster utilizando Kasten MultiCluster