diff --git a/common/utils/cache/regions.py b/common/utils/cache/regions.py index 23dd759..1321a1b 100644 --- a/common/utils/cache/regions.py +++ b/common/utils/cache/regions.py @@ -1,63 +1,49 @@ # common/utils/cache/regions.py import time +import redis from dogpile.cache import make_region -from urllib.parse import urlparse - +import ssl def get_redis_config(app): """ Create Redis configuration dict based on app config. Handles both authenticated and non-authenticated setups. """ + app.logger.debug(f"Creating Redis config") # Parse the REDIS_BASE_URI to get all components - redis_uri = urlparse(app.config['REDIS_BASE_URI']) + # redis_uri = urlparse(app.config['REDIS_BASE_URI']) config = { - 'host': redis_uri.hostname, - 'port': int(redis_uri.port or 6379), - 'db': 0, - 'redis_expiration_time': 3600, - 'distributed_lock': True, - 'thread_local_lock': False, - # Built-in connection pooling parameters - 'connection_pool_class': 'redis.BlockingConnectionPool', - 'connection_pool_class_kwargs': { - 'max_connections': 20, - 'timeout': 20, - 'retry_on_timeout': True, - 'socket_connect_timeout': 5, - 'socket_timeout': 5, - }, - - # Key prefix for namespace isolation - 'key_mangler': lambda key: f"cache:workers:{key}" + 'host': app.config['REDIS_URL'], + 'port': app.config['REDIS_PORT'], + 'max_connections': 20, + 'retry_on_timeout': True, + 'socket_keepalive': True, + 'socket_keepalive_options': {}, } # Add authentication if provided - if redis_uri.username and redis_uri.password: + un = app.config.get('REDIS_USER') + pw = app.config.get('REDIS_PASS') + if un and pw: config.update({ - 'username': redis_uri.username, - 'password': redis_uri.password + 'username': un, + 'password': pw }) # SSL support using centralised config cert_path = app.config.get('REDIS_CA_CERT_PATH') - if cert_path and redis_uri.scheme == 'rediss': - import ssl - # Create SSL context - ssl_context = ssl.create_default_context() - ssl_context.load_verify_locations(cert_path) - ssl_context.verify_mode = ssl.CERT_REQUIRED - ssl_context.check_hostname = app.config.get('REDIS_SSL_CHECK_HOSTNAME', True) + redis_scheme = app.config.get('REDIS_SCHEME') + if cert_path and redis_scheme == 'rediss': + config.update({ + 'connection_class': redis.SSLConnection, + 'ssl_cert_reqs': ssl.CERT_REQUIRED, + 'ssl_check_hostname': app.config.get('REDIS_SSL_CHECK_HOSTNAME', True), + 'ssl_ca_certs': cert_path, + }) - # Add SSL to connection pool kwargs (correct for redis-py) - config['connection_pool_class_kwargs']['ssl'] = True - config['connection_pool_class_kwargs']['ssl_cert_reqs'] = ssl.CERT_REQUIRED - config['connection_pool_class_kwargs']['ssl_ca_certs'] = cert_path - config['connection_pool_class_kwargs']['ssl_check_hostname'] = app.config.get('REDIS_SSL_CHECK_HOSTNAME', True) - # Also pass explicit context (preferred when available) - config['connection_pool_class_kwargs']['ssl_context'] = ssl_context + app.logger.debug(f"config for Redis connection: {config}") return config @@ -65,13 +51,14 @@ def get_redis_config(app): def create_cache_regions(app): """Initialise all cache regions with app config""" redis_config = get_redis_config(app) + redis_pool = redis.ConnectionPool(**redis_config) regions = {} startup_time = int(time.time()) # Region for model-related caching (ModelVariables etc) model_region = make_region(name='eveai_model').configure( 'dogpile.cache.redis', - arguments=redis_config, + arguments={'connection_pool': redis_pool}, replace_existing_backend=True ) regions['eveai_model'] = model_region @@ -79,7 +66,7 @@ def create_cache_regions(app): # Region for eveai_chat_workers components (Specialists, Retrievers, ...) eveai_chat_workers_region = make_region(name='eveai_chat_workers').configure( 'dogpile.cache.redis', - arguments=redis_config, + arguments={'connection_pool': redis_pool}, replace_existing_backend=True ) regions['eveai_chat_workers'] = eveai_chat_workers_region @@ -87,14 +74,14 @@ def create_cache_regions(app): # Region for eveai_workers components (Processors, ...) eveai_workers_region = make_region(name='eveai_workers').configure( 'dogpile.cache.redis', - arguments=redis_config, # Same config for now + arguments={'connection_pool': redis_pool}, # Same config for now replace_existing_backend=True ) regions['eveai_workers'] = eveai_workers_region eveai_config_region = make_region(name='eveai_config').configure( 'dogpile.cache.redis', - arguments=redis_config, + arguments={'connection_pool': redis_pool}, replace_existing_backend=True ) regions['eveai_config'] = eveai_config_region diff --git a/config/config.py b/config/config.py index 6b7eb0c..6260cde 100644 --- a/config/config.py +++ b/config/config.py @@ -32,6 +32,7 @@ class Config(object): REDIS_USER = environ.get('REDIS_USER') REDIS_PASS = environ.get('REDIS_PASS') REDIS_CERT_DATA = environ.get('REDIS_CERT') + REDIS_SCHEME = None # Determine if REDIS_URL is an IP; use it to control hostname checking REDIS_IS_IP = False @@ -52,8 +53,10 @@ class Config(object): REDIS_CA_CERT_PATH = _tmp.name if not REDIS_CERT_DATA: # We are in a simple dev/test environment + REDIS_SCHEME = 'redis' REDIS_BASE_URI = f'redis://{REDIS_URL}:{REDIS_PORT}' else: # We are in a scaleway environment, providing name, user and certificate + REDIS_SCHEME = 'rediss' REDIS_BASE_URI = f'rediss://{REDIS_USER}:{REDIS_PASS}@{REDIS_URL}:{REDIS_PORT}' # Central SSL options dict for reuse (Celery/Dogpile/etc.) @@ -94,12 +97,8 @@ class Config(object): SESSION_REFRESH_EACH_REQUEST = True # Configure SESSION_REDIS with SSL when cert is provided if REDIS_CERT_DATA and REDIS_CA_CERT_PATH: - SESSION_REDIS = redis.Redis( - host=REDIS_URL, - port=int(REDIS_PORT or 6379), - username=REDIS_USER, - password=REDIS_PASS, - ssl=True, + SESSION_REDIS = redis.from_url( + f'{REDIS_BASE_URI}/0', # REDIS_BASE_URI is reeds rediss://user:pass@host:port ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=REDIS_CA_CERT_PATH, ssl_check_hostname=REDIS_SSL_CHECK_HOSTNAME, @@ -136,7 +135,7 @@ class Config(object): SECURITY_CONFIRMABLE = True SECURITY_TRACKABLE = True SECURITY_PASSWORD_COMPLEXITY_CHECKER = 'zxcvbn' - SECURITY_POST_LOGIN_VIEW = '/user/tenant_overview' + SECURITY_POST_LOGIN_VIEW = '/admin/user/tenant_overview' SECURITY_RECOVERABLE = True SECURITY_EMAIL_SENDER = "eveai_super@flow-it.net" SECURITY_EMAIL_SUBJECT_PASSWORD_RESET = 'Reset Your Password' diff --git a/docker/eveai_workers/Dockerfile b/docker/eveai_workers/Dockerfile index 9a36cef..0512ee7 100644 --- a/docker/eveai_workers/Dockerfile +++ b/docker/eveai_workers/Dockerfile @@ -1,4 +1,4 @@ -pcupFROM registry.ask-eve-ai-local.com/josakola/eveai-base:latest +FROM registry.ask-eve-ai-local.com/josakola/eveai-base:latest # Service-specific packages (ffmpeg only needed for this service) USER root diff --git a/documentation/Production Setup/cluster-install.md b/documentation/Production Setup/cluster-install.md index effe7fd..3fec1f0 100644 --- a/documentation/Production Setup/cluster-install.md +++ b/documentation/Production Setup/cluster-install.md @@ -18,13 +18,29 @@ kubectl cluster-info - Kubernetes cluster running - Managed services configured (PostgreSQL, Redis, MinIO) - Secrets stored in Scaleway Secret Manager: - - `eveai-app-keys`, `eveai-mistral`, `eveai-object-storage` + - `eveai-app-keys`, `eveai-mistral`, `eveai-object-storage`, `eveai-tem` - `eveai-openai`, `eveai-postgresql`, `eveai-redis`, `eveai-redis-certificate` - Flexible IP address (LoadBalancer) - Eerst een loadbalancer aanmaken met publiek IP - Daarna de loadbalancer verwijderen maar flexible IPs behouden - Dit externe IP is het IP adres dat moet worden verwerkt in ingress-values.yaml! +## CDN Setup (Bunny.net - Optional) + +### Configure Pull Zone +- Create Pull zone: evie-staging +- Origin: https://[LoadBalancer-IP] (note HTTPS!) -> pas later in het proces gekend +- Host header: evie-staging.askeveai.com +- Force SSL: Enabled +- In the pull zone's Caching - General settings, ensure to disable 'Strip Response Cookies' +- Define edge rules for + - Redirecting the root + - Redirecting security urls + +### Update DNS (eurodns) for CDN +- Change A-record to CNAME pointing to CDN endpoint +- Or update A-record to CDN IP + ## New Modular Deployment Process ### Phase 1: Infrastructure Foundation @@ -230,7 +246,7 @@ kubectl create secret generic scaleway-credentials \ #### Stap 3: Verifieer SecretStore configuratie -Verifieer bestand: `scaleway/manifests/base/secrets/scaleway-secret-store.yaml`. Daar moet de juiste project ID worden ingevoerd. +Verifieer bestand: `scaleway/manifests/base/secrets/clustersecretstore-scaleway.yaml`. Daar moet de juiste project ID worden ingevoerd. #### Stap 4: Verifieer ExternalSecret resource @@ -245,7 +261,7 @@ Verifieer bestand: `scaleway/manifests/base/secrets/eveai-external-secrets.yaml` ```bash # Deploy SecretStore -kubectl apply -f scaleway/manifests/base/secrets/scaleway-secret-store.yaml +kubectl apply -f scaleway/manifests/base/secrets/clustersecretstore-scaleway.yaml # Deploy ExternalSecret kubectl apply -f scaleway/manifests/base/secrets/eveai-external-secrets.yaml @@ -281,7 +297,13 @@ metadata: name: eveai-app namespace: eveai-staging spec: + selector: + matchLabels: + app: eveai-app template: + metadata: + labels: + app: eveai-app spec: containers: - name: eveai-app @@ -296,15 +318,17 @@ spec: Voor SSL Redis connecties met het certificaat: ```python -# In je config.py +# Voorbeeld in je config.py import tempfile import ssl import redis from os import environ -class StagingConfig(Config): - REDIS_CERT_DATA = environ.get('REDIS_CERT') - +class StagingConfig: + def __init__(self): + self.REDIS_CERT_DATA = environ.get('REDIS_CERT') + self.REDIS_BASE_URI = environ.get('REDIS_BASE_URI', 'redis://localhost:6379/0') + def create_redis_connection(self): if self.REDIS_CERT_DATA: # Schrijf certificaat naar tijdelijk bestand @@ -320,9 +344,11 @@ class StagingConfig(Config): ) else: return redis.from_url(self.REDIS_BASE_URI) - + # Gebruik voor session Redis - SESSION_REDIS = property(lambda self: self.create_redis_connection()) + @property + def SESSION_REDIS(self): + return self.create_redis_connection() ``` #### Scaleway Secret Manager Vereisten @@ -389,8 +415,20 @@ kubectl -n eveai-staging describe certificate evie-staging-tls Dit kan even duren. Maar zodra het certificaat is aangemaakt, kan je de de https-only ingress opzetten: +#### Apply per-prefix headers (moet bestaan vóór de Ingress die ernaar verwijst) +```bash +kubectl apply -f scaleway/manifests/base/networking/headers-configmaps.yaml ``` -kubectl apply -f scaleway/manifests/base/networking/ingress-https.yaml + +#### Apply ingresses +```bash +kubectl apply -f scaleway/manifests/base/networking/ingress-https.yaml # alleen /verify +kubectl apply -f scaleway/manifests/base/networking/ingress-admin.yaml # /admin → eveai-app-service +kubectl apply -f scaleway/manifests/base/networking/ingress-api.yaml # /api → eveai-api-service +kubectl apply -f scaleway/manifests/base/networking/ingress-chat-client.yaml # /chat-client → eveai-chat-client-service + +# Alternatief: via overlay (mits kustomization.yaml is bijgewerkt) +kubectl apply -k scaleway/manifests/overlays/staging/ ``` Om bunny.net te gebruiken: @@ -418,6 +456,30 @@ kubectl get ingress -n eveai-staging kubectl get certificates -n eveai-staging ``` +### Verificatie commando's + +Controleer ingresses en headers: + +```bash +kubectl -n eveai-staging get ing +kubectl -n eveai-staging describe ing eveai-admin-ingress +kubectl -n eveai-staging describe ing eveai-api-ingress +kubectl -n eveai-staging describe ing eveai-chat-client-ingress +kubectl -n eveai-staging describe ing eveai-staging-ingress # bevat /verify +kubectl -n eveai-staging get cm eveai-admin-headers eveai-api-headers eveai-chat-headers -o yaml +``` + +- In elke prefix-Ingress moeten de annotations zichtbaar zijn: use-regex: true, rewrite-target: /$2, proxy-set-headers: eveai-staging/eveai--headers. +- In de ConfigMaps moet de key X-Forwarded-Prefix de juiste waarde hebben (/admin, /api, /chat-client). +End-to-end testen: + +- https://evie-staging.askeveai.com/admin/login → loginpagina. In app-logs zie je PATH zonder /admin (door rewrite) maar URL met /admin. +- Na login: 302 Location: /admin/user/tenant_overview. +- API: https://evie-staging.askeveai.com/api/… → backend ontvangt pad zonder /api. +- Chat client: https://evie-staging.askeveai.com/chat-client/… → juiste service. +- Verify: https://evie-staging.askeveai.com/verify → ongewijzigd via ingress-https.yaml. +- Root: zolang Bunny rule niet actief is, geen automatische redirect op / (verwacht gedrag). + ### Phase 7: Install PgAdmin Tool #### Secret eveai-pgadmin-admin in Scaleway Secret Manager aanmaken (indien niet bestaat) @@ -464,6 +526,52 @@ kubectl -n tools port-forward svc/pgadmin-pgadmin4 8080:80 ### Phase 8: RedisInsight Tool Deployment +#### Installatie via kubectl (zonder Helm) +Gebruik een eenvoudig manifest met Deployment + Service + PVC in de `tools` namespace. Dit vermijdt externe chart repositories en extra authenticatie. +```bash +# Apply manifest (maakt namespace tools aan indien nodig) +kubectl apply -f scaleway/manifests/base/tools/redisinsight/redisinsight.yaml + +# Controleer resources +kubectl -n tools get pods,svc,pvc +``` + +#### (Optioneel) ExternalSecrets voor gemak (eigenlijk niet nodig) +Indien je de Redis-credentials en CA-cert in namespace `tools` wil spiegelen (handig om het CA-bestand eenvoudig te exporteren en/of later provisioning te doen): +```bash +kubectl apply -f scaleway/manifests/base/tools/redisinsight/externalsecrets.yaml +kubectl -n tools get externalsecret +kubectl -n tools get secret | grep redisinsight +``` + +CA-bestand lokaal opslaan voor UI-upload (alleen nodig als je ExternalSecrets gebruikte): +```bash +kubectl -n tools get secret redisinsight-ca -o jsonpath='{.data.REDIS_CERT}' | base64 -d > /tmp/redis-ca.pem +``` + +#### Port Forward, Local Access +```bash +# RedisInsight v2 luistert op poort 5540 +kubectl -n tools port-forward svc/redisinsight 5540:5540 +# Browser: http://localhost:5540 +``` + +#### UI: Redis verbinden +- Host: `172.16.16.2` +- Port: `6379` +- Auth: username `luke`, password uit secret (eveai-redis of redisinsight-redis) +- TLS: zet TLS aan en upload het CA-certificaat (PEM) +- Certificaatverificatie: omdat je via IP verbindt en geen hostname in het certificaat staat, kan strict verify falen. Zet dan "Verify server certificate"/"Check server identity" uit in de UI. Dit is normaal bij private networking via IP. + +#### Troubleshooting +- Controleer pods, service en PVC in `tools`: +```bash +kubectl -n tools get pods,svc,pvc +``` +- NetworkPolicies: indien actief, laat egress toe van `tools` → `172.16.16.2:6379`. +- TLS-issues via IP: zet verify uit of gebruik een DNS-hostnaam die met het cert overeenkomt (indien beschikbaar). +- PVC niet bound: specificeer een geldige `storageClassName` in het manifest. + ### Phase 9: Application Services Deployment @@ -663,21 +771,6 @@ nslookup evie-staging.askeveai.com curl https://evie-staging.askeveai.com/verify/ ``` -## CDN Setup (Bunny.net - Optional) - -### Configure Pull Zone -- Create Pull zone: evie-staging -- Origin: https://[LoadBalancer-IP] (note HTTPS!) -- Host header: evie-staging.askeveai.com -- Force SSL: Enabled - -### Update DNS for CDN -- Change A-record to CNAME pointing to CDN endpoint -- Or update A-record to CDN IP - -## Bunny.net notes - -- In the pull zone's Caching - General settings, ensure to disable 'Strip Response Cookies' diff --git a/eveai_app/__init__.py b/eveai_app/__init__.py index f7d2bf7..5089939 100644 --- a/eveai_app/__init__.py +++ b/eveai_app/__init__.py @@ -123,6 +123,7 @@ def create_app(config_file=None): return app.logger.debug(f"Before request - URL: {request.url}") + app.logger.debug(f"Before request - PATH: {request.path}") app.logger.debug(f"Before request - Session permanent: {session.permanent}") @app.route('/debug/session') diff --git a/requirements.txt b/requirements.txt index 5f40c36..6e18641 100644 --- a/requirements.txt +++ b/requirements.txt @@ -45,7 +45,7 @@ python-iso639~=2024.4.27 python-magic~=0.4.27 pytz~=2024.1 PyYAML~=6.0.2 -redis~=5.0.4 +redis~=6.4.0 requests~=2.32.3 SQLAlchemy~=2.0.40 tiktoken~=0.7.0 diff --git a/scaleway/manifests/base/networking/README-ROUTING.md b/scaleway/manifests/base/networking/README-ROUTING.md index 96f228c..ff7c311 100644 --- a/scaleway/manifests/base/networking/README-ROUTING.md +++ b/scaleway/manifests/base/networking/README-ROUTING.md @@ -1,14 +1,19 @@ Routing alignment notes (staging/prod) Summary -- Root (/) issues a 301 redirect to /admin/ via server-snippet on the apps ingress. -- Prefixes /admin, /api, /chat-client are stripped at the edge and forwarded to their backends on /. The applications do not need to be prefix-aware. +- Root (/) redirect will be handled at Bunny (edge). No server-snippet is used in the ingress. +- Prefixes /admin, /api, /chat-client are stripped at the ingress and forwarded to their backends on /. The applications do not need to be prefix-routed internally. +- For consistent external URLs (especially after POST/redirect), each prefix Ingress injects X-Forwarded-Prefix via nginx.ingress.kubernetes.io/proxy-set-headers and a per-prefix ConfigMap. - /verify remains available (Prefix) without any rewrite in a separate Ingress. - No CORS annotations at ingress. Static assets are served by Bunny CDN; API CORS is not handled here. - /flower is intentionally NOT exposed on k8s. Files -- ingress-https.yaml: NGINX Ingress (apps) with regex paths and rewrite-target to strip prefixes; includes server-snippet to 301 redirect root to /admin/. +- ingress-admin.yaml: Ingress for /admin with regex paths, rewrite-target to strip prefix, and proxy-set-headers pointing to eveai-admin-headers. +- ingress-api.yaml: Ingress for /api with regex paths, rewrite-target to strip prefix, and proxy-set-headers pointing to eveai-api-headers. +- ingress-chat-client.yaml: Ingress for /chat-client with regex paths, rewrite-target to strip prefix, and proxy-set-headers pointing to eveai-chat-headers. +- headers-configmaps.yaml: ConfigMaps defining X-Forwarded-Prefix per ingress. +- ingress-https.yaml: Legacy combined ingress retained for reference; server-snippet removed. Consider deprecating once split ingresses are applied. - ingress-verify.yaml: Separate Ingress for /verify without regex/rewrite. Paths behavior diff --git a/scaleway/manifests/base/networking/headers-configmaps.yaml b/scaleway/manifests/base/networking/headers-configmaps.yaml new file mode 100644 index 0000000..965e385 --- /dev/null +++ b/scaleway/manifests/base/networking/headers-configmaps.yaml @@ -0,0 +1,24 @@ +# ConfigMaps defining per-ingress proxy-set-headers +apiVersion: v1 +kind: ConfigMap +metadata: + name: eveai-admin-headers + namespace: eveai-staging +data: + X-Forwarded-Prefix: /admin +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: eveai-api-headers + namespace: eveai-staging +data: + X-Forwarded-Prefix: /api +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: eveai-chat-headers + namespace: eveai-staging +data: + X-Forwarded-Prefix: /chat-client diff --git a/scaleway/manifests/base/networking/ingress-admin.yaml b/scaleway/manifests/base/networking/ingress-admin.yaml new file mode 100644 index 0000000..09b3836 --- /dev/null +++ b/scaleway/manifests/base/networking/ingress-admin.yaml @@ -0,0 +1,36 @@ +# Ingress for /admin prefix with X-Forwarded-Prefix header +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: eveai-admin-ingress + namespace: eveai-staging + labels: + app: eveai + environment: staging + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "10m" + nginx.ingress.kubernetes.io/proxy-read-timeout: "300" + cert-manager.io/cluster-issuer: letsencrypt-staging + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/rewrite-target: "/$2" + nginx.ingress.kubernetes.io/proxy-set-headers: "eveai-staging/eveai-admin-headers" +spec: + ingressClassName: nginx + tls: + - hosts: + - evie-staging.askeveai.com + secretName: evie-staging-tls + rules: + - host: evie-staging.askeveai.com + http: + paths: + - path: /admin(/|$)(.*) + pathType: ImplementationSpecific + backend: + service: + name: eveai-app-service + port: + number: 80 diff --git a/scaleway/manifests/base/networking/ingress-api.yaml b/scaleway/manifests/base/networking/ingress-api.yaml new file mode 100644 index 0000000..a073f78 --- /dev/null +++ b/scaleway/manifests/base/networking/ingress-api.yaml @@ -0,0 +1,36 @@ +# Ingress for /api prefix with X-Forwarded-Prefix header (optional but consistent) +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: eveai-api-ingress + namespace: eveai-staging + labels: + app: eveai + environment: staging + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "10m" + nginx.ingress.kubernetes.io/proxy-read-timeout: "300" + cert-manager.io/cluster-issuer: letsencrypt-staging + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/rewrite-target: "/$2" + nginx.ingress.kubernetes.io/proxy-set-headers: "eveai-staging/eveai-api-headers" +spec: + ingressClassName: nginx + tls: + - hosts: + - evie-staging.askeveai.com + secretName: evie-staging-tls + rules: + - host: evie-staging.askeveai.com + http: + paths: + - path: /api(/|$)(.*) + pathType: ImplementationSpecific + backend: + service: + name: eveai-api-service + port: + number: 80 diff --git a/scaleway/manifests/base/networking/ingress-chat-client.yaml b/scaleway/manifests/base/networking/ingress-chat-client.yaml new file mode 100644 index 0000000..888d626 --- /dev/null +++ b/scaleway/manifests/base/networking/ingress-chat-client.yaml @@ -0,0 +1,36 @@ +# Ingress for /chat-client prefix with X-Forwarded-Prefix header (optional but consistent) +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: eveai-chat-client-ingress + namespace: eveai-staging + labels: + app: eveai + environment: staging + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "10m" + nginx.ingress.kubernetes.io/proxy-read-timeout: "300" + cert-manager.io/cluster-issuer: letsencrypt-staging + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/rewrite-target: "/$2" + nginx.ingress.kubernetes.io/proxy-set-headers: "eveai-staging/eveai-chat-headers" +spec: + ingressClassName: nginx + tls: + - hosts: + - evie-staging.askeveai.com + secretName: evie-staging-tls + rules: + - host: evie-staging.askeveai.com + http: + paths: + - path: /chat-client(/|$)(.*) + pathType: ImplementationSpecific + backend: + service: + name: eveai-chat-client-service + port: + number: 80 diff --git a/scaleway/manifests/base/networking/ingress-https.yaml b/scaleway/manifests/base/networking/ingress-https.yaml index f5c0eef..68f4d1b 100644 --- a/scaleway/manifests/base/networking/ingress-https.yaml +++ b/scaleway/manifests/base/networking/ingress-https.yaml @@ -16,10 +16,6 @@ metadata: cert-manager.io/cluster-issuer: letsencrypt-staging nginx.ingress.kubernetes.io/use-regex: "true" nginx.ingress.kubernetes.io/rewrite-target: "/$2" - nginx.ingress.kubernetes.io/server-snippet: | - location = / { - return 301 /admin/; - } spec: ingressClassName: nginx tls: @@ -30,28 +26,12 @@ spec: - host: evie-staging.askeveai.com http: paths: - # Application services (strip prefix) - - path: /admin(/|$)(.*) - pathType: ImplementationSpecific + - path: /verify + pathType: Prefix backend: service: - name: eveai-app-service - port: - number: 80 - - - path: /api(/|$)(.*) - pathType: ImplementationSpecific - backend: - service: - name: eveai-api-service - port: - number: 80 - - - path: /chat-client(/|$)(.*) - pathType: ImplementationSpecific - backend: - service: - name: eveai-chat-client-service + name: verify-service port: number: 80 + # Application services (strip prefix) are now defined in dedicated ingress files \ No newline at end of file diff --git a/scaleway/manifests/base/secrets/eveai-external-secrets.yaml b/scaleway/manifests/base/secrets/eveai-external-secrets.yaml index 5bfde85..6852c8b 100644 --- a/scaleway/manifests/base/secrets/eveai-external-secrets.yaml +++ b/scaleway/manifests/base/secrets/eveai-external-secrets.yaml @@ -31,6 +31,9 @@ spec: # Alle keys uit eveai-object-storage secret - extract: key: name:eveai-object-storage + # Alle keys uit eveai-tem secret + - extract: + key: name:eveai-tem data: # Certificaat als aparte data entry - secretKey: REDIS_CERT diff --git a/scaleway/manifests/base/tools/redisinsight/externalsecrets.yaml b/scaleway/manifests/base/tools/redisinsight/externalsecrets.yaml new file mode 100644 index 0000000..b37a487 --- /dev/null +++ b/scaleway/manifests/base/tools/redisinsight/externalsecrets.yaml @@ -0,0 +1,49 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: redisinsight-redis + namespace: tools +spec: + refreshInterval: 5m + secretStoreRef: + kind: ClusterSecretStore + name: scaleway-secret-store + target: + name: redisinsight-redis + creationPolicy: Owner + data: + - secretKey: REDIS_USER + remoteRef: + key: eveai-redis + property: REDIS_USER + - secretKey: REDIS_PASS + remoteRef: + key: eveai-redis + property: REDIS_PASS + - secretKey: REDIS_URL + remoteRef: + key: eveai-redis + property: REDIS_URL + - secretKey: REDIS_PORT + remoteRef: + key: eveai-redis + property: REDIS_PORT +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: redisinsight-ca + namespace: tools +spec: + refreshInterval: 5m + secretStoreRef: + kind: ClusterSecretStore + name: scaleway-secret-store + target: + name: redisinsight-ca + creationPolicy: Owner + data: + - secretKey: REDIS_CERT + remoteRef: + key: eveai-redis-certificate + property: REDIS_CERT diff --git a/scaleway/manifests/base/tools/redisinsight/redisinsight.yaml b/scaleway/manifests/base/tools/redisinsight/redisinsight.yaml new file mode 100644 index 0000000..494e3df --- /dev/null +++ b/scaleway/manifests/base/tools/redisinsight/redisinsight.yaml @@ -0,0 +1,95 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: tools +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: redisinsight-data + namespace: tools + labels: + app: redisinsight +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + # storageClassName: default # uncomment and set if your cluster requires an explicit storage class +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redisinsight + namespace: tools + labels: + app: redisinsight +spec: + replicas: 1 + selector: + matchLabels: + app: redisinsight + template: + metadata: + labels: + app: redisinsight + spec: + securityContext: + fsGroup: 1001 + containers: + - name: redisinsight + image: redis/redisinsight:2.54.0 + imagePullPolicy: IfNotPresent + ports: + - name: http + containerPort: 5540 + resources: + requests: + cpu: "200m" + memory: "256Mi" + limits: + cpu: "500m" + memory: "512Mi" + securityContext: + runAsNonRoot: true + runAsUser: 1001 + runAsGroup: 1001 + readOnlyRootFilesystem: false + volumeMounts: + - name: data + mountPath: /data + readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 2 + livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 30 + periodSeconds: 20 + timeoutSeconds: 2 + volumes: + - name: data + persistentVolumeClaim: + claimName: redisinsight-data +--- +apiVersion: v1 +kind: Service +metadata: + name: redisinsight + namespace: tools + labels: + app: redisinsight +spec: + type: ClusterIP + selector: + app: redisinsight + ports: + - name: http + port: 5540 + targetPort: http