Portem tot el mòdul escrivint rutas-norte-dev a cada manifest i a cada ordre, sense haver-nos aturat a explicar què és exactament aquell namespace ni què ens dona. I al final de la lliçó anterior va aparèixer una propietat molt interessant: la configuració d'api-reserves apunta a redis-cache i a postgres-reserves pel seu nom curt, sense esmentar l'entorn, perquè el DNS ho resol dins del namespace on corre el pod. Aquella propietat és la que permet desplegar el mateix manifest tres vegades i obtenir tres plataformes independents. En aquesta lliçó muntem els tres entorns de Rutas Norte —rutas-norte-dev, rutas-norte-pre i rutas-norte-pro—, veurem què aïlla un namespace i què no aïlla en absolut (que és la part que més incidents provoca), distingirem els recursos amb i sense namespace, coneixerem els namespaces del sistema i per què mai no es desplega a default, treballarem còmodament amb -n i amb el context, resoldrem noms DNS entre namespaces, i acabarem amb un advertiment molt seriós sobre el que s'endú per davant un kubectl delete namespace.

Contingut

  1. Què és un namespace i què aïlla
  2. Recursos amb i sense namespace
  3. Els namespaces del sistema i per què no es desplega a default
  4. Els tres entorns de Rutas Norte
  5. El mateix manifest en diversos entorns
  6. Treballar amb namespaces sense tornar-se boig
  7. DNS entre namespaces
  8. Què NO garanteix un namespace
  9. Esborrar un namespace: l'ordre més perillosa de kubectl
  10. Namespaces enfront de clústers separats

  1. Què és un namespace i què aïlla

Un namespace és una partició lògica del clúster que agrupa recursos. La definició operativa, la que de debò serveix:

Un namespace és, sobretot, un espai de noms: dins d'ell, el nom de cada objecte ha de ser únic; fora, es pot repetir lliurement.

Això permet que existeixin simultàniament tres objectes anomenats api-reserves, un a cada entorn, sense col·lidir. I a partir d'aquí se'n deriven la resta d'usos.

El que un namespace que aporta:

Funció Què significa a la pràctica
Unicitat de noms api-reserves pot existir a dev, pre i pro alhora
Àmbit de les consultes kubectl get pods només mostra els del namespace actual
Punt d'ancoratge de les quotes Un ResourceQuota limita el consum total d'un namespace (03-04)
Unitat de permisos de RBAC Un Role concedeix permisos dins d'un namespace (08-01)
Subjecte de les polítiques de xarxa Una NetworkPolicy pot seleccionar per namespace (04-06)
Àmbit del DNS curt redis-cache resol al Service del namespace del pod que pregunta
Àmbit dels selectors Un Service o un ReplicaSet només veuen pods del seu propi namespace
Esborrat en bloc Esborrar el namespace elimina tot el que conté

I el que no aporta, que veurem en detall a l'apartat 8: no aïlla la xarxa, no limita recursos per si sol, no impedeix l'accés i no separa els nodes.

flowchart TB
    subgraph CL["Clúster minikube · perfil rutas-norte"]
        subgraph DEV["namespace rutas-norte-dev"]
            D1["Deployment api-reserves"]
            D2["Service api-reserves"]
            D3["Deployment postgres-reserves"]
        end
        subgraph PRE["namespace rutas-norte-pre"]
            E1["Deployment api-reserves"]
            E2["Service api-reserves"]
            E3["Deployment postgres-reserves"]
        end
        subgraph SYS["namespace kube-system"]
            S1["CoreDNS"]
            S2["kube-proxy"]
        end
        NODES["Nodes, PersistentVolumes, StorageClasses<br/>(sense namespace: comuns a tot el clúster)"]
    end

Fixa't en el detall clau del diagrama: els objectes amb el mateix nom conviuen en namespaces diferents, però els nodes són compartits. Un pod de rutas-norte-dev i un altre de rutas-norte-pre poden acabar a la mateixa màquina.

  1. Recursos amb i sense namespace

No tots els objectes de Kubernetes viuen dins d'un namespace. N'hi ha que pertanyen al clúster sencer, i confondre'ls genera errors desconcertants.

La manera de saber-ho amb certesa, sense memoritzar res:

kubectl api-resources --namespaced=true | head -15
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         StatefulSet
kubectl api-resources --namespaced=false
NAME                        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        VolumeAttachment

La lògica del repartiment és coherent: allò que representa infraestructura física o configuració global del clúster no porta namespace; allò que representa càrrega de treball o configuració d'aplicació, sí.

Amb namespace Sense 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

Dues parelles mereixen atenció perquè són font constant de confusió:

  • PersistentVolume (sense namespace) enfront de PersistentVolumeClaim (amb namespace). El disc és un recurs del clúster; la reclamació d'aquell disc pertany a una aplicació concreta en un namespace. Mòdul 5.
  • Role/RoleBinding (amb namespace) enfront de ClusterRole/ClusterRoleBinding (sense namespace). Els primers concedeixen permisos dins d'un namespace; els segons, a tot el clúster. Mòdul 8.

Un error pràctic derivat d'això:

kubectl get nodes -n rutas-norte-dev
NAME          STATUS   ROLES           AGE   VERSION
rutas-norte   Ready    control-plane   3d    v1.30.0

