# Копия nginx-configmap из base с правками под контур aero. # # Патчем это сделать нельзя: конфиг лежит одной строкой в data.nginx.conf, # и kustomize умеет только заменить значение целиком. # # ЧТО ИЗМЕНЕНО ОТНОСИТЕЛЬНО base — три вещи: # # 1. Убран location /api/pm/. Сервис pm в контуре не нужен и не планируется. # # 2. Для workspaces и processing адрес вынесен в переменную и добавлен # resolver. Причина: nginx резолвит все upstream'ы ПРИ СТАРТЕ и падает # целиком, если хоть один не найден: # nginx: [emerg] host not found in upstream "backend-svc.pm..." # Из-за этого весь frontend уходил в CrashLoopBackOff, хотя не работал # лишь один маршрут. С переменной nginx откладывает резолвинг до запроса: # сейчас эти пути отдают 502, а когда сервисы приедут — заработают сами, # без правки конфига и перезапуска. # # ПОРЯДОК ДИРЕКТИВ ВНУТРИ ТАКОГО location ЗНАЧИМ: set обязан идти ДО # rewrite ... break. Обе директивы принадлежат ngx_http_rewrite_module, а # флаг break прекращает обработку его директив в этом location — set после # него просто не выполняется, переменная остаётся пустой, и запрос падает с # [error] no host in upstream ":80" # отдавая наружу 500. Именно так и было: / работал, а /workspaces-v2/... и # /workflows/... возвращали 500, пока set стоял ниже rewrite. # # 3. backend-svc оставлен прямой ссылкой: он в этом же namespace и существует # всегда, откладывать его резолвинг незачем — наоборот, ошибка в имени # обнаружится сразу при старте. # # Адрес resolver'а — CoreDNS кластера. В k3s он называется kube-dns # (имя сохранено для совместимости), namespace kube-system. apiVersion: v1 kind: ConfigMap metadata: name: nginx-configmap namespace: django data: nginx.conf: | worker_processes auto; pid /var/run/nginx.pid; events { use epoll; worker_connections 1024; } http { # Basic Settings large_client_header_buffers 8 128k; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 300; types_hash_max_size 2048; client_max_body_size 5000M; client_header_buffer_size 5M; include /etc/nginx/mime.types; default_type application/octet-stream; # Logging Settings access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; # GZIP Settings gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; # Резолвер нужен для upstream'ов, заданных переменной (см. ниже). resolver kube-dns.kube-system.svc.cluster.local valid=30s ipv6=off; server { listen 80; listen [::]:80; root /opt/react_client/; add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' '*' always; add_header 'Access-Control-Allow-Headers' '*' always; location = /static/index.bundle.js { add_header Cache-Control 'no-store no-cache, must-revalidate, proxy-revalidate, max-age=0'; if_modified_since off; expires off; } # Выбор способа аутентификации. Фронтенд на старте делает # fetch("/static/config.json") и, если там есть auth_type, # БЕЗУСЛОВНО перекрывает им режим, зашитый в сборку # (src/Model/api/http-service.ts). Значения ровно два: # "zitadel" и "original"; original — классический вход по # логину и паролю с JWT, ради которого backend и получает из # Vault ключи RS512. # # В образе sarex-frontend-dev:contour_* этот файл лежит со # значением zitadel и хостом zitadel.contour.infra.sarex.tech — # чужой контур, из aero недоступен. Из-за него платформа # редиректила на /oauth/v2/authorize и получала # invalid_request: The requested redirect_uri is missing # in the client configuration # то есть войти было нельзя в принципе. # # Отдаём файл прямо из nginx, не подкладывая том: сам # static/config.json в sarex-frontend лежит в .gitignore и # заполняется на каждом стенде своим — это штатная точка # расширения, а не обход. В апстримном nginx.conf под него уже # заведён такой же location =, только читающий с диска. # # Подменить через localStorage нельзя: оверрайд оттуда # действует лишь для endpoint'ов stage, preprod и local, # contour в этом списке нет. location = /static/config.json { default_type application/json; add_header Cache-Control 'no-store no-cache, must-revalidate, proxy-revalidate, max-age=0'; if_modified_since off; expires off; return 200 '{"auth_type":"original"}'; } # location /api/pm/ из base удалён: сервис pm контуру не нужен. location ~^/(api|admin)/ { proxy_http_version 1.1; proxy_set_header Connection ""; proxy_set_header Host $host; proxy_pass http://backend-svc.django.svc.cluster.local:80; } # workspaces появится позже — резолвим лениво, через переменную. location ~^/workspaces-v2/(.+).js { proxy_http_version 1.1; proxy_set_header Connection ""; set $up_workspaces frontend-svc.workspaces.svc.cluster.local; rewrite /workspaces-v2/(.+) /$1 break; proxy_pass http://$up_workspaces:80; } location ~^/workspaces-v2/(.+)\.wasm$ { proxy_http_version 1.1; proxy_set_header Connection ""; set $up_workspaces_wasm frontend-svc.workspaces.svc.cluster.local; rewrite ^/workspaces-v2/(.+) /$1 break; proxy_pass http://$up_workspaces_wasm:80; } location @index { add_header Cache-Control 'no-cache, must-revalidate, proxy-revalidate, max-age=0'; if_modified_since off; expires off; try_files /static/index.html =404; } # processing появится позже — тоже лениво. location ~^/workflows/(.+).js { proxy_http_version 1.1; proxy_set_header Connection ""; set $up_processing frontend-svc.processing.svc.cluster.local; rewrite /workflows/(.+) /$1 break; proxy_pass http://$up_processing:80; } location /service-worker.js { try_files /static/$uri @index; } location / { try_files $uri @index; } } }