diff --git a/base/ingress/pingora-config.yaml b/base/ingress/pingora-config.yaml index e02ab64..aa64b99 100644 --- a/base/ingress/pingora-config.yaml +++ b/base/ingress/pingora-config.yaml @@ -39,8 +39,22 @@ data: [[routes]] host_prefix = "docs" - backend = "http://docs.lasuite.svc.cluster.local:8000" - websocket = true + backend = "http://docs-frontend.lasuite.svc.cluster.local:80" + + # API and admin go to the backend. + [[routes.paths]] + prefix = "/api/" + backend = "http://docs-backend.lasuite.svc.cluster.local:80" + + [[routes.paths]] + prefix = "/admin/" + backend = "http://docs-backend.lasuite.svc.cluster.local:80" + + # Real-time collaboration WebSocket (y-provider / Hocuspocus). + [[routes.paths]] + prefix = "/collaboration/ws/" + backend = "http://docs-y-provider.lasuite.svc.cluster.local:4444" + websocket = true [[routes]] host_prefix = "meet" @@ -113,6 +127,10 @@ data: host_prefix = "admin" backend = "http://kratos-admin-ui.ory.svc.cluster.local:3000" + [[routes]] + host_prefix = "integration" + backend = "http://integration.lasuite.svc.cluster.local:80" + [[routes]] host_prefix = "s3" backend = "http://seaweedfs-filer.storage.svc.cluster.local:8333" diff --git a/base/lasuite/docs-values.yaml b/base/lasuite/docs-values.yaml new file mode 100644 index 0000000..4050ae1 --- /dev/null +++ b/base/lasuite/docs-values.yaml @@ -0,0 +1,162 @@ +# La Suite Numérique — Docs (impress chart). +# Env vars use the chart's dict-based envVars schema: +# string value → rendered as env.value +# map value → rendered as env.valueFrom (configMapKeyRef / secretKeyRef) +# DOMAIN_SUFFIX is substituted by sed at deploy time. +# +# Required secrets (created by seed script): +# oidc-docs — CLIENT_ID, CLIENT_SECRET (created by Hydra Maester) +# docs-db-credentials — password (VaultDynamicSecret, DB engine) +# docs-django-secret — DJANGO_SECRET_KEY (VaultStaticSecret) +# seaweedfs-s3-credentials — S3_ACCESS_KEY, S3_SECRET_KEY (shared) + +fullnameOverride: docs + +backend: + createsuperuser: + # Superuser creation disabled — users authenticate via OIDC. + enabled: false + + envVars: &backendEnvVars + # ── Database ────────────────────────────────────────────────────────────── + DB_NAME: docs_db + DB_USER: docs + DB_HOST: + configMapKeyRef: + name: lasuite-postgres + key: DB_HOST + DB_PORT: + configMapKeyRef: + name: lasuite-postgres + key: DB_PORT + DB_ENGINE: + configMapKeyRef: + name: lasuite-postgres + key: DB_ENGINE + DB_PASSWORD: + secretKeyRef: + name: docs-db-credentials + key: password + + # ── Redis / Celery ──────────────────────────────────────────────────────── + REDIS_URL: + configMapKeyRef: + name: lasuite-valkey + key: REDIS_URL + CELERY_BROKER_URL: + configMapKeyRef: + name: lasuite-valkey + key: CELERY_BROKER_URL + + # ── S3 ──────────────────────────────────────────────────────────────────── + AWS_STORAGE_BUCKET_NAME: sunbeam-docs + AWS_S3_ENDPOINT_URL: + configMapKeyRef: + name: lasuite-s3 + key: AWS_S3_ENDPOINT_URL + AWS_S3_REGION_NAME: + configMapKeyRef: + name: lasuite-s3 + key: AWS_S3_REGION_NAME + AWS_DEFAULT_ACL: + configMapKeyRef: + name: lasuite-s3 + key: AWS_DEFAULT_ACL + AWS_ACCESS_KEY_ID: + secretKeyRef: + name: seaweedfs-s3-credentials + key: S3_ACCESS_KEY + AWS_SECRET_ACCESS_KEY: + secretKeyRef: + name: seaweedfs-s3-credentials + key: S3_SECRET_KEY + + # ── OIDC (Hydra) ────────────────────────────────────────────────────────── + OIDC_RP_CLIENT_ID: + secretKeyRef: + name: oidc-docs + key: CLIENT_ID + OIDC_RP_CLIENT_SECRET: + secretKeyRef: + name: oidc-docs + key: CLIENT_SECRET + OIDC_RP_SIGN_ALGO: + configMapKeyRef: + name: lasuite-oidc-provider + key: OIDC_RP_SIGN_ALGO + OIDC_RP_SCOPES: + configMapKeyRef: + name: lasuite-oidc-provider + key: OIDC_RP_SCOPES + OIDC_OP_JWKS_ENDPOINT: + configMapKeyRef: + name: lasuite-oidc-provider + key: OIDC_OP_JWKS_ENDPOINT + OIDC_OP_AUTHORIZATION_ENDPOINT: + configMapKeyRef: + name: lasuite-oidc-provider + key: OIDC_OP_AUTHORIZATION_ENDPOINT + OIDC_OP_TOKEN_ENDPOINT: + configMapKeyRef: + name: lasuite-oidc-provider + key: OIDC_OP_TOKEN_ENDPOINT + OIDC_OP_USER_ENDPOINT: + configMapKeyRef: + name: lasuite-oidc-provider + key: OIDC_OP_USER_ENDPOINT + OIDC_OP_LOGOUT_ENDPOINT: + configMapKeyRef: + name: lasuite-oidc-provider + key: OIDC_OP_LOGOUT_ENDPOINT + OIDC_VERIFY_SSL: + configMapKeyRef: + name: lasuite-oidc-provider + key: OIDC_VERIFY_SSL + + # ── Django ──────────────────────────────────────────────────────────────── + DJANGO_SECRET_KEY: + secretKeyRef: + name: docs-django-secret + key: DJANGO_SECRET_KEY + DJANGO_CONFIGURATION: Production + ALLOWED_HOSTS: docs.DOMAIN_SUFFIX + DJANGO_ALLOWED_HOSTS: docs.DOMAIN_SUFFIX + DJANGO_CSRF_TRUSTED_ORIGINS: https://docs.DOMAIN_SUFFIX + LOGIN_REDIRECT_URL: / + + # ── Y-Provider ──────────────────────────────────────────────────────────── + # Shared secret for backend ↔ y-provider auth. + COLLABORATION_SERVER_SECRET: + secretKeyRef: + name: docs-collaboration-secret + key: secret + COLLABORATION_SERVER_URL: http://docs-y-provider.lasuite.svc.cluster.local:4444 + +frontend: + envVars: + NEXT_PUBLIC_API_URL: https://docs.DOMAIN_SUFFIX + NEXT_PUBLIC_COLLABORATION_WS_URL: wss://docs.DOMAIN_SUFFIX/collaboration/ws/ + # La Gaufre app launcher — served from our self-hosted integration service. + GAUFREJS_URL: https://integration.DOMAIN_SUFFIX/api/v1/gaufre.js + +yProvider: + envVars: + # Shared secret so y-provider can verify requests from the backend. + COLLABORATION_SERVER_SECRET: + secretKeyRef: + name: docs-collaboration-secret + key: secret + # Impress backend URL for document access verification. + APP_URL: http://docs-backend.lasuite.svc.cluster.local:80 + +ingress: + enabled: false + +ingressCollaborationWS: + enabled: false + +ingressAdmin: + enabled: false + +ingressMedia: + enabled: false diff --git a/base/lasuite/kustomization.yaml b/base/lasuite/kustomization.yaml index e0580e6..345a99c 100644 --- a/base/lasuite/kustomization.yaml +++ b/base/lasuite/kustomization.yaml @@ -13,6 +13,7 @@ resources: - shared-config.yaml - oidc-clients.yaml - vault-secrets.yaml + - integration-deployment.yaml # La Suite Numérique Helm charts. # Charts with a published Helm repo use helmCharts below. @@ -26,3 +27,10 @@ helmCharts: namespace: lasuite valuesFile: people-values.yaml + # helm repo add docs https://suitenumerique.github.io/docs/ + - name: docs + repo: https://suitenumerique.github.io/docs/ + version: "4.5.0" + releaseName: docs + namespace: lasuite + valuesFile: docs-values.yaml diff --git a/base/lasuite/oidc-clients.yaml b/base/lasuite/oidc-clients.yaml index c106230..f3b45fb 100644 --- a/base/lasuite/oidc-clients.yaml +++ b/base/lasuite/oidc-clients.yaml @@ -19,7 +19,7 @@ spec: - code scope: openid email profile redirectUris: - - https://docs.DOMAIN_SUFFIX/oidc/callback/ + - https://docs.DOMAIN_SUFFIX/api/v1.0/callback/ tokenEndpointAuthMethod: client_secret_post secretName: oidc-docs skipConsent: true diff --git a/base/lasuite/vault-secrets.yaml b/base/lasuite/vault-secrets.yaml index 1a07850..7c958aa 100644 --- a/base/lasuite/vault-secrets.yaml +++ b/base/lasuite/vault-secrets.yaml @@ -129,3 +129,73 @@ spec: templates: DJANGO_SECRET_KEY: text: "{{ index .Secrets \"django-secret-key\" }}" +--- +# Docs DB credentials from OpenBao database secrets engine (static role, 24h rotation). +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultDynamicSecret +metadata: + name: docs-db-credentials + namespace: lasuite +spec: + vaultAuthRef: vso-auth + mount: database + path: static-creds/docs + refreshAfter: 1h + rolloutRestartTargets: + - kind: Deployment + name: docs-backend + - kind: Deployment + name: docs-celery-worker + - kind: Deployment + name: docs-y-provider + destination: + name: docs-db-credentials + create: true + overwrite: true + transformation: + excludeRaw: true + templates: + password: + text: "{{ index .Secrets \"password\" }}" +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: docs-django-secret + namespace: lasuite +spec: + vaultAuthRef: vso-auth + mount: secret + type: kv-v2 + path: docs + refreshAfter: 30s + destination: + name: docs-django-secret + create: true + overwrite: true + transformation: + excludeRaw: true + templates: + DJANGO_SECRET_KEY: + text: "{{ index .Secrets \"django-secret-key\" }}" +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: docs-collaboration-secret + namespace: lasuite +spec: + vaultAuthRef: vso-auth + mount: secret + type: kv-v2 + path: docs + refreshAfter: 30s + destination: + name: docs-collaboration-secret + create: true + overwrite: true + transformation: + excludeRaw: true + templates: + secret: + text: "{{ index .Secrets \"collaboration-secret\" }}" diff --git a/overlays/local/kustomization.yaml b/overlays/local/kustomization.yaml index 3f6cc75..14343a1 100644 --- a/overlays/local/kustomization.yaml +++ b/overlays/local/kustomization.yaml @@ -36,6 +36,14 @@ images: - name: lasuite/people-frontend newName: src.DOMAIN_SUFFIX/studio/people-frontend + # amd64-only impress (Docs) images — same mirror pattern. + - name: lasuite/impress-backend + newName: src.DOMAIN_SUFFIX/studio/impress-backend + - name: lasuite/impress-frontend + newName: src.DOMAIN_SUFFIX/studio/impress-frontend + - name: lasuite/impress-y-provider + newName: src.DOMAIN_SUFFIX/studio/impress-y-provider + patches: # Disable SSL verification for OIDC server-side calls — mkcert CA not trusted in pods - path: patch-oidc-verify-ssl.yaml diff --git a/overlays/local/values-resources.yaml b/overlays/local/values-resources.yaml index c7ebe3e..9ac9b1b 100644 --- a/overlays/local/values-resources.yaml +++ b/overlays/local/values-resources.yaml @@ -98,7 +98,9 @@ spec: - name: filer resources: limits: - memory: 256Mi + memory: 512Mi + requests: + memory: 128Mi --- apiVersion: apps/v1 @@ -173,3 +175,83 @@ metadata: namespace: lasuite spec: replicas: 1 + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: docs-celery-worker + namespace: lasuite +spec: + replicas: 1 + template: + spec: + containers: + - name: docs + env: + # Celery workers: 2 concurrent workers fits within local memory budget. + - name: CELERY_WORKER_CONCURRENCY + value: "2" + resources: + limits: + memory: 384Mi + requests: + memory: 128Mi + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: docs-backend + namespace: lasuite +spec: + replicas: 1 + template: + spec: + containers: + - name: docs + env: + # 2 uvicorn workers instead of the default 4 to stay within local memory budget. + # Each worker loads the full Django+impress app (~150 MB), so 4 workers + # pushed peak RSS above 384 Mi and triggered OOMKill at startup. + - name: WEB_CONCURRENCY + value: "2" + resources: + limits: + memory: 512Mi + requests: + memory: 192Mi + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: docs-frontend + namespace: lasuite +spec: + replicas: 1 + template: + spec: + containers: + - name: docs + resources: + limits: + memory: 128Mi + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: docs-y-provider + namespace: lasuite +spec: + replicas: 1 + template: + spec: + containers: + - name: docs + resources: + limits: + memory: 256Mi + requests: + memory: 64Mi