El -n s'ha ignorat en silenci. Els nodes no tenen namespace, així que el flag no filtra res. No és un error, però pot fer-te creure que estàs veient alguna cosa filtrada quan no ho està.

  1. Els namespaces del sistema i per què no es desplega a default

Tot clúster neix amb quatre namespaces:

kubectl get 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 Contingut L'has de tocar?
default Buit al principi. És on van els objectes si no indiques namespace No despleguis aquí
kube-system Els components del mateix Kubernetes: CoreDNS, kube-proxy, controladors CSI, addons Mai no despleguis aquí; mirar sí, tocar no
kube-public Llegible sense autenticar; conté un ConfigMap amb dades públiques del clúster Gairebé mai no es fa servir
kube-node-lease Un objecte Lease per node, que el kubelet renova com a batec de vida Mai

Fes una ullada a kube-system per veure el clúster per dins:

kubectl get pods -n kube-system
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          3d

Aquí els tens, corrent com a pods, tots els components que vas estudiar a Arquitectura de Kubernetes. El pla de control del teu minikube és visible i palpable.

kube-node-lease explica una cosa que potser et vas preguntar: com sap el pla de control si un node continua viu.

kubectl get leases -n kube-node-lease
NAME          HOLDER        AGE
rutas-norte   rutas-norte   3d

El kubelet renova aquell objecte cada pocs segons. Si deixa de fer-ho, el node es marca NotReady.

Per què no es desplega a default

És el namespace que Kubernetes fa servir quan no dius res, i precisament per això és un mal lloc per treballar:

  1. És l'abocador del clúster. Tot el que algú apliqui sense -n hi acaba. En pocs mesos és un calaix de sastre on ningú no sap què és de qui.
  2. No es pot esborrar. Els namespaces del sistema són indestructibles, així que no el pots netejar d'un cop com faries amb rutas-norte-dev.
  3. Els accidents són fàcils. Un kubectl delete deploy --all sense -n, executat creient ser en un altre lloc, s'endú per davant el que hi hagi a default.
  4. Impossibilita l'aïllament. Si tot és a default, no pots aplicar quotes per equip, ni RBAC per entorn, ni polítiques de xarxa diferenciades.
  5. Impedeix reutilitzar noms. Amb tot en un mateix namespace, api-reserves de desenvolupament i de producció no poden coexistir.

La regla del projecte és explícita:

A Rutas Norte, default està prohibit. Tot objecte viu en un namespace anomenat, declarat al seu propi manifest.

  1. Els tres entorns de Rutas Norte

Ha arribat el moment de crear l'estructura completa. Ja coneixes rutas-norte-dev del mòdul 1; hi afegim preproducció i producció, de forma declarativa i en un sol fitxer.

En YAML, --- separa diversos documents dins d'un mateix fitxer. És la manera habitual d'agrupar objectes relacionats:

# k8s/base/namespaces.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: rutas-norte-dev
  labels:
    app.kubernetes.io/part-of: rutas-norte
    entorn: dev
---
apiVersion: v1
kind: Namespace
metadata:
  name: rutas-norte-pre
  labels:
    app.kubernetes.io/part-of: rutas-norte
    entorn: pre
---
apiVersion: v1
kind: Namespace
metadata:
  name: rutas-norte-pro
  labels:
    app.kubernetes.io/part-of: rutas-norte
    entorn: pro
  annotations:
    rutasnorte.example/responsable: [email protected]
    rutasnorte.example/avis: "Entorn productiu. Canvis només per canalització."
kubectl apply -f k8s/base/namespaces.yaml
kubectl get namespaces -l app.kubernetes.io/part-of=rutas-norte
namespace/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   4s

Fixa't en dues decisions deliberades:

  • Els namespaces porten etiquetes. No és decoratiu: al mòdul 4, les NetworkPolicies seleccionaran namespaces per l'etiqueta entorn, i així una política podrà dir "només accepto trànsit de pods del mateix entorn".
  • Producció porta anotacions informatives. Qualsevol que faci kubectl describe ns rutas-norte-pro sabrà a qui avisar i quines regles hi regeixen.

L'estructura del repositori que ja tenim definida hi encaixa de manera natural:

k8s/
├── base/                  # manifests comuns als tres entorns
│   ├── namespaces.yaml
│   ├── botiga-web-deployment.yaml
│   ├── botiga-web-service.yaml
│   ├── api-reserves-deployment.yaml
│   └── ...
└── entorns/
    ├── dev/               # diferències de l'entorn de desenvolupament
    ├── pre/
    └── pro/

Com es combinen base i entorns sense duplicar YAML és feina de Kustomize o Helm, a 10-04 i 10-03. En aquest mòdul ho farem de la manera més simple possible.

  1. El mateix manifest en diversos entorns

Aquí hi ha la propietat que fa valuosos els namespaces. Desplegarem botiga-web i el seu Service a preproducció fent servir exactament els mateixos fitxers que a desenvolupament.

Els nostres manifests porten namespace: rutas-norte-dev escrit a dins, així que hi ha dues maneres de portar-los a un altre entorn.

Opció A: treure el namespace del manifest i decidir-lo en aplicar.

# k8s/base/botiga-web-deployment.yaml (fragment, sense namespace)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: botiga-web
  # sense camp namespace: el decideix qui aplica
  labels:
    app: botiga-web
    app.kubernetes.io/part-of: rutas-norte
