Hablar con el clúster
kubectl es un cliente HTTP
Antes de crear nada conviene saber con qué estás hablando y con qué herramienta.
kubectl es la línea de comandos con la que se trabaja con un clúster, y es importante entender qué no es: no es Kubernetes, no es un agente, no tiene ninguna inteligencia propia y no habla con los nodos. Es un binario que traduce lo que escribes a llamadas HTTP contra el API server y que formatea la respuesta para que se pueda leer.
Todo el trabajo se hace desde la pestaña dev-machine, contra un clúster de Kubernetes real.
💡 Puedes abrir la pestaña Explorer en cualquier momento para ver de forma visual lo que ocurre dentro del clúster.
Paso 1: la sintaxis, que es siempre la misma
Empieza por comprobar qué versión tienes delante:
kubectl version
Verás dos: la del cliente que acabas de ejecutar y la del servidor con el que habla. Son piezas distintas y pueden no coincidir.
A partir de ahí, todo comando tiene la misma forma:
kubectl [verbo] [objeto] [opciones]
kubectl get pods, kubectl delete pod web, kubectl scale deployment web. Si te sabes esa forma, el resto del curso es vocabulario.
Paso 2: mira la petición HTTP con tus propios ojos
Que kubectl sea un cliente HTTP no hay que creérselo: se puede ver. Cualquier comando admite --v, con valores de 0 a 9, que muestra los datos de la petición. El nivel de detalle sale por la salida de error, así que para guardarlo hay que redirigir las dos:
kubectl get pods -A --v=7 > ~/traza.txt 2>&1
Ábrelo y busca la línea de la petición:
grep -i "GET" ~/traza.txt -A4
"Request" verb="GET" url="https://127.0.0.1:6443/api/v1/pods?limit=500"
"Response" status="200 OK" milliseconds=4
"Request" verb="GET" url="https://172.16.0.2:6443/api/v1/pods?limit=500" headers=<
Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json
User-Agent: kubectl/v1.36.3 (linux/amd64) kubernetes/0f29094
>
"Response" status="200 OK" milliseconds=52
Una petición GET a una URL, con sus cabeceras y su código de respuesta. Nada más.
De ahí salen tres consecuencias que conviene tener claras desde el principio:
- Todo lo que hace
kubectllo puede hacer cualquier otro cliente: un script concurl, un programa en Go, Argo CD o el operador que escribirás en el módulo de Extensibilidad. La API es el producto;kubectles una forma cómoda de usarla, no la única. - Cuando algo tarda o falla,
--v=8te dice de qué lado está el problema, porque ves la petición, el código de respuesta y el tiempo. - Los permisos no los tiene
kubectl: los tienes tú, y se comprueban en el API server. Es de lo que va el módulo de Seguridad.
Paso 3: qué tipos existen, y cómo se abrevian
El clúster sabe decirte qué tipos de objeto entiende, sin buscar en ninguna documentación:
kubectl api-resources
Fíjate en las columnas: el nombre del tipo, sus abreviaturas, si vive dentro de un Namespace o es del clúster entero, y a qué grupo de la API pertenece. Esa lista crece: en el módulo de Extensibilidad aparecerá en ella un tipo que habrás inventado tú.
Las abreviaturas son las que se escriben en el día a día, y ahorran cientos de pulsaciones. Para buscar una concreta:
kubectl api-resources | grep persistentvolumeclaims
Paso 4: no memorices campos
Un manifiesto de Pod admite más de cien campos y nadie se los sabe. No hace falta: la documentación está dentro del clúster, y corresponde exactamente a la versión que tienes delante.
kubectl explain pod.spec
Devuelve la descripción de cada campo de ese nivel. Puedes bajar todo lo que quieras por el árbol:
kubectl explain pod.spec.containers
Y con --recursive lo despliega entero de golpe:
kubectl explain pod.spec --recursive | head -40
Funciona igual con tipos que no venían de fábrica, como el Gateway del módulo de Red o la Promocion del de Extensibilidad. Si en cualquier momento del curso te quedas con la duda de qué admite un campo, esta es la respuesta.
Resumen
kubectltraduce comandos a peticiones HTTP contra el API server:--v=7te lo enseña.- La sintaxis es siempre
kubectl [verbo] [objeto] [opciones]. kubectl api-resourcesdice qué tipos existen y cómo se abrevian.kubectl explaindice qué campos admite cada uno, en la versión de tu clúster.
En la siguiente unidad, la otra mitad: el fichero YAML que describe lo que quieres, y a qué clúster van a parar tus comandos.
El fichero, y con qué clúster hablas
Con kubectl se puede trabajar de dos maneras, y las dos aparecen en todo el curso:
- El modo imperativo son comandos que dicen qué hacer:
kubectl run web --image=...,kubectl create namespace tienda,kubectl scale deployment web --replicas=5. - El modo declarativo son ficheros que describen cómo quieres que estén las cosas, y que se envían al clúster con
kubectl apply -f. El fichero se puede leer, revisar, versionar en Git y volver a aplicar.
El criterio para elegir es sencillo: lo imperativo sirve para averiguar qué pasa; lo declarativo, para dejar constancia de lo que quieres. Un arreglo urgente hecho con un comando funciona igual de bien, pero no queda escrito.
Paso 1: casi ningún error de Kubernetes es de Kubernetes
Esos ficheros se escriben en YAML, y merece la pena dedicarle dos minutos, porque casi todos los errores de un principiante con Kubernetes son en realidad errores de YAML.
Solo hay que retener dos reglas. La primera: la indentación decide la estructura, y solo con espacios; un tabulador es un error de sintaxis. La segunda: un guion al principio de la línea crea un elemento de una lista.
apiVersion: v1 # clave: valor
kind: Pod
metadata: # un bloque, con sus claves dentro
name: web
labels:
app: web # tres niveles: metadata, labels, app
spec:
containers: # una lista...
- name: web # ...con un elemento, que es otro bloque
image: ghcr.io/iximiuz/labs/nginx:alpine
Ese guion importa más de lo que parece: cuando llegues a las NetworkPolicy del módulo de Red, un guion de más o de menos cambiará una regla de «hay que cumplir las dos condiciones» a «basta con cumplir una».
Y luego están los tipos. Los valores son texto, números o booleanos, y YAML los adivina. Casi siempre acierta, y las dos veces que no acierta duelen:
- Un valor como
NO,on,offoyesse lee como booleano. El caso clásico es el código de país de Noruega,NO, que acaba convertido enfalse. - Un número de versión se lee como número decimal, y ahí es donde se pierde una tarde entera.
Chócate con ello ahora, que es barato. Escribe este fichero:
cat > ~/tipos.yaml <<'YAML'
apiVersion: v1
kind: ConfigMap
metadata:
name: tipos
namespace: tienda
data:
version: 1.10
YAML
Es un ConfigMap, el objeto que guarda configuración y que verás a fondo en el módulo de Configuración. Aquí solo importa una cosa de él: el bloque data únicamente admite texto. Aplícalo y mira qué pasa:
kubectl apply -f ~/tipos.yaml
No se crea. El clúster se queja de que ahí donde esperaba una cadena ha recibido un número: tú escribiste 1.10, pero YAML no vio una versión, vio un decimal —y en un decimal el cero final no significa nada, así que además ya no es 1.10, es 1.1—. Arréglalo poniéndole comillas al valor en el fichero y vuelve a aplicarlo.
💡 La regla práctica: si el valor es una cadena y hay la menor duda, ponle comillas. Los puertos, las réplicas y los booleanos van sin ellas.
Fíjate en que no has escrito -n en ningún momento: el manifiesto lleva su Namespace dentro, en metadata. Cuando no lo lleva —o cuando el comando es de los que no leen ficheros, como kubectl get— sí hace falta decirlo, y de eso va el último paso de esta lección.
Y antes de aplicar nada, esto valida un fichero sin tocar el clúster:
kubectl apply -f ~/tipos.yaml --dry-run=client
Paso 2: que el comando escriba el fichero por ti
Hay una tercera vía que combina los dos modos: pedirle a un comando imperativo que, en lugar de tocar el clúster, escriba el fichero declarativo que habría aplicado. Se consigue añadiendo -o yaml al --dry-run=client de antes:
kubectl create namespace pruebas --dry-run=client -o yaml > ~/pruebas.yaml
Ábrelo en la pestaña IDE:
cat ~/pruebas.yaml
Tienes el manifiesto, y en el clúster no se ha creado nada:
kubectl get namespace pruebas
Error from server (NotFound): namespaces "pruebas" not found
A partir de ahí editas el fichero y lo aplicas cuando quieras. Es la forma más rápida de empezar un manifiesto que existe, y evita el error clásico de copiar uno de internet sin saber qué hace la mitad de sus líneas. En el módulo Trabajando con el clúster esto se convierte en un método de trabajo completo.
💡 Cambiando client por server, la validación la hace el API server: comprueba también los campos que dependen del clúster y pasa por los controladores de admisión, sin llegar a guardar nada.
Paso 3: con qué clúster estás hablando
Falta responder de dónde saca kubectl la dirección del clúster y quién eres tú.
Lo lee de un fichero llamado kubeconfig, normalmente en ~/.kube/config, que puede contener varios clústeres a la vez. Cada combinación de clúster, usuario y Namespace por defecto se llama contexto, y solo hay uno activo en cada momento. Todo comando que ejecutes va contra el contexto activo.
kubectl config current-context
kubectl config get-contexts
En la columna NAMESPACE verás que ahora mismo está vacía: sin nada puesto, se usa el Namespace default.
⚠️ El error más caro de esta profesión es ejecutar en producción un comando que creías que iba al clúster de pruebas. kubectl config current-context antes de tocar nada cuesta un segundo. Muchos administradores acaban poniendo el contexto activo en el prompt de la terminal por este motivo.
El clúster de este curso ya trae creados los dos Namespaces del libro. Compruébalo:
kubectl get namespaces
Ahí están tienda, donde vive la aplicación, y plataforma, para las piezas que no caben dentro de ella. Todo el curso ocurre en tienda, y como el Namespace forma parte del contexto se puede fijar de una vez y dejar de escribir -n tienda en cada comando:
kubectl config set-context --current --namespace=tienda
Vuelve a mirarlo y compara con lo de antes:
kubectl config get-contexts
En el resto de lecciones del curso este paso viene hecho de fábrica, y verás la bandera -n solo donde importa de verdad: cuando un comando cruza de Namespace o cuando la herramienta lo exige.
Resumen
- Modo imperativo para averiguar; modo declarativo para dejar constancia.
- YAML: la indentación es la estructura, el guion es una lista, y sin comillas
1.10deja de ser una versión. --dry-run=clientvalida sin tocar nada; con-o yamlademás te escribe el manifiesto.- El kubeconfig guarda contextos —clúster, usuario y Namespace—, y solo hay uno activo.
Ya sabes hablar con el clúster. En la siguiente lección le pides algo: tu primer Pod.
- Previous lesson
- Challenge: construye la imagen de la tienda
- Next lesson
- Tu primer Pod