Kubernetes Scheduling Parte 2
Kubernetes Scheduling parte 2 es la continuación del tema referente a cómo asignar Pods en nodos. Si eres nuevo en el tema, te recomiendo que primero leas Kubernetes Scheduling parte 1.
Acerca de los labels
Los labels en Kubernetes son como pequeñas etiquetas que asignamos a los objetos de la plataforma, como pods, servicios, nodos, etc. Estas etiquetas son pares clave-valor (key-value) que nos permiten organizar y filtrar estos objetos de manera flexible.
¿Para qué sirven los labels?
- Organización: Nos permiten agrupar objetos que comparten características comunes, como por ejemplo todos los pods que pertenecen a una misma aplicación.
- Selección: Los labels son la base para los selectores, que nos permiten seleccionar un conjunto de objetos basados en sus etiquetas. Esto es fundamental para muchas operaciones en Kubernetes, como:
- Deployments: Desplegar aplicaciones en un conjunto específico de nodos.
- Servicios: Exponer servicios a un conjunto de pods con ciertas etiquetas.
- ReplicaSets: Asegurar que se mantenga un número determinado de réplicas de un pod con ciertas etiquetas.
- Automatización: Los labels permiten crear reglas de automatización basadas en las características de los objetos, lo que facilita la gestión de grandes entornos Kubernetes.
Labels en los nodos
Como vimos antes, a los nodos también se les pueden asignar labels. Así es como se los nodos con el detalle de sus labels cada uno:
kubectl get node --show-labels
Una de las razones principales de asignar labels a los nodos worker es para poder configurar reglas de asignación de pods. Precisamente ese es el tema que veremos a continuación.
Scheduling de Pods con nodeSelector
La especificación de los Pods soporta el atributo nodeSelector
. Puede consultarse su documentación así:
kubectl explain pod.spec.nodeSelector
La explicación es corta y no brinda ejemplos, pero sí una referencia a la documentación de Kubernetes donde se debe buscar el enlace que habla sobre nodeSelector
.
El uso de este atributo es la forma más básica de asignar pods a nodos según el valor de uno o más labels de estos últimos. Existen otras formas de asignación basado también en el uso de labels pero que son más flexibles pero complejas y lo revisaremos en un próximo artículo.
Consulta de nodos y creación sencilla de Pod
Recordemos del artículo anterior que tenemos ya creado un cluster con al menos 3 nodos. Aquí está el mío:
Todos tienen varios labels asignados, pero me interesa mostrar el valor de un label particular, como sigue:
kubectl get node -L aplicacion
Elegí un label arbitrario como «aplicacion», el cual nadie lo tiene asignado. Por eso esa columna aparece vacía.
Ahora, voy a crear un Pod común y corriente y luego revisaré en qué nodo aleatorio fue colocado:
kubectl run nginx2 --image nginx kubectl get pods -o wide
Como se ve, el pod fue asignado al nodo k3d-demo-agent-2. Fue uno cualquiera y pudo quizá haber sido otro distinto. El Scheduler de Kubernetes simplemente colocó el pod en cualquier nodo.
Creación de Pod con nodeSelector
Ahora la prueba consiste en crear el Pod pero definiendo uno o más labels en el atributo nodeSelector
.
Para eso, primero creamos el archivo de manifiesto de un nuevo Pod:
kubectl run nginx3 --image=nginx --dry-run=client -o yaml > nginx3-pod.yaml
Así luce el archivo de manifiesto creado (nginx3-pod.yaml):
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: nginx3 name: nginx3 spec: containers: - image: nginx name: nginx3 resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {}
Editamos el archivo para que quede así (agregamos spec.nodeSelector
):
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: nginx3 name: nginx3 spec: nodeSelector: aplicacion: demo containers: - image: nginx name: nginx3 resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {}
Ahora, procedemos a crear el pod desde el archivo de manifiesto y luego de unos segundos, consultamos la lista de Pods:
kubectl apply -f nginx3-pod.yaml sleep 10 kubectl get pods -o wide
Tras esperar varios segundos o minutos, vemos que el estado del Pod es «Pending»:
Una mirada más detallada del pod permite conocer por qué no ha sido aún asignado a ningún nodo y se mantiene en «Pending»:
kubectl describe pod nginx3
Dado que ningún nodo worker tiene un label aplicacion=demo
, el Scheduler de Kubernetes no asigna el pod a ningún nodo.
La solución es asignar dicho label y valor a por lo menos uno de los nodos. Luego de unos segundos, se comprueba que el Pod fue asignado al mismo nodo al cual le asignamos el label.
kubectl label nodes k3d-demo-agent-0 aplicacion=demo kubectl get node -L aplicacion sleep 10 kubectl get pods -o wide
¿Notaste cómo el pod fue asignado al mismo nodo worker al cual le aplicamos el label?
Múltiples labels con nodeSelector
No estamos limitados a especificar un único label con el atributo nodeSelector
. Aquí un ejemplo de cómo indicar al pod que encuentre un nodo con los 3 labels indicados debajo:
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: nginx4 name: nginx4 spec: nodeSelector: aplicacion: demo entorno: dev capa: frontend containers: - image: nginx name: nginx4 resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {}
En este caso, obligatoriamente tiene que existir al menos un nodo worker que tenga los 3 labels aplicacion=demo
, entorno=dev
y capa=frontend
. Cumplir solo 1 o 2 de los labels no es suficiente: debe cumplirlos todos.
Conclusión
En este artículo vimos una forma adicional de seleccionar nodos para los Pods a través del uso de labels y el atributo nodeSelector
. Esto es más flexible que el uso básico del atributo nodeName, pues este selecciona un único nodo.
El uso de nodeSelector permite poder elegir entre uno o más nodos disponibles, siempre que cumplan con los criterios de los labels definidos.
Si bien se hizo la explicación sobre cómo hacerlo con pods, la misma configuración se hace con deployments (ver ejemplo debajo):
apiVersion: apps/v1 kind: Deployment metadata: creationTimestamp: null labels: app: nginx5 name: nginx5 spec: replicas: 1 selector: matchLabels: app: nginx5 strategy: {} template: metadata: creationTimestamp: null labels: app: nginx5 spec: nodeSelector: aplicacion: demo containers: - image: nginx name: nginx5 resources: {} status: {}
Espero esta información te haya sido de más utilidad en tu uso diario de Kubernetes. En el siguiente artículo explicaré cómo asignar pods con reglas de afinidad.
Deja un comentario