kubectl apply -f k8s/base/botiga-web-deployment.yaml -n rutas-norte-pre
kubectl apply -f k8s/base/botiga-web-service.yaml -n rutas-norte-pre

Opció B: mantenir el namespace al manifest i substituir-lo en desplegar. És el que faran Kustomize o Helm per tu; a mà es veuria així:

sed 's/rutas-norte-dev/rutas-norte-pre/g' k8s/base/botiga-web-deployment.yaml | kubectl apply -f -
sed 's/rutas-norte-dev/rutas-norte-pre/g' k8s/base/botiga-web-service.yaml | kubectl apply -f -

Hi ha una regla important que convé conèixer: si un manifest declara metadata.namespace i a més hi passes -n amb un valor diferent, kubectl dona error en lloc de triar pel seu compte.

kubectl apply -f k8s/base/botiga-web-deployment.yaml -n rutas-norte-pre
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.

És un comportament desitjable: evita desplegar a producció per accident.

Fem-ho amb l'opció B, que respecta els nostres manifests actuals:

for f in botiga-web-deployment botiga-web-service api-reserves-deployment api-reserves-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-pre
NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/api-reserves  2/2     2            2           25s
deployment.apps/botiga-web    3/3     3            3           26s
deployment.apps/redis-cache   1/1     1            1           24s

NAME                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/api-reserves   ClusterIP   10.96.229.14    <none>        3000/TCP   25s
service/botiga-web     ClusterIP   10.96.44.71     <none>        80/TCP     26s
service/redis-cache    ClusterIP   10.96.88.107    <none>        6379/TCP   24s

Ara observa la situació completa del clúster:

kubectl get pods -A -l app.kubernetes.io/part-of=rutas-norte
NAMESPACE         NAME                                     READY   STATUS    RESTARTS   AGE
rutas-norte-dev   api-reserves-7f1d3e942-b8mrs             1/1     Running   0          48m
rutas-norte-dev   api-reserves-7f1d3e942-n4jvt             1/1     Running   0          48m
rutas-norte-dev   botiga-web-6f9c4b8d7-42kxr               1/1     Running   0          55m
rutas-norte-dev   botiga-web-6f9c4b8d7-8vnwq               1/1     Running   0          55m
rutas-norte-dev   botiga-web-6f9c4b8d7-t9mzd               1/1     Running   0          55m
rutas-norte-dev   postgres-reserves-59d7c4b8f-k3xqp        1/1     Running   0          40m
rutas-norte-dev   redis-cache-6c8f9d745-w2mtb              1/1     Running   0          52m
rutas-norte-pre   api-reserves-7f1d3e942-c9plk             1/1     Running   0          1m
rutas-norte-pre   api-reserves-7f1d3e942-r5vwj             1/1     Running   0          1m
rutas-norte-pre   botiga-web-6f9c4b8d7-d3jbx               1/1     Running   0          1m
rutas-norte-pre   botiga-web-6f9c4b8d7-m7kwr               1/1     Running   0          1m
rutas-norte-pre   botiga-web-6f9c4b8d7-p2fst               1/1     Running   0          1m
rutas-norte-pre   redis-cache-6c8f9d745-h8nqz              1/1     Running   0          1m

Dues plataformes Rutas Norte completes, amb els mateixos noms de Deployment i de Service, convivint sense la menor col·lisió. Aquest és el valor central del namespace.

I una comprovació que il·lustra l'aïllament de noms:

kubectl get svc api-reserves -n rutas-norte-dev -o jsonpath='{.spec.clusterIP}{"\n"}'
kubectl get svc api-reserves -n rutas-norte-pre -o jsonpath='{.spec.clusterIP}{"\n"}'
10.96.184.22
10.96.229.14

Mateix nom, dos objectes diferents, dues IPs virtuals diferents.

  1. Treballar amb namespaces sense tornar-se boig

Escriure -n rutas-norte-dev cent vegades al dia és tediós i, pitjor, oblidar-ho és la via ràpida a un accident.

El flag -n i -A

kubectl get pods -n rutas-norte-pre          # un namespace concret
kubectl get pods --all-namespaces            # tots
kubectl get pods -A                          # abreviatura de l'anterior

-A és imprescindible quan busques alguna cosa i no recordes on és:

kubectl get deploy -A -l app=api-reserves
NAMESPACE         NAME           READY   UP-TO-DATE   AVAILABLE   AGE
rutas-norte-dev   api-reserves   2/2     2            2           50m
rutas-norte-pre   api-reserves   2/2     2            2           3m

Fixar el namespace del context

És l'opció que més temps estalvia. Modifica el teu kubeconfig perquè totes les ordres facin servir aquell namespace per defecte:

kubectl config set-context --current --namespace=rutas-norte-pre
kubectl get pods
Context "rutas-norte" modified.

NAME                           READY   STATUS    RESTARTS   AGE
api-reserves-7f1d3e942-c9plk   1/1     Running   0          4m
api-reserves-7f1d3e942-r5vwj   1/1     Running   0          4m
botiga-web-6f9c4b8d7-d3jbx     1/1     Running   0          4m
botiga-web-6f9c4b8d7-m7kwr     1/1     Running   0          4m
botiga-web-6f9c4b8d7-p2fst     1/1     Running   0          4m
redis-cache-6c8f9d745-h8nqz    1/1     Running   0          4m

I la comprovació que hauries de convertir en un reflex abans de qualsevol ordre destructiva:

