— Nube y DevOps
Multinube, contenedores, entrega
La nube es una capa de commodity que ensamblo — no un proveedor al que estoy atado.
Despliego en GCP, Azure y AWS, con runtimes de edge y backends gestionados, eligiendo el servicio más fuerte para cada rol y orquestando entre proveedores. Contenedores, CI/CD e infraestructura como código están en el centro; Linux corre por debajo a nivel de administrador.
No elijo una nube y doblego cada problema hacia ella. Elijo el servicio más fuerte para cada rol y orquesto entre proveedores.
Multinube, para mí, no es una palabra de moda — es una negativa deliberada a dejar que un proveedor posea la arquitectura. GCP, Azure y AWS cada uno hace algunas cosas mejor que los otros, y los runtimes de edge y los backends gestionados cubren roles que ninguno de los tres grandes cubre limpiamente. El trabajo es elegir bien por rol y mantener todo portátil.
Lo que lo hace posible es la capa de debajo: contenedores e infraestructura como código en el centro, para que una carga definida una vez pueda apuntar a cualquier proveedor en el que ya viva un proyecto. La nube se convierte en un commodity que puedo intercambiar, en lugar de una dependencia alrededor de la que tengo que planificar.
Y bajo el orquestador sigue habiendo un host. Opero Linux a nivel de administrador — ajuste del kernel, endurecimiento con sysctl, systemd, runtimes de contenedores y la red bajo los servicios — porque las partes que la mayoría hereda como valores por defecto son las partes que preferiría operar de forma deliberada.
nubes principales en las que despliego — GCP, Azure y AWS — elegidas por rol, no por costumbre
proveedores de los que dejo depender a la arquitectura; la nube es una capa de commodity que puedo intercambiar
runtimes de edge que ejecuto en la frontera de la red — Cloudflare Workers y Vercel Edge
backends de base de datos gestionados que mantengo listos — Supabase, Firebase, PlanetScale, Neon
Una aplicación, tres nubes, sin lock-in.
Una carga que mantengo portátil: contenedores e infraestructura como código en el centro, desplegables al proveedor en el que ya corra un proyecto. Cada proveedor se conecta para el rol que hace mejor, y el edge se sitúa al frente de todos ellos.
Selección de servicios — la herramienta más fuerte por rol
- Entrenamiento y serving de modelos
- Vertex AI (GCP)
- Consultas analíticas a escala
- BigQuery (GCP)
- Bus de eventos / difusión
- Pub/Sub (GCP) · SQS/SNS (AWS)
- Contenedores con escalado a cero
- Cloud Run (GCP) · Container Apps (Azure)
- Kubernetes completo
- GKE · AKS · EKS
- Funciones dirigidas por eventos
- Cloud Functions · Azure Functions · Lambda
- Almacenamiento de objetos
- Cloud Storage (GCP) · S3 (AWS)
- Base de datos relacional
- RDS (AWS) · Neon · PlanetScale
- Cómputo en el edge
- Cloudflare Workers · Vercel Edge
- CDN
- CloudFront (AWS)
Para cada rol elijo el proveedor que lo hace mejor, y luego orquesto entre ellos — la nube debería ser un commodity que puedo intercambiar, nunca una dependencia que posee el producto.
Para qué sirve realmente cada nube.
Las cuatro pestañas de abajo no son un ranking. Cada una es un conjunto de roles que un proveedor dado hace bien, y la disciplina es emparejar una carga con el que encaja en lugar de forzar todo sobre una sola cuenta. GCP para datos y modelos, Azure dentro del ecosistema de Microsoft, AWS como el estándar amplio, y el edge y los backends gestionados para la vía rápida.
Google Cloud — donde suele vivir el trabajo de datos y modelos
En GCP coloco las cargas de trabajo que tocan datos y modelos. Vertex AI para entrenamiento y serving, BigQuery para consultas analíticas sobre tablas grandes, y Pub/Sub como bus de mensajes cuando los servicios necesitan difundir eventos sin conocerse entre sí.
Para cómputo recurro a Cloud Run cuando un contenedor debe escalar a cero entre peticiones, Cloud Functions para pequeños manejadores dirigidos por eventos, y GKE cuando una carga necesita toda la superficie de Kubernetes. Firestore y Cloud Storage cubren el estado de documentos y los objetos.
- Vertex AI para entrenamiento y serving de modelos
- Cloud Run · Cloud Functions · GKE para cómputo en todo el espectro de escalado
- Pub/Sub · BigQuery · Firestore · Cloud Storage para mensajería, analítica, estado y objetos
Azure — cuando un proyecto ya vive en el ecosistema de Microsoft
Cuando un cliente ya opera sobre identidad y herramientas de Microsoft, pelear contra eso es esfuerzo desperdiciado. Azure Kubernetes Service ofrece el mismo contrato de Kubernetes que uso en otros lados, así que una carga definida como contenedores y manifiestos se traslada con pocos cambios.
Azure Functions cubre el cómputo dirigido por eventos, Container Apps gestiona el caso de contenedor con escalado a cero, y Cognitive Services es una vía pragmática hacia visión, voz y lenguaje cuando construir el modelo en casa no es el objetivo del proyecto.
- AKS para Kubernetes gestionado dentro del ecosistema de Microsoft
- Functions y Container Apps para cómputo por eventos y escalado a cero
- Cognitive Services para visión, voz y lenguaje como capacidad gestionada
AWS — el estándar amplio con el catálogo de servicios más profundo
AWS es el estándar amplio: cuando un equipo ya está ahí, o cuando un servicio gestionado específico es la respuesta más limpia, despliego directamente en él. Lambda para funciones dirigidas por eventos, ECS o EKS para contenedores según cuánto Kubernetes quiera administrar el equipo.
S3 para almacenamiento de objetos duradero, RDS para bases de datos relacionales gestionadas, y SQS y SNS para colas y pub/sub. CloudFront se sitúa al frente como CDN. Los mismos contenedores e infraestructura como código que apuntan a GCP también apuntan aquí.
- Lambda para funciones · ECS / EKS para contenedores
- S3 · RDS para almacenamiento de objetos y relacional
- SQS · SNS para colas y pub/sub · CloudFront en el edge
Runtimes de edge y backends gestionados — la vía rápida
En la frontera de la red ejecuto Cloudflare Workers y Vercel Edge: código que corre cerca del usuario, con arranques en frío medidos en milisegundos, para enrutamiento, verificaciones de autenticación y transformaciones ligeras antes de que una petición llegue siquiera a una región.
Para productos que necesitan moverse rápido, un backend gestionado se gana su lugar. Supabase y Firebase dan autenticación, almacenamiento y una base de datos sin levantar servidores; PlanetScale y Neon dan SQL gestionado y ramificable. Los elijo cuando la velocidad hacia un producto funcional importa más que poseer la infraestructura.
- Cloudflare Workers y Vercel Edge en la frontera
- Supabase y Firebase como backends gestionados completos
- PlanetScale y Neon para SQL gestionado y ramificable
La unidad de despliegue es la misma donde sea que aterrice.
Docker · Kubernetes · seguridad de contenedores
Una imagen inmutable, planificada por Kubernetes, idéntica en todos los proveedores.
Todo se envía como contenedor. Una carga se empaqueta como una imagen Docker inmutable, construida una vez, y esa imagen exacta es la que corre en cada entorno — no hay recompilación que pudiera diferir silenciosamente entre staging y producción.
Kubernetes la planifica de la misma forma ya sea que el clúster sea GKE, AKS o EKS, así que la carga es portátil por construcción. La seguridad está integrada en la imagen en lugar de añadida después: imágenes base mínimas, usuarios sin root, sistemas de archivos de solo lectura, capacidades de Linux descartadas, y un escaneo antes de subir nada.
- Una imagen inmutable, construida una vez, ejecutada en todas partes
- Planificada de forma idéntica en GKE, AKS o EKS
- Imágenes base mínimas, sin root, solo lectura, capacidades descartadas
- Escaneada antes de llegar a un registro
Carga de Kubernetes — forma de operación
- Orquestador
- Kubernetes — GKE, AKS o EKS
- Unidad de despliegue
- Imagen de contenedor inmutable, build único
- Escalado
- Autoescalado horizontal de pods por métricas
- Config y secretos
- ConfigMaps y Secrets, montados en tiempo de ejecución
- Ingress
- Balanceador de carga gestionado · CDN al frente
- Despliegue
- Rolling, canary o blue-green
- Origen de imagen
- Registro con etiquetas inmutables y firmadas
La imagen se construye una vez y se promueve sin cambios.
Un pipeline que trato como infraestructura no negociable. A partir de un commit, la imagen se construye y prueba una vez, se escanea, se sube con una etiqueta inmutable, y se promueve a través de cada puerta — para que lo que corre en producción sea byte a byte lo que pasó las pruebas.
Del commit a producción — GitHub Actions / GitLab CI
- 01 Commit Un push al repositorio es el único disparador; nada se construye a mano.
- 02 Build + test GitHub Actions o GitLab CI construye la imagen del contenedor una vez y corre la suite de pruebas contra ella.
- 03 Escaneo Se escanea la imagen en busca de vulnerabilidades conocidas y se revisa el árbol de dependencias antes de poder avanzar.
- 04 Push La imagen firmada se sube a un registro con una etiqueta inmutable — nunca se sobrescribe.
- 05 Aplicar IaC La infraestructura como código planifica el cambio, muestra el diff y luego lo aplica para que el entorno coincida con el repositorio.
- 06 Promoción La misma imagen se despliega tras un conmutador canary o blue-green, con la versión anterior a un comando de distancia.
El pipeline, como archivo.
Un flujo de GitHub Actions recortado — construir la imagen una vez, probarla, escanearla, luego subirla con una etiqueta inmutable. La misma imagen se promueve después a cada entorno; nada se recompila aguas abajo.
name: build-and-deploy
on:
push:
branches: [ main ]
jobs:
ship:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
env:
IMAGE: ghcr.io/${{ github.repository }}:${{ github.sha }}
steps:
- uses: actions/checkout@v4
- name: Build image (once)
run: docker build -t "$IMAGE" .
- name: Test
run: docker run --rm "$IMAGE" go test ./...
- name: Scan for vulnerabilities
run: trivy image --exit-code 1 --severity HIGH,CRITICAL "$IMAGE"
- name: Push immutable tag
run: |
echo "${{ secrets.REGISTRY_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
docker push "$IMAGE" La imagen, definida tal como se envía.
Un Dockerfile multietapa — compilar en una imagen de build completa, luego copiar solo el binario a un runtime mínimo que corre como usuario sin root. Superficie pequeña, nada en la imagen que el programa no necesite.
# --- build stage: full toolchain, thrown away after compile ---
FROM golang:1.22 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -o /out/app ./cmd/app
# --- runtime stage: minimal, non-root, only the binary ---
FROM gcr.io/distroless/static:nonroot
COPY --from=build /out/app /app
USER nonroot:nonroot
EXPOSE 8080
ENTRYPOINT ["/app"] Declarada, planificada, revisada, aplicada.
El entorno vive en el repositorio
Nadie hace clic para que producción exista.
Cada pieza de infraestructura — redes, clústeres, colas, bases de datos — se declara como código y vive en control de versiones junto a la aplicación. Un cambio se propone como un diff, se planifica como una ejecución en seco, se revisa como cualquier otro código, y luego se aplica.
El punto es que el repositorio es la única fuente de verdad. Una replanificación periódica detecta cualquier deriva manual, de modo que el entorno en vivo siempre se reconcilia con lo que el código dice que debería ser. Un entorno se vuelve reproducible en lugar de ser el producto de clics recordados en una consola.
- Redes, clústeres, colas y bases de datos como código
- El plan muestra el diff antes de que algo cambie
- Revisado como código, no clicado en una consola
- Las verificaciones de deriva mantienen al repositorio como autoridad
Infraestructura como código — de declarar a reconciliar
- 01 Escribir La infraestructura se declara como código — redes, clústeres, colas, bases de datos — en control de versiones junto a la aplicación.
- 02 Planificar Una ejecución en seco calcula el diff entre el estado declarado y el estado en vivo, de modo que cada cambio es visible antes de ocurrir.
- 03 Revisar El plan se revisa como cualquier otro cambio de código; nadie hace clic en una consola para mutar producción.
- 04 Aplicar El plan se aplica; el entorno en vivo coincide ahora exactamente con el repositorio.
- 05 Verificar deriva Replanificaciones periódicas detectan cambios manuales, de modo que el estado declarado sigue siendo la única fuente de verdad.
Linux a nivel de administrador.
Por encima del orquestador hay Kubernetes; por debajo sigue habiendo un host Linux, y esa es una capa que opero de forma deliberada en lugar de heredar.
Los contenedores no eliminan el sistema operativo — se asientan sobre él. Opero Linux a nivel de administrador: ajuste del kernel para la carga, endurecimiento con sysctl para apretar la superficie del kernel en ejecución, systemd para definir servicios con políticas de reinicio y límites de recursos, los propios runtimes de contenedores, y la red que transporta cada paquete desde el edge hasta un pod.
Este es el mismo instinto que recorre el resto de mi trabajo. Las partes que la mayoría acepta como valores por defecto — los parámetros del kernel, las reglas de firewall, la imagen base a partir de la que se construye un contenedor — son las partes que preferiría entender y fijar a propósito, porque ahí es donde la fiabilidad y la seguridad nacen silenciosamente.
Ajuste del kernel
Ajustar los parámetros del kernel para la carga de trabajo — límites de descriptores de archivo, búferes de red, comportamiento del planificador — en lugar de aceptar los valores por defecto de la distribución.
Endurecimiento con sysctl
Endurecer la superficie del kernel en ejecución mediante sysctl: ajustes de la pila de red, protecciones del espacio de direcciones y desactivar lo que un servidor no tiene motivo de exponer.
systemd
Servicios definidos como unidades systemd con políticas de reinicio, límites de recursos y orden de dependencias, para que el host se comporte de forma predecible entre reinicios.
Runtimes de contenedores
Trabajar a nivel del runtime — Docker y la capa OCI debajo — incluyendo namespaces, cgroups y los internos de la imagen, no solo los comandos de alto nivel.
Redes
La red bajo los servicios: enrutamiento, reglas de firewall, DNS, terminación TLS y la ruta que toma un paquete desde el edge hasta un pod.
Seguridad de contenedores
Imágenes base mínimas, usuarios sin root, sistemas de archivos de solo lectura, capacidades descartadas y escaneo de imágenes — reduciendo lo que un contenedor comprometido puede alcanzar.
Un sistema en el que no puedes ver es uno que no puedes operar.
Una vez que una carga está repartida entre funciones, contenedores y colas en más de un proveedor, no puedes operarla por intuición. La observabilidad es la parte que convierte un sistema distribuido de vuelta en algo sobre lo que puedes razonar — métricas para tendencias, logs para detalle, trazas para la ruta que tomó una petición, y alertas que avisan ante síntomas que un usuario realmente sentiría.
Trato la pila de observabilidad como parte del build, no como algo añadido después del primer incidente. Las cuatro pestañas de abajo son las capas que instrumento, y el orden importa: una métrica apunta al problema, una traza lo estrecha a un salto, y los logs explican qué pasó en esa petición exacta.
Números a lo largo del tiempo, para que las tendencias se vean antes de convertirse en incidentes
Las métricas son la señal barata y siempre activa: tasas de petición, tasas de error, percentiles de latencia, saturación de recursos. Son lo que lee un autoescalador y lo que dispara una alerta, porque son numéricas y continuas.
Instrumento las cosas que se corresponden con una experiencia de usuario — la latencia que una petición realmente experimenta, la tasa de error que un cliente realmente sufre — en lugar de solo contadores a nivel de host que parecen sanos mientras el producto está fallando.
- Tasa de peticiones, tasa de error, percentiles de latencia
- Saturación de recursos que impulsa el autoescalado
- Señales ligadas a la experiencia de usuario, no solo contadores de host
El detalle al que recurres una vez que una métrica te ha dicho dónde mirar
Los logs son estructurados y centralizados para que una sola petición pueda seguirse a través de los servicios que tocó. Una métrica me dice que algo está mal; los logs me dicen qué, en cuál petición, con qué entrada.
Los campos estructurados importan más que el texto libre — un log que puedes consultar y agregar vale mucho más que uno que solo puedes leer línea por línea durante un incidente.
- Estructurados, consultables, centralizados
- Una sola petición rastreable entre servicios
- Campos consultables por encima de líneas de texto libre
La forma de una petición conforme cruza fronteras de servicio
El trazado distribuido sigue una petición a través de cada salto — gateway, servicio, base de datos, cola — y muestra a dónde se fue realmente el tiempo. En un sistema repartido entre funciones, contenedores y colas, esta es la única respuesta honesta a dónde está lento.
Una traza convierte un vago se siente lento en un span específico que posee la mayor parte de la latencia, que es la diferencia entre adivinar y arreglar.
- Una petición seguida a través de cada salto
- Latencia atribuida al span que la posee
- La respuesta honesta a dónde se fue el tiempo
Avisos ligados a síntomas que un usuario sentiría, no al ruido
Las alertas se disparan ante síntomas — tasa de error elevada, latencia más allá de un umbral, un recurso que se satura — no ante cada parpadeo transitorio. Una alerta que avisa a alguien a las 3 a. m. tiene que corresponder a algo que un usuario realmente notaría.
El objetivo es un número pequeño de alertas de alta señal. Demasiados avisos de baja señal entrenan a la gente a ignorarlos, lo cual es peor que no tener ninguno.
- Basadas en síntomas, ligadas a impacto visible para el usuario
- Alta señal por encima de alto volumen
- Umbrales elegidos para que un aviso signifique algo
Del kernel a la nube, una sola pila.
Host, contenedor, pipeline, nube — leído de abajo arriba, el trabajo es una pila continua en lugar de cuatro preocupaciones separadas.
Cada capa descansa sobre la de debajo. Un host Linux endurecido carga un runtime de contenedores; una imagen inmutable corre en Kubernetes; un pipeline de CI/CD y la infraestructura como código hacen todo reproducible; y un despliegue multinube lo distribuye sin atarse a un solo proveedor.
Separadas, parecen especialidades distintas. Operadas juntas, son una sola disciplina: deliberada en cada capa, portátil entre proveedores, y reproducible desde un repositorio en lugar de desde la memoria.
- Host Linux a nivel de administrador Ajuste del kernel, endurecimiento con sysctl, unidades systemd, runtimes de contenedores y la red por debajo — la capa que la mayoría hereda, operada de forma deliberada.
- Contenedor Docker y Kubernetes Cargas empaquetadas como imágenes de contenedor inmutables y ejecutadas en Kubernetes — GKE, AKS o EKS — para que la unidad de despliegue sea la misma donde sea que aterrice.
- Pipeline CI/CD e infraestructura como código GitHub Actions y GitLab CI construyen y promueven la imagen; la infraestructura declarada como código hace todo el entorno reproducible en lugar de construido a mano.
- Nube Multinube, por rol GCP, Azure y AWS — más runtimes de edge y backends gestionados — seleccionados por rol y orquestados juntos, sin que ningún proveedor único posea la arquitectura.
Los principios bajo la plataforma.
Los proveedores y las herramientas cambian con el proyecto; los principios no. Estas son las reglas que aplico ya sea que el objetivo sea GCP, Azure, AWS, el edge o un backend gestionado — la parte que hace la plataforma reproducible en lugar de incidental.
Elegir el servicio más fuerte por rol
Para cada rol — serving de modelos, el bus de eventos, la base de datos, el edge — elijo el proveedor que lo hace mejor, y luego orquesto entre ellos. El resultado es un sistema ensamblado con las piezas correctas, no con las convenientes.
Nunca depender de una sola nube
Los contenedores y la infraestructura como código están en el centro para que la misma carga pueda apuntar a GCP, Azure o AWS. La nube es un commodity que puedo intercambiar, no una dependencia que posee el producto.
Construir la imagen una vez, promoverla sin cambios
Una imagen se construye una sola vez y se mueve a través de cada puerta hacia producción byte a byte. Lo que corre en producción es exactamente lo que pasó las pruebas, no una recompilación que podría diferir.
Declarar la infraestructura, nunca hacer clic en ella
Redes, clústeres, colas y bases de datos se declaran como código, se planifican, se revisan y se aplican. Nadie muta producción en una consola, así que el repositorio sigue siendo la única fuente de verdad.
Endurecer el host por debajo
Operar Linux a nivel de administrador — ajuste del kernel, endurecimiento con sysctl, systemd, runtimes de contenedores, redes — significa que la capa bajo el orquestador es deliberada, no dejada en sus valores por defecto.
Hacer el sistema observable
Métricas, logs y trazas son parte del build, no algo añadido después de un incidente. Un sistema en el que no puedes ver es un sistema que no puedes operar.
Elegir el servicio más fuerte por rol, mantener la carga portátil con contenedores y código, construir la imagen una vez, y endurecer el host por debajo — todo lo demás es detalle.
Open to the right work
Si necesitas una plataforma que corra entre nubes sin pertenecer a ninguna de ellas, ese es el trabajo que hago.
If you are holding a problem that doesn't fit inside one field, that is the conversation I want.