Es habitual trabajar con varios clústeres de Kubernetes a la vez: uno de desarrollo y otro de producción, o uno por región. kubectl lo resuelve con los contextos del fichero kubeconfig, pero sin orden es fácil lanzar un comando en el clúster equivocado. En este tutorial combinarás los kubeconfig de dos clústeres en uno, cambiarás de clúster y namespace de forma segura con kubectx y kubens, crearás un kubeconfig de acceso limitado para otra persona o herramienta, y ejecutarás comandos en todos los clústeres a la vez.

Requisitos previos

Para seguir esta guía necesitas:

  • Acceso de administrador a dos o más clústeres de Kubernetes, por ejemplo desplegados sobre VPS de CubePath en ubicaciones distintas, y el fichero kubeconfig de cada uno.
  • Una estación de trabajo con Ubuntu 24.04 (o cualquier Linux o macOS) con kubectl instalado.

En los ejemplos, los clústeres se llaman dev y prod, y sus kubeconfig originales están en ~/Descargas/dev.yaml y ~/Descargas/prod.yaml. Sustitúyelos por tus rutas.

Cómo está organizado un kubeconfig

Un kubeconfig tiene tres listas y un valor activo:

SecciónContenido
clustersDirección de la API y certificado de la CA de cada clúster.
usersCredenciales: certificado de cliente, token o plugin de autenticación.
contextsCombinaciones de un clúster, un usuario y, opcionalmente, un namespace.
current-contextEl contexto que usa kubectl cuando no indicas otro.

kubectl busca la configuración en la variable KUBECONFIG (una lista de ficheros separados por :) o, si no existe, en ~/.kube/config.

Paso 1: Dar nombres únicos a cada kubeconfig

Los kubeconfig generados por kubeadm usan siempre los mismos nombres: el clúster se llama kubernetes, el usuario kubernetes-admin y el contexto kubernetes-admin@kubernetes. Si combinas dos ficheros con esos nombres, las entradas del segundo se ignoran en silencio y acabarías con dos contextos apuntando al mismo clúster. Comprueba los nombres de cada fichero:

kubectl --kubeconfig ~/Descargas/dev.yaml config get-contexts
CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
*         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin

Copia cada fichero a ~/.kube/ y edítalo para dar nombres únicos a las tres entradas:

mkdir -p ~/.kube
cp ~/Descargas/dev.yaml ~/.kube/dev.yaml
cp ~/Descargas/prod.yaml ~/.kube/prod.yaml
chmod 600 ~/.kube/dev.yaml ~/.kube/prod.yaml
nano ~/.kube/dev.yaml

Cambia los nombres en las secciones clusters, users y contexts, y en current-context, de modo que queden así (los certificados y la dirección del servidor no se tocan):

apiVersion: v1
kind: Config
clusters:
  - name: dev
    cluster:
      server: https://203.0.113.10:6443
      certificate-authority-data: LS0tLS1CRUdJTi...
users:
  - name: dev-admin
    user:
      client-certificate-data: LS0tLS1CRUdJTi...
      client-key-data: LS0tLS1CRUdJTi...
contexts:
  - name: dev
    context:
      cluster: dev
      user: dev-admin
current-context: dev

Haz lo mismo en ~/.kube/prod.yaml con los nombres prod, prod-admin y prod.

Paso 2: Combinar los kubeconfig en uno

Haz una copia del fichero actual si ya tienes uno, y genera el fichero combinado. La opción --flatten incrusta los certificados para que el resultado no dependa de otros ficheros:

[ -f ~/.kube/config ] && cp ~/.kube/config ~/.kube/config.bak
KUBECONFIG=~/.kube/dev.yaml:~/.kube/prod.yaml kubectl config view --flatten > ~/.kube/config.new
mv ~/.kube/config.new ~/.kube/config
chmod 600 ~/.kube/config

Lista los contextos disponibles:

kubectl config get-contexts
CURRENT   NAME   CLUSTER   AUTHINFO     NAMESPACE
*         dev    dev       dev-admin
          prod   prod      prod-admin

Comprueba que cada contexto llega a su clúster con la opción --context, que sirve para lanzar un comando en otro clúster sin cambiar el contexto activo:

kubectl --context dev get nodes
kubectl --context prod get nodes

Cada comando debe devolver los nodos de un clúster distinto.

Paso 3: Cambiar de contexto y namespace

Con kubectl puro, se cambia de clúster y de namespace así:

kubectl config use-context prod
kubectl config set-context --current --namespace=kube-system
kubectl config current-context
Switched to context "prod".
Context "prod" modified.
prod

Los comandos son largos para algo que se hace decenas de veces al día. Las herramientas kubectx y kubens los simplifican y están en los repositorios de Ubuntu:

sudo apt update
sudo apt install kubectx

Ahora puedes listar y cambiar contextos y namespaces con órdenes cortas:

kubectx          # lista los contextos y marca el activo
kubectx dev      # cambia al contexto dev
kubectx -        # vuelve al contexto anterior
kubens default   # cambia el namespace del contexto actual
kubens -         # vuelve al namespace anterior

Comprueba el resultado:

kubectx -c
kubens -c
dev
default

Si instalas también fzf (sudo apt install fzf), kubectx y kubens sin argumentos abren un selector interactivo.

Paso 4: Evitar comandos en el clúster equivocado

El error más caro en un entorno multiclúster es aplicar en producción algo pensado para desarrollo. Dos medidas sencillas lo reducen mucho.

La primera es ver siempre el contexto activo en el prompt. Añade estas líneas al final de ~/.bashrc:

nano ~/.bashrc
kube_ctx() {
  local ctx
  ctx=$(kubectl config current-context 2>/dev/null) || return
  printf '[%s] ' "$ctx"
}
PS1='$(kube_ctx)'"$PS1"