kubectl config view --minify -o jsonpath='{..namespace}{"\n"}'
rutas-norte-pre

Consell molt recomanable: configura el prompt de la teva terminal perquè mostri context i namespace. Eines com kube-ps1 ho fan, i veure (rutas-norte:rutas-norte-pro) a la pantalla abans de teclejar delete ha salvat moltes tardes.

kubens

Del conjunt kubectx, kubens canvia de namespace de forma interactiva:

kubens                       # llista els namespaces i marca l'actual
kubens rutas-norte-pro       # canvia a produccio
kubens -                     # torna a l'anterior

És sucre sintàctic sobre kubectl config set-context, però amb llistat interactiu i salt ràpid a l'anterior. S'instal·la com a binari solt o mitjançant krew, el gestor de connectors de kubectl que vam veure a La CLI de Kubernetes.

Torna a desenvolupament abans de continuar:

kubectl config set-context --current --namespace=rutas-norte-dev

  1. DNS entre namespaces

Ja coneixes el nom complet d'un Service: <servei>.<namespace>.svc.cluster.local. Els namespaces són la raó que existeixi aquella estructura.

Quan un pod resol un nom, el DNS del clúster prova una sèrie de sufixos de cerca en ordre. Mira'ls en un pod real:

kubectl exec deploy/api-reserves -- cat /etc/resolv.conf
search rutas-norte-dev.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5

La primera línia explica tot el comportament: en buscar redis-cache, el pod prova primer redis-cache.rutas-norte-dev.svc.cluster.local. Com que existeix, allà s'acaba. El nom curt sempre resol dins del propi namespace.

Des d'un pod de rutas-norte-dev, si escriu... Resol 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 Aquest mateix, sense ambigüitat

Comprova-ho:

kubectl run test-dns --rm -it --image=busybox:1.36 --restart=Never -n rutas-norte-dev -- \
  sh -c 'nslookup api-reserves; nslookup api-reserves.rutas-norte-pre'
Name:      api-reserves.rutas-norte-dev.svc.cluster.local
Address:   10.96.184.22

Name:      api-reserves.rutas-norte-pre.svc.cluster.local
Address:   10.96.229.14

pod "test-dns" deleted

Aquí hi ha dues notícies. La bona: el mateix manifest d'api-reserves, amb DATABASE_HOST: postgres-reserves, funciona als tres entorns i cadascun parla amb la seva pròpia base de dades, sense condicionals ni plantilles.

La dolenta, i és important: un pod de desenvolupament acaba de resoldre i es podria connectar a un Service de preproducció. No hi ha res que ho impedeixi. Això ens porta directament a l'apartat següent.

  1. Què NO garanteix un namespace

Aquest és l'apartat que evita incidents. La creença que "cada equip al seu namespace i així estan aïllats" és perillosament falsa.

No és una frontera de xarxa

Per defecte, qualsevol pod de qualsevol namespace es pot connectar a qualsevol pod o Service de qualsevol altre namespace. El model de xarxa pla de Kubernetes és explícit en això: tots els pods es veuen entre ells.

Demostració incòmoda: un pod de desenvolupament escrivint a la memòria cau de preproducció.

kubectl run intrus --rm -it --image=redis:7.2-alpine --restart=Never -n rutas-norte-dev -- \
  redis-cli -h redis-cache.rutas-norte-pre SET places:BIL-SAN:2026-08-14 0
OK
pod "intrus deleted"

Acabem de posar a zero les places disponibles a la memòria cau de preproducció des de desenvolupament. Si hagués estat rutas-norte-pro, seria un incident seriós. I ningú no ha necessitat permisos especials: n'hi ha hagut prou amb conèixer el nom.

La solució no és el namespace, són les NetworkPolicies de 04-06, que sí que permeten declarar regles del tipus "postgres-reserves només accepta connexions de pods amb l'etiqueta app=api-reserves del mateix namespace".

No és una frontera de seguretat ni de permisos

Crear un namespace no restringeix qui pot fer què dins d'ell. Si les teves credencials tenen permisos amplis sobre el clúster, els tens sobre tots els namespaces, existents i futurs.

kubectl auth can-i delete deployments -n rutas-norte-pro
yes

Amb un usuari d'administrador, la resposta és yes per a qualsevol namespace. L'aïllament de permisos el donen els Role i RoleBinding de RBAC. El namespace és només l'àmbit sobre el qual aquelles regles s'apliquen: necessari, però no suficient.

No limita el consum de recursos

Un namespace no imposa cap sostre. Un Deployment mal configurat a rutas-norte-dev pot consumir tota la CPU i la memòria del clúster i deixar sense recursos els pods de rutas-norte-pro, perquè comparteixen els mateixos nodes.

kubectl describe namespace rutas-norte-dev
Name:         rutas-norte-dev
Labels:       app.kubernetes.io/part-of=rutas-norte
              entorn=dev
Status:       Active

No resource quota.

No LimitRange resource.

Aquelles dues línies finals ho diuen tot: sense quota i sense límits. Posar-los és matèria de Quotes i Límits de Recursos i LimitRanges i QoS.

No aïlla els nodes

Els pods de tots els namespaces es reparteixen pels mateixos nodes. Un pod de desenvolupament i un de producció poden ser veïns a la mateixa màquina, compartint CPU, memòria i disc.

