From 3ce3793186f51eb6d8985f9a732a6e50a051b705 Mon Sep 17 00:00:00 2001 From: Mondo Diaz Date: Tue, 13 Jan 2026 16:18:08 +0000 Subject: [PATCH] Add feature branch deployment pipeline - Add deploy_feature job for ephemeral dev environments - Use unique identifier (feat-{short_sha}) for K8s resource isolation - Dynamic hostnames for ingress (orchard-{sha}.common.global.bsf.tools) - Add cleanup_feature job with on_stop for automatic cleanup on merge - Add values-dev.yaml with lighter resources for ephemeral deployments - Refactor deploy_stage to use dynamic image tag from CI --- .gitlab-ci.yml | 93 +++++++++++++++----- CHANGELOG.md | 4 + helm/orchard/values-dev.yaml | 165 +++++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+), 20 deletions(-) create mode 100644 helm/orchard/values-dev.yaml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 46fe71c..7337a7d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -66,25 +66,78 @@ python_tests: kubernetes: agent: $AGENT -deploy_helm_chart: +# Deploy to stage (main branch) +deploy_stage: stage: deploy - parallel: - matrix: - # - ENV: dev - # NAMESPACE: dev - # CHART: ./charts/chart-a - # AGENT: dev-agent - - ENV: stage - NAMESPACE: orch-stage-namespace - VALUES_FILE: "helm/orchard/values-stage.yaml" - AGENT: orchard-stage - IMAGE: git.linux-amd64-81458b3bcb5ace97109ba4c16f4afa6e55b1b8bd - # rules: - # # - if: '$CI_COMMIT_TAG && $CI_JOB_NAME == "deploy (production)"' - # # when: always - # # - if: '$CI_COMMIT_BRANCH == "main" && $CI_JOB_NAME == "deploy (stage)" && $CI_COMMIT_TAG == null' - # # when: always - # - if: '$CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != "main" && $ENV == "dev" && $CI_COMMIT_TAG == null' - # when: always - # - when: never + variables: + ENV: stage + NAMESPACE: orch-stage-namespace + VALUES_FILE: "helm/orchard/values-stage.yaml" + AGENT: orchard-stage + IMAGE: $CI_COMMIT_SHA + rules: + - if: '$CI_COMMIT_BRANCH == "main"' + when: always <<: *deploy_template + +# Deploy feature branch to dev namespace +deploy_feature: + stage: deploy + variables: + FEATURE_ID: feat-$CI_COMMIT_SHORT_SHA + ENV: feat-$CI_COMMIT_SHORT_SHA + NAMESPACE: orch-dev-namespace + VALUES_FILE: "helm/orchard/values-dev.yaml" + AGENT: orchard-dev + IMAGE: $CI_COMMIT_SHA + FEATURE_HOST: orchard-$CI_COMMIT_SHORT_SHA.common.global.bsf.tools + MINIO_HOST: minio-$CI_COMMIT_SHORT_SHA.common.global.bsf.tools + before_script: + - helm version + - helm repo add stable https://charts.helm.sh/stable + - helm repo add bitnami https://charts.bitnami.com/bitnami + - cd helm/orchard + - helm dependency update + - helm repo update + script: + - echo "Deploying feature branch to $ENV environment" + - | + helm upgrade --install orchard-$FEATURE_ID ./helm/orchard \ + --namespace $NAMESPACE \ + -f $VALUES_FILE \ + --set image.tag=$IMAGE \ + --set ingress.hosts[0].host=$FEATURE_HOST \ + --set ingress.tls[0].hosts[0]=$FEATURE_HOST \ + --set ingress.tls[0].secretName=orchard-$FEATURE_ID-tls \ + --set minioIngress.host=$MINIO_HOST \ + --set minioIngress.tls.secretName=minio-$FEATURE_ID-tls + environment: + name: review/$CI_COMMIT_REF_SLUG + url: https://orchard-$CI_COMMIT_SHORT_SHA.common.global.bsf.tools + on_stop: cleanup_feature + kubernetes: + agent: $AGENT + rules: + - if: '$CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != "main"' + when: always + +# Cleanup feature branch deployment +cleanup_feature: + stage: deploy + variables: + FEATURE_ID: feat-$CI_COMMIT_SHORT_SHA + NAMESPACE: orch-dev-namespace + AGENT: orchard-dev + image: deps.global.bsf.tools/registry-1.docker.io/alpine/k8s:1.29.12 + script: + - echo "Cleaning up feature deployment orchard-$FEATURE_ID" + - helm uninstall orchard-$FEATURE_ID --namespace $NAMESPACE || true + environment: + name: review/$CI_COMMIT_REF_SLUG + action: stop + kubernetes: + agent: $AGENT + rules: + - if: '$CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != "main"' + when: manual + allow_failure: true diff --git a/CHANGELOG.md b/CHANGELOG.md index db52574..aceae30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- 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) +- Added `values-dev.yaml` Helm values for lightweight ephemeral environments (#51) - Added `StorageBackend` protocol/interface for backend-agnostic storage (#33) - Added `health_check()` method to storage backend with `/health` endpoint integration (#33) - Added `verify_integrity()` method for post-upload hash validation (#33) diff --git a/helm/orchard/values-dev.yaml b/helm/orchard/values-dev.yaml new file mode 100644 index 0000000..6dd6130 --- /dev/null +++ b/helm/orchard/values-dev.yaml @@ -0,0 +1,165 @@ +# Values for feature branch deployments (ephemeral dev environments) +# Hostnames are overridden by CI pipeline via --set flags +replicaCount: 1 + +image: + repository: registry.global.bsf.tools/esv/bsf/bsf-integration/orchard/orchard-mvp + pullPolicy: Always + 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: "" # Auto-generated based on release name + +podAnnotations: {} +podLabels: {} + +podSecurityContext: {} + +securityContext: + readOnlyRootFilesystem: false + runAsNonRoot: true + runAsUser: 1000 + +service: + type: ClusterIP + port: 8080 + +# Ingress - hostnames overridden by CI pipeline +ingress: + enabled: true + className: "nginx" + annotations: + cert-manager.io/cluster-issuer: "letsencrypt" + hosts: + - host: orchard-dev.common.global.bsf.tools # Overridden by CI + paths: + - path: / + pathType: Prefix + tls: + - secretName: orchard-tls # Overridden by CI + hosts: + - orchard-dev.common.global.bsf.tools # Overridden by CI + +# Lighter resources for ephemeral environments +resources: + limits: + cpu: 250m + memory: 256Mi + requests: + cpu: 100m + memory: 128Mi + +livenessProbe: + httpGet: + path: /health + port: http + initialDelaySeconds: 10 + periodSeconds: 10 + +readinessProbe: + httpGet: + path: /health + port: http + initialDelaySeconds: 5 + periodSeconds: 5 + +autoscaling: + enabled: false + +nodeSelector: {} +tolerations: [] +affinity: {} + +orchard: + server: + host: "0.0.0.0" + port: 8080 + + database: + host: "" + port: 5432 + user: orchard + password: "" + dbname: orchard + sslmode: disable + existingSecret: "" + existingSecretPasswordKey: "password" + + 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 - ephemeral, no persistence +postgresql: + enabled: true + image: + registry: containers.global.bsf.tools + repository: bitnami/postgresql + tag: "15" + pullPolicy: IfNotPresent + auth: + username: orchard + password: orchard-password + database: orchard + primary: + persistence: + enabled: false + +# MinIO - ephemeral, no persistence +minio: + enabled: true + image: + registry: containers.global.bsf.tools + repository: bitnami/minio + tag: "latest" + pullPolicy: IfNotPresent + auth: + rootUser: minioadmin + rootPassword: minioadmin + defaultBuckets: "orchard-artifacts" + persistence: + enabled: false + +# MinIO ingress - hostname overridden by CI +minioIngress: + enabled: true + className: "nginx" + annotations: + cert-manager.io/cluster-issuer: "letsencrypt" + nginx.ingress.kubernetes.io/proxy-body-size: "0" + host: "minio-dev.common.global.bsf.tools" # Overridden by CI + tls: + enabled: true + secretName: minio-tls # Overridden by CI + +redis: + enabled: false + +waitForDatabase: true + +global: + security: + allowInsecureImages: true