Skaffold es una herramienta de línea de comandos de Google que automatiza el ciclo de construir la imagen, publicarla y desplegarla en Kubernetes cada vez que cambias el código. En este tutorial instalarás Skaffold en Ubuntu 24.04, prepararás una pequeña aplicación Python, la desarrollarás con skaffold dev usando sincronización de archivos en caliente y crearás perfiles para desplegar la misma aplicación desde un pipeline de CI/CD.
Requisitos previos
- Ubuntu 24.04 LTS en tu equipo de desarrollo o en un VPS de CubePath, con un usuario no root con
sudo. - Docker Engine instalado y tu usuario en el grupo
docker(docker run hello-worlddebe funcionar sinsudo). kubectlinstalado.- Un clúster de Kubernetes. Para desarrollo local se recomienda kind, que se instala en el paso 1.
Paso 1: Crear un clúster local con kind
Skaffold detecta los clústeres locales (kind, k3d, minikube) y carga en ellos las imágenes directamente, sin necesidad de un registro. Descarga kind desde su página de releases. Consulta la última versión en https://github.com/kubernetes-sigs/kind/releases y ajusta la variable si hay una más reciente:
KIND_VERSION=v0.27.0
curl -fsSLo kind "https://kind.sigs.k8s.io/dl/${KIND_VERSION}/kind-linux-amd64"
sudo install -m 0755 kind /usr/local/bin/kind
Crea el clúster. kind configura automáticamente el contexto kind-desarrollo en kubectl:
kind create cluster --name desarrollo
kubectl get nodes
NAME STATUS ROLES AGE VERSION
desarrollo-control-plane Ready control-plane 40s v1.32.2
Paso 2: Instalar Skaffold
Skaffold se distribuye como un binario estático. Descarga la última versión estable y colócala en /usr/local/bin:
curl -fsSLo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
sudo install -m 0755 skaffold /usr/local/bin/skaffold
En servidores ARM64 usa skaffold-linux-arm64 en lugar de skaffold-linux-amd64. Comprueba la instalación:
skaffold version
v2.16.0
Opcionalmente, activa el autocompletado en Bash:
echo 'source <(skaffold completion bash)' >> ~/.bashrc
Paso 3: Preparar una aplicación de ejemplo
Crea un directorio de proyecto con una aplicación Flask mínima:
mkdir -p ~/hola-skaffold/k8s
cd ~/hola-skaffold
nano app.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "Hola desde Skaffold\n"
Crea el Dockerfile. El servidor se arranca con --debug, que recarga la aplicación cuando un archivo .py cambia dentro del contenedor. Esto es lo que aprovechará la sincronización de Skaffold:
nano Dockerfile
FROM python:3.12-slim
WORKDIR /app
RUN pip install --no-cache-dir flask
COPY app.py .
CMD ["flask", "--app", "app", "run", "--host", "0.0.0.0", "--port", "8080", "--debug"]
Advertenciael modo
--debugde Flask es solo para desarrollo. En producción usa un servidor WSGI como Gunicorn.
Crea los manifiestos de Kubernetes. La imagen se llama hola-skaffold, sin etiqueta: Skaffold la sustituye por la etiqueta que genera en cada build.
nano k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hola-skaffold
spec:
replicas: 1
selector:
matchLabels:
app: hola-skaffold
template:
metadata:
labels:
app: hola-skaffold
spec:
containers:
- name: app
image: hola-skaffold
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: hola-skaffold
spec:
selector:
app: hola-skaffold
ports:
- port: 80
targetPort: 8080
Paso 4: Crear el archivo skaffold.yaml
skaffold init puede generar el archivo detectando el Dockerfile y los manifiestos, pero es mejor entender cada bloque. Crea skaffold.yaml en la raíz del proyecto:
nano skaffold.yaml
apiVersion: skaffold/v4beta11
kind: Config
metadata:
name: hola-skaffold
build:
artifacts:
- image: hola-skaffold
docker:
dockerfile: Dockerfile
sync:
manual:
- src: "*.py"
dest: .
local:
push: false
manifests:
rawYaml:
- k8s/deployment.yaml
deploy:
kubectl: {}
portForward:
- resourceType: service
resourceName: hola-skaffold
port: 80
localPort: 8080
Qué hace cada sección:
build.artifactsdefine la imagen y cómo se construye.sync.manualindica que los cambios en archivos.pyse copian al contenedor en ejecución (en elWORKDIR,/app) en lugar de reconstruir la imagen.build.local.push: falseevita subir la imagen a un registro. Con kind, Skaffold la carga directamente en el clúster.manifestsydeployseparan qué se renderiza (YAML plano, Kustomize o Helm) de cómo se aplica (kubectlohelm).portForwardredirigelocalhost:8080al Service cuando ejecutas Skaffold con--port-forward.
Notasi tu versión de Skaffold usa un esquema más reciente, ejecuta
skaffold fix --overwritepara actualizar elapiVersiondel archivo. Las versiones nuevas siguen aceptando esquemas anteriores.
Valida la configuración renderizando los manifiestos sin desplegar nada:
skaffold render --digest-source=tag
La salida muestra el Deployment con la imagen ya etiquetada por Skaffold. Por defecto la etiqueta se basa en el commit de Git, así que conviene que el proyecto sea un repositorio (git init y un primer commit).
Paso 5: Desarrollar con skaffold dev
skaffold dev construye la imagen, la despliega, muestra los logs de los pods y vigila el directorio. Cuando detecta cambios, sincroniza o reconstruye según corresponda. Al pulsar Ctrl+C elimina lo que ha desplegado.
skaffold dev --port-forward
Generating tags...
- hola-skaffold -> hola-skaffold:3f2c1ab
Building [hola-skaffold]...
Loading images into kind cluster nodes...
Starting deploy...
- deployment.apps/hola-skaffold created
- service/hola-skaffold created
Waiting for deployments to stabilize...
- deployment/hola-skaffold is ready.
Port forwarding service/hola-skaffold in namespace default, remote port 80 -> http://127.0.0.1:8080
Watching for changes...
En otra terminal, comprueba la respuesta:
curl http://127.0.0.1:8080
Hola desde Skaffold
Ahora edita app.py y cambia el texto a Hola de nuevo. En la terminal de Skaffold verás Syncing 1 files for hola-skaffold en lugar de un build completo, y Flask recargará la aplicación en uno o dos segundos:
curl http://127.0.0.1:8080
Hola de nuevo
Si en cambio modificas el Dockerfile, Skaffold reconstruye la imagen y vuelve a desplegar, porque ese archivo no está cubierto por la regla de sincronización.
Paso 6: Añadir perfiles para otros entornos
Los perfiles modifican partes de skaffold.yaml según el entorno. Añade al final del archivo un perfil ci que publica la imagen en un registro y comprueba el estado del despliegue con un límite de tiempo:
nano skaffold.yaml
profiles:
- name: ci
build:
artifacts:
- image: hola-skaffold
docker:
dockerfile: Dockerfile
local:
push: true
deploy:
kubectl: {}
statusCheckDeadlineSeconds: 180
Las listas de un perfil sustituyen por completo a las de la configuración principal, por eso el perfil vuelve a declarar el artefacto, esta vez sin sync, que no tiene sentido en CI. Comprueba que el perfil se resuelve correctamente:
skaffold diagnose -p ci
Un perfil también puede activarse solo con un contexto o un comando concretos mediante activation, por ejemplo para usar siempre el perfil ci al apuntar al clúster de staging:
activation:
- kubeContext: staging
Paso 7: Desplegar desde CI/CD
En un pipeline no quieres el modo de vigilancia, sino un build y un deploy únicos. Inicia sesión en tu registro y usa skaffold run con el perfil ci. La opción --default-repo antepone el registro al nombre de la imagen y --tag fija la etiqueta al commit:
docker login registry.example.com
skaffold run -p ci \
--default-repo registry.example.com/your_team \
--tag "$(git rev-parse --short HEAD)"
Sustituye registry.example.com/your_team por la ruta de tu registro. El clúster de destino es el contexto actual de kubectl, así que el job de CI debe tener un kubeconfig con permisos sobre el namespace.
Si prefieres separar el build del despliegue (por ejemplo, construir una vez y promocionar la misma imagen entre entornos), Skaffold puede guardar el resultado del build en un archivo y reutilizarlo:
skaffold build -p ci --default-repo registry.example.com/your_team --file-output=build.json
skaffold deploy -p ci --build-artifacts=build.json
Para borrar lo desplegado por skaffold run:
skaffold delete -p ci
Solución de problemas
ErrImagePull o ImagePullBackOff en un clúster remoto: con push: false la imagen solo existe en tu Docker local. En clústeres que no son kind, k3d ni minikube necesitas push: true, --default-repo y, si el registro es privado, un imagePullSecret.
Los cambios no se sincronizan: ejecuta skaffold dev -v debug y busca líneas con sync. El patrón de src es relativo al contexto del artefacto y dest es relativo al WORKDIR del contenedor.
Build lento o que reutiliza una capa antigua: desactiva la caché de artefactos de Skaffold con skaffold dev --cache-artifacts=false.
Ver la configuración efectiva tras aplicar perfiles: skaffold diagnose --yaml-only -p ci imprime el skaffold.yaml resultante.
Conclusión
Has instalado Skaffold, creado un flujo de desarrollo en el que los cambios de código llegan al pod en segundos sin reconstruir la imagen, y un perfil para construir, publicar y desplegar desde CI/CD. Como siguientes pasos, puedes sustituir rawYaml por kustomize o helm para gestionar varios entornos, usar skaffold debug para conectar un depurador a los pods, o comparar este flujo con Tilt si trabajas con muchos microservicios a la vez.