kubectl get pods -A -l app=botiga-web -o custom-columns=NS:.metadata.namespace,POD:.metadata.name,NODE:.spec.nodeName
NS                POD                          NODE
rutas-norte-dev   botiga-web-6f9c4b8d7-42kxr   rutas-norte
rutas-norte-pre   botiga-web-6f9c4b8d7-d3jbx   rutas-norte

Separar càrregues per nodes requereix taints, toleracions i afinitat (06-05).

Resum honest

Creença habitual Realitat
"Els namespaces aïllen la xarxa" Fals. Tot es veu amb tot. Calen NetworkPolicies
"Els namespaces aïllen permisos" Fals per si sols. Calen Roles i RoleBindings
"Un namespace no pot consumir recursos d'un altre" Fals. Cal ResourceQuota
"Producció està protegida per ser en un altre namespace" Fals. És una separació organitzativa, no una barrera
"Els namespaces separen els nodes" Fals. Els nodes són comuns
"Els namespaces eviten col·lisions de noms" Cert. Aquesta sí que és la seva funció nativa

La frase que resumeix l'apartat: el namespace és l'àmbit sobre el qual s'apliquen els mecanismes d'aïllament, no el mecanisme d'aïllament. Sense quotes, RBAC i polítiques de xarxa a sobre, un namespace és només una carpeta.

  1. Esborrar un namespace: l'ordre més perillosa de kubectl

kubectl delete namespace rutas-norte-pre

Aquella ordre esborra tot el que hi ha a dins: Deployments, ReplicaSets, Pods, Services, ConfigMaps, Secrets, PersistentVolumeClaims, ServiceAccounts, Roles... I amb els PVC se'n van, segons la política de recuperació, les dades.

Característiques que la fan especialment perillosa:

  • No demana confirmació. Cap.
  • No hi ha desfer. No existeix paperera ni kubectl undelete.
  • És asíncrona. El namespace passa a estat Terminating mentre s'esborra el contingut, i en aquell estat no admet objectes nous.
  • Un error de teclat és catastròfic. rutas-norte-pro en lloc de rutas-norte-pre són tres caràcters de diferència.

Mira-ho en acció, amb un namespace d'usar i llençar:

kubectl create namespace prova-esborrat
kubectl run temporal --image=nginx:1.27-alpine -n prova-esborrat
kubectl delete namespace prova-esborrat
kubectl get namespace prova-esborrat
namespace/prova-esborrat created
pod/temporal created
namespace "prova-esborrat" deleted

Error from server (NotFound): namespaces "prova-esborrat" not found

El pod se'n va anar amb ell, sense preguntar res.

Namespaces encallats en Terminating

Un problema que trobaràs tard o d'hora: un namespace que es queda en Terminating indefinidament. La causa és gairebé sempre un finalizer —aquells ganxos que vam estudiar a Objectes i Manifests— que no es pot completar, típicament el d'una API estesa el servidor de la qual ja no existeix.

kubectl get namespace rutas-norte-pre -o jsonpath='{.spec.finalizers}{"\n"}'
kubectl get namespace rutas-norte-pre -o jsonpath='{.status.conditions}' | python3 -m json.tool

Abans de forçar res, esbrina quin recurs està bloquejant, perquè treure el finalizer a la brava deixa objectes orfes a etcd. La manera correcta és eliminar el recurs conflictiu o restaurar el servei que l'ha de processar.

Mesures de protecció per a Rutas Norte

  1. Etiquetar i anotar producció, com vam fer a namespaces.yaml: en descriure el namespace es llegeix l'avís.
  2. RBAC restrictiu: ningú no té permís de delete namespaces a rutas-norte-pro tret d'un parell de persones (08-01).
  3. Verificar el context abans de qualsevol esborrat, amb el reflex de l'apartat 6.
  4. Còpies de seguretat: l'única xarxa real. Eines com Velero permeten restaurar un namespace sencer, i és matèria de Còpies de Seguretat i Restauració.
  5. Comprovar abans de disparar, sempre:
kubectl get all -n rutas-norte-pre

Un bon hàbit addicional: fer servir --dry-run=client mentalment. Abans d'esborrar, pregunta't en veu alta quin namespace estàs mirant.

Deixa preproducció muntada, la continuarem fent servir:

kubectl get ns -l app.kubernetes.io/part-of=rutas-norte
NAME              STATUS   AGE
rutas-norte-dev   Active   2d
rutas-norte-pre   Active   25m
rutas-norte-pro   Active   25m

  1. Namespaces enfront de clústers separats

La pregunta estratègica: han de viure els tres entorns de Rutas Norte en un clúster amb tres namespaces, o en tres clústers separats?

Criteri Namespaces en un clúster Clústers separats
Cost Un pla de control, nodes compartits: molt més barat Multiplicat pel nombre de clústers
Aïllament real Lògic; requereix quotes, RBAC i NetworkPolicies ben fetes Total: infraestructura diferent
Radi d'impacte d'una fallada Un problema del pla de control afecta tot Un clúster caigut no toca els altres
Versió de Kubernetes La mateixa per a tots els entorns Cadascun la seva: es pot provar una actualització a pre
Complexitat operativa Baixa: un kubeconfig, un joc d'eines Alta: multiplica monitoratge, actualitzacions i accessos
Risc d'error humà Alt: un -n mal posat toca producció Baix: canviar de clúster és un acte conscient
Compliment normatiu Difícil de justificar davant d'un auditor Fàcil de justificar
Latència entre entorns Nul·la, comparteixen xarxa Requereix connectivitat externa

