diff --git a/.gitea/workflows/APP_NAME-build.yaml b/.gitea/workflows/APP_NAME-build.yaml index 54f26eb..d948418 100644 --- a/.gitea/workflows/APP_NAME-build.yaml +++ b/.gitea/workflows/APP_NAME-build.yaml @@ -66,8 +66,13 @@ jobs: kubectl -n apps rollout status deploy/__APP_NAME__ --timeout=3m - name: Smoke check post-deploy + # FQDN con tenant-id CON guiones — coincide con el A record que crea + # cloudflare-provisioner (Gap 5) y con el host del Ingress NGINX + # (helm/APP_NAME/values.yaml). Antes usaba TENANT_ID_NODASHES, lo + # que no resolvía al A record canónico — corregido APERTURA COVE + # Sesión 3 (TENANT-INGRESS-CONTROLLER-MISMATCH, paridad ADR-053 §11.1). env: - INGRESS_HOST: __APP_NAME__-${{ vars.TENANT_ID_NODASHES }}.apps.coralware.cloud + INGRESS_HOST: __APP_NAME__-${{ vars.TENANT_ID }}.apps.coralware.cloud run: | for i in $(seq 1 12); do if wget -q -O - --timeout=10 "https://${INGRESS_HOST}/health" | grep -q '"status":"ok"'; then diff --git a/helm/APP_NAME/Chart.yaml b/helm/APP_NAME/Chart.yaml index de72d7f..ce19645 100644 --- a/helm/APP_NAME/Chart.yaml +++ b/helm/APP_NAME/Chart.yaml @@ -1,8 +1,16 @@ apiVersion: v2 name: __APP_NAME__ +# Helm chart del Golden Path rest-api/python. +# 0.2.0 (2026-05-19): cambio Ingress controller Traefik (IngressRoute CRD) +# → rke2-ingress-nginx (networking.k8s.io/v1 Ingress). Razón: +# TENANT-INGRESS-CONTROLLER-MISMATCH (APERTURA COVE Sesión 3) — paridad +# con shape web-backend/python (ADR-053 §11.1). El cluster tenant nace +# con rke2-ingress-nginx y no se quiere instalar Traefik adicional. +# tlsSecretName por default = apps-wildcard-tls (Gap 3); host con +# tenant-id CON guiones (Gap 5). description: Helm chart del Golden Path rest-api/python type: application -version: 0.1.0 +version: 0.2.0 appVersion: "0.1.0" keywords: - fastapi diff --git a/helm/APP_NAME/templates/ingress.yaml b/helm/APP_NAME/templates/ingress.yaml new file mode 100644 index 0000000..c74540c --- /dev/null +++ b/helm/APP_NAME/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled }} +# Ingress estándar networking.k8s.io/v1 con ingressClassName=nginx. +# Razón: el cluster tenant nace con rke2-ingress-nginx por default — +# instalar Traefik añade footprint e inconsistencia respecto al control +# plane (donde Traefik sí está). NGINX Ingress es más portable y permite +# que el tenant siga su exit plan sin lock-in. Además RKE2 es la +# distribución certificada CIS Kubernetes Benchmark con soporte SUSE CSP +# — sustituir el ingress controller default rompe la certificación. +# Decisión: APERTURA COVE Sesión 3 (2026-05-19) — ADR-053 §11.1 +# (replicado al shape rest-api/python por paridad). +# Nota: el shape rest-api/python es stateless por diseño; proxyBodySize +# default 1m es suficiente para payloads JSON típicos. Sube vía values +# si necesitás aceptar uploads más grandes. +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Release.Name }} + labels: + {{- include "app.labels" . | nindent 4 }} + annotations: + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/proxy-body-size: {{ .Values.ingress.proxyBodySize | default "1m" | quote }} +spec: + ingressClassName: {{ .Values.ingress.className | default "nginx" }} + tls: + - hosts: + - {{ .Values.ingress.host | quote }} + secretName: {{ .Values.ingress.tlsSecretName | default "apps-wildcard-tls" }} + rules: + - host: {{ .Values.ingress.host | quote }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ .Release.Name }} + port: + number: {{ .Values.service.port }} +{{- end }} diff --git a/helm/APP_NAME/templates/ingressroute.yaml b/helm/APP_NAME/templates/ingressroute.yaml deleted file mode 100644 index e85a4dc..0000000 --- a/helm/APP_NAME/templates/ingressroute.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{- if .Values.ingress.enabled }} -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: {{ .Release.Name }} - labels: - {{- include "app.labels" . | nindent 4 }} -spec: - entryPoints: - - websecure - routes: - - match: Host(`{{ .Values.ingress.host }}`) - kind: Rule - services: - - name: {{ .Release.Name }} - port: {{ .Values.service.port }} - tls: - secretName: {{ .Values.ingress.tlsSecretName }} -{{- end }} diff --git a/helm/APP_NAME/templates/networkpolicy.yaml b/helm/APP_NAME/templates/networkpolicy.yaml index 36e265a..fad9e47 100644 --- a/helm/APP_NAME/templates/networkpolicy.yaml +++ b/helm/APP_NAME/templates/networkpolicy.yaml @@ -1,8 +1,9 @@ {{- if .Values.networkPolicy.enabled }} # NetworkPolicy mínima del shape rest-api: bajo deny-all-default del namespace, permite: -# - Ingress: Traefik (público) + Prometheus (scrape de /metrics). +# - Ingress: rke2-ingress-nginx (público) + Prometheus (scrape de /metrics). # - Egress: DNS, Harbor pull HTTPS. # Sin acceso a ns-addons (rest-api no tiene BD por diseño). +# Nota: el cluster tenant usa rke2-ingress-nginx en kube-system, NO Traefik. apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: @@ -16,11 +17,12 @@ spec: policyTypes: [Ingress, Egress] ingress: - # Tráfico HTTP desde Traefik (IngressRoute) + # Tráfico HTTP desde rke2-ingress-nginx (Ingress estándar). + # El controller corre en kube-system por default en RKE2. - from: - namespaceSelector: matchLabels: - kubernetes.io/metadata.name: traefik-system + kubernetes.io/metadata.name: {{ .Values.networkPolicy.ingressControllerNamespace | default "kube-system" }} ports: - protocol: TCP port: 8000 diff --git a/helm/APP_NAME/values.yaml b/helm/APP_NAME/values.yaml index 0526032..8d55cc9 100644 --- a/helm/APP_NAME/values.yaml +++ b/helm/APP_NAME/values.yaml @@ -45,8 +45,24 @@ service: ingress: enabled: true - host: __APP_NAME__-__TENANT_ID_NODASHES__.apps.coralware.cloud - tlsSecretName: __APP_NAME__-tls + # className por defecto = nginx (rke2-ingress-nginx pre-instalado en cluster tenant). + # Cambiar solo si el tenant trae su propio IngressClass. + className: nginx + # Host con tenant-id CON guiones (formato canónico Cove): coincide con + # los A records que crea cloudflare-provisioner (Gap 5) y el wildcard + # cert apps-wildcard-tls (Gap 3). + host: __APP_NAME__-__TENANT_ID__.apps.coralware.cloud + # Secret TLS provisto por el wildcard *.apps.coralware.cloud sembrado + # en el cluster tenant por el agente cloudflare/cert-manager (Gap 3). + # NO se renombra por app — todas las apps del tenant lo comparten. + tlsSecretName: apps-wildcard-tls + # Body size para subidas/uploads de la app — rest-api es stateless por + # diseño (sin upload), default conservador 1m. Ajustar si la API acepta + # payloads grandes (ej. file POST). + proxyBodySize: 1m networkPolicy: enabled: true + # Namespace donde corre el ingress controller del cluster tenant. + # RKE2 instala rke2-ingress-nginx en kube-system por default. + ingressControllerNamespace: kube-system