diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6b07e94f4..1a7004010 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,7 +17,10 @@ variables: AWS_ACCESS_KEY_ID: $SCW_ACCESS_KEY AWS_SECRET_ACCESS_KEY: $SCW_SECRET_KEY RUSTC_WRAPPER: /usr/local/bin/sccache - REGISTRY: ${CI_REGISTRY_IMAGE} + # External: git.fxhnt.ai:5050/root/foxhunt (via Tailscale — not reachable from pods) + # Internal: gitlab-registry.foxhunt.svc.cluster.local:5000 (HTTP, reachable from pods) + INTERNAL_REGISTRY: gitlab-registry.foxhunt.svc.cluster.local:5000 + REGISTRY: ${INTERNAL_REGISTRY}/root/foxhunt # Base template for Rust jobs .rust-base: @@ -63,11 +66,12 @@ test: entrypoint: [""] tags: - kapsule + - docker rules: - if: $CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "push" before_script: - mkdir -p /kaniko/.docker - - echo "{\"auths\":{\"${CI_REGISTRY}\":{\"auth\":\"$(printf '%s:%s' "${CI_REGISTRY_USER}" "${CI_REGISTRY_PASSWORD}" | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json + - echo "{\"auths\":{\"${INTERNAL_REGISTRY}\":{\"auth\":\"$(printf '%s:%s' "${CI_REGISTRY_USER}" "${CI_REGISTRY_PASSWORD}" | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json build-trading-service: extends: .kaniko-base @@ -75,6 +79,7 @@ build-trading-service: - /kaniko/executor --context "${CI_PROJECT_DIR}" --dockerfile "${CI_PROJECT_DIR}/infra/docker/Dockerfile.service" + --insecure-registry "${INTERNAL_REGISTRY}" --build-arg SERVICE=trading_service --build-arg SCCACHE_BUCKET=${SCCACHE_BUCKET} --build-arg AWS_ACCESS_KEY_ID=${SCW_ACCESS_KEY} @@ -89,6 +94,7 @@ build-api-gateway: - /kaniko/executor --context "${CI_PROJECT_DIR}" --dockerfile "${CI_PROJECT_DIR}/infra/docker/Dockerfile.service" + --insecure-registry "${INTERNAL_REGISTRY}" --build-arg SERVICE=api_gateway --build-arg SCCACHE_BUCKET=${SCCACHE_BUCKET} --build-arg AWS_ACCESS_KEY_ID=${SCW_ACCESS_KEY} @@ -103,6 +109,7 @@ build-broker-gateway: - /kaniko/executor --context "${CI_PROJECT_DIR}" --dockerfile "${CI_PROJECT_DIR}/infra/docker/Dockerfile.service" + --insecure-registry "${INTERNAL_REGISTRY}" --build-arg SERVICE=broker_gateway_service --build-arg SCCACHE_BUCKET=${SCCACHE_BUCKET} --build-arg AWS_ACCESS_KEY_ID=${SCW_ACCESS_KEY} @@ -117,6 +124,7 @@ build-ml-training: - /kaniko/executor --context "${CI_PROJECT_DIR}" --dockerfile "${CI_PROJECT_DIR}/infra/docker/Dockerfile.service" + --insecure-registry "${INTERNAL_REGISTRY}" --build-arg SERVICE=ml_training_service --build-arg SCCACHE_BUCKET=${SCCACHE_BUCKET} --build-arg AWS_ACCESS_KEY_ID=${SCW_ACCESS_KEY} @@ -131,6 +139,7 @@ build-backtesting: - /kaniko/executor --context "${CI_PROJECT_DIR}" --dockerfile "${CI_PROJECT_DIR}/infra/docker/Dockerfile.service" + --insecure-registry "${INTERNAL_REGISTRY}" --build-arg SERVICE=backtesting_service --build-arg SCCACHE_BUCKET=${SCCACHE_BUCKET} --build-arg AWS_ACCESS_KEY_ID=${SCW_ACCESS_KEY} @@ -145,6 +154,7 @@ build-trading-agent: - /kaniko/executor --context "${CI_PROJECT_DIR}" --dockerfile "${CI_PROJECT_DIR}/infra/docker/Dockerfile.service" + --insecure-registry "${INTERNAL_REGISTRY}" --build-arg SERVICE=trading_agent_service --build-arg SCCACHE_BUCKET=${SCCACHE_BUCKET} --build-arg AWS_ACCESS_KEY_ID=${SCW_ACCESS_KEY} @@ -153,12 +163,28 @@ build-trading-agent: --destination "${REGISTRY}/trading_agent_service:${CI_COMMIT_SHA}" --destination "${REGISTRY}/trading_agent_service:latest" +build-data-acquisition: + extends: .kaniko-base + script: + - /kaniko/executor + --context "${CI_PROJECT_DIR}" + --dockerfile "${CI_PROJECT_DIR}/infra/docker/Dockerfile.service" + --insecure-registry "${INTERNAL_REGISTRY}" + --build-arg SERVICE=data_acquisition_service + --build-arg SCCACHE_BUCKET=${SCCACHE_BUCKET} + --build-arg AWS_ACCESS_KEY_ID=${SCW_ACCESS_KEY} + --build-arg AWS_SECRET_ACCESS_KEY=${SCW_SECRET_KEY} + --build-arg SCCACHE_ENDPOINT=${SCCACHE_ENDPOINT} + --destination "${REGISTRY}/data_acquisition_service:${CI_COMMIT_SHA}" + --destination "${REGISTRY}/data_acquisition_service:latest" + build-web-gateway: extends: .kaniko-base script: - /kaniko/executor --context "${CI_PROJECT_DIR}" --dockerfile "${CI_PROJECT_DIR}/infra/docker/Dockerfile.web-gateway" + --insecure-registry "${INTERNAL_REGISTRY}" --destination "${REGISTRY}/web-gateway:${CI_COMMIT_SHA}" --destination "${REGISTRY}/web-gateway:latest" @@ -168,6 +194,7 @@ build-training: - /kaniko/executor --context "${CI_PROJECT_DIR}" --dockerfile "${CI_PROJECT_DIR}/infra/docker/Dockerfile.training" + --insecure-registry "${INTERNAL_REGISTRY}" --build-arg SCCACHE_BUCKET=${SCCACHE_BUCKET} --build-arg AWS_ACCESS_KEY_ID=${SCW_ACCESS_KEY} --build-arg AWS_SECRET_ACCESS_KEY=${SCW_SECRET_KEY} @@ -190,30 +217,23 @@ deploy: - build-ml-training - build-backtesting - build-trading-agent + - build-data-acquisition - build-web-gateway - build-training rules: - if: $CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "push" before_script: - mkdir -p ~/.kube - - echo "$KUBECONFIG_DATA" | base64 -d > ~/.kube/config + - echo "$KUBECONFIG_B64" | base64 -d > ~/.kube/config - chmod 600 ~/.kube/config environment: name: production kubernetes: namespace: foxhunt script: - # Apply manifests (picks up any config/resource changes) - - kubectl apply -f infra/k8s/databases/ - - kubectl apply -f infra/k8s/services/ # Update images to this commit's build - | - for svc in trading-service api-gateway broker-gateway-service ml-training-service backtesting-service trading-agent-service; do + for svc in trading_service api_gateway broker_gateway_service ml_training_service backtesting_service trading_agent_service data_acquisition_service; do kubectl -n foxhunt set image deployment/${svc} ${svc}=${REGISTRY}/${svc}:${CI_COMMIT_SHA} || true done kubectl -n foxhunt set image deployment/web-gateway web-gateway=${REGISTRY}/web-gateway:${CI_COMMIT_SHA} || true - # Wait for rollouts - - | - for svc in trading-service api-gateway broker-gateway-service ml-training-service backtesting-service trading-agent-service web-gateway; do - kubectl -n foxhunt rollout status deployment/${svc} --timeout=300s || true - done diff --git a/infra/k8s/gitlab/grafana-values.yaml b/infra/k8s/gitlab/grafana-values.yaml new file mode 100644 index 000000000..12f145629 --- /dev/null +++ b/infra/k8s/gitlab/grafana-values.yaml @@ -0,0 +1,61 @@ +# Grafana — Foxhunt monitoring dashboard +# Accessed via Tailscale proxy on port 3000 + +replicas: 1 + +nodeSelector: + k8s.scaleway.com/pool-name: gitlab +tolerations: + - key: gitlab + operator: Equal + value: "true" + effect: NoSchedule + +resources: + requests: + cpu: 50m + memory: 128Mi + limits: + cpu: 200m + memory: 256Mi + +persistence: + enabled: true + size: 2Gi + +adminUser: admin +adminPassword: Welcome01 + +grafana.ini: + server: + root_url: https://grafana.fxhnt.ai + +datasources: + datasources.yaml: + apiVersion: 1 + datasources: + - name: Prometheus + type: prometheus + url: http://gitlab-prometheus-server.foxhunt.svc.cluster.local:80 + access: proxy + isDefault: true + +dashboardProviders: + dashboardproviders.yaml: + apiVersion: 1 + providers: + - name: default + orgId: 1 + folder: GitLab + type: file + disableDeletion: false + editable: true + options: + path: /var/lib/grafana/dashboards/default + +dashboards: + default: + gitlab-overview: + gnetId: 1860 + revision: 37 + datasource: Prometheus diff --git a/infra/k8s/gitlab/tailscale-proxy.yaml b/infra/k8s/gitlab/tailscale-proxy.yaml index 52e8ef357..a06b535fe 100644 --- a/infra/k8s/gitlab/tailscale-proxy.yaml +++ b/infra/k8s/gitlab/tailscale-proxy.yaml @@ -67,6 +67,9 @@ spec: volumeMounts: - name: nginx-conf mountPath: /etc/nginx/conf.d + - name: tls-certs + mountPath: /etc/nginx/certs + readOnly: true resources: requests: cpu: 25m @@ -122,6 +125,9 @@ spec: - name: nginx-conf configMap: name: tailscale-gitlab-nginx + - name: tls-certs + secret: + secretName: gitlab-tls-cert --- apiVersion: v1 kind: ConfigMap @@ -130,10 +136,22 @@ metadata: namespace: foxhunt data: default.conf: | + # HTTP → HTTPS redirect for all subdomains server { listen 80; + server_name *.fxhnt.ai; + return 301 https://$host$request_uri; + } + + # GitLab — git.fxhnt.ai + server { + listen 443 ssl; server_name git.fxhnt.ai; + ssl_certificate /etc/nginx/certs/tls.crt; + ssl_certificate_key /etc/nginx/certs/tls.key; + ssl_protocols TLSv1.2 TLSv1.3; + client_max_body_size 0; location / { @@ -141,7 +159,7 @@ data: proxy_set_header Host $http_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; + proxy_set_header X-Forwarded-Proto https; proxy_buffering off; proxy_request_buffering off; @@ -152,10 +170,15 @@ data: } } + # Container Registry — git.fxhnt.ai:5050 server { - listen 5050; + listen 5050 ssl; server_name git.fxhnt.ai; + ssl_certificate /etc/nginx/certs/tls.crt; + ssl_certificate_key /etc/nginx/certs/tls.key; + ssl_protocols TLSv1.2 TLSv1.3; + client_max_body_size 0; location / { @@ -163,7 +186,7 @@ data: proxy_set_header Host $http_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; + proxy_set_header X-Forwarded-Proto https; proxy_buffering off; proxy_request_buffering off; @@ -172,3 +195,43 @@ data: proxy_send_timeout 3600s; } } + + # Grafana — grafana.fxhnt.ai + server { + listen 443 ssl; + server_name grafana.fxhnt.ai; + + ssl_certificate /etc/nginx/certs/tls.crt; + ssl_certificate_key /etc/nginx/certs/tls.key; + ssl_protocols TLSv1.2 TLSv1.3; + + location / { + proxy_pass http://grafana.foxhunt.svc.cluster.local:80; + proxy_set_header Host $http_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 https; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + } + + # Prometheus — prometheus.fxhnt.ai + server { + listen 443 ssl; + server_name prometheus.fxhnt.ai; + + ssl_certificate /etc/nginx/certs/tls.crt; + ssl_certificate_key /etc/nginx/certs/tls.key; + ssl_protocols TLSv1.2 TLSv1.3; + + location / { + proxy_pass http://gitlab-prometheus-server.foxhunt.svc.cluster.local:80; + proxy_set_header Host $http_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 https; + proxy_http_version 1.1; + } + } diff --git a/infra/k8s/gitlab/values.yaml b/infra/k8s/gitlab/values.yaml index f0f0dbfbd..065a15af8 100644 --- a/infra/k8s/gitlab/values.yaml +++ b/infra/k8s/gitlab/values.yaml @@ -8,8 +8,10 @@ global: domain: fxhnt.ai gitlab: name: git.fxhnt.ai + https: true registry: name: git.fxhnt.ai + https: true ingress: enabled: false configureCertmanager: false diff --git a/infra/live/production/kapsule/terragrunt.hcl b/infra/live/production/kapsule/terragrunt.hcl index acb6977be..ad4524b23 100644 --- a/infra/live/production/kapsule/terragrunt.hcl +++ b/infra/live/production/kapsule/terragrunt.hcl @@ -21,9 +21,9 @@ inputs = { gpu_inference_type = "L4-1-24G" gpu_inference_max_size = 1 - # GitLab CE pool (dedicated for GitLab + Runner manager) + # GitLab CE pool (dedicated for GitLab + Prometheus + Runner manager) enable_gitlab_pool = true - gitlab_type = "DEV1-L" + gitlab_type = "GP1-XS" # CI build pool (ephemeral runner pods, scale-to-zero) enable_ci_build_pool = true