Criteris pràctics de decisió:

Namespaces en un clúster quan:

  • Els entorns són de confiança equivalent (dev i pre del mateix equip).
  • L'equip és petit i el pressupost limitat.
  • Es domina RBAC, quotes i polítiques de xarxa.

Clústers separats quan:

  • Hi ha dades regulades: personals, sanitàries, financeres.
  • S'ofereix servei a clients que no es fien entre ells (multi-tenant real).
  • Calen versions diferents de Kubernetes o de components del clúster.
  • Una fallada de producció no pot dependre de la salut d'un entorn de proves.

La decisió de Rutas Norte

L'empresa té dades personals de clients —nom, DNI, telèfon i correu— a postgres-reserves. La decisió, i el seu perquè:

Entorn Ubicació Justificació
rutas-norte-dev Namespace al clúster de no producció Dades anonimitzades, cost mínim, iteració ràpida
rutas-norte-pre Namespace al mateix clúster que dev Rèplica funcional de producció amb dades fictícies
rutas-norte-pro Clúster propi i separat Dades personals reals, requisits de disponibilitat i auditoria, radi d'impacte acotat

És a dir: dos clústers, tres namespaces. El namespace rutas-norte-pro existeix també al clúster de no producció perquè els manifests siguin idèntics i es pugui assajar el desplegament, però la producció real viu a part.

Durant el curs treballarem amb un sol minikube i els tres namespaces, que és el pràctic per aprendre. La gestió de diversos clústers alhora, amb els seus contextos i les seves eines, es tracta a Gestió Multi-Clúster.

Un últim apunt sobre com organitzar namespaces: per entorn (el que fem), per equip (equip-pagaments, equip-rutes) o per aplicació (rutas-norte, intranet). L'habitual és combinar dos eixos: rutas-norte-pro, intranet-pro. El que mai no funciona és un namespace per microservei: multiplica la burocràcia sense aportar aïllament útil.

Errors Comuns i Consells

  • Desplegar a default per oblit. El símptoma és kubectl get pods sense resultats on esperaves veure'ls. Comprova-ho amb kubectl get pods -A -l app=<component>.
  • Creure que un namespace aïlla la xarxa. No ho fa. Qualsevol pod es pot connectar a qualsevol Service d'un altre namespace coneixent-ne el nom.
  • Creure que un namespace aïlla permisos o recursos. Calen RBAC i ResourceQuota. El namespace és l'àmbit, no el mecanisme.
  • Posar -n a un recurs sense namespace. kubectl get nodes -n elquesigui ignora el flag en silenci i et pot confondre.
  • Discrepància entre metadata.namespace i -n. kubectl dona error en lloc de decidir per tu. És una protecció, no una molèstia.
  • Buscar al namespace equivocat i concloure que alguna cosa no existeix. Davant del dubte, -A.
  • Esborrar un namespace sense mirar què conté. No hi ha confirmació ni desfer. kubectl get all -n <ns> abans, sempre.
  • Forçar l'esborrat d'un namespace encallat traient-li els finalizers. Deixa objectes orfes a etcd. Investiga primer quin recurs el bloqueja.
  • Un namespace per microservei. Multiplica la càrrega administrativa sense aportar aïllament real. Organitza per entorn, equip o aplicació.
  • Consell: configura el prompt perquè mostri context i namespace (kube-ps1). Veure (rutas-norte:rutas-norte-pro) abans de teclejar delete evita accidents.
  • Consell: declara metadata.namespace als manifests que siguin específics d'un entorn i omet-lo als que siguin genèrics. L'ambigüitat és el que provoca desplegaments al lloc equivocat.
  • Consell: etiqueta sempre els teus namespaces. Les NetworkPolicies del mòdul 4 seleccionaran namespaces per etiqueta, i sense elles hauràs de tornar enrere a posar-les.

Exercicis

Exercici 1: Classificar recursos i explorar el sistema

  1. Amb una sola ordre, compta quants tipus de recursos tenen namespace i quants no.
  2. Determina, sense consultar taules, si aquests recursos porten namespace: PersistentVolume, PersistentVolumeClaim, Role, ClusterRole, Ingress, StorageClass.
  3. Llista els pods de kube-system i identifica quins són els cinc components del pla de control que vas estudiar al mòdul 1.
  4. Esbrina què hi ha dins de kube-public i explica què té de particular aquell namespace.

Exercici 2: Desplegar la plataforma a producció i comprovar l'aïllament

  1. Desplega botiga-web (Deployment i Service) a rutas-norte-pro, amb l'etiqueta entorn: pro en lloc de dev.
  2. Demostra amb una sola ordre que existeixen tres Deployments anomenats botiga-web al clúster, en namespaces diferents.
  3. Comprova que les ClusterIP dels tres Services botiga-web són diferents.
  4. Des d'un pod efímer a rutas-norte-dev, fes una petició HTTP al botiga-web de rutas-norte-pro fent servir el nom DNS complet. Funciona? Explica què implica això i quin objecte caldria crear per impedir-ho.

Exercici 3: Auditoria de namespaces

