Fix deploy job dependencies and add production deployment (#63)

This commit is contained in:
Mondo Diaz
2026-01-15 15:16:07 -06:00
parent 0ad106a141
commit 823dfcb400
3 changed files with 281 additions and 9 deletions

View File

@@ -124,8 +124,8 @@ python_tests:
- .pip-cache/
policy: pull-push
before_script:
- pip install -r backend/requirements.txt
- pip install pytest pytest-asyncio pytest-cov httpx
- pip install --index-url "$PIP_INDEX_URL" -r backend/requirements.txt
- pip install --index-url "$PIP_INDEX_URL" pytest pytest-asyncio pytest-cov httpx
script:
- cd backend
# Only run unit tests - integration tests require Docker Compose services
@@ -175,7 +175,7 @@ frontend_tests:
# Shared deploy configuration
.deploy_template: &deploy_template
stage: deploy
needs: [build_image, kics, hadolint, python_tests, frontend_tests, secrets]
needs: [build_image, test_image, kics, hadolint, python_tests, frontend_tests, secrets, app_deps_scan, cve_scan, cve_sbom_analysis, app_sbom_analysis]
image: deps.global.bsf.tools/registry-1.docker.io/alpine/k8s:1.29.12
.helm_setup: &helm_setup
@@ -246,8 +246,8 @@ deploy_stage:
--set image.tag=git.linux-amd64-$CI_COMMIT_SHA \
--wait \
--atomic \
--timeout 5m
- kubectl rollout status deployment/orchard-stage-server -n $NAMESPACE --timeout=5m
--timeout 10m
- kubectl rollout status deployment/orchard-stage-server -n $NAMESPACE --timeout=10m
- *verify_deployment
environment:
name: stage
@@ -256,7 +256,7 @@ deploy_stage:
agent: esv/bsf/bsf-integration/orchard/orchard-mvp:orchard-stage
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: always
when: on_success
# Deploy feature branch to dev namespace
deploy_feature:
@@ -282,8 +282,8 @@ deploy_feature:
--set minioIngress.tls.secretName=minio-$CI_COMMIT_REF_SLUG-tls \
--wait \
--atomic \
--timeout 5m
- kubectl rollout status deployment/orchard-$CI_COMMIT_REF_SLUG-server -n $NAMESPACE --timeout=5m
--timeout 10m
- kubectl rollout status deployment/orchard-$CI_COMMIT_REF_SLUG-server -n $NAMESPACE --timeout=10m
- export BASE_URL="https://orchard-$CI_COMMIT_REF_SLUG.common.global.bsf.tools"
- *verify_deployment
environment:
@@ -295,7 +295,7 @@ deploy_feature:
agent: esv/bsf/bsf-integration/orchard/orchard-mvp:orchard
rules:
- if: '$CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != "main"'
when: always
when: on_success
# Cleanup feature branch deployment
cleanup_feature:
@@ -318,3 +318,51 @@ cleanup_feature:
- if: '$CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != "main"'
when: manual
allow_failure: true
# Deploy to production (version tags only, manual approval required)
deploy_prod:
stage: deploy
# For tag pipelines, most jobs don't run (trusting main was tested)
# We only need build_image to have the image available
needs: [build_image]
image: deps.global.bsf.tools/registry-1.docker.io/alpine/k8s:1.29.12
variables:
NAMESPACE: orch-prod-namespace
VALUES_FILE: helm/orchard/values-prod.yaml
BASE_URL: https://orchard.common.global.bsf.tools
before_script:
- kubectl config use-context esv/bsf/bsf-integration/orchard/orchard-mvp:orchard-prod
- *helm_setup
script:
- echo "Deploying to PRODUCTION - version $CI_COMMIT_TAG"
- cd $CI_PROJECT_DIR
- |
helm upgrade --install orchard-prod ./helm/orchard \
--namespace $NAMESPACE \
-f $VALUES_FILE \
--set image.tag=git.linux-amd64-$CI_COMMIT_SHA \
--wait \
--atomic \
--timeout 10m
- kubectl rollout status deployment/orchard-prod-server -n $NAMESPACE --timeout=10m
- *verify_deployment
environment:
name: production
url: https://orchard.common.global.bsf.tools
kubernetes:
agent: esv/bsf/bsf-integration/orchard/orchard-mvp:orchard-prod
rules:
# Only run on semantic version tags (v1.0.0, v1.2.3, etc.)
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
when: manual # Require manual approval for prod
allow_failure: false
# Integration tests for production deployment
integration_test_prod:
<<: *integration_test_template
needs: [deploy_prod]
variables:
BASE_URL: https://orchard.common.global.bsf.tools
rules:
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
when: on_success

View File

@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- Added production deployment job triggered by semantic version tags (v1.0.0) with manual approval gate (#63)
- Added production Helm values file with persistence enabled (20Gi PostgreSQL, 100Gi MinIO) (#63)
- Added integration tests for production deployment (#63)
- Added GitLab CI pipeline for feature branch deployments to dev namespace (#51)
- Added `deploy_feature` job with dynamic hostnames and unique release names (#51)
- Added `cleanup_feature` job with `on_stop` for automatic cleanup on merge (#51)
@@ -16,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added internal proxy configuration for npm, pip, helm, and apt (#51)
### Changed
- Deploy jobs now require all security scans to pass before deployment (added test_image, app_deps_scan, cve_scan, cve_sbom_analysis, app_sbom_analysis to dependencies) (#63)
- Increased deploy job timeout from 5m to 10m (#63)
- Added `--atomic` flag to Helm deployments for automatic rollback on failure
- Adjusted dark mode color palette to use lighter background tones for better readability and reduced eye strain (#52)
- Replaced project card grid with sortable data table on Home page for better handling of large project lists
@@ -26,6 +31,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Improved pod naming: Orchard pods now named `orchard-{env}-server-*` for clarity (#51)
### Fixed
- Fixed deploy jobs running even when tests or security scans fail (changed rules from `when: always` to `when: on_success`) (#63)
- Fixed python_tests job not using internal PyPI proxy (#63)
- Fixed `cleanup_feature` job failing when branch is deleted (`GIT_STRATEGY: none`) (#51)
- Fixed gitleaks false positives with fingerprints for historical commits (#51)
- Fixed integration tests running when deploy fails (`when: on_success`) (#51)

View File

@@ -0,0 +1,217 @@
# Production values for orchard
# TODO: Replace subcharts with managed services (RDS, S3) when ready
replicaCount: 1
image:
repository: registry.global.bsf.tools/esv/bsf/bsf-integration/orchard/orchard-mvp
pullPolicy: IfNotPresent # Don't always pull in prod
tag: "latest" # Overridden by CI
imagePullSecrets:
- name: orchard-pull-secret
initContainer:
image:
repository: containers.global.bsf.tools/busybox
tag: "1.36"
pullPolicy: IfNotPresent
serviceAccount:
create: true
automount: true
annotations: {}
name: "orchard"
podAnnotations: {}
podLabels: {}
podSecurityContext: {}
securityContext:
readOnlyRootFilesystem: false
runAsNonRoot: true
runAsUser: 1000
service:
type: ClusterIP
port: 8080
ingress:
enabled: true
className: "nginx"
annotations:
cert-manager.io/cluster-issuer: "letsencrypt"
hosts:
- host: orchard.common.global.bsf.tools
paths:
- path: /
pathType: Prefix
tls:
- secretName: orchard-prod-tls
hosts:
- orchard.common.global.bsf.tools
# Production resources - same as stage for MVP, increase as needed
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 5
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 80
targetMemoryUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}
orchard:
server:
host: "0.0.0.0"
port: 8080
# Database configuration (used when postgresql.enabled is false)
# TODO: Configure for managed PostgreSQL when ready
database:
host: ""
port: 5432
user: orchard
password: ""
dbname: orchard
sslmode: disable
existingSecret: ""
existingSecretPasswordKey: "password"
# S3 configuration (used when minio.enabled is false)
# TODO: Configure for real S3 when ready
s3:
endpoint: ""
region: us-east-1
bucket: orchard-artifacts
accessKeyId: ""
secretAccessKey: ""
usePathStyle: true
existingSecret: ""
existingSecretAccessKeyKey: "access-key-id"
existingSecretSecretKeyKey: "secret-access-key"
download:
mode: "presigned"
presignedUrlExpiry: 3600
# PostgreSQL subchart - MVP uses subchart, switch to managed later
postgresql:
enabled: true
image:
registry: containers.global.bsf.tools
repository: bitnami/postgresql
tag: "15"
pullPolicy: IfNotPresent
auth:
username: orchard
password: orchard-prod-password # TODO: Use existingSecret
database: orchard
primary:
persistence:
enabled: true # Enable persistence for prod
size: 20Gi
resourcesPreset: "none"
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 512Mi
volumePermissions:
resourcesPreset: "none"
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 50m
memory: 128Mi
# MinIO subchart - MVP uses subchart, switch to real S3 later
minio:
enabled: true
image:
registry: containers.global.bsf.tools
repository: bitnami/minio
tag: "latest"
pullPolicy: IfNotPresent
auth:
rootUser: minioadmin
rootPassword: minioadmin-prod # TODO: Use existingSecret
defaultBuckets: "orchard-artifacts"
persistence:
enabled: true # Enable persistence for prod
size: 100Gi
resourcesPreset: "none"
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 512Mi
defaultInitContainers:
volumePermissions:
resourcesPreset: "none"
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 50m
memory: 128Mi
provisioning:
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 100m
memory: 256Mi
# MinIO external ingress for presigned URL access
minioIngress:
enabled: true
className: "nginx"
annotations:
cert-manager.io/cluster-issuer: "letsencrypt"
nginx.ingress.kubernetes.io/proxy-body-size: "0"
host: "minio-orchard.common.global.bsf.tools"
tls:
enabled: true
secretName: minio-prod-tls
redis:
enabled: false
waitForDatabase: true
global:
security:
allowInsecureImages: true