--- title: "Patrones de diseño de una plataforma interna de desarrollo" description: "Patrones para diseñar una plataforma interna de desarrollo (IDP): golden paths, plantillas de servicio, alta de equipos por GitOps, observabilidad y métricas." category: "Ingeniería de Plataformas" language: es source: https://cubepath.com/es/docs/ingeniería-de-plataformas/patrones-de-diseno-de-plataforma-interna updated: 2026-09-25 --- # Patrones de diseño de una plataforma interna de desarrollo Una plataforma interna de desarrollo (IDP, Internal Developer Platform) es el conjunto de herramientas, plantillas y automatizaciones que un equipo de plataforma ofrece al resto de ingenieros para crear, desplegar y operar servicios sin abrir tickets. Esta guía explica los patrones de diseño que funcionan en la práctica, con ejemplos concretos sobre Kubernetes que puedes probar: un golden path basado en plantillas, el onboarding de equipos mediante GitOps y la forma de medir si la plataforma se usa. ## Requisitos previos Esta guía es conceptual, pero los ejemplos son ejecutables. Para probarlos necesitas: - Un clúster de Kubernetes con permisos de administrador, por ejemplo k3s en un VPS de CubePath o kind en tu equipo. - `kubectl` instalado en Ubuntu 24.04 LTS o similar. - Opcionalmente, `pipx` para instalar Cookiecutter y una instancia de Backstage si quieres probar su plantilla. ## Qué es y qué no es una plataforma interna Una IDP no es un producto que se instala: es una capa de abstracción que el equipo de plataforma construye combinando herramientas existentes. Los principios que separan una plataforma útil de un conjunto de scripts son: - **Autoservicio**: un desarrollador obtiene un namespace, un repositorio o una base de datos sin esperar a otra persona. - **Golden paths**: existe una forma recomendada de hacer cada cosa, y es también la más fácil. No es obligatoria, pero salirse de ella tiene un coste visible. - **Abstracciones finas**: se ocultan los detalles repetitivos (etiquetas, cuotas, observabilidad), no Kubernetes entero. Los equipos deben poder mirar debajo cuando lo necesiten. - **Plataforma como producto**: tiene usuarios, un roadmap, documentación y métricas de adopción, igual que cualquier producto. ## Capas de una IDP y herramientas habituales La mayoría de las plataformas se organizan en las mismas capas. No hace falta cubrirlas todas desde el principio: | Capa | Función | Herramientas habituales | |---|---|---| | Portal | Catálogo de servicios, documentación, plantillas | Backstage, Port | | Plantillas | Crear servicios nuevos con la estructura estándar | Backstage Software Templates, Cookiecutter | | Entrega | Construir y desplegar a partir de Git | GitHub Actions, GitLab CI, Argo CD, Flux | | Configuración | Manifiestos por entorno sin duplicar YAML | Kustomize, Helm | | Infraestructura | Bases de datos, colas, buckets bajo demanda | Terraform/OpenTofu, Crossplane | | Guardarraíles | Cuotas, políticas y permisos por equipo | ResourceQuota, LimitRange, RBAC, Kyverno | | Observabilidad | Métricas, logs y trazas incluidos por defecto | Prometheus, Grafana, Loki, OpenTelemetry | Un error frecuente es empezar por el portal. Un portal sin golden paths detrás es solo una página de enlaces. Empieza por automatizar lo que más tickets genera hoy (normalmente, crear un servicio nuevo y dar acceso a un entorno) y añade el portal cuando haya algo que mostrar. ## Patrón 1: golden path con plantillas de servicio El golden path para un servicio nuevo produce, en un solo paso, un repositorio con código base, Dockerfile, pipeline, manifiestos y la configuración de observabilidad. La herramienta más sencilla para empezar es Cookiecutter, que genera un proyecto a partir de una plantilla con variables. En Ubuntu 24.04, instala Cookiecutter con `pipx` (instalar paquetes con `pip` fuera de un entorno virtual está bloqueado por PEP 668): ```bash sudo apt update sudo apt install pipx pipx ensurepath pipx install cookiecutter ``` Crea la plantilla. Las variables se definen en `cookiecutter.json` y el directorio del proyecto usa una de ellas como nombre: ```bash mkdir -p ~/plantilla-servicio/'{{cookiecutter.nombre_servicio}}'/k8s nano ~/plantilla-servicio/cookiecutter.json ``` ```json { "nombre_servicio": "mi-servicio", "equipo": "equipo-backend", "puerto": "8080" } ``` Añade un manifiesto que ya incluye las etiquetas y anotaciones que la plataforma necesita (propietario, métricas, versión del golden path): ```bash nano ~/plantilla-servicio/'{{cookiecutter.nombre_servicio}}'/k8s/deployment.yaml ``` ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: {{ cookiecutter.nombre_servicio }} labels: app.kubernetes.io/name: {{ cookiecutter.nombre_servicio }} app.kubernetes.io/part-of: {{ cookiecutter.equipo }} plataforma.example.com/golden-path: v1 spec: replicas: 2 selector: matchLabels: app.kubernetes.io/name: {{ cookiecutter.nombre_servicio }} template: metadata: labels: app.kubernetes.io/name: {{ cookiecutter.nombre_servicio }} spec: containers: - name: app image: registry.example.com/{{ cookiecutter.nombre_servicio }}:latest ports: - name: http containerPort: {{ cookiecutter.puerto }} readinessProbe: httpGet: path: /healthz port: http resources: requests: cpu: 100m memory: 128Mi limits: memory: 256Mi ``` Genera un servicio a partir de la plantilla sin preguntas interactivas: ```bash cd ~ cookiecutter --no-input ~/plantilla-servicio nombre_servicio=pagos equipo=equipo-pagos head -n 8 pagos/k8s/deployment.yaml ``` ```output apiVersion: apps/v1 kind: Deployment metadata: name: pagos labels: app.kubernetes.io/name: pagos app.kubernetes.io/part-of: equipo-pagos plataforma.example.com/golden-path: v1 ``` La etiqueta `plataforma.example.com/golden-path` es importante: permite medir más adelante cuántos servicios usan la plantilla y en qué versión. ### El mismo golden path en Backstage Cuando la plataforma crece, las plantillas suelen pasar al Scaffolder de Backstage, que añade un formulario web, crea el repositorio y registra el servicio en el catálogo. Una plantilla mínima tiene esta forma: ```yaml apiVersion: scaffolder.backstage.io/v1beta3 kind: Template metadata: name: servicio-python title: Servicio Python estándar description: Crea un servicio con Dockerfile, pipeline de CI y manifiestos de Kubernetes. spec: owner: group:equipo-plataforma type: service parameters: - title: Datos del servicio required: - nombre - propietario properties: nombre: title: Nombre type: string pattern: '^[a-z][a-z0-9-]*$' propietario: title: Equipo propietario type: string ui:field: OwnerPicker ui:options: catalogFilter: kind: Group steps: - id: plantilla name: Generar código action: fetch:template input: url: ./skeleton values: nombre: ${{ parameters.nombre }} propietario: ${{ parameters.propietario }} - id: publicar name: Crear repositorio action: publish:github input: repoUrl: github.com?owner=your_org&repo=${{ parameters.nombre }} description: Servicio ${{ parameters.nombre }} - id: registrar name: Registrar en el catálogo action: catalog:register input: repoContentsUrl: ${{ steps['publicar'].output.repoContentsUrl }} catalogInfoPath: /catalog-info.yaml output: links: - title: Repositorio url: ${{ steps['publicar'].output.remoteUrl }} ``` El directorio `skeleton/` contiene los mismos archivos que la plantilla de Cookiecutter, con la sintaxis `${{ values.nombre }}` y un `catalog-info.yaml` que declara el propietario del servicio. ## Patrón 2: onboarding de equipos por GitOps El segundo ticket más habitual es "necesito un entorno". En lugar de un script que crea namespaces a mano, define cada equipo como un directorio en un repositorio de plataforma y deja que Argo CD o Flux lo aplique. Los guardarraíles (cuotas, límites por defecto y permisos) forman parte de la definición. Crea una base común para todos los equipos: ```bash mkdir -p ~/plataforma/equipos/base ~/plataforma/equipos/equipo-pagos nano ~/plataforma/equipos/base/equipo.yaml ``` ```yaml apiVersion: v1 kind: Namespace metadata: name: equipo --- apiVersion: v1 kind: ResourceQuota metadata: name: cuota namespace: equipo spec: hard: requests.cpu: "4" requests.memory: 8Gi limits.memory: 16Gi pods: "50" --- apiVersion: v1 kind: LimitRange metadata: name: limites-por-defecto namespace: equipo spec: limits: - type: Container defaultRequest: cpu: 100m memory: 128Mi default: memory: 256Mi --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: desarrolladores namespace: equipo roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: edit subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: equipo ``` ```bash nano ~/plataforma/equipos/base/kustomization.yaml ``` ```yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - equipo.yaml ``` Cada equipo es un overlay de pocas líneas que fija el namespace, el grupo con permisos y, si lo necesita, una cuota distinta: ```bash nano ~/plataforma/equipos/equipo-pagos/kustomization.yaml ``` ```yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ../base namespace: equipo-pagos patches: - target: kind: Namespace patch: |- - op: replace path: /metadata/name value: equipo-pagos - target: kind: RoleBinding patch: |- - op: replace path: /subjects/0/name value: equipo-pagos - target: kind: ResourceQuota patch: |- - op: replace path: /spec/hard/requests.cpu value: "8" ``` Aplica el overlay (en producción lo haría Argo CD al detectar el commit) y comprueba el resultado: ```bash kubectl apply -k ~/plataforma/equipos/equipo-pagos kubectl describe resourcequota cuota -n equipo-pagos ``` ```output Name: cuota Namespace: equipo-pagos Resource Used Hard -------- ---- ---- limits.memory 0 16Gi pods 0 50 requests.cpu 0 8 requests.memory 0 8Gi ``` Verifica que un miembro del grupo puede desplegar en su namespace pero no en otros: ```bash kubectl auth can-i create deployments -n equipo-pagos --as=ana --as-group=equipo-pagos kubectl auth can-i create deployments -n kube-system --as=ana --as-group=equipo-pagos ``` ```output yes no ``` Dar de alta un equipo nuevo pasa a ser una pull request de tres líneas que el equipo de plataforma revisa y fusiona. El historial de Git sirve además como registro de auditoría. ## Patrón 3: observabilidad incluida por defecto Si cada equipo tiene que configurar sus métricas, la mitad no lo hará. El golden path debe incluir la integración. Con Prometheus Operator (por ejemplo, instalado con el chart `kube-prometheus-stack`), añade a la plantilla un `ServiceMonitor` que recoge las métricas del puerto llamado `metrics` del Service de cada servicio generado (la plantilla debe incluir ese puerto en el Deployment y en el Service): ```yaml apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: {{ cookiecutter.nombre_servicio }} labels: release: kube-prometheus-stack spec: selector: matchLabels: app.kubernetes.io/name: {{ cookiecutter.nombre_servicio }} endpoints: - port: metrics path: /metrics interval: 30s ``` La etiqueta `release` debe coincidir con el `serviceMonitorSelector` de tu instalación de Prometheus. Complementa esto con un dashboard de Grafana común que filtre por la etiqueta `app.kubernetes.io/name`, de modo que cada servicio nuevo tenga paneles de peticiones, errores y latencia desde el primer despliegue. ## Patrón 4: medir la plataforma Tratar la plataforma como producto implica medirla. Tres indicadores sencillos: - **Adopción del golden path**: proporción de workloads con la etiqueta de la plantilla. - **Tiempo hasta el primer despliegue**: desde que se crea el repositorio hasta que el servicio responde en un entorno. Se obtiene de las fechas del sistema de CI/CD. - **Métricas DORA**: frecuencia de despliegue, tiempo de entrega, tasa de fallos en cambios y tiempo de recuperación. La adopción se puede consultar directamente en el clúster gracias a la etiqueta de la plantilla: ```bash kubectl get deployments -A -l plataforma.example.com/golden-path --no-headers | wc -l kubectl get deployments -A --no-headers | wc -l ``` El primer número son los Deployments creados desde la plantilla (en cualquier versión) y el segundo el total. Para ver qué versiones de la plantilla siguen en uso: ```bash kubectl get deployments -A -L plataforma.example.com/golden-path ``` Si la adopción no sube, pregunta a los equipos antes de añadir funcionalidades: normalmente el golden path es más lento o más rígido de lo que parece desde el equipo de plataforma. ## Por dónde empezar No todas las organizaciones necesitan todas las capas. Una guía orientativa según el tamaño: | Situación | Qué construir primero | |---|---| | Menos de 5 equipos, un clúster | Plantilla Cookiecutter, overlays de Kustomize por equipo, Argo CD | | 5 a 20 equipos | Lo anterior más Backstage con catálogo y Software Templates, observabilidad por defecto | | Más de 20 equipos o varios clústeres | Infraestructura bajo demanda con Crossplane o Terraform, políticas con Kyverno, métricas DORA automatizadas | ## Conclusión Una plataforma interna eficaz se construye por capas a partir de los problemas reales de los equipos: primero un golden path que crea servicios con todo lo necesario, después el onboarding de equipos por GitOps con cuotas y permisos, y la observabilidad incluida por defecto. Como siguientes pasos, puedes gestionar los overlays de equipos con Argo CD, añadir políticas de admisión con Kyverno para exigir las etiquetas de la plantilla, o desplegar Backstage para dar a todo ello un catálogo y un portal.