Merge branch 'fix/deploy-job-dependencies' into 'main'
Fix deploy job dependencies and add production deployment (#63) Closes #63 See merge request esv/bsf/bsf-integration/orchard/orchard-mvp!32
This commit is contained in:
@@ -124,8 +124,8 @@ python_tests:
|
|||||||
- .pip-cache/
|
- .pip-cache/
|
||||||
policy: pull-push
|
policy: pull-push
|
||||||
before_script:
|
before_script:
|
||||||
- pip install -r backend/requirements.txt
|
- pip install --index-url "$PIP_INDEX_URL" -r backend/requirements.txt
|
||||||
- pip install pytest pytest-asyncio pytest-cov httpx
|
- pip install --index-url "$PIP_INDEX_URL" pytest pytest-asyncio pytest-cov httpx
|
||||||
script:
|
script:
|
||||||
- cd backend
|
- cd backend
|
||||||
# Only run unit tests - integration tests require Docker Compose services
|
# Only run unit tests - integration tests require Docker Compose services
|
||||||
@@ -175,7 +175,7 @@ frontend_tests:
|
|||||||
# Shared deploy configuration
|
# Shared deploy configuration
|
||||||
.deploy_template: &deploy_template
|
.deploy_template: &deploy_template
|
||||||
stage: deploy
|
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
|
image: deps.global.bsf.tools/registry-1.docker.io/alpine/k8s:1.29.12
|
||||||
|
|
||||||
.helm_setup: &helm_setup
|
.helm_setup: &helm_setup
|
||||||
@@ -246,8 +246,8 @@ deploy_stage:
|
|||||||
--set image.tag=git.linux-amd64-$CI_COMMIT_SHA \
|
--set image.tag=git.linux-amd64-$CI_COMMIT_SHA \
|
||||||
--wait \
|
--wait \
|
||||||
--atomic \
|
--atomic \
|
||||||
--timeout 5m
|
--timeout 10m
|
||||||
- kubectl rollout status deployment/orchard-stage-server -n $NAMESPACE --timeout=5m
|
- kubectl rollout status deployment/orchard-stage-server -n $NAMESPACE --timeout=10m
|
||||||
- *verify_deployment
|
- *verify_deployment
|
||||||
environment:
|
environment:
|
||||||
name: stage
|
name: stage
|
||||||
@@ -256,7 +256,7 @@ deploy_stage:
|
|||||||
agent: esv/bsf/bsf-integration/orchard/orchard-mvp:orchard-stage
|
agent: esv/bsf/bsf-integration/orchard/orchard-mvp:orchard-stage
|
||||||
rules:
|
rules:
|
||||||
- if: '$CI_COMMIT_BRANCH == "main"'
|
- if: '$CI_COMMIT_BRANCH == "main"'
|
||||||
when: always
|
when: on_success
|
||||||
|
|
||||||
# Deploy feature branch to dev namespace
|
# Deploy feature branch to dev namespace
|
||||||
deploy_feature:
|
deploy_feature:
|
||||||
@@ -282,8 +282,8 @@ deploy_feature:
|
|||||||
--set minioIngress.tls.secretName=minio-$CI_COMMIT_REF_SLUG-tls \
|
--set minioIngress.tls.secretName=minio-$CI_COMMIT_REF_SLUG-tls \
|
||||||
--wait \
|
--wait \
|
||||||
--atomic \
|
--atomic \
|
||||||
--timeout 5m
|
--timeout 10m
|
||||||
- kubectl rollout status deployment/orchard-$CI_COMMIT_REF_SLUG-server -n $NAMESPACE --timeout=5m
|
- 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"
|
- export BASE_URL="https://orchard-$CI_COMMIT_REF_SLUG.common.global.bsf.tools"
|
||||||
- *verify_deployment
|
- *verify_deployment
|
||||||
environment:
|
environment:
|
||||||
@@ -295,7 +295,7 @@ deploy_feature:
|
|||||||
agent: esv/bsf/bsf-integration/orchard/orchard-mvp:orchard
|
agent: esv/bsf/bsf-integration/orchard/orchard-mvp:orchard
|
||||||
rules:
|
rules:
|
||||||
- if: '$CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != "main"'
|
- if: '$CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != "main"'
|
||||||
when: always
|
when: on_success
|
||||||
|
|
||||||
# Cleanup feature branch deployment
|
# Cleanup feature branch deployment
|
||||||
cleanup_feature:
|
cleanup_feature:
|
||||||
@@ -318,3 +318,51 @@ cleanup_feature:
|
|||||||
- if: '$CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != "main"'
|
- if: '$CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != "main"'
|
||||||
when: manual
|
when: manual
|
||||||
allow_failure: true
|
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
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### 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 GitLab CI pipeline for feature branch deployments to dev namespace (#51)
|
||||||
- Added `deploy_feature` job with dynamic hostnames and unique release names (#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)
|
- 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)
|
- Added internal proxy configuration for npm, pip, helm, and apt (#51)
|
||||||
|
|
||||||
### Changed
|
### 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
|
- 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)
|
- 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
|
- 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)
|
- Improved pod naming: Orchard pods now named `orchard-{env}-server-*` for clarity (#51)
|
||||||
|
|
||||||
### Fixed
|
### 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 `cleanup_feature` job failing when branch is deleted (`GIT_STRATEGY: none`) (#51)
|
||||||
- Fixed gitleaks false positives with fingerprints for historical commits (#51)
|
- Fixed gitleaks false positives with fingerprints for historical commits (#51)
|
||||||
- Fixed integration tests running when deploy fails (`when: on_success`) (#51)
|
- Fixed integration tests running when deploy fails (`when: on_success`) (#51)
|
||||||
|
|||||||
217
helm/orchard/values-prod.yaml
Normal file
217
helm/orchard/values-prod.yaml
Normal 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
|
||||||
Reference in New Issue
Block a user