Instalar Open Cluster Management en un equipo personal
Open Cluster Management (OCM) es una herramienta modular y extensible para orquestar múltiples clusters de Kubernetes. Este artículo es un tutorial paso a paso de instalación de una versión mínima de Kubernetes y OCM en un equipo personal para poder experimentar con esta herramienta.
Se trata de un proyecto de código abierto, con licencia Apache 2.0 cuyo código fuente podemos encontrar en https://github.com/open-cluster-management-io y que constituye el proyecto upstream de Advanced Cluster Management (RHACM) de Red Hat.
Este tutorial se basa en el artículo de introducción a esta herramienta que figura directamente como guía de inicio rápido en la documentación OCM.
Contenido
En cuanto a hardware, los requisitos mínimos necesarios con los que se ha conseguido probar son los siguientes:
- CPU. Procesador con 4 cores, Intel Core i5 de sexta generación o equivalente.
- RAM. 12 Gb.
- Disco. Al menos 30 Gb de almacenamiento.
En cuanto a software, la prueba se ha realizado con Ubuntu 20.04 y Fedora 34, pero con ligeros cambios se puede ejecutar en cualquier distribución de Linux. Se utiliza la herramienta multipass para gestionar las dos máquinas virtuales necesarias. Es una herramienta que se puede instalar tanto en Windows 10 como en MacOS, y por lo tanto se podría aplicar en estos sistemas operativos de forma similar casi todo lo expuesto aquí, pero no se ha comprobado realmente el funcionamiento y si los requisitos de hardware mínimos indicados son suficientes en esos casos. Además de multipass es necesario instalar:
- MicroK8s
- kubectl
- clusteradm
Un cluster de Kubernetes está constituido por varios nodos (equipos físicos o máquinas virtuales) que incluyen el plano de control (pods necesarios para el funcionamiento de la propia infraestructura de Kubernetes) y la capacidad de carga útil para ejecutar aplicaciones. Dependiendo de los recursos y las necesidades nos podemos encontrar con clusters en los que idealmente hay como mínimo cinco nodos:
- 3 nodos para el plano de control denominados masters y que por lo tanto se utilizan para la gestión de la propia plataforma Kubernetes.
- 2 nodos denominados workers que ejecutan la carga útil, es decir, las aplicaciones.
Utiliza por tanto un patrón que se denomina master-kubelet o master-agent, ya que en cada worker se ejecuta un pod agente, llamado kubelet, encargado de comunicarse con los nodos master para obtener información de cuál es el estado deseado para las aplicaciones y transmitir a los componentes necesarios las tareas para conseguir ese estado (imagen, número de pods de la aplicación, cuenta de servicio, etc.).
El mínimo de dos nodos workers proporciona tolerancia a fallos en uno de los nodos, en cuyo caso la carga pasaría a ejecutarse en el otro. Este número de nodos es un mínimo, pero lo habitual en un cluster productivo es que haya muchos más nodos workers, incluso decenas de ellos.
Podemos encontrarnos también con clusters constituidos por tres nodos que desempeñan simultáneamente las funciones de master y de worker, aunque generalmente se trata de configuraciones para entornos de laboratorio con pocos recursos. No es lo recomendable para un entorno de producción.
El término cluster implica la existencia de varios elementos que se comportan como uno sólo. Es posible tener una instalación de Kubernetes en un sólo nodo, útil para pruebas de concepto o entornos locales, aunque en este caso se pierden muchas de las bondades de Kubernetes como el reparto de la carga de trabajo. Para este tutorial se crearán dos instalaciones de Kubernetes, cada una con un sólo nodo. Nos tomaremos la libertad de utilizar el término cluster para cada una de ellas, aunque estrictamente hablando es incorrecto. Las operaciones a realizar serían casi idénticas en un cluster de varios nodos y por lo tanto se podrían aplicar a un cluster real. De esta forma nos adaptamos a la terminología que utiliza OCM, que se refiere a la orquestación de clusters.
OCM utiliza una arquitectura maestro-agente (master-agent) entre los clusters, que imita la idea del patrón master-kubelet que existe entre los diferentes nodos de un cluster de Kubernetes, como se ha mencionado anteriormente. Existirán por tanto dos tipos de clusters:
- Cluster Hub. Se trata del cluster sobre el que se ejecuta el plano de control de OCM. Se trataría de un cluster muy ligero sobre el que se ejecutan un pequeño conjunto de servicios.
- Cluster Gestionado, Managed cluster o Klusterlet. Serían los clusters que son gestionados por el cluster hub. El servicio klusterlet está continuamente consultando las últimas especificaciones del cluster hub y ajustando de forma consistente el cluster de Kubernetes para que coincida con el estado esperado.
A continuación vamos a describir la instalación de las herramientas y la realización de configuraciones necesarias para conseguir tener un cluster hub y un cluster gestionado en una configuración mínima que pueda ejecutarse en un ordenador personal sin excesivos recursos de hardware.
kubectl es la herramienta de línea de comandos (CLI) necesaria para gestionar cualquier cluster de Kubernetes. Dependiendo del sistema operativo, se puede obtener de forma sencilla de los gestores de software integrados en el sistema, pero para este ejemplo utilizaremos la descarga directa del binario. Si queremos instalar la versión más reciente:
cd /tmp
curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
Si queremos descargar una versión específica, en este caso la 1.21.8:
cd /tmp
curl -LO "https://storage.googleapis.com/kubernetes-release/release/v1.21.8/bin/linux/amd64/kubectl"
Una vez descargado, le damos permisos de ejecución y lo movemos a una ruta que se encuentre en el PATH
:
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
Comprobamos que la versión mostrada coincide con la que queremos:
kubectl version --client
Client Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.8",
GitCommit:"4a3b558c52eb6995b3c5c1db5e54111bd0645a64", GitTreeState:"clean",
BuildDate:"2021-12-15T14:52:11Z", GoVersion:"go1.16.12", Compiler:"gc", Platform:"linux/amd64"}
Si se desea utiilizar otro método de instalación como los repositorios de paquetes, puede consultarse cómo hacerlo en https://kubernetes.io/es/docs/tasks/tools/install-kubectl/#instalar-mediante-el-gestor-de-paquetes-del-sistema.
Para la creación de los clusters vamos a utilizar máquinas virtuales con Ubuntu LTS. Por simplicidad vamos a instalar la herramienta multipass, que nos permite crear y gestionar máquinas virtuales de Ubuntu muy fácilmente. Se instala mediante un paquete snap:
sudo snap install multipass --classic
Nuestro usuario debe pertenecer al grupo que otorga permisos de escritura en el directorio /var/snap/multipass/common/multipass_socket
. En el siguiente ejemplo, realizado en un host Ubuntu se trata del grupo sudo:
ls -l /var/snap/multipass/common/multipass_socket
srw-rw---- 1 root sudo 0 ene 10 23:30 /var/snap/multipass/common/multipass_socket
Si hacemos la misma comprobación en Fedora veremos que el grupo que otorga el permiso es wheel:
srw-rw----. 1 root wheel 0 ene 10 23:40 /var/snap/multipass/common/multipass_socket
Comprobamos si nuestro usuario pertenece al grupo sudo o wheel:
groups | grep -E "sudo|wheel"
tty uucp dialout cdrom sudo dip video plugdev kvm syslog lpadmin lxd sambashare libvirt
En Fedora (y cualquier distribución que utilice firewalld), si está activado firewalld, es necesario añadir la interfaz bridge mpqemubr0, que es la que utiliza multipass, a la zona trusted para que puedan arrancar las máquinas virtuales:
firewall-cmd --zone=trusted --change-interface=mpqemubr0
firewall-cmd --runtime-to-permanent
Creamos una máquina virtual con una CPU, 4 Gb de RAM, llamada ocm-hub, con 10G de disco y basada en la versión LTS de Ubuntu, que al momento de escribir esto es la 20.04 :
multipass launch -m 3Gb -c 1 -n ocm-hub --disk 10G lts
Una vez terminada la operación, comprobamos que aparece en la lista de máquinas virtuales, con su dirección IP asignada y el estado Running:
multipass list
Name State IPv4 Image
ocm-hub Running 10.89.130.31 Ubuntu 20.04 LTS
Está en ejecución, así que conectamos por shell con ella:
multipass shell ocm-hub
Y comprobamos el usuario por defecto:
whoami
ubuntu
Por defecto nos conectamos con un usuario llamado ubuntu, con permisos de sudo. Vamos a instalar MicroK8s en la máquina virtual ocm-hub, con una versión concreta de Kubernetes (channel). También asignaremos los permisos necesarios para gestionar MicroK8s, agregando el usuario al grupo microk8s:
sudo snap install microk8s --classic --channel=1.21
sudo usermod -a -G microk8s $USER
sudo chown -f -R $USER ~/.kube
Salimos y volvemos a entrar en la máquina para que se aplique el grupo a nuestro usuario:
exit
multipass shell ocm-hub
Comprobamos el estado del nuevo cluster, que se creará y arrancará automáticamente tras la instalación de MicroK8s:
microk8s status
microk8s is running
high-availability: no
datastore master nodes: 127.0.0.1:19001
datastore standby nodes: none
addons:
enabled:
ha-cluster # Configure high availability on the current node
disabled:
ambassador # Ambassador API Gateway and Ingress
cilium # SDN, fast with full network policy
. . .
Podemos obtener la url del plano de control:
microk8s kubectl cluster-info
Kubernetes control plane is running at https://127.0.0.1:16443
Vamos a habilitar el addon de DNS, que nos hará falta más adelante:
microk8s enable dns
Enabling DNS
Applying manifest
serviceaccount/coredns created
configmap/coredns created
deployment.apps/coredns created
service/kube-dns created
clusterrole.rbac.authorization.k8s.io/coredns created
clusterrolebinding.rbac.authorization.k8s.io/coredns created
Restarting kubelet
DNS is enabled
Salimos de la shell de la máquina virtual ocm-hub con exit
y comprobamos de nuevo el listado de máquinas. Podemos ver que aparece una nueva dirección IP asignada a la máquina ocm-hub, correspondiente a una interfaz de red creada por MicroK8s:
multipass list
Name State IPv4 Image
ocm-hub Running 10.89.130.31 Ubuntu 20.04 LTS
10.1.96.0
Abrimos una shell en la máquina ocm-hub:
multipass shell ocm-hub
y editamos el archivo de plantilla de los certificados
vi /var/snap/microk8s/current/certs/csr.conf.template
Agregamos en la sección [ alt_names ]
dos entradas DNS nuevas, en este caso DNS.6
y DNS.7
con el nombre que queremos utilizar desde fuera del cluster para conectarnos.
DNS.6 = ocm-hub.local
DNS.7 = ocm-hub
Quedará algo similar a lo siguiente, aunque la cantidad de entradas puede diferir y sobre todo el campo IP.2
será diferente en cada caso y no debemos modificarlo:
[ alt_names ]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster
DNS.5 = kubernetes.default.svc.cluster.local
DNS.6 = ocm-hub.local
DNS.7 = ocm-hub
IP.1 = 127.0.0.1
IP.2 = 10.152.183.1
#MOREIPS
Ejecutamos la regeneración de los certificados:
sudo microk8s refresh-certs
Taking a backup of the current certificates under /var/snap/microk8s/2694/var/log/ca-backup/
Creating new certificates
Can't load /root/.rnd into RNG
140555660350912:error:2406F079:random number generator:RAND_load_file:Cannot open file:../crypto/rand/randfile.c:88:Filename=/root/.rnd
Can't load /root/.rnd into RNG
140458579322304:error:2406F079:random number generator:RAND_load_file:Cannot open file:../crypto/rand/randfile.c:88:Filename=/root/.rnd
Signature ok
subject=C = GB, ST = Canonical, L = Canonical, O = Canonical, OU = Canonical, CN = 127.0.0.1
Getting CA Private Key
Signature ok
subject=CN = front-proxy-client
Getting CA Private Key
1
Creating new kubeconfig file
Stopped.
Started.
The CA certificates have been replaced. Kubernetes will restart the pods of your workloads.
Any worker nodes you may have in your cluster need to be removed and re-joined to become aware of the new CA.
Salimos de la máquina ocm-hub:
exit
En el equipo host vamos a editar el archivo /etc/hosts
y añadir una entrada con la dirección IP de la máquina ocm-hub y su nombre. La IP la obtuvimos con el comando multipass list
o de forma más directa con:
multipass info ocm-hub | grep IPv4
IPv4: 10.89.130.31
La entrada en este caso será:
10.89.130.31 ocm-hub.local ocm-hub
Probamos el acceso desde el host:
curl -kL https://ocm-hub.local:16443
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
}
Preparamos el archivo de configuración para poder utilizar kubectl
desde nuestro host. Para ello vamos a copiar el archivo /var/snap/microk8s/current/credentials/client.config
de la máquina ocm-hub al directorio $HOME/.kube
de nuestro equipo:
KUBECONFIG=$HOME/.kube/ocm-hub.config
multipass exec ocm-hub cat /var/snap/microk8s/current/credentials/client.config > $KUBECONFIG
Editamos el archivo de configuración con vi $KUBECONFIG
, cambiando la línea:
server: https://127.0.0.1:16443
por
server: https://ocm-hub.local:16443
Probamos a lanzar un comando con kubectl
especificando el archivo de configuración que hemos creado para ver los nodos en ejecución. No sería estrictamente necesario especificar el parámetro --kubeconfig
puesto que ahora mismo hemos creado la variable la variable KUBECONFIG
que determina la ubicación del archivo de configuración para kubectl
. Si no existe la variable KUBECONFIG
y no utilizamos el parámetro --kubeconfig
intentará buscar un archivo de configuración por defecto: $HOME/.kube/config
.
kubectl --kubeconfig=$HOME/.kube/ocm-hub.config get nodes
NAME STATUS ROLES AGE VERSION
ocm-hub Ready <none> 30m v1.21.7-3+7700880a5c71e2
Con esto verificamos que el comando kubectl
funciona correctamente y que podemos lanzar comandos contra el cluster ocm-hub desde fuera de la máquina virtual.
Sin utilizar kubectl
desde la máquina host podríamos conseguir el mismo resultado lanzando un comando contra la máquina virtual utilizando multipass
y la CLI de MicroK8s:
multipass exec ocm-hub microk8s kubectl get nodes
NAME STATUS ROLES AGE VERSION
ocm-hub Ready <none> 30m v1.21.7-3+7700880a5c71e2
Creamos una máquina virtual con una CPU, 4 Gb de RAM, llamada ocm-managed, con 10G total de disco y basada en la versión LTS de Ubuntu, que al momento de escribir esto es la 20.04 :
multipass launch -m 3Gb -c 1 -n ocm-managed --disk 10G lts
Comprobamos que aparece en la lista de máquinas virtuales, la dirección IP asignada y su estado:
multipass list
Name State IPv4 Image
ocm-hub Running 10.89.130.31 Ubuntu 20.04 LTS
10.1.96.0
ocm-managed Running 10.89.130.239 Ubuntu 20.04 LTS
Está en ejecución, así que conectamos por shell con ella:
multipass shell ocm-managed
De la misma forma que se ha hecho con la máquina ocm-hub
, vamos a instalar MicroK8s y a dar los permisos necesarios:
sudo snap install microk8s --classic --channel=1.21
sudo usermod -a -G microk8s $USER
sudo chown -f -R $USER ~/.kube
exit
multipass shell ocm-managed
Comprobamos el estado del cluster de kubernetes:
microk8s status
microk8s is running
high-availability: no
datastore master nodes: 127.0.0.1:19001
datastore standby nodes: none
addons:
enabled:
ha-cluster # Configure high availability on the current node
disabled:
ambassador # Ambassador API Gateway and Ingress
cilium # SDN, fast with full network policy
microk8s kubectl cluster-info
Kubernetes control plane is running at https://127.0.0.1:16443
Vamos a habilitar el addon de DNS, que nos hará falta más adelante:
microk8s enable dns
Enabling DNS
Applying manifest
serviceaccount/coredns created
configmap/coredns created
deployment.apps/coredns created
service/kube-dns created
clusterrole.rbac.authorization.k8s.io/coredns created
clusterrolebinding.rbac.authorization.k8s.io/coredns created
Restarting kubelet
DNS is enabled
Salimos de la shell de la máquina virtual ocm-managed con exit
y comprobamos de nuevo el listado de máquinas. Podemos ver que aparece una nueva dirección IP asignada, correspondiente a una interfaz de red creada por MicroK8s:
multipass list
Name State IPv4 Image
ocm-hub Running 10.89.130.31 Ubuntu 20.04 LTS
10.1.96.0
ocm-managed Running 10.89.130.239 Ubuntu 20.04 LTS
10.1.37.0
Abrimos una shell en la máquina ocm-managed:
multipass shell ocm-managed
y editamos el archivo de plantilla de los certificados:
vi /var/snap/microk8s/current/certs/csr.conf.template
Agregamos en la sección [ alt_names ]
dos entradas DNS nuevas, en este caso DNS.6
y DNS.7
con el nombre que queremos utilizar desde fuera del cluster para conectarnos (ocm-managed.local y ocm-managed)
).
DNS.6 = ocm-managed.local
DNS.7 = ocm-managed
Quedará algo similar a lo siguiente, aunque la cantidad de entradas puede diferir y sobre todo el campo IP.2
será diferente en cada caso y no debemos modificarlo:
[ alt_names ]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster
DNS.5 = kubernetes.default.svc.cluster.local
DNS.6 = ocm-managed.local
DNS.7 = ocm-managed
IP.1 = 127.0.0.1
IP.2 = 10.152.183.1
#MOREIPS
Ejecutamos la regeneración de los certificados:
sudo microk8s refresh-certs
Taking a backup of the current certificates under /var/snap/microk8s/2694/var/log/ca-backup/
Creating new certificates
Can't load /root/.rnd into RNG
140603790988736:error:2406F079:random number generator:RAND_load_file:Cannot open file:../crypto/rand/randfile.c:88:Filename=/root/.rnd
Can't load /root/.rnd into RNG
140352521098688:error:2406F079:random number generator:RAND_load_file:Cannot open file:../crypto/rand/randfile.c:88:Filename=/root/.rnd
Signature ok
subject=C = GB, ST = Canonical, L = Canonical, O = Canonical, OU = Canonical, CN = 127.0.0.1
Getting CA Private Key
Signature ok
subject=CN = front-proxy-client
Getting CA Private Key
1
Creating new kubeconfig file
Stopped.
Started.
The CA certificates have been replaced. Kubernetes will restart the pods of your workloads.
Any worker nodes you may have in your cluster need to be removed and re-joined to become aware of the new CA.
Salimos de la máquina ocm-managed:
exit
En el equipo host vamos editar el archivo /etc/hosts
y añadir una entrada con la dirección IP de la máquina ocm-managed
y su nombre. La IP la obtuvimos con el comando multipass list
o de forma más directa con:
multipass info ocm-managed | grep IPv4
IPv4: 10.89.130.239
La entrada en este caso será:
10.89.130.239 ocm-managed.local ocm-managed
Probamos el acceso desde el host:
curl -kL https://ocm-managed.local:16443
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
}
Preparamos el archivo de configuración para poder utilizar kubectl
desde nuestro host:
KUBECONFIG=$HOME/.kube/ocm-managed.config
multipass exec ocm-managed cat /var/snap/microk8s/current/credentials/client.config > $KUBECONFIG
Editamos el archivo de configuración con:
vi $KUBECONFIG
cambiando la línea:
server: https://127.0.0.1:16443
por
server: https://ocm-managed.local:16443
Probamos a lanzar un comando con kubectl
especificando el archivo de configuración que hemos creado para ver los nodos en ejecución:
kubectl --kubeconfig=$HOME/.kube/ocm-managed.config get nodes
No sería estrictamente necesario especificar el parámetro --kubeconfig
puesto que ahora mismo hemos creado la variable la variable KUBECONFIG
que determina la ubicación del archivo de configuración para kubectl
. Si no existe la variable KUBECONFIG
y no utilizamos el parámetro --kubeconfig
, el comando kubectl
intentará buscar un archivo de configuración en $HOME/.kube/config
. Nos aparecerá algo como lo siguiente:
NAME STATUS ROLES AGE VERSION
ocm-managed Ready <none> 34m v1.21.7-3+7700880a5c71e2
Con esto verificamos que el comando kubectl
funciona correctamente y que podemos lanzar comandos contra el cluster ocm-managed desde fuera de la máquina virtual.
Sin utilizar kubectl
desde la máquina host podríamos conseguir el mismo resultado lanzando un comando contra la máquina virtual utilizando multipass
y la CLI de MicroK8s:
multipass exec ocm-managed microk8s kubectl get nodes
Para interactuar con Open Cluster Management (a partir de ahora OCM) existe una herramienta CLI llamada clusteradm
.
El primer paso será instalarla. Para ello, descargamos el script de instalación:
curl -L https://raw.githubusercontent.com/open-cluster-management-io/clusteradm/main/install.sh -o /tmp/install-clusteradm.sh
chmod +x /tmp/install-clusteradm.sh
Examinamos el contenido antes de ejecutarlo. Básicamente descarga de github la última versión del binario adecuada para nuestra máquina y la copia en /usr/local/bin
, aunque podemos modificar el lugar de destino modificando una variable. Si cambiamos la línea:
: ${INSTALL_DIR:="/usr/local/bin"}
por cualquier otra ruta que se encuentre en el PATH y sobre la que tengamos permisos de escritura, no será necesario ejecutar este script con sudo
. Si queremos instalar en la ruta por defecto /usr/local/bin
tendremos que utilizar sudo
al ejecutar /tmp/install-clusteradm.sh
.
Ejecutamos el script:
/tmp/install-clusteradm.sh
y se realizará la instalación:
Getting the latest clusteradm CLI...
Your system is linux_amd64
Installing clusteradm CLI...
Installing v0.1.0-alpha.7 OCM clusteradm CLI...
Downloading https://github.com/open-cluster-management-io/clusteradm/releases/download/v0.1.0-alpha.7/clusteradm_linux_amd64.tar.gz ...
clusteradm installed into /opt/k8stools successfully.
To get started with clusteradm, please visit https://open-cluster-management.io/getting-started/
Comprobamos que clusteradm
funciona y puede conectar con nuestros clusters:
clusteradm --kubeconfig=$HOME/.kube/ocm-hub.config version
client version :0.1.0-alpha.7
server release version :v1.21.7-3+7700880a5c71e2
clusteradm --kubeconfig=$HOME/.kube/ocm-managed.config version
client version :0.1.0-alpha.7
server release version :v1.21.7-3+7700880a5c71e2
Vamos a definir unos alias para que resulte más fácil ejecutar clusteradm
contra nuestros clusters. Serán cahub
para conectarnos al cluster hub y camng
para conectarnos al cluster gestionado:
alias cahub='clusteradm --kubeconfig=$HOME/.kube/ocm-hub.config'
alias camng='clusteradm --kubeconfig=$HOME/.kube/ocm-managed.config'
y comprobamos que funciona ejecutando el comando version
de clusteradm
:
cahub version
client version :0.1.0-alpha.7
server release version :v1.21.7-3+7700880a5c71e2
camng version
client version :0.1.0-alpha.7
server release version :v1.21.7-3+7700880a5c71e2
y hacemos lo mismo con kubectl
. Creamos los alias khub
para ejecutar kubectl
contra el cluster hub y kmng
para ejecutar comandos contra el cluster gestionado:
alias khub='kubectl --kubeconfig=$HOME/.kube/ocm-hub.config'
alias kmng='kubectl --kubeconfig=$HOME/.kube/ocm-managed.config'
y comprobamos que funcionan correctamente:
khub version
kmng version
nos devolverá la versión del cliente y del servidor:
Client Version: version.Info{Major:"1", Minor:"23", GitVersion:"v1.23.1", GitCommit:"86ec240af8cbd1b60bcc4c03c20da9b98005b92e", GitTreeState:"clean", BuildDate:"2021-12-16T11:41:01Z", GoVersion:"go1.17.5", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"21+", GitVersion:"v1.21.7-3+7700880a5c71e2", GitCommit:"7700880a5c71e25c44491ef5c7d7fb30527d8337", GitTreeState:"clean", BuildDate:"2021-11-17T22:02:47Z", GoVersion:"go1.16.10", Compiler:"gc", Platform:"linux/amd64"}
WARNING: version difference between client (1.23) and server (1.21) exceeds the supported minor version skew of +/-1
Client Version: version.Info{Major:"1", Minor:"23", GitVersion:"v1.23.1", GitCommit:"86ec240af8cbd1b60bcc4c03c20da9b98005b92e", GitTreeState:"clean", BuildDate:"2021-12-16T11:41:01Z", GoVersion:"go1.17.5", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"21+", GitVersion:"v1.21.7-3+7700880a5c71e2", GitCommit:"7700880a5c71e25c44491ef5c7d7fb30527d8337", GitTreeState:"clean", BuildDate:"2021-11-17T22:02:47Z", GoVersion:"go1.16.10", Compiler:"gc", Platform:"linux/amd64"}
Vamos a comprobar los namespaces existentes en nuestro cluster hub:
khub get namespaces
NAME STATUS AGE
kube-system Active 40m
kube-public Active 40m
kube-node-lease Active 40m
default Active 40m
Una vez instalado clusteradm
y creados los alias, instalamos un Cluster Manager de OCM en el cluster de Kubernetes que utilizaremos como hub:
cahub init
The multicluster hub control plane has been initialized successfully!
You can now register cluster(s) to the hub control plane. Log onto those cluster(s) and run the following command:
clusteradm join \
--hub-token eyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQ.eyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQeyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQeyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQeyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQeyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQeyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQeyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQ \
--hub-apiserver https://ocm-hub.local:16443 \
--cluster-name <cluster_name>
Replace <cluster_name> with a cluster name of your choice. For example, cluster1.
Con este comando, clusteradm
instala en el cluster hub el operador registration-operator que es el responsable de instalar y actualizar de forma consistente varios componentes del entorno de OCM.
Al final de la ejecución nos muestra un comando con un token que debemos guardar, ya que nos permitirá registrar los clusters gestionados desde el hub.
Comprobamos los pods que están en ejecución en el cluster hub tras el comando init
:
khub get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system calico-kube-controllers-f7868dd95-tm7nq 1/1 Running 3 2d
kube-system calico-node-8kfnv 1/1 Running 3 2d
open-cluster-management cluster-manager-6bc5bd8856-6mpm6 1/1 Running 0 5m3s
open-cluster-management-hub cluster-manager-registration-controller-59f487d68-dtrjt 1/1 Running 0 4m46s
open-cluster-management-hub cluster-manager-registration-webhook-c96d56db-9bxcc 1/1 Running 0 4m46s
open-cluster-management-hub cluster-manager-work-webhook-547d7cc954-ctxbs 1/1 Running 0 4m46s
open-cluster-management-hub cluster-manager-placement-controller-66485c45fd-2kdkt 1/1 Running 0 4m46s
Tras la ejecución en el cluster hub del comando init
vamos a comprobar los namespaces que tenemos disponibles:
khub get namespaces
NAME STATUS AGE
kube-system Active 40m
kube-public Active 40m
kube-node-lease Active 40m
default Active 40m
open-cluster-management Active 5m
open-cluster-management-hub Active 5m
podemos ver que nos ha añadido dos nuevos namespaces: open-cluster-management y open-cluster-management-hub.
En el namespace open-cluster-management se encuentra el pod del registration operator:
khub -n open-cluster-management get pods
NAME READY STATUS RESTARTS AGE
cluster-manager-6bc5bd8856-6mpm6 1/1 Running 0 24m
En el namespace open-cluster-management-hub se ejecutan los pods del control plane de OCM:
khub -n open-cluster-management-hub get pods
NAME READY STATUS RESTARTS AGE
cluster-manager-registration-controller-59f487d68-dtrjt 1/1 Running 0 25m
cluster-manager-registration-webhook-c96d56db-9bxcc 1/1 Running 0 25m
cluster-manager-work-webhook-547d7cc954-ctxbs 1/1 Running 0 25m
cluster-manager-placement-controller-66485c45fd-2kdkt 1/1 Running 0 25m
Se ha creado un Custom Resource de tipo clustermanager llamado cluster-manager:
khub get clustermanager
NAME AGE
cluster-manager 27m
Para examinar la información de la instalación podemos examinar el contenido de ese objeto:
khub get clustermanager cluster-manager -o yaml
Una vez que se han instalado todos los componentes del control plane en el cluster hub y que están en ejecución, podemos pasar a registrar un cluster en OCM para que sea gestionado por él.
Para ello, primero tenemos que asegurarnos de que la API del cluster hub es accesible desde el cluster que queremos que sea gestionado.
Obtenemos la dirección IP del cluster hub:
multipass info ocm-hub | grep IPv4 | tr -s ' ' | cut -d ' ' -f 2
10.89.130.31
Podemos lanzar una petición con curl
sobre una dirección htttps en el puerto 16443 correspondiente a esa dirección IP. Si llegamos correctamente nos devolverá un mensaje JSON de autenticación incorrecta (código 401):
multipass exec ocm-managed -- \
curl -kL https://$(multipass info ocm-hub | grep IPv4 | tr -s ' ' | cut -d ' ' -f 2):16443
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
}
Para registrar el cluster gestionado utilizaremos el comando que nos generó clusteradm init
y lo lanzaremos desde nuestro equipo. Salimos de la máquina del cluster gestionado y lanzamos el comando con clusteradmin
(concretamente con el alias camng
) contra nuestro cluster gestionado. El valor del parámetro --cluster-name
no tiene por qué coincidir con el nombre de la máquina virtual, puede ser cualquier nombre que queramos asignarle.
Salimos de la máquina virtual:
exit
y desde el host lanzamos el comando join
contra el cluster gestionado, utilizando el alias de clusteradm
camng
y la dirección IP de la MV ocm-hub en el parámetro --hub-apiserver
, ya que desde nuestro cluster gestionado no resolverá el nombre ocm-hub
u ocm-hub.local
:
camng join \
--hub-token eyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQ.eyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQeyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQeyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQeyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQeyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQeyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQeyJhbGciOiJSUzI1NiIsImtpZCI6Ik5Va2FPSXVCYTM2WDExVHBqaEFkdm92Slp0SWwxcTlkM29DQnVIczlnNTQifQ \
--hub-apiserver https://10.89.130.31:16443 \
--cluster-name managed1
Waiting for the management components to become ready...
Please log onto the hub cluster and run the following command:
clusteradm accept --clusters managed1
Los CSR, Certificate Signing Request o Solicitudes de Firma de Certificados, son uno de los primeros pasos para la obtención de un certificado TLS. Cuando se realiza la operación join correctamente, el cluster gestionado genera CSRs en el cluster hub, que deben ser aceptadas. Por ello revisamos si hay recursos CSR en el cluster hub:
khub get csr -w
NAME AGE SIGNERNAME REQUESTOR CONDITION
managed1-d479q 5m kubernetes.io/kube-apiserver-client system:serviceaccount:open-cluster-management:cluster-bootstrap Pending
Aceptamos la petición de unión del cluster gestionado al cluster hub:
cahub accept --clusters managed1
CSR managed1-d479q approved
set hubAcceptsClient to true for managed cluster managed1
Verificamos que el objeto managedcluster se ha creado correctamente:
khub get managedcluster
NAME HUB ACCEPTED MANAGED CLUSTER URLS JOINED AVAILABLE AGE
managed1 true https://10.248.21.90:16443 True True 10m
Comprobamos la creación de namespaces en el cluster gestionado:
kmng get namespace
NAME STATUS AGE
kube-system Active 1h
kube-public Active 1h
kube-node-lease Active 1h
default Active 1h
open-cluster-management Active 10m
open-cluster-management-agent-addon Active 10m
open-cluster-management-agent Active 10m
Verficamos la instalación de los agentes de OCM en el cluster gestionado con:
kmng -n open-cluster-management-agent get pod
NAME READY STATUS RESTARTS AGE
klusterlet-registration-agent-598fd79988-jxx7n 1/1 Running 0 10m
klusterlet-work-agent-7d47f4b5c5-dnkqw 1/1 Running 0 10m
La información de instalación debe figurar en un custom resource llamado klusterlet que sólo debe estar instalado en el cluster gestionado:
kmng get klusterlet klusterlet -o yaml
En el cluster hub se habrá creado un namespace con el nombre que hamos dado al managedcluster:
khub get namespace
NAME STATUS AGE
kube-system Active 2h
kube-public Active 2h
kube-node-lease Active 2h
default Active 2h
open-cluster-management Active 15m
open-cluster-management-hub Active 15m
managed1 Active 10m
Vemos que se ha creado lo que se denomina cluster namespace, un namespace con el mismo nombre que se ha dado al cluster gestionado durante el registro. Este namespace lo crea el registration controller del hub de forma automática cuando finaliza el registro y se utiliza para almacenar custom resources y configuraciones que pertenezcan al cluster gestionado.
Ya disponemos de dos clusters de Kubernetes, uno que sirve como hub para gestionar otros clusters y un cluster gestionado. Lo recomendado es que el cluster hub se utilice sólamente para gestionar otros clusters, pero es posible instalar el agente en el propio cluster hub y que sea gestionado para cargas de trabajo y otros fines como cualquier otro cluster gestionado, a través de OCM.
Vamos a hacer un despliegue de una aplicación sencilla en el cluster gestionado para comprobar que funciona correctamente OCM.
Vamos a manejar dos conceptos:
- ManifestWork: Un custom resource que se encuentra en el cluster hub y que agrupa una lista de recursos de Kubernetes que se desean aplicar en el cluster gestionado.
- AppliedManifestWork: Un custom resource del cluster gestionado que se utiliza para persistir la lista de recursos definidos en un ManifestWork.
Primero debemos verificar tres puntos:
- Que la Custom Resource Definition (CRD) ManifestWork está instalada en el cluster hub:
khub get crd manifestworks.work.open-cluster-management.io
manifestworks.work.open-cluster-management.io 2022-01-14T23:30:58Z
- Que la CRD AppliedManifestWork está instalada en el cluster gestionado:
kmng get crd appliedmanifestworks.work.open-cluster-management.io
NAME CREATED AT
appliedmanifestworks.work.open-cluster-management.io 2022-01-14T23:31:12Z
- Que el agente está ejecutándose correctamente en el cluster gestionado:
kmng -n open-cluster-management-agent get pod
NAME READY STATUS RESTARTS AGE
klusterlet-registration-agent-69c5568fcc-98fj9 1/1 Running 1 1h
klusterlet-work-agent-54dfddf7b-78llj 1/1 Running 11 1h
Una vez comprobados los puntos anteriores, vamos a crear en el clusternamespace (en nuestro caso managed1) un ManifestWork. Este ManifestWork crea los siguientes objetos en el cluster:
- Un namespace llamado frontend.
- Una service account llamada nginx-sa en el namespace frontend.
- Un deployment en el namespace frontend llamado nginx-deployment que desplegará 3 pods de nginx a la escucha en el puerto 8080.
- Un servicio de tipo NodePort que apuntará a los pods del deployment anterior, que permitirá acceder a los nginx desde fuera del cluster.
khub apply -f - <<EOF
apiVersion: work.open-cluster-management.io/v1
kind: ManifestWork
metadata:
namespace: managed1
name: nginx-simple
spec:
workload:
manifests:
- apiVersion: v1
kind: Namespace
metadata:
name: frontend
- apiVersion: v1
kind: ServiceAccount
metadata:
namespace: frontend
name: nginx-sa
- apiVersion: apps/v1
kind: Deployment
metadata:
namespace: frontend
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
serviceAccountName: nginx-sa
containers:
- name: nginx
image: nginx:1.21.5
ports:
- containerPort: 8080
- apiVersion: v1
kind: Service
metadata:
namespace: frontend
name: nginx
labels:
app: nginx
spec:
type: NodePort
ports:
- nodePort: 30001
port: 8080
protocol: TCP
targetPort: 8080
selector:
app: nginx
EOF
manifestwork.work.open-cluster-management.io/nginx-simple created
Comprobamos el resultado con:
khub get manifestwork nginx-simple -n managed1 -o yaml
En el apartado .status.resourceStatus
del comando anterior aparecerá información de cómo se ha aplicado el recurso:
resourceStatus:
manifests:
- conditions:
- lastTransitionTime: "2022-01-11T08:31:07Z"
message: Apply manifest complete
reason: AppliedManifestComplete
status: "True"
type: Applied
- lastTransitionTime: "2022-01-11T08:31:07Z"
message: Resource is available
reason: ResourceAvailable
status: "True"
type: Available
Comprobamos si en el cluster gestionado se han desplegado los pods de ngnix en el namespace frontend:
kmng get pods -n frontend
NAME READY STATUS RESTARTS AGE
nginx-deployment-844674d9b-m2vgn 1/1 Running 0 5m
nginx-deployment-844674d9b-7z6ph 1/1 Running 0 5m
nginx-deployment-844674d9b-z9jz6 1/1 Running 0 5m
En la especificación del servicio hemos indicado el puerto 30001 en la línea:
- nodePort: 30001
Comprobamos el servicio creado en el namespace frontend:
kmng get svc -n frontend
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx NodePort 10.152.183.92 <none> 8080:30001/TCP 5m
Vemos que efectivamente el puerto expuesto al exterior del cluster es el 30001. Vamos a hacer una petición con curl
:
curl http://ocm-managed:30001/
$ curl http://ocm-managed:30001/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
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>
También podemos introducir la url http://ocm-managed:30001/ en nuestro navegador:
Con esto hemos hecho una breve prueba de que OCM está funcionando. Cualquier cambio que hagamos sobre el ManifestWork se aplicará en el cluster managed en unos segundos.
Una vez terminada la prueba, el orden recomendado para parar el entorno que hemos creado sería detener los clusters y luego las máquinas virtuales, aunque microk8s se ejecuta como un servicio de las máquinas y por lo tanto se detendría en caso de parada ordenada de la máquina.
Para detener el cluster gestionado:
multipass exec ocm-managed microk8s stop
Parada del cluster hub:
multipass exec ocm-hub microk8s stop
Y por último parada de las máquinas virtuales:
multipass stop ocm-managed
multipass stop ocm-hub
Si en otro momento queremos arrancar de nuevo los clusters, arrancaríamos las máquinas virtuales y luego los clusters:
multipass start ocm-hub
multipass start ocm-managed
multipass exec ocm-hub microk8s start
multipass exec ocm-managed microk8s start