diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dc228d1..38a6514 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -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 diff --git a/helm/orchard/values-prod.yaml b/helm/orchard/values-prod.yaml new file mode 100644 index 0000000..6d8caf6 --- /dev/null +++ b/helm/orchard/values-prod.yaml @@ -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