diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index ba9ee81..9592416 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -126,8 +126,13 @@ jobs: env: APP_DIR: workloads/ecommerce - MANIFEST_FILE: workloads/ecommerce/frontend/patches/deployment.yaml - KUSTOMIZE_DIR: workloads/ecommerce/frontend + # Cambio 2026-09-14: todo push a main promueve a STAGING + # automaticamente (workloads/ecommerce-staging), no a Produccion + # directo -- decision del usuario para dejar de probar cambios en + # vivo contra Prod. Promover a Produccion (workloads/ecommerce) es + # una accion manual aparte, ver scripts/promote-to-production.sh. + MANIFEST_FILE: workloads/ecommerce-staging/frontend/patches/deployment.yaml + KUSTOMIZE_DIR: workloads/ecommerce-staging/frontend IMAGE_NAME: gitea.cruzcloud.net/devops/ecommerce-frontend steps: diff --git a/apps/ecommerce-staging-app.yaml b/apps/ecommerce-staging-app.yaml new file mode 100644 index 0000000..1fe2131 --- /dev/null +++ b/apps/ecommerce-staging-app.yaml @@ -0,0 +1,26 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application + +metadata: + name: ecommerce-staging-app + namespace: argocd + +spec: + project: default + + source: + repoURL: https://gitea.cruzcloud.net/devops/apps-registry.git + targetRevision: main + path: workloads/ecommerce-staging + kustomize: {} + + destination: + server: https://kubernetes.default.svc + namespace: ecommerce-staging + + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true diff --git a/apps/ecommerce-staging-governance-app.yaml b/apps/ecommerce-staging-governance-app.yaml new file mode 100644 index 0000000..1a2a978 --- /dev/null +++ b/apps/ecommerce-staging-governance-app.yaml @@ -0,0 +1,20 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: ecommerce-staging-governance + namespace: argocd +spec: + project: default + source: + repoURL: https://gitea.cruzcloud.net/devops/platform-infra.git + path: ecommerce-staging-governance + targetRevision: main + destination: + server: https://kubernetes.default.svc + namespace: ecommerce-staging + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true diff --git a/workloads/ecommerce-staging/frontend/kustomization.yaml b/workloads/ecommerce-staging/frontend/kustomization.yaml new file mode 100644 index 0000000..937ad6f --- /dev/null +++ b/workloads/ecommerce-staging/frontend/kustomization.yaml @@ -0,0 +1,51 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: ecommerce-staging + +resources: + - https://gitea.cruzcloud.net/devops/platform-templates.git//k8s-manifests/base?ref=main + +patches: + # Mismo criterio que workloads/ecommerce/frontend/kustomization.yaml: + # sin anchors/aliases de YAML a propósito (el parser de Gitea Actions no + # los resuelve en "on:", pero acá aplica igual por consistencia con el + # resto del repo). Ingress propio via ingress-staging.yaml en vez del + # generico de 1-backend del base. + - target: + kind: Ingress + name: app-ingress + patch: |- + $patch: delete + apiVersion: networking.k8s.io/v1 + kind: Ingress + metadata: + name: app-ingress + - target: + kind: Deployment + name: app-deployment + path: patches/deployment.yaml + - target: + kind: Service + name: app-svc + path: patches/service.yaml + + - target: + kind: Deployment + name: app-deployment + patch: |- + - op: replace + path: /metadata/name + value: frontend-deploy + - op: replace + path: /spec/template/spec/containers/0/ports + value: + - name: http + containerPort: 80 + - target: + kind: Service + name: app-svc + patch: |- + - op: replace + path: /metadata/name + value: frontend-svc diff --git a/workloads/ecommerce-staging/frontend/patches/deployment.yaml b/workloads/ecommerce-staging/frontend/patches/deployment.yaml new file mode 100644 index 0000000..4e3e2d6 --- /dev/null +++ b/workloads/ecommerce-staging/frontend/patches/deployment.yaml @@ -0,0 +1,86 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: app-deployment + labels: + app: frontend +spec: + # 1 réplica (no 2 como Producción): Staging es para verificar cambios + # antes de promover, no para servir tráfico real -- alcanza, y deja más + # margen de recursos en la NAS para el resto del cluster. + replicas: 1 + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 0 + maxSurge: 1 + selector: + matchLabels: + app: frontend + template: + metadata: + labels: + app: frontend + spec: + securityContext: + runAsUser: 1001 + containers: + - name: app + image: gitea.cruzcloud.net/devops/ecommerce-frontend:v1.0.260 + env: + - name: HEADLESS_PROVIDER + value: medusa + # Backend COMPARTIDO con Producción a propósito (decisión del + # usuario 2026-09-14: armar un backend propio para Staging + # -Postgres/Medusa/Meilisearch- duplicaría el consumo de la + # NAS sin necesidad todavía). FQDN cross-namespace: "ecommerce" + # es el namespace real de medusa-svc -- el nombre corto + # "medusa-svc" solo resuelve dentro del mismo namespace. + - name: MEDUSA_BACKEND_URL + value: http://medusa-svc.ecommerce.svc.cluster.local:9000 + - name: MEDUSA_REGION_ID + value: reg_01KZT86WPAH7A7ZZRDSX3350V2 + envFrom: + - secretRef: + name: commerce-storefront + readinessProbe: + httpGet: + path: /api/health + port: http + livenessProbe: + httpGet: + path: /api/health + port: http + # Mismo securityContext que Producción -- ver comentario largo en + # workloads/ecommerce/frontend/patches/deployment.yaml (misma + # imagen, mismos motivos: runAsUser numérico por el Dockerfile + # usando "nextjs" por nombre, NET_BIND_SERVICE por el puerto 80, + # volumenes por el cache de Next.js con root filesystem de solo + # lectura). + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + add: + - NET_BIND_SERVICE + # Requests/limits mas chicos que Produccion -- una sola replica + # de verificacion, no trafico real. + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + volumeMounts: + - name: next-cache + mountPath: /app/.next/cache + - name: tmp + mountPath: /tmp + volumes: + - name: next-cache + emptyDir: {} + - name: tmp + emptyDir: {} diff --git a/workloads/ecommerce-staging/frontend/patches/service.yaml b/workloads/ecommerce-staging/frontend/patches/service.yaml new file mode 100644 index 0000000..533f611 --- /dev/null +++ b/workloads/ecommerce-staging/frontend/patches/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: app-svc +spec: + selector: + app: frontend + ports: + - name: http + port: 80 + targetPort: 80 diff --git a/workloads/ecommerce-staging/ingress-staging.yaml b/workloads/ecommerce-staging/ingress-staging.yaml new file mode 100644 index 0000000..061e63c --- /dev/null +++ b/workloads/ecommerce-staging/ingress-staging.yaml @@ -0,0 +1,19 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ecommerce-staging-ingress + annotations: + traefik.ingress.kubernetes.io/router.entrypoints: web +spec: + ingressClassName: traefik + rules: + - host: staging.cruzcloud.net + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: frontend-svc + port: + number: 80 diff --git a/workloads/ecommerce-staging/kustomization.yaml b/workloads/ecommerce-staging/kustomization.yaml new file mode 100644 index 0000000..1b5b1e8 --- /dev/null +++ b/workloads/ecommerce-staging/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: ecommerce-staging + +resources: + - frontend/ + - ingress-staging.yaml