Llevamos todo el módulo escribiendo rutas-norte-dev en cada manifiesto y en cada comando, sin habernos detenido a explicar qué es exactamente ese namespace ni qué nos da. Y al final de la lección anterior apareció una propiedad muy interesante: la configuración de api-reservas apunta a redis-cache y a postgres-reservas por su nombre corto, sin mencionar el entorno, porque el DNS lo resuelve dentro del namespace donde corre el pod. Esa propiedad es la que permite desplegar el mismo manifiesto tres veces y obtener tres plataformas independientes. En esta lección montamos los tres entornos de Rutas Norte —rutas-norte-dev, rutas-norte-pre y rutas-norte-pro—, veremos qué aísla un namespace y qué no aísla en absoluto (que es la parte que más incidentes provoca), distinguiremos los recursos con y sin namespace, conoceremos los namespaces del sistema y por qué nunca se despliega en default, trabajaremos cómodamente con -n y con el contexto, resolveremos nombres DNS entre namespaces, y terminaremos con una advertencia muy seria sobre lo que se lleva por delante un kubectl delete namespace.
Contenido
- Qué es un namespace y qué aísla
- Recursos con y sin namespace
- Los namespaces del sistema y por qué no se despliega en
default - Los tres entornos de Rutas Norte
- El mismo manifiesto en varios entornos
- Trabajar con namespaces sin volverse loco
- DNS entre namespaces
- Qué NO garantiza un namespace
- Borrar un namespace: la orden más peligrosa de kubectl
- Namespaces frente a clústeres separados
- Qué es un namespace y qué aísla
Un namespace es una partición lógica del clúster que agrupa recursos. La definición operativa, la que de verdad sirve:
Un namespace es, sobre todo, un espacio de nombres: dentro de él, el nombre de cada objeto debe ser único; fuera, puede repetirse libremente.
Eso permite que existan simultáneamente tres objetos llamados api-reservas, uno en cada entorno, sin colisionar. Y a partir de ahí se derivan sus demás usos.
Lo que un namespace sí aporta:
| Función | Qué significa en la práctica |
|---|---|
| Unicidad de nombres | api-reservas puede existir en dev, pre y pro a la vez |
| Ámbito de las consultas | kubectl get pods solo muestra los del namespace actual |
| Punto de anclaje de las cuotas | Un ResourceQuota limita el consumo total de un namespace (03-04) |
| Unidad de permisos de RBAC | Un Role concede permisos dentro de un namespace (08-01) |
| Sujeto de las políticas de red | Una NetworkPolicy puede seleccionar por namespace (04-06) |
| Ámbito del DNS corto | redis-cache resuelve al Service del namespace del pod que pregunta |
| Ámbito de los selectores | Un Service o un ReplicaSet solo ven pods de su propio namespace |
| Borrado en bloque | Borrar el namespace elimina todo lo que contiene |
Y lo que no aporta, que veremos en detalle en el apartado 8: no aísla la red, no limita recursos por sí solo, no impide el acceso y no separa los nodos.
flowchart TB
subgraph CL["Clúster minikube · perfil rutas-norte"]
subgraph DEV["namespace rutas-norte-dev"]
D1["Deployment api-reservas"]
D2["Service api-reservas"]
D3["Deployment postgres-reservas"]
end
subgraph PRE["namespace rutas-norte-pre"]
E1["Deployment api-reservas"]
E2["Service api-reservas"]
E3["Deployment postgres-reservas"]
end
subgraph SYS["namespace kube-system"]
S1["CoreDNS"]
S2["kube-proxy"]
end
NODOS["Nodos, PersistentVolumes, StorageClasses<br/>(sin namespace: comunes a todo el clúster)"]
end
Fíjate en el detalle clave del diagrama: los objetos con el mismo nombre conviven en namespaces distintos, pero los nodos son compartidos. Un pod de rutas-norte-dev y otro de rutas-norte-pre pueden acabar en la misma máquina.
- Recursos con y sin namespace
No todos los objetos de Kubernetes viven dentro de un namespace. Los hay que pertenecen al clúster entero, y confundirlos genera errores desconcertantes.
La forma de saberlo con certeza, sin memorizar nada:
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bindings v1 true Binding
configmaps cm v1 true ConfigMap
endpoints ep v1 true Endpoints
events ev v1 true Event
limitranges limits v1 true LimitRange
persistentvolumeclaims pvc v1 true PersistentVolumeClaim
pods po v1 true Pod
replicationcontrollers rc v1 true ReplicationController
resourcequotas quota v1 true ResourceQuota
secrets v1 true Secret
serviceaccounts sa v1 true ServiceAccount
services svc v1 true Service
deployments deploy apps/v1 true Deployment
replicasets rs apps/v1 true ReplicaSet
statefulsets sts apps/v1 true StatefulSetNAME SHORTNAMES APIVERSION NAMESPACED KIND
componentstatuses cs v1 false ComponentStatus
namespaces ns v1 false Namespace
nodes no v1 false Node
persistentvolumes pv v1 false PersistentVolume
mutatingwebhookconfigurations admissionregistration.k8s.io/v1 false MutatingWebhookConfiguration
customresourcedefinitions crd apiextensions.k8s.io/v1 false CustomResourceDefinition
apiservices apiregistration.k8s.io/v1 false APIService
tokenreviews authentication.k8s.io/v1 false TokenReview
clusterrolebindings rbac.authorization.k8s.io/v1 false ClusterRoleBinding
clusterroles rbac.authorization.k8s.io/v1 false ClusterRole
priorityclasses pc scheduling.k8s.io/v1 false PriorityClass
csidrivers storage.k8s.io/v1 false CSIDriver
storageclasses sc storage.k8s.io/v1 false StorageClass
volumeattachments storage.k8s.io/v1 false VolumeAttachmentLa lógica detrás del reparto es coherente: lo que representa infraestructura física o configuración global del clúster no lleva namespace; lo que representa carga de trabajo o configuración de aplicación, sí.
| Con namespace | Sin namespace |
|---|---|
| Pod, Deployment, ReplicaSet, StatefulSet, DaemonSet, Job, CronJob | Node |
| Service, Endpoints, EndpointSlice, Ingress, NetworkPolicy | Namespace |
| ConfigMap, Secret, ServiceAccount | PersistentVolume, StorageClass, CSIDriver |
| PersistentVolumeClaim | ClusterRole, ClusterRoleBinding |
| Role, RoleBinding | CustomResourceDefinition, PriorityClass |
| ResourceQuota, LimitRange, HorizontalPodAutoscaler | IngressClass |
Dos parejas merecen atención porque son fuente constante de confusión:
- PersistentVolume (sin namespace) frente a PersistentVolumeClaim (con namespace). El disco es un recurso del clúster; la reclamación de ese disco pertenece a una aplicación concreta en un namespace. Módulo 5.
- Role/RoleBinding (con namespace) frente a ClusterRole/ClusterRoleBinding (sin namespace). Los primeros conceden permisos dentro de un namespace; los segundos, en todo el clúster. Módulo 8.
Un error práctico derivado de esto:
El -n se ha ignorado en silencio. Los nodos no tienen namespace, así que el flag no filtra nada. No es un error, pero puede hacerte creer que estás viendo algo filtrado cuando no lo estás.
- Los namespaces del sistema y por qué no se despliega en
default
defaultTodo clúster nace con cuatro namespaces:
NAME STATUS AGE
default Active 3d
kube-node-lease Active 3d
kube-public Active 3d
kube-system Active 3d
rutas-norte-dev Active 2d| Namespace | Contenido | ¿Debes tocarlo? |
|---|---|---|
default |
Vacío al principio. Es donde van los objetos si no indicas namespace | No despliegues aquí |
kube-system |
Los componentes del propio Kubernetes: CoreDNS, kube-proxy, controladores CSI, addons | Nunca despliegues aquí; mirar sí, tocar no |
kube-public |
Legible sin autenticar; contiene un ConfigMap con datos públicos del clúster | Casi nunca se usa |
kube-node-lease |
Un objeto Lease por nodo, que el kubelet renueva como latido de vida |
Nunca |
Echa un vistazo a kube-system para ver el clúster por dentro:
NAME READY STATUS RESTARTS AGE
coredns-668d6bf9bc-x8k2m 1/1 Running 0 3d
etcd-rutas-norte 1/1 Running 0 3d
kube-apiserver-rutas-norte 1/1 Running 0 3d
kube-controller-manager-rutas-norte 1/1 Running 0 3d
kube-proxy-7wfnz 1/1 Running 0 3d
kube-scheduler-rutas-norte 1/1 Running 0 3d
metrics-server-6d94bc8694-p4rzt 1/1 Running 0 3d
storage-provisioner 1/1 Running 0 3dAhí están, corriendo como pods, todos los componentes que estudiaste en Arquitectura de Kubernetes. El plano de control de tu minikube es visible y palpable.
kube-node-lease explica algo que quizá te preguntaste: cómo sabe el plano de control si un nodo sigue vivo.
El kubelet renueva ese objeto cada pocos segundos. Si deja de hacerlo, el nodo se marca NotReady.
Por qué no se despliega en default
Es el namespace que Kubernetes usa cuando no dices nada, y precisamente por eso es un mal sitio para trabajar:
- Es el vertedero del clúster. Todo lo que alguien aplique sin
-nacaba ahí. En pocos meses es un cajón de sastre donde nadie sabe qué es de quién. - No se puede borrar. Los namespaces del sistema son indestructibles, así que no puedes limpiarlo de un golpe como harías con
rutas-norte-dev. - Los accidentes son fáciles. Un
kubectl delete deploy --allsin-n, ejecutado creyendo estar en otro sitio, se lleva por delante lo que haya endefault. - Imposibilita el aislamiento. Si todo está en
default, no puedes aplicar cuotas por equipo, ni RBAC por entorno, ni políticas de red diferenciadas. - Impide reutilizar nombres. Con todo en un mismo namespace,
api-reservasde desarrollo y de producción no pueden coexistir.
La regla del proyecto es explícita:
En Rutas Norte,
defaultestá prohibido. Todo objeto vive en un namespace nombrado, declarado en su propio manifiesto.
- Los tres entornos de Rutas Norte
Ha llegado el momento de crear la estructura completa. Ya conoces rutas-norte-dev del módulo 1; le añadimos preproducción y producción, de forma declarativa y en un solo fichero.
En YAML, --- separa varios documentos dentro de un mismo fichero. Es la forma habitual de agrupar objetos relacionados:
# k8s/base/namespaces.yaml
apiVersion: v1
kind: Namespace
metadata:
name: rutas-norte-dev
labels:
app.kubernetes.io/part-of: rutas-norte
entorno: dev
---
apiVersion: v1
kind: Namespace
metadata:
name: rutas-norte-pre
labels:
app.kubernetes.io/part-of: rutas-norte
entorno: pre
---
apiVersion: v1
kind: Namespace
metadata:
name: rutas-norte-pro
labels:
app.kubernetes.io/part-of: rutas-norte
entorno: pro
annotations:
rutasnorte.example/responsable: [email protected]
rutasnorte.example/aviso: "Entorno productivo. Cambios solo por pipeline."kubectl apply -f k8s/base/namespaces.yaml
kubectl get namespaces -l app.kubernetes.io/part-of=rutas-nortenamespace/rutas-norte-dev configured
namespace/rutas-norte-pre created
namespace/rutas-norte-pro created
NAME STATUS AGE
rutas-norte-dev Active 2d
rutas-norte-pre Active 4s
rutas-norte-pro Active 4sFíjate en dos decisiones deliberadas:
- Los namespaces llevan etiquetas. No es decorativo: en el módulo 4, las NetworkPolicies seleccionarán namespaces por la etiqueta
entorno, y así una política podrá decir "solo acepto tráfico de pods del mismo entorno". - Producción lleva anotaciones informativas. Cualquiera que haga
kubectl describe ns rutas-norte-prosabrá a quién avisar y qué reglas rigen.
La estructura del repositorio que ya tenemos definida encaja de forma natural:
k8s/
├── base/ # manifiestos comunes a los tres entornos
│ ├── namespaces.yaml
│ ├── tienda-web-deployment.yaml
│ ├── tienda-web-service.yaml
│ ├── api-reservas-deployment.yaml
│ └── ...
└── entornos/
├── dev/ # diferencias del entorno de desarrollo
├── pre/
└── pro/Cómo se combinan base y entornos sin duplicar YAML es trabajo de Kustomize o Helm, en 10-04 y 10-03. En este módulo lo haremos de la forma más simple posible.
- El mismo manifiesto en varios entornos
Aquí está la propiedad que hace valiosos los namespaces. Vamos a desplegar tienda-web y su Service en preproducción usando exactamente los mismos ficheros que en desarrollo.
Nuestros manifiestos llevan namespace: rutas-norte-dev escrito dentro, así que hay dos formas de llevarlos a otro entorno.
Opción A: quitar el namespace del manifiesto y decidirlo al aplicar.
# k8s/base/tienda-web-deployment.yaml (fragmento, sin namespace)
apiVersion: apps/v1
kind: Deployment
metadata:
name: tienda-web
# sin campo namespace: lo decide quien aplica
labels:
app: tienda-web
app.kubernetes.io/part-of: rutas-nortekubectl apply -f k8s/base/tienda-web-deployment.yaml -n rutas-norte-pre
kubectl apply -f k8s/base/tienda-web-service.yaml -n rutas-norte-preOpción B: mantener el namespace en el manifiesto y sustituirlo al desplegar. Es lo que harán Kustomize o Helm por ti; a mano se vería así:
sed 's/rutas-norte-dev/rutas-norte-pre/g' k8s/base/tienda-web-deployment.yaml | kubectl apply -f -
sed 's/rutas-norte-dev/rutas-norte-pre/g' k8s/base/tienda-web-service.yaml | kubectl apply -f -Hay una regla importante que conviene conocer: si un manifiesto declara metadata.namespace y además pasas -n con otro valor distinto, kubectl da error en lugar de elegir por su cuenta.
error: the namespace from the provided object "rutas-norte-dev" does not match
the namespace "rutas-norte-pre". You must pass '--namespace=rutas-norte-dev' to perform this operation.Es un comportamiento deseable: evita desplegar en producción por accidente.
Hagámoslo con la opción B, que respeta nuestros manifiestos actuales:
for f in tienda-web-deployment tienda-web-service api-reservas-deployment api-reservas-service redis-cache-deployment redis-cache-service; do
sed 's/rutas-norte-dev/rutas-norte-pre/g' k8s/base/$f.yaml | kubectl apply -f -
done
kubectl get deploy,svc -n rutas-norte-preNAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/api-reservas 2/2 2 2 25s
deployment.apps/redis-cache 1/1 1 1 24s
deployment.apps/tienda-web 3/3 3 3 26s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/api-reservas ClusterIP 10.96.229.14 <none> 3000/TCP 25s
service/redis-cache ClusterIP 10.96.88.107 <none> 6379/TCP 24s
service/tienda-web ClusterIP 10.96.44.71 <none> 80/TCP 26sAhora observa la situación completa del clúster:
NAMESPACE NAME READY STATUS RESTARTS AGE
rutas-norte-dev api-reservas-7f1d3e942-b8mrs 1/1 Running 0 48m
rutas-norte-dev api-reservas-7f1d3e942-n4jvt 1/1 Running 0 48m
rutas-norte-dev postgres-reservas-59d7c4b8f-k3xqp 1/1 Running 0 40m
rutas-norte-dev redis-cache-6c8f9d745-w2mtb 1/1 Running 0 52m
rutas-norte-dev tienda-web-6f9c4b8d7-42kxr 1/1 Running 0 55m
rutas-norte-dev tienda-web-6f9c4b8d7-8vnwq 1/1 Running 0 55m
rutas-norte-dev tienda-web-6f9c4b8d7-t9mzd 1/1 Running 0 55m
rutas-norte-pre api-reservas-7f1d3e942-c9plk 1/1 Running 0 1m
rutas-norte-pre api-reservas-7f1d3e942-r5vwj 1/1 Running 0 1m
rutas-norte-pre redis-cache-6c8f9d745-h8nqz 1/1 Running 0 1m
rutas-norte-pre tienda-web-6f9c4b8d7-d3jbx 1/1 Running 0 1m
rutas-norte-pre tienda-web-6f9c4b8d7-m7kwr 1/1 Running 0 1m
rutas-norte-pre tienda-web-6f9c4b8d7-p2fst 1/1 Running 0 1mDos plataformas Rutas Norte completas, con los mismos nombres de Deployment y de Service, conviviendo sin la menor colisión. Ese es el valor central del namespace.
Y una comprobación que ilustra el aislamiento de nombres:
kubectl get svc api-reservas -n rutas-norte-dev -o jsonpath='{.spec.clusterIP}{"\n"}'
kubectl get svc api-reservas -n rutas-norte-pre -o jsonpath='{.spec.clusterIP}{"\n"}'Mismo nombre, dos objetos distintos, dos IPs virtuales distintas.
- Trabajar con namespaces sin volverse loco
Escribir -n rutas-norte-dev cien veces al día es tedioso y, peor, olvidarlo es la vía rápida a un accidente.
El flag -n y -A
kubectl get pods -n rutas-norte-pre # un namespace concreto
kubectl get pods --all-namespaces # todos
kubectl get pods -A # abreviatura de lo anterior-A es imprescindible cuando buscas algo y no recuerdas dónde está:
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
rutas-norte-dev api-reservas 2/2 2 2 50m
rutas-norte-pre api-reservas 2/2 2 2 3mFijar el namespace del contexto
Es la opción que más tiempo ahorra. Modifica tu kubeconfig para que todos los comandos usen ese namespace por defecto:
Context "rutas-norte" modified.
NAME READY STATUS RESTARTS AGE
api-reservas-7f1d3e942-c9plk 1/1 Running 0 4m
api-reservas-7f1d3e942-r5vwj 1/1 Running 0 4m
redis-cache-6c8f9d745-h8nqz 1/1 Running 0 4m
tienda-web-6f9c4b8d7-d3jbx 1/1 Running 0 4m
tienda-web-6f9c4b8d7-m7kwr 1/1 Running 0 4m
tienda-web-6f9c4b8d7-p2fst 1/1 Running 0 4mY la comprobación que deberías hacer un reflejo antes de cualquier comando destructivo:
Consejo muy recomendable: configura el prompt de tu terminal para mostrar contexto y namespace. Herramientas como kube-ps1 lo hacen, y ver (rutas-norte:rutas-norte-pro) en pantalla antes de teclear delete ha salvado muchas tardes.
kubens
Del conjunto kubectx, kubens cambia de namespace de forma interactiva:
kubens # lista los namespaces y marca el actual
kubens rutas-norte-pro # cambia a produccion
kubens - # vuelve al anteriorEs azúcar sintáctico sobre kubectl config set-context, pero con listado interactivo y salto rápido al anterior. Se instala como binario suelto o mediante krew, el gestor de plugins de kubectl que vimos en La CLI de Kubernetes.
Vuelve a desarrollo antes de continuar:
- DNS entre namespaces
Ya conoces el nombre completo de un Service: <servicio>.<namespace>.svc.cluster.local. Los namespaces son la razón de que exista esa estructura.
Cuando un pod resuelve un nombre, el DNS del clúster prueba una serie de sufijos de búsqueda en orden. Míralos en un pod real:
search rutas-norte-dev.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5La primera línea explica todo el comportamiento: al buscar redis-cache, el pod prueba primero redis-cache.rutas-norte-dev.svc.cluster.local. Como existe, ahí termina. El nombre corto siempre resuelve dentro del propio namespace.
Desde un pod de rutas-norte-dev, si escribe... |
Resuelve a... |
|---|---|
redis-cache |
redis-cache.rutas-norte-dev.svc.cluster.local |
redis-cache.rutas-norte-pre |
redis-cache.rutas-norte-pre.svc.cluster.local |
redis-cache.rutas-norte-pro.svc.cluster.local |
Ese mismo, sin ambigüedad |
Compruébalo:
kubectl run test-dns --rm -it --image=busybox:1.36 --restart=Never -n rutas-norte-dev -- \
sh -c 'nslookup api-reservas; nslookup api-reservas.rutas-norte-pre'Name: api-reservas.rutas-norte-dev.svc.cluster.local
Address: 10.96.184.22
Name: api-reservas.rutas-norte-pre.svc.cluster.local
Address: 10.96.229.14
pod "test-dns" deletedAquí hay dos noticias. La buena: el mismo manifiesto de api-reservas, con DATABASE_HOST: postgres-reservas, funciona en los tres entornos y cada uno habla con su propia base de datos, sin condicionales ni plantillas.
La mala, y es importante: un pod de desarrollo acaba de resolver y podría conectarse a un Service de preproducción. Nada se lo impide. Eso nos lleva directamente al apartado siguiente.
- Qué NO garantiza un namespace
Este es el apartado que evita incidentes. La creencia de que "cada equipo en su namespace y así están aislados" es peligrosamente falsa.
No es una frontera de red
Por defecto, cualquier pod de cualquier namespace puede conectarse a cualquier pod o Service de cualquier otro namespace. El modelo de red plano de Kubernetes es explícito en esto: todos los pods se ven entre sí.
Demostración incómoda: un pod de desarrollo escribiendo en la caché de preproducción.
kubectl run intruso --rm -it --image=redis:7.2-alpine --restart=Never -n rutas-norte-dev -- \
redis-cli -h redis-cache.rutas-norte-pre SET plazas:BIL-SAN:2026-08-14 0Acabamos de poner a cero las plazas disponibles en la caché de preproducción desde desarrollo. Si hubiera sido rutas-norte-pro, sería un incidente serio. Y nadie ha necesitado permisos especiales: ha bastado con conocer el nombre.
La solución no es el namespace, son las NetworkPolicies de 04-06, que sí permiten declarar reglas del tipo "postgres-reservas solo acepta conexiones de pods con la etiqueta app=api-reservas del mismo namespace".
No es una frontera de seguridad ni de permisos
Crear un namespace no restringe quién puede hacer qué en él. Si tus credenciales tienen permisos amplios sobre el clúster, los tienes sobre todos los namespaces, existentes y futuros.
Con un usuario de administrador, la respuesta es yes para cualquier namespace. El aislamiento de permisos lo dan los Role y RoleBinding de RBAC. El namespace es solo el ámbito sobre el que esas reglas se aplican: necesario, pero no suficiente.
No limita el consumo de recursos
Un namespace no impone ningún techo. Un Deployment mal configurado en rutas-norte-dev puede consumir toda la CPU y la memoria del clúster y dejar sin recursos a los pods de rutas-norte-pro, porque comparten los mismos nodos.
Name: rutas-norte-dev
Labels: app.kubernetes.io/part-of=rutas-norte
entorno=dev
Status: Active
No resource quota.
No LimitRange resource.Esas dos líneas finales lo dicen todo: sin cuota y sin límites. Ponerlos es materia de Cuotas y Límites de Recursos y LimitRanges y QoS.
No aísla los nodos
Los pods de todos los namespaces se reparten por los mismos nodos. Un pod de desarrollo y uno de producción pueden ser vecinos en la misma máquina, compartiendo CPU, memoria y disco.
kubectl get pods -A -l app=tienda-web -o custom-columns=NS:.metadata.namespace,POD:.metadata.name,NODO:.spec.nodeNameNS POD NODO
rutas-norte-dev tienda-web-6f9c4b8d7-42kxr rutas-norte
rutas-norte-pre tienda-web-6f9c4b8d7-d3jbx rutas-norteSeparar cargas por nodos requiere taints, tolerations y afinidad (06-05).
Resumen honesto
| Creencia habitual | Realidad |
|---|---|
| "Los namespaces aíslan la red" | Falso. Todo se ve con todo. Hacen falta NetworkPolicies |
| "Los namespaces aíslan permisos" | Falso por sí solos. Hacen falta Roles y RoleBindings |
| "Un namespace no puede consumir recursos de otro" | Falso. Hace falta ResourceQuota |
| "Producción está protegida por estar en otro namespace" | Falso. Es una separación organizativa, no una barrera |
| "Los namespaces separan los nodos" | Falso. Los nodos son comunes |
| "Los namespaces evitan colisiones de nombres" | Verdadero. Esa sí es su función nativa |
La frase que resume el apartado: el namespace es el ámbito sobre el que se aplican los mecanismos de aislamiento, no el mecanismo de aislamiento. Sin cuotas, RBAC y políticas de red encima, un namespace es solo una carpeta.
- Borrar un namespace: la orden más peligrosa de kubectl
Ese comando borra todo lo que hay dentro: Deployments, ReplicaSets, Pods, Services, ConfigMaps, Secrets, PersistentVolumeClaims, ServiceAccounts, Roles... Y con los PVC se van, según la política de recuperación, los datos.
Características que lo hacen especialmente peligroso:
- No pide confirmación. Ninguna.
- No hay deshacer. No existe papelera ni
kubectl undelete. - Es asíncrono. El namespace pasa a estado
Terminatingmientras se borra el contenido, y en ese estado no admite objetos nuevos. - Un error de tecleo es catastrófico.
rutas-norte-proen lugar derutas-norte-preson tres caracteres de diferencia.
Míralo en acción, con un namespace de usar y tirar:
kubectl create namespace prueba-borrado
kubectl run temporal --image=nginx:1.27-alpine -n prueba-borrado
kubectl delete namespace prueba-borrado
kubectl get namespace prueba-borradonamespace/prueba-borrado created
pod/temporal created
namespace "prueba-borrado" deleted
Error from server (NotFound): namespaces "prueba-borrado" not foundEl pod se fue con él, sin preguntar nada.
Namespaces atascados en Terminating
Un problema que encontrarás tarde o temprano: un namespace que se queda en Terminating indefinidamente. La causa casi siempre es un finalizer —esos ganchos que estudiamos en Objetos y Manifiestos— que no puede completarse, típicamente el de una API extendida cuyo servidor ya no existe.
kubectl get namespace rutas-norte-pre -o jsonpath='{.spec.finalizers}{"\n"}'
kubectl get namespace rutas-norte-pre -o jsonpath='{.status.conditions}' | python3 -m json.toolAntes de forzar nada, averigua qué recurso está bloqueando, porque quitar el finalizer a lo bruto deja objetos huérfanos en etcd. La forma correcta es eliminar el recurso conflictivo o restaurar el servicio que debe procesarlo.
Medidas de protección para Rutas Norte
- Etiquetar y anotar producción, como hicimos en
namespaces.yaml: al describir el namespace se lee el aviso. - RBAC restrictivo: nadie tiene permiso de
delete namespacesenrutas-norte-prosalvo un par de personas (08-01). - Verificar el contexto antes de cualquier borrado, con el reflejo del apartado 6.
- Copias de seguridad: la única red real. Herramientas como Velero permiten restaurar un namespace entero, y es materia de Copias de Seguridad y Restauración.
- Comprobar antes de disparar, siempre:
Un buen hábito adicional: usar --dry-run=client mentalmente. Antes de borrar, pregúntate en voz alta qué namespace estás mirando.
Deja preproducción montada, la seguiremos usando:
- Namespaces frente a clústeres separados
La pregunta estratégica: ¿deben los tres entornos de Rutas Norte vivir en un clúster con tres namespaces, o en tres clústeres separados?
| Criterio | Namespaces en un clúster | Clústeres separados |
|---|---|---|
| Coste | Un plano de control, nodos compartidos: mucho más barato | Multiplicado por el número de clústeres |
| Aislamiento real | Lógico; requiere cuotas, RBAC y NetworkPolicies bien hechas | Total: infraestructura distinta |
| Radio de impacto de un fallo | Un problema del plano de control afecta a todo | Un clúster caído no toca a los demás |
| Versión de Kubernetes | La misma para todos los entornos | Cada uno la suya: se puede probar una actualización en pre |
| Complejidad operativa | Baja: un kubeconfig, un juego de herramientas | Alta: multiplica monitorización, actualizaciones y accesos |
| Riesgo de error humano | Alto: un -n mal puesto toca producción |
Bajo: cambiar de clúster es un acto consciente |
| Cumplimiento normativo | Difícil de justificar ante un auditor | Fácil de justificar |
| Latencia entre entornos | Nula, comparten red | Requiere conectividad externa |
Criterios prácticos de decisión:
Namespaces en un clúster cuando:
- Los entornos son de confianza equivalente (dev y pre del mismo equipo).
- El equipo es pequeño y el presupuesto limitado.
- Se domina RBAC, cuotas y políticas de red.
Clústeres separados cuando:
- Hay datos regulados: personales, sanitarios, financieros.
- Se ofrece servicio a clientes que no confían entre sí (multi-tenant real).
- Se necesitan versiones distintas de Kubernetes o de componentes del clúster.
- Un fallo de producción no puede depender de la salud de un entorno de pruebas.
La decisión de Rutas Norte
La empresa tiene datos personales de clientes —nombre, DNI, teléfono y correo— en postgres-reservas. La decisión, y su porqué:
| Entorno | Ubicación | Justificación |
|---|---|---|
rutas-norte-dev |
Namespace en el clúster de no producción | Datos anonimizados, coste mínimo, iteración rápida |
rutas-norte-pre |
Namespace en el mismo clúster que dev | Réplica funcional de producción con datos ficticios |
rutas-norte-pro |
Clúster propio y separado | Datos personales reales, requisitos de disponibilidad y auditoría, radio de impacto acotado |
Es decir: dos clústeres, tres namespaces. El namespace rutas-norte-pro existe también en el clúster de no producción para que los manifiestos sean idénticos y se pueda ensayar el despliegue, pero la producción real vive aparte.
Durante el curso trabajaremos con un solo minikube y los tres namespaces, que es lo práctico para aprender. La gestión de varios clústeres a la vez, con sus contextos y sus herramientas, se trata en Gestión Multi-Clúster.
Un último apunte sobre cómo organizar namespaces: por entorno (lo que hacemos), por equipo (equipo-pagos, equipo-rutas) o por aplicación (rutas-norte, intranet). Lo habitual es combinar dos ejes: rutas-norte-pro, intranet-pro. Lo que nunca funciona es un namespace por microservicio: multiplica la burocracia sin aportar aislamiento útil.
Errores Comunes y Consejos
- Desplegar en
defaultpor olvido. El síntoma eskubectl get podssin resultados donde esperabas verlos. Comprueba conkubectl get pods -A -l app=<componente>. - Creer que un namespace aísla la red. No lo hace. Cualquier pod puede conectarse a cualquier Service de otro namespace conociendo su nombre.
- Creer que un namespace aísla permisos o recursos. Hacen falta RBAC y ResourceQuota. El namespace es el ámbito, no el mecanismo.
- Poner
-na un recurso sin namespace.kubectl get nodes -n loqueseaignora el flag en silencio y puede confundirte. - Discrepancia entre
metadata.namespacey-n.kubectlda error en lugar de decidir por ti. Es una protección, no un fastidio. - Buscar en el namespace equivocado y concluir que algo no existe. Ante la duda,
-A. - Borrar un namespace sin mirar qué contiene. No hay confirmación ni deshacer.
kubectl get all -n <ns>antes, siempre. - Forzar el borrado de un namespace atascado quitándole los finalizers. Deja objetos huérfanos en etcd. Investiga primero qué recurso bloquea.
- Un namespace por microservicio. Multiplica la carga administrativa sin aportar aislamiento real. Organiza por entorno, equipo o aplicación.
- Consejo: configura el prompt para mostrar contexto y namespace (
kube-ps1). Ver(rutas-norte:rutas-norte-pro)antes de tecleardeleteevita accidentes. - Consejo: declara
metadata.namespaceen los manifiestos que sean específicos de un entorno y omítelo en los que sean genéricos. La ambigüedad es lo que provoca despliegues en el sitio equivocado. - Consejo: etiqueta siempre tus namespaces. Las NetworkPolicies del módulo 4 seleccionarán namespaces por etiqueta, y sin ellas tendrás que volver atrás a ponerlas.
Ejercicios
Ejercicio 1: Clasificar recursos y explorar el sistema
- Con un solo comando, cuenta cuántos tipos de recursos tienen namespace y cuántos no.
- Determina, sin consultar tablas, si estos recursos llevan namespace:
PersistentVolume,PersistentVolumeClaim,Role,ClusterRole,Ingress,StorageClass. - Lista los pods de
kube-systeme identifica cuáles son los cinco componentes del plano de control que estudiaste en el módulo 1. - Averigua qué hay dentro de
kube-publicy explica qué tiene de particular ese namespace.
Ejercicio 2: Desplegar la plataforma en producción y comprobar el aislamiento
- Despliega
tienda-web(Deployment y Service) enrutas-norte-pro, con la etiquetaentorno: proen lugar dedev. - Demuestra con un solo comando que existen tres Deployments llamados
tienda-weben el clúster, en namespaces distintos. - Comprueba que las
ClusterIPde los tres Servicestienda-webson diferentes. - Desde un pod efímero en
rutas-norte-dev, haz una petición HTTP altienda-webderutas-norte-prousando el nombre DNS completo. ¿Funciona? Explica qué implica esto y qué objeto habría que crear para impedirlo.
Ejercicio 3: Auditoría de namespaces
Te incorporas al equipo de plataforma de Rutas Norte y te encargan una auditoría rápida del clúster. Responde con comandos y su salida:
- ¿Qué namespaces existen y cuáles pertenecen a la plataforma Rutas Norte?
- ¿Hay algún objeto desplegado en
default? Si lo hay, muévelo al namespace correcto. - ¿Qué namespaces tienen
ResourceQuotadefinida? ¿Qué implica que no la tengan? - ¿Puedes borrar el namespace de producción con tus credenciales actuales? ¿Qué mecanismo debería impedirlo y en qué lección se estudia?
- Elabora una tabla con los tres entornos indicando: número de pods, número de Services y si tienen cuota.
Soluciones
Solución 1
echo "Con namespace: $(kubectl api-resources --namespaced=true --no-headers | wc -l)"
echo "Sin namespace: $(kubectl api-resources --namespaced=false --no-headers | wc -l)"Los números varían según los CRDs y addons instalados en tu clúster.
- El razonamiento, antes de comprobarlo: lleva namespace lo que pertenece a una aplicación concreta; no lo lleva lo que es infraestructura o configuración global.
| Recurso | ¿Namespace? | Razonamiento |
|---|---|---|
PersistentVolume |
No | Es un disco del clúster, existe antes de que nadie lo reclame |
PersistentVolumeClaim |
Sí | Es la petición de una aplicación concreta |
Role |
Sí | Concede permisos dentro de un namespace |
ClusterRole |
No | Concede permisos en todo el clúster |
Ingress |
Sí | Enruta hacia Services, que tienen namespace |
StorageClass |
No | Define un tipo de almacenamiento disponible para todo el clúster |
kubectl api-resources --no-headers | grep -E "^(persistentvolumes|persistentvolumeclaims|roles|clusterroles|ingresses|storageclasses) "persistentvolumeclaims pvc v1 true PersistentVolumeClaim
persistentvolumes pv v1 false PersistentVolume
storageclasses sc storage.k8s.io/v1 false StorageClass
ingresses ing networking.k8s.io/v1 true Ingress
clusterroles rbac.authorization.k8s.io/v1 false ClusterRole
roles rbac.authorization.k8s.io/v1 true Role# 3. Componentes del plano de control
kubectl get pods -n kube-system --no-headers | awk '{print $1}' | grep -E "apiserver|etcd|scheduler|controller-manager|coredns"coredns-668d6bf9bc-x8k2m
etcd-rutas-norte
kube-apiserver-rutas-norte
kube-controller-manager-rutas-norte
kube-scheduler-rutas-norteLos cinco: kube-apiserver (la única puerta a la API), etcd (el almacén de estado), kube-scheduler (asigna pods a nodos), kube-controller-manager (donde viven los controladores de ReplicaSet, Deployment, endpoints...) y CoreDNS (que resuelve los nombres de Service que usamos en la lección anterior).
# 4. kube-public
kubectl get configmaps -n kube-public
kubectl get configmap cluster-info -n kube-public -o jsonpath='{.data.jws-kubeconfig-*}' | head -3kube-public es el único namespace legible sin autenticarse: cualquiera que alcance el apiserver puede leer su contenido. Contiene cluster-info, con los datos que un nodo necesita para unirse al clúster durante el proceso de kubeadm join. Por eso nunca debe guardarse nada sensible ahí.
Solución 2
# 1. Desplegar en produccion
for f in tienda-web-deployment tienda-web-service; do
sed -e 's/rutas-norte-dev/rutas-norte-pro/g' -e 's/entorno: dev/entorno: pro/g' \
k8s/base/$f.yaml | kubectl apply -f -
done
kubectl get deploy,svc -n rutas-norte-prodeployment.apps/tienda-web created
service/tienda-web created
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/tienda-web 3/3 3 3 15s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/tienda-web ClusterIP 10.96.171.55 <none> 80/TCP 15sNAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
rutas-norte-dev tienda-web 3/3 3 3 1h
rutas-norte-pre tienda-web 3/3 3 3 35m
rutas-norte-pro tienda-web 3/3 3 3 1m# 3. Tres ClusterIP distintas
kubectl get svc tienda-web -A -o custom-columns=NS:.metadata.namespace,NOMBRE:.metadata.name,IP:.spec.clusterIPNS NOMBRE IP
rutas-norte-dev tienda-web 10.96.12.209
rutas-norte-pre tienda-web 10.96.44.71
rutas-norte-pro tienda-web 10.96.171.55# 4. Desde dev hacia pro
kubectl run intruso --rm -it --image=curlimages/curl:8.8.0 --restart=Never -n rutas-norte-dev -- \
curl -s -o /dev/null -w "%{http_code}\n" http://tienda-web.rutas-norte-pro.svc.cluster.local/Funciona. Un pod de desarrollo ha accedido sin ningún obstáculo a un servicio de producción. Implicación directa: el namespace no es una frontera de red. En el modelo por defecto de Kubernetes, todos los pods se ven entre sí, y basta conocer el nombre DNS para conectarse.
Para impedirlo hace falta una NetworkPolicy en rutas-norte-pro que rechace todo el tráfico entrante salvo el que proceda de namespaces con la etiqueta entorno: pro (por eso etiquetamos los namespaces al crearlos). Es el contenido de Políticas de Red y Seguridad de Red.
Solución 3
# 1. Namespaces existentes y los de la plataforma
kubectl get ns
kubectl get ns -l app.kubernetes.io/part-of=rutas-norteNAME STATUS AGE
default Active 3d
kube-node-lease Active 3d
kube-public Active 3d
kube-system Active 3d
rutas-norte-dev Active 2d
rutas-norte-pre Active 40m
rutas-norte-pro Active 40m
NAME STATUS AGE
rutas-norte-dev Active 2d
rutas-norte-pre Active 40m
rutas-norte-pro Active 40mLa etiqueta común permite distinguir de un vistazo los namespaces de la plataforma de los del sistema.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3dSolo aparece service/kubernetes, que es el Service del propio apiserver y debe estar ahí: es el que permite a los pods hablar con la API. Si hubiera cualquier otra cosa, el procedimiento sería exportarla, corregir su namespace y volver a aplicarla:
kubectl get deploy <nombre> -n default -o yaml > /tmp/objeto.yaml
# editar metadata.namespace y quitar metadata.uid, resourceVersion y status
kubectl apply -f /tmp/objeto.yaml -n rutas-norte-dev
kubectl delete deploy <nombre> -n defaultNingún namespace tiene cuota. Implicación: cualquier Deployment de rutas-norte-dev puede consumir toda la CPU y la memoria del clúster y dejar sin recursos a los pods de rutas-norte-pro, porque comparten nodos. Un bucle mal escrito en desarrollo puede tumbar la producción. Se corrige con ResourceQuota y LimitRange en 03-04 y 03-05.
Sí puedo borrarlo, y con él toda la producción, sin confirmación y sin deshacer. Lo que debería impedirlo es RBAC: un Role/ClusterRole que no incluya el verbo delete sobre namespaces para las credenciales habituales, dejando ese permiso a un rol de emergencia usado por dos personas. Se estudia en Control de Acceso Basado en Roles. Como red de seguridad complementaria, copias de seguridad con Velero (05-06).
# 5. Tabla resumen
for ns in rutas-norte-dev rutas-norte-pre rutas-norte-pro; do
pods=$(kubectl get pods -n $ns --no-headers 2>/dev/null | wc -l)
svcs=$(kubectl get svc -n $ns --no-headers 2>/dev/null | wc -l)
quota=$(kubectl get resourcequota -n $ns --no-headers 2>/dev/null | wc -l)
echo "$ns | $pods pods | $svcs services | cuotas: $quota"
donerutas-norte-dev | 7 pods | 4 services | cuotas: 0
rutas-norte-pre | 6 pods | 3 services | cuotas: 0
rutas-norte-pro | 3 pods | 1 services | cuotas: 0| Entorno | Pods | Services | ¿Cuota? | Observación |
|---|---|---|---|---|
rutas-norte-dev |
7 | 4 | No | Entorno completo: los cuatro componentes desplegados |
rutas-norte-pre |
6 | 3 | No | Falta postgres-reservas |
rutas-norte-pro |
3 | 1 | No | Solo tienda-web; sin cuota es el riesgo más grave del clúster |
Conclusión
Los namespaces han dejado de ser esa palabra que repetíamos en cada comando. Sabes que su función nativa es la unicidad de nombres, y que de ella se derivan el ámbito de las consultas, de los selectores, del DNS corto, de las cuotas, del RBAC y de las políticas de red. Distingues los recursos que llevan namespace —pods, Deployments, Services, ConfigMaps, Secrets, PVCs— de los que pertenecen al clúster entero —nodos, PersistentVolumes, StorageClasses, ClusterRoles—, y sabes averiguarlo en cualquier momento con kubectl api-resources --namespaced. Conoces los cuatro namespaces del sistema, has visto el plano de control corriendo como pods en kube-system, y tienes claro por qué default es un vertedero en el que Rutas Norte no despliega nada.
Has montado los tres entornos del proyecto de forma declarativa y con etiquetas que las NetworkPolicies aprovecharán después, y has desplegado los mismos manifiestos en varios de ellos comprobando que tienda-web y api-reservas conviven con idéntico nombre en namespaces distintos, cada uno con su propia ClusterIP y hablando con su propia base de datos gracias al DNS corto. Trabajas con -n, con -A y fijando el namespace del contexto, con el reflejo de verificar dónde estás antes de cualquier comando destructivo.
Y te llevas las dos advertencias que más incidentes evitan. La primera: un namespace no aísla nada por sí solo. No es frontera de red —lo has demostrado escribiendo en la caché de preproducción desde desarrollo y llamando a producción desde un pod de dev—, no es frontera de permisos, no limita recursos y no separa nodos. Es el ámbito sobre el que se aplican cuotas, RBAC y políticas de red, que llegarán en los módulos 3, 4 y 8. La segunda: kubectl delete namespace se lo lleva todo sin confirmación y sin marcha atrás, motivo por el cual producción real de Rutas Norte vive en un clúster aparte.
Queda un hilo suelto que ha recorrido todo el módulo. Los selectores de los ReplicaSets, los selectores de los Services, la etiqueta entorno de los namespaces, la anotación kubernetes.io/change-cause del historial de revisiones, el pod-template-hash que el Deployment añade solo, las consultas con -l que llevamos usando desde la primera lección... Todo eso son etiquetas y anotaciones, y hasta ahora las hemos ido usando sin sistematizar. En Etiquetas, Selectores y Anotaciones, la lección que cierra el módulo, pondremos orden: sintaxis y restricciones, etiquetas recomendadas por Kubernetes, el esquema de etiquetado definitivo de los seis componentes de Rutas Norte en sus tres entornos, selectores de igualdad y de conjunto, y las consultas del día a día que convierten un clúster grande en algo navegable.
Curso de Kubernetes
Módulo 1: Introducción a Kubernetes
- ¿Qué es Kubernetes?
- Arquitectura de Kubernetes
- Conceptos y Terminología Clave
- Configuración de un Clúster de Kubernetes
- La CLI de Kubernetes: kubectl
- Objetos, Manifiestos YAML y el Modelo Declarativo
- El Proyecto del Curso: la Plataforma Rutas Norte
Módulo 2: Componentes Principales de Kubernetes
- Pods
- ReplicaSets
- Deployments
- Actualizaciones, Rollbacks y Estrategias de Despliegue
- Servicios
- Namespaces
- Etiquetas, Selectores y Anotaciones
Módulo 3: Gestión de Configuración y Secretos
- ConfigMaps
- Secrets
- Variables de Entorno
- Cuotas y Límites de Recursos
- LimitRanges y Clases de Calidad de Servicio (QoS)
- ServiceAccounts y Acceso a la API desde los Pods
Módulo 4: Redes en Kubernetes
- Redes de Clúster
- Tipos de Servicios
- DNS Interno y Descubrimiento de Servicios
- Controladores de Ingress
- TLS y Gestión de Certificados con cert-manager
- Políticas de Red
Módulo 5: Almacenamiento en Kubernetes
- Volúmenes
- Volúmenes Persistentes
- Reclamaciones de Volúmenes Persistentes
- Clases de Almacenamiento
- Aprovisionamiento Dinámico, Expansión y Snapshots
- Copias de Seguridad y Restauración de Datos
Módulo 6: Conceptos Avanzados de Kubernetes
- StatefulSets
- DaemonSets
- Trabajos y CronJobs
- Init Containers, Sidecars y Patrones Multi-Contenedor
- Planificación: Afinidad, Taints y Tolerations
- Definiciones de Recursos Personalizados (CRDs)
- Operadores y el Patrón Controlador
Módulo 7: Monitoreo y Registro
- Verificaciones de Salud y Sondas
- Servidor de Métricas y kubectl top
- Monitoreo con Prometheus
- Visualización y Alertas con Grafana y Alertmanager
- Registro Centralizado con Elasticsearch, Fluentd y Kibana (EFK)
- Depuración de Aplicaciones y Eventos del Clúster
Módulo 8: Seguridad en Kubernetes
- Control de Acceso Basado en Roles (RBAC)
- Contextos de Seguridad y Endurecimiento del Contenedor
- Políticas de Seguridad de Pods y Pod Security Standards
- Seguridad de Red
- Seguridad de Imágenes
- Auditoría, Escaneo y Gestión de Vulnerabilidades
Módulo 9: Escalado y Rendimiento
- Autoescalado Horizontal de Pods
- Autoescalado Vertical de Pods
- Autoescalado de Clúster
- Escalado por Eventos y Métricas Personalizadas con KEDA
- Alta Disponibilidad: PodDisruptionBudgets y Topología
- Ajuste de Rendimiento
Módulo 10: Ecosistema y Herramientas de Kubernetes
- Minikube y Entornos Locales con kind
- Kubeadm
- Helm
- Kustomize
- GitOps con Argo CD y Flux
- Kubernetes Gestionado: EKS, AKS y GKE
Módulo 11: Estudios de Caso y Aplicaciones del Mundo Real
- Despliegue de una Aplicación Web
- Ejecución de Aplicaciones con Estado
- CI/CD con Kubernetes
- Estrategias de Despliegue: Blue-Green y Canary
- Gestión Multi-Clúster
- Operación en Producción: Incidencias, Runbooks y Costes