Recarga la configuración y comprueba que el prompt muestra el contexto:

source ~/.bashrc
[dev] usuario@estacion:~$

La segunda es usar --context de forma explícita en scripts y en cualquier operación destructiva sobre producción, en lugar de depender del contexto activo:

kubectl --context prod -n web rollout restart deployment/frontend

Paso 5: Crear un kubeconfig de acceso limitado

No compartas el kubeconfig de administrador con compañeros, pipelines de CI o herramientas de monitoreo. Crea una ServiceAccount con los permisos justos y un kubeconfig propio para ella. En este ejemplo, una cuenta de solo lectura en el clúster prod:

kubectl --context prod create serviceaccount readonly -n kube-system
kubectl --context prod create clusterrolebinding readonly-view \
  --clusterrole=view --serviceaccount=kube-system:readonly

El ClusterRole view incluido en Kubernetes permite leer la mayoría de objetos pero no los Secret. Genera un token con caducidad para la cuenta, en este caso de 30 días:

TOKEN=$(kubectl --context prod create token readonly -n kube-system --duration=720h)

Extrae la dirección y la CA del clúster prod y construye el nuevo kubeconfig:

SERVER=$(kubectl config view --raw -o jsonpath='{.clusters[?(@.name=="prod")].cluster.server}')
kubectl config view --raw -o jsonpath='{.clusters[?(@.name=="prod")].cluster.certificate-authority-data}' | base64 -d > prod-ca.crt

kubectl config set-cluster prod --kubeconfig=prod-readonly.yaml \
  --server="$SERVER" --certificate-authority=prod-ca.crt --embed-certs=true
kubectl config set-credentials readonly --kubeconfig=prod-readonly.yaml --token="$TOKEN"
kubectl config set-context prod-readonly --kubeconfig=prod-readonly.yaml \
  --cluster=prod --user=readonly
kubectl config use-context prod-readonly --kubeconfig=prod-readonly.yaml
rm prod-ca.crt

Comprueba que el acceso funciona para lectura y que se deniega la escritura:

kubectl --kubeconfig=prod-readonly.yaml get pods -A | head -3
kubectl --kubeconfig=prod-readonly.yaml auth can-i create deployments
NAMESPACE     NAME                               READY   STATUS    RESTARTS   AGE
kube-system   coredns-76f75df574-8xk2p           1/1     Running   0          12d
kube-system   coredns-76f75df574-qz7lw           1/1     Running   0          12d
no

Entrega prod-readonly.yaml por un canal seguro. Para revocar el acceso, borra la ServiceAccount: kubectl --context prod delete serviceaccount readonly -n kube-system.

Paso 6: Ejecutar un comando en todos los clústeres

Para revisiones rápidas, un bucle sobre los contextos evita repetir el mismo comando a mano. Por ejemplo, para ver la versión y el estado de los nodos de cada clúster:

for ctx in $(kubectl config get-contexts -o name); do
  echo "=== $ctx"
  kubectl --context "$ctx" get nodes -o wide
done
=== dev
NAME       STATUS   ROLES           AGE   VERSION   INTERNAL-IP    ...
dev-cp-1   Ready    control-plane   40d   v1.33.4   10.0.0.10      ...
=== prod
NAME        STATUS   ROLES           AGE   VERSION   INTERNAL-IP   ...
prod-cp-1   Ready    control-plane   90d   v1.33.4   10.1.0.10     ...

El mismo patrón sirve para buscar pods que no están en Running en todos los clústeres:

for ctx in $(kubectl config get-contexts -o name); do
  echo "=== $ctx"
  kubectl --context "$ctx" get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded
done

Úsalo para consultas. Para desplegar aplicaciones en varios clústeres, es mejor una herramienta declarativa (ver la conclusión) que un bucle de kubectl apply.

Herramientas para flotas más grandes

Cuando el número de clústeres crece, conviene pasar de kubeconfig y bucles a herramientas dedicadas:

HerramientaPara qué sirve
Argo CD (ApplicationSet) o FluxDesplegar las mismas aplicaciones desde Git en varios clústeres, con estado declarativo.
RancherInterfaz web y gestión centralizada de usuarios, permisos y actualizaciones de muchos clústeres.
Cluster APICrear, actualizar y borrar clústeres de forma declarativa con recursos de Kubernetes.

KubeFed (Kubernetes Cluster Federation), que aparece en muchas guías antiguas, fue archivado por el proyecto Kubernetes en 2023 y no debe usarse en instalaciones nuevas.

Solución de problemas

  • Después de combinar, dos contextos muestran los mismos nodos. Los ficheros originales tenían entradas de clúster o usuario con el mismo nombre. Restaura ~/.kube/config.bak y repite el paso 1 con nombres únicos.
  • error: You must be logged in to the server (Unauthorized). El certificado de cliente o el token ha caducado. En kubeadm, los certificados del administrador duran un año; renuévalos en el plano de control con sudo kubeadm certs renew admin.conf y copia de nuevo /etc/kubernetes/admin.conf.
  • Helm avisa de que el kubeconfig es legible por el grupo u otros usuarios. Ejecuta chmod 600 ~/.kube/config.

Conclusión

Ahora tienes un único kubeconfig con nombres claros para cada clúster, cambias de contexto y namespace con kubectx y kubens, ves siempre en el prompt dónde estás trabajando y sabes crear accesos limitados y revocables. Como siguientes pasos, puedes adoptar Argo CD con ApplicationSets para desplegar desde Git en todos tus clústeres, centralizar la autenticación con OIDC en lugar de certificados de cliente, y monitorizar todos los clústeres desde un mismo Grafana.