docs: READMEs completos, estructura final de arquetipos
Mueve los reusable workflows a .gitea/workflows/ (restriccion real de Gitea: workflow_call no puede vivir en una ruta arbitraria, confirmado en vivo). Corrige todos los 'uses:' cross-repo a URL absoluta (https://gitea.cruzcloud.net/...) -- la forma corta de GitHub se resuelve contra github.com en esta instancia, confirmado en vivo con un test real (reusable workflow + composite action ejecutando gitleaks de punta a punta). Limpia los archivos de prueba.
This commit is contained in:
1 parent
018d424a1c
commit
a3c022c024
11 files changed
+514
-49
No files matched your search
@@ -1 +1,205 @@
|
||||
# platform-templates
|
||||
|
||||
Patrones reutilizables para dar de alta una app nueva en el lab
|
||||
CruzCloud (ZimaOS + k3d + Gitea + Argo CD) sin escribir el pipeline y
|
||||
los manifiestos K8s desde cero cada vez. Copiás una plantilla, completás
|
||||
unos pocos valores, y tenés: pipeline de CI con el gate completo de
|
||||
DevSecOps (Gitleaks, Trivy, Semgrep, Syft, Cosign) + manifiestos K8s con
|
||||
buenas prácticas por default (resource limits, probes, non-root).
|
||||
|
||||
**Para quién es esto:** si estás dando de alta una app nueva en el lab,
|
||||
seguí el ejemplo de abajo. Si estás migrando una app existente, mirá el
|
||||
punto "Migración de apps existentes" más abajo, y andá con más cuidado
|
||||
— tocás algo que ya está en producción.
|
||||
|
||||
## Mapa del repo
|
||||
|
||||
```
|
||||
pipelines/ -- documentación de cada arquetipo de pipeline
|
||||
(el archivo real que se invoca vive en
|
||||
.gitea/workflows/, ver por qué más abajo)
|
||||
.gitea/workflows/ -- los reusable workflows reales (workflow_call)
|
||||
dockerfiles/ -- Dockerfiles genéricos, un ARG por cosa a cambiar
|
||||
k8s-manifests/base/ -- Kustomize base: Deployment+Service+Ingress
|
||||
genéricos, con securityContext/probes/resources
|
||||
ya puestos
|
||||
k8s-manifests/overlays-ejemplo/ -- el ejemplo de abajo, ya armado
|
||||
devsecops-snippets/ -- los 6 composite actions que arman cada pipeline
|
||||
```
|
||||
|
||||
## Hallazgo importante sobre Gitea Actions (leer antes de copiar nada)
|
||||
|
||||
Este repo se armó verificando en vivo, no asumiendo que Gitea Actions es
|
||||
100% igual a GitHub Actions. Dos diferencias reales, confirmadas
|
||||
corriendo pipelines de verdad contra esta instancia:
|
||||
|
||||
1. **Los reusable workflows (`workflow_call`) tienen que vivir bajo
|
||||
`.gitea/workflows/`** — no en una carpeta cualquiera. Por eso
|
||||
`pipelines/archetype-*/` solo tiene un `README.md`, el archivo
|
||||
invocable real está en `.gitea/workflows/archetype-*.yaml`.
|
||||
2. **Toda referencia cross-repo en un `uses:` necesita la URL completa**
|
||||
(`https://gitea.cruzcloud.net/owner/repo/path@ref`), no la forma
|
||||
corta de GitHub (`owner/repo/path@ref`) — esa forma corta se resuelve
|
||||
contra **github.com** por default en esta instancia (confirmado:
|
||||
intentar usarla hace que el runner intente clonar
|
||||
`github.com/devops/platform-templates`, que no existe, y falle con
|
||||
"Repository not found"). `actions/checkout@v3` sigue andando con la
|
||||
forma corta porque ESE sí existe en github.com de verdad.
|
||||
|
||||
## Ejemplo end-to-end: dar de alta "mi-app-ejemplo"
|
||||
|
||||
Pensado para seguirse sin conocer nada más del lab que "existe Gitea en
|
||||
gitea.cruzcloud.net y un cluster k3d con Argo CD sincronizando desde
|
||||
ahí". Asumimos una API Node (arquetipo `node-api`) — para Next.js o un
|
||||
sitio estático es el mismo procedimiento, cambiando el arquetipo.
|
||||
|
||||
### 1. Creá el repo de tu app en Gitea
|
||||
|
||||
Vía la UI (`https://gitea.cruzcloud.net/repo/create`) o `gh`/API si
|
||||
tenés token con el scope correcto. Nombre: `mi-app-ejemplo`.
|
||||
|
||||
### 2. Copiá el Dockerfile
|
||||
|
||||
```bash
|
||||
curl -o Dockerfile \
|
||||
https://gitea.cruzcloud.net/devops/platform-templates/raw/branch/main/dockerfiles/node-api.Dockerfile
|
||||
```
|
||||
|
||||
Ajustá los `ARG` del inicio del archivo a tu caso (puerto real, comando
|
||||
de arranque) — están documentados inline, no hace falta adivinar.
|
||||
|
||||
### 3. Agregá el pipeline
|
||||
|
||||
`.gitea/workflows/build.yaml` en tu repo:
|
||||
|
||||
```yaml
|
||||
name: Build and Push
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'src/**'
|
||||
- 'package.json'
|
||||
- 'package-lock.json'
|
||||
- 'Dockerfile'
|
||||
- '.gitea/workflows/build.yaml'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
uses: https://gitea.cruzcloud.net/devops/platform-templates/.gitea/workflows/archetype-node-api.yaml@main
|
||||
with:
|
||||
app_dir: .
|
||||
image_name: gitea.cruzcloud.net/devops/mi-app-ejemplo
|
||||
manifest_file: k8s/deployment.yaml
|
||||
secrets:
|
||||
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
|
||||
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
|
||||
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
|
||||
```
|
||||
|
||||
Los 4 secrets tienen que existir en tu repo (Settings → Actions →
|
||||
Secrets). Si tu lab ya los tiene a nivel de organización/compartidos,
|
||||
puede que no haga falta redeclararlos — depende de cómo esté armado tu
|
||||
Gitea.
|
||||
|
||||
### 4. Generá tu par de llaves de Cosign (una vez)
|
||||
|
||||
```bash
|
||||
cosign generate-key-pair
|
||||
# genera cosign.key (privada) y cosign.pub (pública)
|
||||
```
|
||||
|
||||
- `cosign.pub` → commiteala en tu repo (es pública a propósito).
|
||||
- `cosign.key` → **no la commitees**. Subila como secret
|
||||
`COSIGN_PRIVATE_KEY` (contenido del archivo) y la password que
|
||||
elegiste como secret `COSIGN_PASSWORD`.
|
||||
|
||||
### 5. Manifiestos K8s: copiá el base y armá tu overlay
|
||||
|
||||
```bash
|
||||
mkdir -p k8s/patches
|
||||
curl -o k8s/kustomization.yaml \
|
||||
https://gitea.cruzcloud.net/devops/platform-templates/raw/branch/main/k8s-manifests/overlays-ejemplo/mi-app-ejemplo/kustomization.yaml
|
||||
curl -o k8s/patches/deployment.yaml \
|
||||
https://gitea.cruzcloud.net/devops/platform-templates/raw/branch/main/k8s-manifests/overlays-ejemplo/mi-app-ejemplo/patches/deployment.yaml
|
||||
curl -o k8s/patches/service.yaml \
|
||||
https://gitea.cruzcloud.net/devops/platform-templates/raw/branch/main/k8s-manifests/overlays-ejemplo/mi-app-ejemplo/patches/service.yaml
|
||||
curl -o k8s/patches/ingress.yaml \
|
||||
https://gitea.cruzcloud.net/devops/platform-templates/raw/branch/main/k8s-manifests/overlays-ejemplo/mi-app-ejemplo/patches/ingress.yaml
|
||||
```
|
||||
|
||||
Esto ya viene armado con el patrón real (ver
|
||||
`k8s-manifests/overlays-ejemplo/mi-app-ejemplo/` en este mismo repo) —
|
||||
solo tenés que:
|
||||
|
||||
1. Cambiar `mi-app-ejemplo` por el nombre real de tu app en los 3
|
||||
`patches/*.yaml` y en el `kustomization.yaml` (nombre del
|
||||
Deployment/Service/Ingress, `host:`, `namespace:`).
|
||||
2. Ajustar imagen, puerto, y ruta del healthcheck a los reales de tu
|
||||
app.
|
||||
3. **Leer los comentarios de `patches/deployment.yaml` sobre
|
||||
`$patch: replace`/JSON6902** antes de tocar `ports` — Kustomize NO
|
||||
reemplaza esa lista con un patch de merge normal, la duplica
|
||||
(confirmado en vivo armando este repo). Si tu puerto real es
|
||||
distinto al 8080 del base, el rename+ports va en un patch JSON6902
|
||||
aparte en tu `kustomization.yaml`, exactamente como en el ejemplo.
|
||||
4. **Si tu app escucha en un puerto <1024** (80, por ejemplo): el base
|
||||
saca TODAS las capabilities del contenedor por default —
|
||||
necesitás agregar `capabilities.add: [NET_BIND_SERVICE]` en tu
|
||||
patch, o el bind falla. Ver el comentario en
|
||||
`k8s-manifests/overlays-ejemplo/mi-app-ejemplo/kustomization.yaml`
|
||||
si tu imagen corre como root en vez de un usuario propio (necesitás
|
||||
además `runAsNonRoot: false` a nivel pod).
|
||||
|
||||
### 6. Validá el resultado ANTES de commitear
|
||||
|
||||
```bash
|
||||
kubectl kustomize k8s/
|
||||
```
|
||||
|
||||
Revisá que el YAML que sale tenga sentido — nombre, imagen, puerto,
|
||||
host correctos, sin recursos duplicados. Si algo se ve raro (dos
|
||||
`ports:`, dos contenedores), revisá el punto 3 de arriba.
|
||||
|
||||
### 7. Creá la Application de Argo CD
|
||||
|
||||
Sigue el patrón de este lab: una Application de workload
|
||||
(`syncPolicy` con `prune: true, selfHeal: true`) apuntando al
|
||||
`k8s/` de tu repo. Preguntale a quien mantiene `apps-registry` cómo se
|
||||
registra — no es parte de este repo.
|
||||
|
||||
### 8. Push, mirá el pipeline correr, y listo
|
||||
|
||||
Un `git push` a `main` dispara Gitleaks → build → Trivy → Semgrep → Syft
|
||||
→ Cosign → push al registry → Argo CD sincroniza. Si algo bloquea
|
||||
(CRITICAL de Trivy, firma de Cosign inválida), el log del job te dice
|
||||
exactamente cuál.
|
||||
|
||||
## Migración de apps existentes
|
||||
|
||||
Si estás moviendo una app que **ya está corriendo en producción** hacia
|
||||
este patrón base+overlay: no es lo mismo que dar de alta una nueva.
|
||||
Antes de tocar nada:
|
||||
|
||||
1. Guardá el manifest actual desplegado (`kubectl get deploy <nombre>
|
||||
-n <ns> -o yaml`) para comparar.
|
||||
2. Armá el overlay apuntando **al mismo nombre** que ya existe (usando
|
||||
los patches JSON6902 de rename, como en el ejemplo) — no dejes que
|
||||
Kustomize invente un nombre nuevo, rompe el tracking de Argo CD y
|
||||
la resolución DNS de otros servicios que dependan del nombre viejo.
|
||||
3. **Revisá con qué usuario corre tu imagen actual.** Si no tiene un
|
||||
`USER` no-root en su Dockerfile, el `runAsNonRoot: true` del base
|
||||
rompe el pod (`CreateContainerConfigError`) — hace falta un override
|
||||
explícito hasta que la imagen se actualice aparte. Pasó exactamente
|
||||
esto migrando `docs-portal` en este mismo lab.
|
||||
4. Corré `kubectl kustomize` sobre tu overlay y compará el resultado
|
||||
contra el manifest guardado en el paso 1 antes de dejar que Argo CD
|
||||
sincronice nada.
|
||||
|
||||
## Documentación ampliada
|
||||
|
||||
`docs.cruzcloud.net` tiene una sección dedicada a este repo con un
|
||||
diagrama del flujo completo y el detalle de la migración real que se
|
||||
hizo sobre `ecommerce-frontend`, `commerce-backend` y `docs-portal`.
|
||||
Reference in new issue
Block a user