T'incorpores a l'equip de plataforma de Rutas Norte i t'encarreguen una auditoria ràpida del clúster. Respon amb ordres i la seva sortida:

  1. Quins namespaces existeixen i quins pertanyen a la plataforma Rutas Norte?
  2. Hi ha algun objecte desplegat a default? Si n'hi ha, mou-lo al namespace correcte.
  3. Quins namespaces tenen ResourceQuota definida? Què implica que no en tinguin?
  4. Pots esborrar el namespace de producció amb les teves credencials actuals? Quin mecanisme ho hauria d'impedir i en quina lliçó s'estudia?
  5. Elabora una taula amb els tres entorns indicant: nombre de pods, nombre de Services i si tenen quota.

Solucions

Solució 1

echo "Amb namespace: $(kubectl api-resources --namespaced=true --no-headers | wc -l)"
echo "Sense namespace: $(kubectl api-resources --namespaced=false --no-headers | wc -l)"
Amb namespace: 43
Sense namespace: 26

Els números varien segons els CRDs i els addons instal·lats al teu clúster.

  1. El raonament, abans de comprovar-ho: porta namespace allò que pertany a una aplicació concreta; no en porta allò que és infraestructura o configuració global.
Recurs Namespace? Raonament
PersistentVolume No És un disc del clúster, existeix abans que ningú el reclami
PersistentVolumeClaim És la petició d'una aplicació concreta
Role Concedeix permisos dins d'un namespace
ClusterRole No Concedeix permisos a tot el clúster
Ingress Enruta cap a Services, que tenen namespace
StorageClass No Defineix un tipus d'emmagatzematge disponible per a tot 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. Components del pla 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-norte

