feat(gateway): сервис pcp-gateway-service + сворачивание маршрутизации фронта на него
- новый Spring Cloud Gateway (WebFlux): доменные маршруты /api/pcp-<x>/**
со StripPrefix=2, /api/stations без среза пути, catch-all /api/** → ui-service;
опциональная JWT-валидация на edge (gateway.security.jwt-enabled, по умолчанию off)
- config-repo: pcp-gateway-service.yaml (маршруты) + порт/адрес gateway в реестрах
application-{local,docker-local,dev}
- build: репозитории переведены на mavenCentral (nstart-proxy закомментирован),
включены mavenLocal/gradlePluginPortal; settings: include модуля
- pcp-tgu-ui-service: vite-proxy и nginx.conf свёрнуты на единый /api → gateway
(вместо набора per-service правил)
- deploy: сервис gateway в docker-compose; helm-чарт pcp-gateway-service
- CI: .gitlab/ci/pcp-gateway-service.yml + проводка в .gitlab-ci.yml
This commit is contained in:
@@ -20,6 +20,7 @@ workflow:
|
||||
- services/pcp-tgu-service/**/*
|
||||
- services/pcp-tgu-ui-service/**/*
|
||||
- services/pcp-dynamic-plan-service/**/*
|
||||
- services/pcp-gateway-service/**/*
|
||||
- libs/pcp-types-lib/**/*
|
||||
- libs/ballistics-lib/**/*
|
||||
- build.gradle.kts
|
||||
@@ -43,6 +44,7 @@ workflow:
|
||||
- helm/pcp-tgu-service/**/*
|
||||
- helm/pcp-tgu-ui-service/**/*
|
||||
- helm/pcp-dynamic-plan-service/**/*
|
||||
- helm/pcp-gateway-service/**/*
|
||||
- if: '$CI_PIPELINE_SOURCE == "push"'
|
||||
changes:
|
||||
- .gitlab-ci.yml
|
||||
@@ -64,6 +66,7 @@ workflow:
|
||||
- services/pcp-tgu-service/**/*
|
||||
- services/pcp-tgu-ui-service/**/*
|
||||
- services/pcp-dynamic-plan-service/**/*
|
||||
- services/pcp-gateway-service/**/*
|
||||
- libs/pcp-types-lib/**/*
|
||||
- libs/ballistics-lib/**/*
|
||||
- build.gradle.kts
|
||||
@@ -87,6 +90,7 @@ workflow:
|
||||
- helm/pcp-tgu-service/**/*
|
||||
- helm/pcp-tgu-ui-service/**/*
|
||||
- helm/pcp-dynamic-plan-service/**/*
|
||||
- helm/pcp-gateway-service/**/*
|
||||
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "master"'
|
||||
changes:
|
||||
- services/pcp-ballistics-service/**/*
|
||||
@@ -104,6 +108,7 @@ workflow:
|
||||
- services/pcp-tgu-service/**/*
|
||||
- services/pcp-tgu-ui-service/**/*
|
||||
- services/pcp-dynamic-plan-service/**/*
|
||||
- services/pcp-gateway-service/**/*
|
||||
- libs/pcp-types-lib/**/*
|
||||
- libs/ballistics-lib/**/*
|
||||
- build.gradle.kts
|
||||
@@ -127,6 +132,7 @@ workflow:
|
||||
- helm/pcp-tgu-service/**/*
|
||||
- helm/pcp-tgu-ui-service/**/*
|
||||
- helm/pcp-dynamic-plan-service/**/*
|
||||
- helm/pcp-gateway-service/**/*
|
||||
- when: never
|
||||
|
||||
default:
|
||||
@@ -168,3 +174,4 @@ include:
|
||||
- local: .gitlab/ci/pcp-tgu-service.yml
|
||||
- local: .gitlab/ci/pcp-tgu-ui-service.yml
|
||||
- local: .gitlab/ci/pcp-dynamic-plan-service.yml
|
||||
- local: .gitlab/ci/pcp-gateway-service.yml
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
variables:
|
||||
GRADLE_USER_HOME: "$CI_PROJECT_DIR/.gradle"
|
||||
|
||||
GATEWAY_SERVICE_DIR: "services/pcp-gateway-service"
|
||||
GATEWAY_HELM_CHART_DIR: "helm/pcp-gateway-service"
|
||||
GATEWAY_HELM_RELEASE: "pcp-gateway-service"
|
||||
GATEWAY_IMAGE_REPOSITORY: "$INTERNAL_REGISTRY/pcp-gateway-service"
|
||||
GATEWAY_IMAGE_TAG: "$CI_COMMIT_SHORT_SHA"
|
||||
GATEWAY_K8S_NAMESPACE_DEV: "pcp-dev"
|
||||
|
||||
.gateway_changes: &gateway_changes
|
||||
- services/pcp-gateway-service/**/*
|
||||
- build.gradle.kts
|
||||
- settings.gradle.kts
|
||||
- .gitlab/ci/pcp-gateway-service.yml
|
||||
- helm/pcp-gateway-service/**/*
|
||||
- deploy/**/*
|
||||
|
||||
.gateway:rules:build-and-image:
|
||||
rules:
|
||||
- if: '$RUN_ALL == "true"'
|
||||
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
||||
changes: *gateway_changes
|
||||
- if: '$CI_COMMIT_BRANCH == "dev"'
|
||||
changes: *gateway_changes
|
||||
- if: '$CI_COMMIT_BRANCH == "master"'
|
||||
changes: *gateway_changes
|
||||
- when: never
|
||||
|
||||
.gateway:rules:test:
|
||||
rules:
|
||||
- if: '$RUN_ALL == "true"'
|
||||
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
||||
changes: *gateway_changes
|
||||
- if: '$CI_COMMIT_BRANCH == "dev"'
|
||||
changes: *gateway_changes
|
||||
when: manual
|
||||
- if: '$CI_COMMIT_BRANCH == "master"'
|
||||
changes: *gateway_changes
|
||||
- when: never
|
||||
|
||||
.gateway:rules:deploy-dev:
|
||||
rules:
|
||||
- if: '$RUN_ALL == "true"'
|
||||
when: manual
|
||||
- if: '$CI_COMMIT_BRANCH == "dev"'
|
||||
changes: *gateway_changes
|
||||
when: manual
|
||||
- when: never
|
||||
|
||||
.gateway:gradle-cache:
|
||||
cache:
|
||||
key: "gradle-gateway-$CI_DEFAULT_BRANCH"
|
||||
paths:
|
||||
- .gradle/wrapper
|
||||
- .gradle/caches
|
||||
policy: pull-push
|
||||
|
||||
.gateway:docker-build:
|
||||
image: repo.nstart.cloud/library/docker:26
|
||||
services:
|
||||
- name: repo.nstart.cloud/library/docker:26-dind
|
||||
alias: docker
|
||||
command: ["--tls=false", "--insecure-registry=registry.k8s.265.nstart.local"]
|
||||
variables:
|
||||
DOCKER_HOST: tcp://docker:2375
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
DOCKER_BUILDKIT: "1"
|
||||
before_script:
|
||||
- docker version
|
||||
- docker info
|
||||
|
||||
.gateway:helm-deploy:
|
||||
image: repo.nstart.cloud/dtzar/helm-kubectl:3.14.0
|
||||
before_script:
|
||||
- mkdir -p /root/.kube
|
||||
- helm version
|
||||
after_script:
|
||||
- rm -f /root/.kube/config
|
||||
|
||||
gateway:test:
|
||||
stage: test
|
||||
image: repo.nstart.cloud/library/gradle:jdk21-ubi10
|
||||
extends:
|
||||
- .gateway:rules:test
|
||||
- .gateway:gradle-cache
|
||||
script:
|
||||
- gradle --no-daemon :services:pcp-gateway-service:test
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
junit:
|
||||
- services/pcp-gateway-service/build/test-results/test/*.xml
|
||||
paths:
|
||||
- services/pcp-gateway-service/build/reports/tests/
|
||||
expire_in: 7 days
|
||||
|
||||
gateway:build:
|
||||
stage: build
|
||||
image: repo.nstart.cloud/library/gradle:jdk21-ubi10
|
||||
extends:
|
||||
- .gateway:rules:build-and-image
|
||||
- .gateway:gradle-cache
|
||||
needs:
|
||||
- job: gateway:test
|
||||
artifacts: true
|
||||
script:
|
||||
- gradle --no-daemon :services:pcp-gateway-service:bootJar
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- services/pcp-gateway-service/build/libs/*.jar
|
||||
expire_in: 7 days
|
||||
|
||||
gateway:package:
|
||||
stage: package
|
||||
extends:
|
||||
- .gateway:rules:build-and-image
|
||||
- .gateway:docker-build
|
||||
needs:
|
||||
- job: gateway:build
|
||||
artifacts: true
|
||||
script:
|
||||
- 'echo "GATEWAY_IMAGE_REPOSITORY=$GATEWAY_IMAGE_REPOSITORY"'
|
||||
- |
|
||||
JAR_COUNT="$(find "$GATEWAY_SERVICE_DIR/build/libs" -maxdepth 1 -type f -name '*.jar' ! -name '*-plain.jar' | wc -l)"
|
||||
|
||||
if [ "$JAR_COUNT" -ne 1 ]; then
|
||||
echo "Expected exactly one executable jar, found: $JAR_COUNT"
|
||||
find "$GATEWAY_SERVICE_DIR/build/libs" -maxdepth 1 -type f -name '*.jar' -print || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
JAR_FILE="$(find "$GATEWAY_SERVICE_DIR/build/libs" -maxdepth 1 -type f -name '*.jar' ! -name '*-plain.jar' | head -n 1)"
|
||||
- rm -rf docker-context
|
||||
- mkdir -p docker-context/build/libs
|
||||
- cp "$GATEWAY_SERVICE_DIR/Dockerfile" docker-context/Dockerfile
|
||||
- cp "$JAR_FILE" docker-context/build/libs/app.jar
|
||||
- find docker-context -maxdepth 4 -type f -print -exec ls -la {} \;
|
||||
- docker build --file docker-context/Dockerfile --tag "$GATEWAY_IMAGE_REPOSITORY:$GATEWAY_IMAGE_TAG" docker-context
|
||||
- docker push "$GATEWAY_IMAGE_REPOSITORY:$GATEWAY_IMAGE_TAG"
|
||||
- printf "GATEWAY_IMAGE=%s\n" "$GATEWAY_IMAGE_REPOSITORY:$GATEWAY_IMAGE_TAG" > gateway-image.env
|
||||
artifacts:
|
||||
reports:
|
||||
dotenv: gateway-image.env
|
||||
expire_in: 7 days
|
||||
|
||||
gateway:deploy:dev:
|
||||
stage: deploy
|
||||
extends:
|
||||
- .gateway:rules:deploy-dev
|
||||
- .gateway:helm-deploy
|
||||
needs:
|
||||
- job: gateway:package
|
||||
artifacts: true
|
||||
environment:
|
||||
name: dev/pcp-gateway-service
|
||||
script:
|
||||
- |
|
||||
if [ -n "${KUBE_CONFIG_DEV:-}" ]; then
|
||||
printf '%s' "$KUBE_CONFIG_DEV" > /root/.kube/config
|
||||
elif [ -n "${KUBE_CONFIG_DEV_B64:-}" ]; then
|
||||
if printf '%s' "$KUBE_CONFIG_DEV_B64" | grep -qE '(^apiVersion:|^kind: Config|^clusters:)'; then
|
||||
printf '%s' "$KUBE_CONFIG_DEV_B64" > /root/.kube/config
|
||||
elif ! printf '%s' "$KUBE_CONFIG_DEV_B64" | base64 -d > /root/.kube/config; then
|
||||
echo "KUBE_CONFIG_DEV_B64 is not valid base64. Set KUBE_CONFIG_DEV to raw kubeconfig or KUBE_CONFIG_DEV_B64 to base64 kubeconfig."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "KUBE_CONFIG_DEV or KUBE_CONFIG_DEV_B64 must be set."
|
||||
exit 1
|
||||
fi
|
||||
- chmod 600 /root/.kube/config
|
||||
- export KUBECONFIG=/root/.kube/config
|
||||
- 'export IMAGE_REPOSITORY="${GATEWAY_IMAGE%:*}"'
|
||||
- 'export IMAGE_TAG="${GATEWAY_IMAGE##*:}"'
|
||||
- 'echo "Deploy image: $IMAGE_REPOSITORY:$IMAGE_TAG"'
|
||||
- >
|
||||
helm upgrade --install "$GATEWAY_HELM_RELEASE"
|
||||
"$GATEWAY_HELM_CHART_DIR"
|
||||
--namespace "$GATEWAY_K8S_NAMESPACE_DEV"
|
||||
--create-namespace
|
||||
--values "$GATEWAY_HELM_CHART_DIR/values.yaml"
|
||||
--values "$GATEWAY_HELM_CHART_DIR/values-dev.yaml"
|
||||
--set-string image.repository="$IMAGE_REPOSITORY"
|
||||
--set-string image.tag="$IMAGE_TAG"
|
||||
--set-string app.profile=dev
|
||||
--set-string app.configLabel=dev
|
||||
--atomic
|
||||
--wait
|
||||
--timeout 15m
|
||||
+6
-6
@@ -16,18 +16,18 @@ allprojects {
|
||||
group = "space.nstart.pcp"
|
||||
ext.set("kotlinVersion", "2.2.20")
|
||||
repositories {
|
||||
maven {
|
||||
url = uri("https://repo.nstart.cloud/repository/maven-proxy/")
|
||||
}
|
||||
// maven {
|
||||
// url = uri("https://repo.nstart.cloud/repository/maven-proxy/")
|
||||
// }
|
||||
mavenCentral {
|
||||
content {
|
||||
includeGroup("org.jacoco")
|
||||
includeGroup("org.ow2.asm")
|
||||
}
|
||||
}
|
||||
// mavenCentral()
|
||||
// mavenLocal()
|
||||
// gradlePluginPortal()
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
gradlePluginPortal()
|
||||
maven { url = uri("https://jitpack.io") }
|
||||
|
||||
exclusiveContent {
|
||||
|
||||
@@ -29,6 +29,7 @@ pcp:
|
||||
coverage-scheme: 8080
|
||||
satellite-catalog: 8080
|
||||
dynamic-plan: 8080
|
||||
gateway: 8080
|
||||
|
||||
services:
|
||||
config: http://${pcp.network.host}:${pcp.ports.config}
|
||||
@@ -47,6 +48,7 @@ pcp:
|
||||
coverage-scheme: http://pcp-coverage-scheme-service:${pcp.ports.coverage-scheme}
|
||||
satellite-catalog: http://pcp-satellite-catalog-service:${pcp.ports.satellite-catalog}
|
||||
dynamic-plan: http://pcp-dynamic-plan-service:${pcp.ports.dynamic-plan}
|
||||
gateway: http://pcp-gateway-service:${pcp.ports.gateway}
|
||||
|
||||
spring:
|
||||
boot:
|
||||
|
||||
@@ -27,6 +27,7 @@ pcp:
|
||||
coverage-scheme: 7012
|
||||
satellite-catalog: 7013
|
||||
dynamic-plan: 7014
|
||||
gateway: 7080
|
||||
|
||||
services:
|
||||
config: http://spring-cloud-config-server:${pcp.ports.config}
|
||||
@@ -45,6 +46,7 @@ pcp:
|
||||
coverage-scheme: http://pcp-coverage-scheme-service:${pcp.ports.coverage-scheme}
|
||||
satellite-catalog: http://pcp-satellite-catalog-service:${pcp.ports.satellite-catalog}
|
||||
dynamic-plan: http://pcp-dynamic-plan-service:${pcp.ports.dynamic-plan}
|
||||
gateway: http://pcp-gateway-service:${pcp.ports.gateway}
|
||||
|
||||
spring:
|
||||
kafka:
|
||||
|
||||
@@ -31,6 +31,7 @@ pcp:
|
||||
coverage-scheme: 7012
|
||||
satellite-catalog: 7013
|
||||
dynamic-plan: 7014
|
||||
gateway: 7080
|
||||
|
||||
services:
|
||||
config: http://${pcp.network.host}:${pcp.ports.config}
|
||||
@@ -49,6 +50,7 @@ pcp:
|
||||
coverage-scheme: http://${pcp.network.host}:${pcp.ports.coverage-scheme}
|
||||
satellite-catalog: http://${pcp.network.host}:${pcp.ports.satellite-catalog}
|
||||
dynamic-plan: http://${pcp.network.host}:${pcp.ports.dynamic-plan}
|
||||
gateway: http://${pcp.network.host}:${pcp.ports.gateway}
|
||||
|
||||
spring:
|
||||
boot:
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
spring:
|
||||
boot:
|
||||
admin:
|
||||
client:
|
||||
instance:
|
||||
service-base-url: ${pcp.services.gateway}
|
||||
management-base-url: ${pcp.services.gateway}
|
||||
cloud:
|
||||
gateway:
|
||||
server:
|
||||
# WebFlux-вариант Spring Cloud Gateway (Boot 4 / Spring Cloud 2025.1).
|
||||
webflux:
|
||||
routes:
|
||||
# --- Доменные сервисы. Префикс /api/pcp-<x> СРЕЗАЕТСЯ (StripPrefix=2 убирает
|
||||
# 2 сегмента: api + pcp-<x>), т.е. /api/pcp-tgu/api/plans -> бэкенд /api/plans.
|
||||
# Это ровно семантика прежнего vite-rewrite. Цели берём из реестра pcp.services.*.
|
||||
- id: tgu
|
||||
uri: ${pcp.services.tgu}
|
||||
predicates:
|
||||
- Path=/api/pcp-tgu/**
|
||||
filters:
|
||||
- StripPrefix=2
|
||||
- id: ballistics
|
||||
uri: ${pcp.services.ballistics}
|
||||
predicates:
|
||||
- Path=/api/pcp-ballistics/**
|
||||
filters:
|
||||
- StripPrefix=2
|
||||
- id: mission
|
||||
uri: ${pcp.services.mission}
|
||||
predicates:
|
||||
- Path=/api/pcp-mission/**
|
||||
filters:
|
||||
- StripPrefix=2
|
||||
- id: request
|
||||
uri: ${pcp.services.request}
|
||||
predicates:
|
||||
- Path=/api/pcp-request/**
|
||||
filters:
|
||||
- StripPrefix=2
|
||||
- id: complex
|
||||
uri: ${pcp.services.complex-mission-service}
|
||||
predicates:
|
||||
- Path=/api/pcp-complex/**
|
||||
filters:
|
||||
- StripPrefix=2
|
||||
# --- Станции: путь СОХРАНЯЕМ (в vite было без rewrite) — без StripPrefix.
|
||||
- id: stations
|
||||
uri: ${pcp.services.stations}
|
||||
predicates:
|
||||
- Path=/api/stations/**
|
||||
# --- Общий catch-all /api/** -> ui-service. Матчится ПОСЛЕДНИМ (order выше).
|
||||
- id: ui-catch-all
|
||||
uri: ${pcp.services.ui}
|
||||
predicates:
|
||||
- Path=/api/**
|
||||
order: 1
|
||||
|
||||
# Валидация JWT на edge. По умолчанию ВЫКЛЮЧЕНА (anonymous, как сейчас работает фронт).
|
||||
# Для закрытого контура: GATEWAY_JWT_ENABLED=true И задать issuer через env
|
||||
# SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI=<realm new-start>.
|
||||
# Issuer намеренно НЕ объявлен здесь: пустое значение заставило бы автоконфиг поднимать
|
||||
# JwtDecoder и падать на старте.
|
||||
gateway:
|
||||
security:
|
||||
jwt-enabled: ${GATEWAY_JWT_ENABLED:false}
|
||||
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: health,info,metrics,prometheus
|
||||
|
||||
---
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: local
|
||||
server:
|
||||
port: ${pcp.ports.gateway:7080}
|
||||
|
||||
---
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: dev
|
||||
server:
|
||||
port: ${pcp.ports.gateway:8080}
|
||||
@@ -182,6 +182,14 @@ services:
|
||||
ports:
|
||||
- "${PCP_DYNAMIC_PLAN_PORT:-7014}:7014"
|
||||
|
||||
pcp-gateway-service:
|
||||
<<: *pcp-service-common
|
||||
image: pcp/pcp-gateway-service:${PCP_IMAGE_TAG:-local}
|
||||
environment:
|
||||
<<: *pcp-service-env
|
||||
ports:
|
||||
- "${PCP_GATEWAY_PORT:-7080}:7080"
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
kafka-data:
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
apiVersion: v2
|
||||
name: pcp-gateway-service
|
||||
description: Helm chart for deploying pcp-gateway-service from GitLab CI/CD.
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "1.0.0"
|
||||
@@ -0,0 +1,18 @@
|
||||
{{- define "pcp-gateway-service.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "pcp-gateway-service.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- include "pcp-gateway-service.name" . | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "pcp-gateway-service.labels" -}}
|
||||
app.kubernetes.io/name: {{ include "pcp-gateway-service.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end -}}
|
||||
@@ -0,0 +1,68 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "pcp-gateway-service.fullname" . }}
|
||||
labels:
|
||||
{{- include "pcp-gateway-service.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "pcp-gateway-service.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "pcp-gateway-service.labels" . | nindent 8 }}
|
||||
{{- with .Values.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.image.pullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- range . }}
|
||||
- name: {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: {{ include "pcp-gateway-service.name" . }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.service.port }}
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: SPRING_PROFILES_ACTIVE
|
||||
value: {{ .Values.app.profile | quote }}
|
||||
- name: CONFIG_SERVER_URI
|
||||
value: {{ .Values.app.configServerUri | quote }}
|
||||
- name: SPRING_CLOUD_CONFIG_LABEL
|
||||
value: {{ .Values.app.configLabel | quote }}
|
||||
- name: CONFIG_SERVER_FAIL_FAST
|
||||
value: {{ .Values.app.configServerFailFast | quote }}
|
||||
- name: SERVER_PORT
|
||||
value: {{ .Values.service.port | quote }}
|
||||
{{- with .Values.extraEnv }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: http
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 15
|
||||
timeoutSeconds: 5
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: http
|
||||
initialDelaySeconds: 40
|
||||
periodSeconds: 20
|
||||
timeoutSeconds: 5
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
@@ -0,0 +1,31 @@
|
||||
{{- if .Values.ingress.enabled -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "pcp-gateway-service.fullname" . }}
|
||||
labels:
|
||||
{{- include "pcp-gateway-service.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.className }}
|
||||
ingressClassName: {{ .Values.ingress.className | quote }}
|
||||
{{- end }}
|
||||
{{- with .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
rules:
|
||||
- host: {{ .Values.ingress.host | quote }}
|
||||
http:
|
||||
paths:
|
||||
- path: {{ .Values.ingress.path | quote }}
|
||||
pathType: {{ .Values.ingress.pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "pcp-gateway-service.fullname" . }}
|
||||
port:
|
||||
number: {{ .Values.service.port }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,16 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "pcp-gateway-service.fullname" . }}
|
||||
labels:
|
||||
{{- include "pcp-gateway-service.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ include "pcp-gateway-service.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
ports:
|
||||
- name: http
|
||||
port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
@@ -0,0 +1,10 @@
|
||||
app:
|
||||
profile: dev
|
||||
configLabel: dev
|
||||
|
||||
service:
|
||||
port: 8080
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
host: pcp-gateway-service.dev.k8s.264.nstart.cloud
|
||||
@@ -0,0 +1,10 @@
|
||||
app:
|
||||
profile: master
|
||||
configLabel: master
|
||||
|
||||
service:
|
||||
port: 8080
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
host: pcp-gateway-service.master.k8s.264.nstart.cloud
|
||||
@@ -0,0 +1,36 @@
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: registry.example.com/pcp/pcp-gateway-service
|
||||
tag: latest
|
||||
pullPolicy: IfNotPresent
|
||||
pullSecrets: []
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8080
|
||||
|
||||
app:
|
||||
profile: master
|
||||
configServerUri: "http://spring-cloud-config-server:38888"
|
||||
configServerFailFast: "true"
|
||||
configLabel: master
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
className: ""
|
||||
annotations: {}
|
||||
host: ""
|
||||
path: /
|
||||
pathType: Prefix
|
||||
tls: []
|
||||
|
||||
extraEnv: []
|
||||
|
||||
resources: {}
|
||||
|
||||
podAnnotations: {}
|
||||
podLabels: {}
|
||||
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
@@ -0,0 +1,9 @@
|
||||
ARG RUNTIME_IMAGE=repo.nstart.cloud/bellsoft/liberica-openjre-alpine:21.0.5
|
||||
FROM ${RUNTIME_IMAGE}
|
||||
|
||||
ENV JAVA_OPTS=""
|
||||
|
||||
ADD ./build/libs/*.jar /app.jar
|
||||
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app.jar"]
|
||||
@@ -0,0 +1,50 @@
|
||||
group = "space.nstart.pcp"
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
kotlin("plugin.spring")
|
||||
id("org.springframework.boot")
|
||||
id("io.spring.dependency-management")
|
||||
}
|
||||
|
||||
version = "0.0.1"
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of((property("versions.java") as String).toInt())
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
freeCompilerArgs.addAll("-Xjsr305=strict")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Реактивный edge: Spring Cloud Gateway (WebFlux-вариант) + конфиг из config-server.
|
||||
// Маршруты живут в config-repo/pcp-gateway-service.yaml — единый источник правды.
|
||||
implementation("org.springframework.cloud:spring-cloud-starter-gateway-server-webflux")
|
||||
implementation("org.springframework.cloud:spring-cloud-starter-config")
|
||||
implementation("org.springframework.boot:spring-boot-starter-actuator")
|
||||
// Валидация JWT на edge (Keycloak/new-start-id) — включается флагом gateway.security.jwt-enabled.
|
||||
// Тянет reactive Spring Security (ServerHttpSecurity/@EnableWebFluxSecurity).
|
||||
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
|
||||
runtimeOnly("io.micrometer:micrometer-registry-prometheus")
|
||||
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("versions.spring.cloud")}")
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package space.nstart.pcp_gateway_service
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.runApplication
|
||||
|
||||
/**
|
||||
* Единая точка входа в бэкенд для фронта (pcp-tgu-ui-service): reverse-proxy поверх
|
||||
* микросервисов. Маршрутная таблица — в config-repo/pcp-gateway-service.yaml и ссылается
|
||||
* на реестр `pcp.services.*`, так что топологию знает только gateway, а не браузер.
|
||||
*/
|
||||
@SpringBootApplication
|
||||
class GatewayApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
runApplication<GatewayApplication>(*args)
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package space.nstart.pcp_gateway_service.config
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.http.HttpMethod
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain
|
||||
|
||||
/**
|
||||
* Политика edge. Две взаимоисключающие цепочки, переключаемые флагом
|
||||
* `gateway.security.jwt-enabled` (завязан на режим входа фронта):
|
||||
* - выключено (anonymous, текущий дефолт) — пропускаем всё: поведение как при прямых вызовах;
|
||||
* - включено (закрытый контур new-start-id) — валидируем Bearer JWT один раз здесь, дальше
|
||||
* gateway по умолчанию пробрасывает заголовок Authorization вниз к сервисам.
|
||||
*
|
||||
* Когда JWT выключен, `spring.security.oauth2.resourceserver.jwt.issuer-uri` не задаётся,
|
||||
* поэтому JwtDecoder не создаётся и старт не падает из-за пустого issuer.
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebFluxSecurity
|
||||
class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = "gateway.security", name = ["jwt-enabled"], havingValue = "true")
|
||||
fun securedChain(http: ServerHttpSecurity): SecurityWebFilterChain =
|
||||
http
|
||||
.csrf { it.disable() }
|
||||
.authorizeExchange { exchanges ->
|
||||
exchanges
|
||||
.pathMatchers(HttpMethod.OPTIONS).permitAll()
|
||||
.pathMatchers("/healthz", "/actuator/**").permitAll()
|
||||
.anyExchange().authenticated()
|
||||
}
|
||||
.oauth2ResourceServer { it.jwt {} }
|
||||
.build()
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(
|
||||
prefix = "gateway.security",
|
||||
name = ["jwt-enabled"],
|
||||
havingValue = "false",
|
||||
matchIfMissing = true,
|
||||
)
|
||||
fun openChain(http: ServerHttpSecurity): SecurityWebFilterChain =
|
||||
http
|
||||
.csrf { it.disable() }
|
||||
.authorizeExchange { it.anyExchange().permitAll() }
|
||||
.build()
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
spring:
|
||||
application:
|
||||
name: pcp-gateway-service
|
||||
profiles:
|
||||
default: local
|
||||
config:
|
||||
import: "configserver:"
|
||||
cloud:
|
||||
config:
|
||||
uri: ${CONFIG_SERVER_URI:http://localhost:8888}
|
||||
fail-fast: ${CONFIG_SERVER_FAIL_FAST:true}
|
||||
profile: ${SPRING_CLOUD_CONFIG_PROFILE:${SPRING_PROFILES_ACTIVE:${spring.profiles.default}}}
|
||||
label: ${SPRING_CLOUD_CONFIG_LABEL:master}
|
||||
@@ -21,64 +21,14 @@ server {
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# --- ТГУ: маршрутизация на бэкенды (зеркало server.proxy из vite.config.ts).
|
||||
# СЕМАНТИКА (важно повторить точно, иначе бэкенды получат неверный путь):
|
||||
# - префиксы pcp-* СРЕЗАЮТСЯ: trailing-slash в proxy_pass отбрасывает префикс
|
||||
# location (как rewrite в vite). Пример: /api/pcp-tgu/api/plans → бэкенд /api/plans.
|
||||
# - /api/stations путь СОХРАНЯЕТ (в vite без rewrite): proxy_pass без URI-части.
|
||||
# - общий /api/ — catch-all (tgu-planning, current-plans, auth) на ui-service/gateway.
|
||||
# Порядок важен: специфичные префиксы идут РАНЬШЕ общего /api/.
|
||||
# Цели (UPSTREAM_*) — заглушки: подставьте реальные адреса кластера ЛИБО перенесите
|
||||
# маршрутизацию на gateway/ingress. Порты dev (vite) даны как ориентир в комментариях.
|
||||
# Раскомментируйте после подстановки реальных upstream (нерезолвимый хост ломает старт nginx).
|
||||
# Заголовки proxy_set_header в каждом блоке — те же, что в активном /api/ ниже.
|
||||
#
|
||||
# location /api/pcp-request/ { # dev :7005
|
||||
# proxy_pass http://UPSTREAM_REQUEST/;
|
||||
# proxy_set_header Host $host;
|
||||
# proxy_set_header X-Real-IP $remote_addr;
|
||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||
# }
|
||||
# location /api/pcp-ballistics/ { # dev :7003
|
||||
# proxy_pass http://UPSTREAM_BALLISTICS/;
|
||||
# proxy_set_header Host $host;
|
||||
# proxy_set_header X-Real-IP $remote_addr;
|
||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||
# }
|
||||
# location /api/pcp-mission/ { # dev :7010
|
||||
# proxy_pass http://UPSTREAM_MISSION/;
|
||||
# proxy_set_header Host $host;
|
||||
# proxy_set_header X-Real-IP $remote_addr;
|
||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||
# }
|
||||
# location /api/pcp-tgu/ { # dev :7011
|
||||
# proxy_pass http://UPSTREAM_TGU/;
|
||||
# proxy_set_header Host $host;
|
||||
# proxy_set_header X-Real-IP $remote_addr;
|
||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||
# }
|
||||
# location /api/pcp-complex/ { # dev :7002
|
||||
# proxy_pass http://UPSTREAM_COMPLEX/;
|
||||
# proxy_set_header Host $host;
|
||||
# proxy_set_header X-Real-IP $remote_addr;
|
||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||
# }
|
||||
# location /api/stations/ { # dev :7009 — путь СОХРАНЯЕМ (proxy_pass без / и без URI)
|
||||
# proxy_pass http://UPSTREAM_STATIONS;
|
||||
# proxy_set_header Host $host;
|
||||
# proxy_set_header X-Real-IP $remote_addr;
|
||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||
# }
|
||||
#
|
||||
# Общий catch-all. В деве это ui-service (:7008): /api/tgu-planning, /api/current-plans, /api/auth.
|
||||
# --- ТГУ: вся маршрутизация /api/* уходит на gateway (Spring Cloud Gateway).
|
||||
# Gateway сам срезает префиксы pcp-* (StripPrefix) и выбирает бэкенд —
|
||||
# см. config-repo/pcp-gateway-service.yaml. Здесь прозрачный reverse-proxy:
|
||||
# proxy_pass БЕЗ URI-части → путь /api/... передаётся gateway без изменений
|
||||
# (он разбирает его сам). Это заменяет прежний набор per-service location'ов.
|
||||
# Адрес gateway в кластере — pcp-gateway-service:8080 (dev/master-профиль).
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:8000/api/; # ЗАГЛУШКА: замените на ui-service/gateway
|
||||
proxy_pass http://pcp-gateway-service:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
@@ -21,40 +21,12 @@ export default defineConfig({
|
||||
server: {
|
||||
host: '0.0.0.0',
|
||||
port: 5174,
|
||||
// ТГУ ходит в несколько бэкендов через префиксы. В проде эти маршруты
|
||||
// повторяются в nginx.conf (зеркало) либо на gateway/ingress.
|
||||
// Всё /api/* уходит на gateway (Spring Cloud Gateway, dev :7080). Gateway сам
|
||||
// срезает префиксы pcp-* (StripPrefix) и выбирает бэкенд — ровно то, что раньше
|
||||
// делали правила-зеркала здесь. В проде то же делает nginx.conf.
|
||||
proxy: {
|
||||
'/api/pcp-request': {
|
||||
target: 'http://localhost:7005',
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/api\/pcp-request/, ''),
|
||||
},
|
||||
'/api/pcp-ballistics': {
|
||||
target: 'http://localhost:7003',
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/api\/pcp-ballistics/, ''),
|
||||
},
|
||||
'/api/pcp-mission': {
|
||||
target: 'http://localhost:7010',
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/api\/pcp-mission/, ''),
|
||||
},
|
||||
'/api/pcp-tgu': {
|
||||
target: 'http://localhost:7011',
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/api\/pcp-tgu/, ''),
|
||||
},
|
||||
'/api/pcp-complex': {
|
||||
target: 'http://localhost:7002',
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/api\/pcp-complex/, ''),
|
||||
},
|
||||
'/api/stations': {
|
||||
target: 'http://localhost:7009',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/api': {
|
||||
target: 'http://localhost:7008',
|
||||
target: 'http://localhost:7080',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -24,6 +24,7 @@ include(":services:pcp-coverage-scheme-service")
|
||||
include(":services:pcp-dynamic-plan-service")
|
||||
include(":services:spring-cloud-config-server")
|
||||
include(":services:pcp-srpring-boot-admin-server")
|
||||
include(":services:pcp-gateway-service")
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
|
||||
Reference in New Issue
Block a user