Els cinc: kube-apiserver (l'única porta a l'API), etcd (el magatzem d'estat), kube-scheduler (assigna pods a nodes), kube-controller-manager (on viuen els controladors de ReplicaSet, Deployment, endpoints...) i CoreDNS (que resol els noms de Service que vam fer servir a la lliçó anterior).

# 4. kube-public
kubectl get configmaps -n kube-public
kubectl get configmap cluster-info -n kube-public -o jsonpath='{.data.jws-kubeconfig-*}' | head -3
NAME               DATA   AGE
cluster-info       2      3d
kube-root-ca.crt   1      3d

kube-public és l'únic namespace llegible sense autenticar-se: qualsevol que arribi a l'apiserver pot llegir-ne el contingut. Conté cluster-info, amb les dades que un node necessita per unir-se al clúster durant el procés de kubeadm join. Per això mai no s'hi ha de guardar res sensible.

Solució 2

# 1. Desplegar a produccio
for f in botiga-web-deployment botiga-web-service; do
  sed -e 's/rutas-norte-dev/rutas-norte-pro/g' -e 's/entorn: dev/entorn: pro/g' \
    k8s/base/$f.yaml | kubectl apply -f -
done
kubectl get deploy,svc -n rutas-norte-pro
deployment.apps/botiga-web created
service/botiga-web created

NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/botiga-web   3/3     3            3           15s

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/botiga-web   ClusterIP   10.96.171.55    <none>        80/TCP    15s
# 2. Els tres Deployments
kubectl get deploy botiga-web -A
NAMESPACE         NAME         READY   UP-TO-DATE   AVAILABLE   AGE
rutas-norte-dev   botiga-web   3/3     3            3           1h
rutas-norte-pre   botiga-web   3/3     3            3           35m
rutas-norte-pro   botiga-web   3/3     3            3           1m
# 3. Tres ClusterIP diferents
kubectl get svc botiga-web -A -o custom-columns=NS:.metadata.namespace,NOM:.metadata.name,IP:.spec.clusterIP
NS                NOM          IP
rutas-norte-dev   botiga-web   10.96.12.209
rutas-norte-pre   botiga-web   10.96.44.71
rutas-norte-pro   botiga-web   10.96.171.55
# 4. Des de dev cap a pro
kubectl run intrus --rm -it --image=curlimages/curl:8.8.0 --restart=Never -n rutas-norte-dev -- \
  curl -s -o /dev/null -w "%{http_code}\n" http://botiga-web.rutas-norte-pro.svc.cluster.local/
200
pod "intrus" deleted

Funciona. Un pod de desenvolupament ha accedit sense cap obstacle a un servei de producció. Implicació directa: el namespace no és una frontera de xarxa. En el model per defecte de Kubernetes, tots els pods es veuen entre ells, i n'hi ha prou amb conèixer el nom DNS per connectar-s'hi.

Per impedir-ho cal una NetworkPolicy a rutas-norte-pro que rebutgi tot el trànsit entrant tret del que provingui de namespaces amb l'etiqueta entorn: pro (per això vam etiquetar els namespaces en crear-los). És el contingut de Polítiques de Xarxa i Seguretat de Xarxa.

Solució 3

# 1. Namespaces existents i els de la plataforma
kubectl get ns
kubectl get ns -l app.kubernetes.io/part-of=rutas-norte
NAME              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   40m

L'etiqueta comuna permet distingir d'un cop d'ull els namespaces de la plataforma dels del sistema.

# 2. Objectes a default
kubectl get all -n default
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   3d

Només apareix service/kubernetes, que és el Service del mateix apiserver i ha de ser-hi: és el que permet als pods parlar amb l'API. Si hi hagués qualsevol altra cosa, el procediment seria exportar-la, corregir-ne el namespace i tornar-la a aplicar:

kubectl get deploy <nom> -n default -o yaml > /tmp/objecte.yaml
# editar metadata.namespace i treure metadata.uid, resourceVersion i status
kubectl apply -f /tmp/objecte.yaml -n rutas-norte-dev
kubectl delete deploy <nom> -n default
# 3. Quotes
kubectl get resourcequota -A
No resources found

Cap namespace no té quota. Implicació: qualsevol Deployment de rutas-norte-dev pot consumir tota la CPU i la memòria del clúster i deixar sense recursos els pods de rutas-norte-pro, perquè comparteixen nodes. Un bucle mal escrit a desenvolupament pot tombar la producció. Es corregeix amb ResourceQuota i LimitRange a 03-04 i 03-05.

# 4. Permisos d'esborrat
kubectl auth can-i delete namespace rutas-norte-pro
yes

Sí que el puc esborrar, i amb ell tota la producció, sense confirmació i sense desfer. El que ho hauria d'impedir és RBAC: un Role/ClusterRole que no inclogui el verb delete sobre namespaces per a les credencials habituals, deixant aquell permís a un rol d'emergència fet servir per dues persones. S'estudia a Control d'Accés Basat en Rols. Com a xarxa de seguretat complementària, còpies de seguretat amb Velero (05-06).

# 5. Taula resum
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 | quotes: $quota"
done
rutas-norte-dev | 7 pods | 4 services | quotes: 0
rutas-norte-pre | 6 pods | 3 services | quotes: 0
rutas-norte-pro | 3 pods | 1 services | quotes: 0
Entorn Pods Services Quota? Observació
rutas-norte-dev 7 4 No Entorn complet: els quatre components desplegats
rutas-norte-pre 6 3 No Falta postgres-reserves
rutas-norte-pro 3 1 No Només botiga-web; sense quota és el risc més greu del clúster

Conclusió

Els namespaces han deixat de ser aquella paraula que repetíem a cada ordre. Saps que la seva funció nativa és la unicitat de noms, i que d'ella se'n deriven l'àmbit de les consultes, dels selectors, del DNS curt, de les quotes, del RBAC i de les polítiques de xarxa. Distingeixes els recursos que porten namespace —pods, Deployments, Services, ConfigMaps, Secrets, PVCs— dels que pertanyen al clúster sencer —nodes, PersistentVolumes, StorageClasses, ClusterRoles—, i saps esbrinar-ho en qualsevol moment amb kubectl api-resources --namespaced. Coneixes els quatre namespaces del sistema, has vist el pla de control corrent com a pods a kube-system, i tens clar per què default és un abocador on Rutas Norte no desplega res.

Has muntat els tres entorns del projecte de forma declarativa i amb etiquetes que les NetworkPolicies aprofitaran després, i has desplegat els mateixos manifests en diversos d'ells comprovant que botiga-web i api-reserves conviuen amb idèntic nom en namespaces diferents, cadascun amb la seva pròpia ClusterIP i parlant amb la seva pròpia base de dades gràcies al DNS curt. Treballes amb -n, amb -A i fixant el namespace del context, amb el reflex de verificar on ets abans de qualsevol ordre destructiva.

I t'emportes els dos advertiments que més incidents eviten. El primer: un namespace no aïlla res per si sol. No és frontera de xarxa —ho has demostrat escrivint a la memòria cau de preproducció des de desenvolupament i cridant producció des d'un pod de dev—, no és frontera de permisos, no limita recursos i no separa nodes. És l'àmbit sobre el qual s'apliquen quotes, RBAC i polítiques de xarxa, que arribaran als mòduls 3, 4 i 8. El segon: kubectl delete namespace s'ho endú tot sense confirmació i sense marxa enrere, motiu pel qual la producció real de Rutas Norte viu en un clúster a part.

Queda un fil solt que ha recorregut tot el mòdul. Els selectors dels ReplicaSets, els selectors dels Services, l'etiqueta entorn dels namespaces, l'anotació kubernetes.io/change-cause de l'historial de revisions, el pod-template-hash que el Deployment afegeix sol, les consultes amb -l que fem servir des de la primera lliçó... Tot això són etiquetes i anotacions, i fins ara les hem anat fent servir sense sistematitzar. A Etiquetes, Selectors i Anotacions, la lliçó que tanca el mòdul, hi posarem ordre: sintaxi i restriccions, etiquetes recomanades per Kubernetes, l'esquema d'etiquetatge definitiu dels sis components de Rutas Norte als seus tres entorns, selectors d'igualtat i de conjunt, i les consultes del dia a dia que converteixen un clúster gran en una cosa navegable.

Curs de Kubernetes

Mòdul 1: Introducció a Kubernetes

Mòdul 2: Components Principals de Kubernetes

Mòdul 3: Gestió de Configuració i Secrets

Mòdul 4: Xarxes a Kubernetes

Mòdul 5: Emmagatzematge a Kubernetes

Mòdul 6: Conceptes Avançats de Kubernetes

Mòdul 7: Monitoratge i Registre

Mòdul 8: Seguretat a Kubernetes

Mòdul 9: Escalat i Rendiment

Mòdul 10: Ecosistema i Eines de Kubernetes

Mòdul 11: Estudis de Cas i Aplicacions del Món Real

Mòdul 12: Preparació per a la Certificació de Kubernetes

© Copyright 2026. Tots els drets reservats