diff --git a/.github/workflows/preview-helm-charts.yml b/.github/workflows/preview-helm-charts.yml index 3673ae6a..e28e9ee0 100644 --- a/.github/workflows/preview-helm-charts.yml +++ b/.github/workflows/preview-helm-charts.yml @@ -160,8 +160,6 @@ jobs: RUNTIME_API_PREVIEW="${RUNTIME_API_VERSION}-alpha.${{ github.event.pull_request.number }}" yq -i "(.dependencies[] | select(.name == \"runtime-api\")).version = \"${RUNTIME_API_PREVIEW}\"" charts/openhands/Chart.yaml - - helm dependency update charts/openhands - name: Update automation dependency version if: steps.check.outputs.should_publish == 'true' && matrix.chart.name == 'openhands' && needs.detect-changes.outputs.automation == 'true' diff --git a/charts/automation/Chart.lock b/charts/automation/Chart.lock index 4c232433..fae81246 100644 --- a/charts/automation/Chart.lock +++ b/charts/automation/Chart.lock @@ -1,9 +1,6 @@ dependencies: -- name: postgresql - repository: https://charts.bitnami.com/bitnami - version: 15.5.38 - name: minio repository: https://charts.min.io/ version: 5.0.10 -digest: sha256:bb32f5ad11adfc7b0563aeba08a608cfaaa57343152b6439794722dcd02be4ac -generated: "2026-03-26T15:24:25.529071776Z" +digest: sha256:58db3f82aecc29448840f9e5349645bc682bb4575ce2d493a9651a7a99f54935 +generated: "2026-04-03T15:12:16.155332-04:00" diff --git a/charts/automation/Chart.yaml b/charts/automation/Chart.yaml index 709072c2..8e8af7a1 100644 --- a/charts/automation/Chart.yaml +++ b/charts/automation/Chart.yaml @@ -2,13 +2,9 @@ apiVersion: v2 name: automation description: OpenHands Automations Service — scheduled and event-driven automation execution type: application -version: 0.1.0 +version: 0.2.0 appVersion: "0.1.0" dependencies: - - name: postgresql - version: 15.x.x - repository: https://charts.bitnami.com/bitnami - condition: postgresql.enabled - name: minio version: 5.0.10 repository: https://charts.min.io/ diff --git a/charts/automation/templates/deployment.yaml b/charts/automation/templates/deployment.yaml index 3fc82d67..c19439e7 100644 --- a/charts/automation/templates/deployment.yaml +++ b/charts/automation/templates/deployment.yaml @@ -24,63 +24,14 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} initContainers: - {{- if .Values.database.createDatabaseUser }} - # Create automation database and user in an existing PostgreSQL instance - - name: create-db-user - image: postgres:14 - env: - - name: PGPASSWORD - valueFrom: - secretKeyRef: - name: {{ .Values.database.superuserSecretName }} - key: {{ .Values.database.superuserSecretKey }} - - name: DB_HOST - value: {{ .Values.database.host | quote }} - - name: DB_PORT - value: {{ .Values.database.port | quote }} - - name: DB_NAME - value: {{ .Values.database.name | quote }} - - name: DB_USER - value: {{ .Values.database.user | quote }} - - name: DB_PASSWORD - valueFrom: - secretKeyRef: - name: {{ .Values.database.secretName }} - key: {{ .Values.database.secretKey }} - command: - - sh - - -c - - | - echo "Waiting for PostgreSQL at $DB_HOST to be available..." - for i in $(seq 1 60); do - if psql -h $DB_HOST -p $DB_PORT -U postgres -d postgres -c "SELECT 1;" > /dev/null 2>&1; then - echo "PostgreSQL is up!" - - echo "Creating the database $DB_NAME if it doesn't exist..." - psql -h $DB_HOST -p $DB_PORT -U postgres -d postgres -tc "SELECT 1 FROM pg_database WHERE datname='$DB_NAME'" | grep -q 1 || \ - psql -h $DB_HOST -p $DB_PORT -U postgres -d postgres -c "CREATE DATABASE $DB_NAME;" - - echo "Creating the user $DB_USER if it doesn't exist..." - psql -h $DB_HOST -p $DB_PORT -U postgres -d $DB_NAME -tc "SELECT 1 FROM pg_roles WHERE rolname='$DB_USER'" | grep -q 1 || \ - (psql -h $DB_HOST -p $DB_PORT -U postgres -d $DB_NAME -c "CREATE USER $DB_USER WITH PASSWORD '$DB_PASSWORD'; GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_USER; GRANT USAGE ON SCHEMA public TO $DB_USER; GRANT CREATE ON SCHEMA public TO $DB_USER; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO $DB_USER;") - - exit 0 - fi - echo "Waiting for PostgreSQL... ($i/60)" - sleep 5 - done - echo "PostgreSQL did not become available in time." - exit 1 - {{- else if .Values.postgresql.enabled }} - # Wait for the automation's own PostgreSQL subchart to be ready - - name: wait-for-postgres - image: bitnamilegacy/postgresql:latest + {{- if .Values.database.waitForDatabase }} + - name: wait-for-db + image: postgres:16 command: ['sh', '-c'] args: - | - DB_HOST="{{ .Values.database.host }}" - echo "Waiting for PostgreSQL at $DB_HOST to be ready..." - until PGPASSWORD=$AUTOMATION_DB_PASS psql -h $DB_HOST -p {{ .Values.database.port }} -U {{ .Values.database.user }} -c '\q' > /dev/null 2>&1; do + echo "Waiting for PostgreSQL at $AUTOMATION_DB_HOST to be ready..." + until PGPASSWORD=$AUTOMATION_DB_PASS pg_isready -h $AUTOMATION_DB_HOST -p $AUTOMATION_DB_PORT -U $AUTOMATION_DB_USER > /dev/null 2>&1; do echo "PostgreSQL is unavailable - sleeping for 2 seconds" sleep 2 done @@ -88,11 +39,27 @@ spec: env: {{- include "automation.env" . | nindent 8 }} {{- end }} + {{- if .Values.database.createDatabases }} + - name: create-db + image: postgres:16 + command: ['sh', '-c'] + args: + - | + export PGPASSWORD=$AUTOMATION_DB_PASS + PSQL="psql -h $AUTOMATION_DB_HOST -p $AUTOMATION_DB_PORT -U $AUTOMATION_DB_USER" + echo "Ensuring database \"$AUTOMATION_DB_NAME\" exists..." + $PSQL -d postgres -tc "SELECT 1 FROM pg_database WHERE datname='$AUTOMATION_DB_NAME'" | grep -q 1 || \ + $PSQL -d postgres -c "CREATE DATABASE $AUTOMATION_DB_NAME;" + env: + {{- include "automation.env" . | nindent 8 }} + {{- end }} + {{- if .Values.database.migrate }} - name: migrate image: '{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}' command: ["alembic", "upgrade", "head"] env: {{- include "automation.env" . | nindent 8 }} + {{- end }} containers: - name: automation imagePullPolicy: Always diff --git a/charts/automation/values.yaml b/charts/automation/values.yaml index 7f4b6626..ae7874b2 100644 --- a/charts/automation/values.yaml +++ b/charts/automation/values.yaml @@ -45,26 +45,24 @@ automationBaseUrl: "" # PostgreSQL database configuration database: - # Full hostname of the PostgreSQL server - # Examples: - # - Cloud SQL: "my-project:us-central1:my-instance" - # - In-cluster: "openhands-main-postgresql" - # - Feature env: "openhands-feature-branch-postgresql" + # Hostname of the PostgreSQL server host: "" + # Port of the PostgreSQL server port: "5432" + # Database user user: "automation_user" + # Database name name: "automations" - # Secret containing the automation database password + # Name of the Kubernetes secret containing the database password secretName: "automation-db-secret" + # Key within the secret that holds the password secretKey: "db-password" - # Create database and user in an existing PostgreSQL instance - # When true, runs an init container to create the database and user - # Useful when sharing a PostgreSQL instance with other services - createDatabaseUser: false - # Secret containing the postgres superuser password (for creating the automation user) - # Only used when createDatabaseUser=true - superuserSecretName: "postgres-password" - superuserSecretKey: "password" + # Wait for the database to be ready before starting the application + waitForDatabase: true + # Create the database if it does not exist + createDatabases: false + # Run database migrations on startup + migrate: true # GCP Cloud SQL (leave empty for non-GCP) gcp: @@ -137,25 +135,6 @@ datadog: # Env vars passed directly to the container env: {} -# PostgreSQL subchart configuration (for ephemeral/feature environments) -# When enabled, deploys an in-cluster PostgreSQL instance -# Service name will be "{release-name}-postgresql", secret name also "{release-name}-postgresql" -postgresql: - enabled: false - auth: - username: postgres - database: automations - primary: - persistence: - enabled: false - initdb: - scriptsConfigMap: "" - service: - ports: - postgresql: 5432 - image: - repository: bitnamilegacy/postgresql - global: security: # This allows using the bitnamilegacy image repo diff --git a/charts/infra/Chart.lock b/charts/infra/Chart.lock new file mode 100644 index 00000000..3fa9c7f2 --- /dev/null +++ b/charts/infra/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: cloudnative-pg + repository: https://cloudnative-pg.github.io/charts + version: 0.23.2 +digest: sha256:db9f0efc07f208bcd280bc9c19e7c1c5983a36b45ac9b2976e16503a8dea45ab +generated: "2026-04-03T15:12:06.037216-04:00" diff --git a/charts/infra/Chart.yaml b/charts/infra/Chart.yaml new file mode 100644 index 00000000..921ca112 --- /dev/null +++ b/charts/infra/Chart.yaml @@ -0,0 +1,11 @@ +apiVersion: v2 +name: infra +description: Infrastructure components for OpenHands (CNPG operator) +type: application +version: 0.1.0 +appVersion: "1.0" +dependencies: + - name: cloudnative-pg + repository: https://cloudnative-pg.github.io/charts + version: 0.23.x + condition: cloudnative-pg.enabled diff --git a/charts/infra/values.yaml b/charts/infra/values.yaml new file mode 100644 index 00000000..e2b2f68d --- /dev/null +++ b/charts/infra/values.yaml @@ -0,0 +1,2 @@ +cloudnative-pg: + enabled: true diff --git a/charts/openhands/Chart.lock b/charts/openhands/Chart.lock index 04e282b0..c22b2b81 100644 --- a/charts/openhands/Chart.lock +++ b/charts/openhands/Chart.lock @@ -14,9 +14,6 @@ dependencies: - name: minio repository: https://charts.min.io/ version: 5.0.10 -- name: postgresql - repository: https://charts.bitnami.com/bitnami - version: 15.5.38 - name: redis repository: oci://registry-1.docker.io/bitnamicharts version: 20.3.0 @@ -25,6 +22,9 @@ dependencies: version: 1.9.0 - name: runtime-api repository: oci://ghcr.io/all-hands-ai/helm-charts - version: 0.1.24 -digest: sha256:bca3722cdd4840a4557955ea2b80e38991cc2d0a0211855a791cf98e37410e45 -generated: "2026-03-18T00:28:58.972983917-04:00" + version: 0.2.6 +- name: automation + repository: oci://ghcr.io/all-hands-ai/helm-charts + version: 0.1.0 +digest: sha256:bf943198f5990e2b0e752f9d35cd984dc3863f8b4321f40c08a0c8d440d951df +generated: "2026-04-03T15:12:20.635728-04:00" diff --git a/charts/openhands/Chart.yaml b/charts/openhands/Chart.yaml index 5278cc11..15d7303e 100644 --- a/charts/openhands/Chart.yaml +++ b/charts/openhands/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 description: OpenHands is an AI-driven autonomous software engineer name: openhands appVersion: cloud-1.19.0 -version: 0.3.12 +version: 0.4.0 maintainers: - name: rbren - name: xingyao @@ -28,10 +28,6 @@ dependencies: version: 5.0.10 condition: filestore.ephemeral repository: https://charts.min.io/ - - name: postgresql - version: 15.x.x - repository: https://charts.bitnami.com/bitnami - condition: postgresql.enabled - name: redis version: 20.3.0 repository: oci://registry-1.docker.io/bitnamicharts @@ -42,9 +38,9 @@ dependencies: condition: replicated.enabled - name: runtime-api repository: oci://ghcr.io/all-hands-ai/helm-charts - version: 0.2.7 + version: 0.3.0 condition: runtime-api.enabled - name: automation repository: oci://ghcr.io/all-hands-ai/helm-charts - version: 0.1.0 + version: 0.2.0 condition: automation.enabled diff --git a/charts/openhands/templates/_env.yaml b/charts/openhands/templates/_env.yaml index 0b164b7c..9cda0eb5 100644 --- a/charts/openhands/templates/_env.yaml +++ b/charts/openhands/templates/_env.yaml @@ -305,21 +305,14 @@ value: "1" {{- end }} -{{- if .Values.postgresql.enabled }} - name: DB_HOST - value: "{{ .Release.Name }}-postgresql" + value: {{ .Values.database.host | quote }} +- name: DB_PORT + value: {{ .Values.database.port | quote }} - name: DB_USER - value: "{{ .Values.postgresql.auth.username }}" + value: {{ .Values.database.user | quote }} - name: DB_NAME - value: "{{ .Values.postgresql.auth.database }}" -{{- else }} -- name: DB_HOST - value: "{{ .Values.externalDatabase.host }}" -- name: DB_USER - value: "{{ .Values.externalDatabase.username }}" -- name: DB_NAME - value: "{{ .Values.externalDatabase.database }}" -{{- end }} + value: {{ .Values.database.name | quote }} {{- if .Values.datadog.enabled }} # Datadog configuration - name: DD_AGENT_HOST @@ -342,8 +335,8 @@ - name: DB_PASS valueFrom: secretKeyRef: - name: {{ .Values.postgresql.auth.existingSecret }} - key: password + name: {{ .Values.database.secretName }} + key: {{ .Values.database.secretKey }} {{- if .Values.jira.enabled }} - name: ENABLE_JIRA value: "true" diff --git a/charts/openhands/templates/_init-containers.yaml b/charts/openhands/templates/_init-containers.yaml index 72cce29d..bf672c8c 100644 --- a/charts/openhands/templates/_init-containers.yaml +++ b/charts/openhands/templates/_init-containers.yaml @@ -1,7 +1,7 @@ {{- define "openhands.dbInitContainers" }} -{{- if .Values.databaseMigrations.waitForDatabase }} +{{- if .Values.database.waitForDatabase }} - name: wait-for-db - image: "bitnamilegacy/postgresql:latest" + image: "postgres:16" command: ['sh', '-c'] args: - | @@ -16,9 +16,9 @@ env: {{- include "openhands.env" . | nindent 4 }} {{- end }} -{{- if .Values.databaseMigrations.createDatabases }} +{{- if .Values.database.createDatabases }} - name: create-db - image: "bitnamilegacy/postgresql:latest" + image: "postgres:16" command: ['sh', '-c'] args: - | @@ -35,7 +35,7 @@ value: "{{ .Values.keycloak.externalDatabase.database }}{{- if (index .Values "litellm-helm").enabled }} {{ (index .Values "litellm-helm").db.database }}{{- end }}{{- if .Values.langfuse.enabled }} {{ .Values.langfuse.postgresql.auth.database }}{{- end }}" {{- include "openhands.env" . | nindent 4 }} {{- end }} -{{- if .Values.databaseMigrations.migrate }} +{{- if .Values.database.migrate }} - name: migrate-db image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" command: ["/bin/sh", "-c"] diff --git a/charts/openhands/templates/cnpg-cluster.yaml b/charts/openhands/templates/cnpg-cluster.yaml new file mode 100644 index 00000000..fade532a --- /dev/null +++ b/charts/openhands/templates/cnpg-cluster.yaml @@ -0,0 +1,33 @@ +{{- if .Values.cnpg.enabled }} +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: oh-main-postgresql + namespace: {{ .Release.Namespace }} +spec: + instances: {{ .Values.cnpg.instances | default 1 }} + + enableSuperuserAccess: true + superuserSecret: + name: {{ .Values.database.secretName }} + + bootstrap: + initdb: + database: postgres + owner: {{ .Values.database.user }} + + storage: + size: {{ .Values.cnpg.storage.size | default "10Gi" }} + {{- if .Values.cnpg.storage.storageClass }} + storageClass: {{ .Values.cnpg.storage.storageClass }} + {{- end }} + + {{- if .Values.cnpg.imageName }} + imageName: {{ .Values.cnpg.imageName }} + {{- end }} + + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/openhands/templates/service.yaml b/charts/openhands/templates/service.yaml index f1c577c9..82e03da7 100644 --- a/charts/openhands/templates/service.yaml +++ b/charts/openhands/templates/service.yaml @@ -30,25 +30,6 @@ spec: app.kubernetes.io/name: runtime-api app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} -{{- if .Values.postgresql.enabled }} ---- -apiVersion: v1 -kind: Service -metadata: - name: oh-main-postgresql -spec: - type: ClusterIP - sessionAffinity: None - ports: - - name: tcp-postgresql - port: 5432 - targetPort: tcp-postgresql - nodePort: null - selector: - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/name: postgresql - app.kubernetes.io/component: primary -{{- end }} {{- if and .Values.redis.enabled .Values.langfuse.enabled }} --- apiVersion: v1 diff --git a/charts/openhands/templates/troubleshoot/_shared.tpl b/charts/openhands/templates/troubleshoot/_shared.tpl index 6de48e01..88432680 100644 --- a/charts/openhands/templates/troubleshoot/_shared.tpl +++ b/charts/openhands/templates/troubleshoot/_shared.tpl @@ -1,18 +1,16 @@ {{- define "troubleshoot.collectors.shared" -}} - clusterInfo: {} - clusterResources: {} -{{- if .Values.externalDatabase.enabled }} -{{- with .Values.externalDatabase }} -{{- if .host }} +{{- if not .Values.cnpg.enabled }} +{{- with .Values.database }} - postgresql: collectorName: external-postgresql - uri: postgresql://{{ .username | default "postgres" }}:@{{ .host }}:{{ .port | default 5432 }}/{{ .database | default "openhands" }}?sslmode=disable + uri: postgresql://{{ .user }}:@{{ .host }}:{{ .port }}/{{ .name }}?sslmode=disable tls: disabled: true password: - secretName: {{ .existingSecret | default "postgres-password" }} - secretKey: {{ .existingSecretPasswordKey | default "password" }} -{{- end }} + secretName: {{ .secretName }} + secretKey: {{ .secretKey }} {{- end }} {{- end }} {{- end -}} @@ -54,7 +52,7 @@ message: "No default storage class found - required for PostgreSQL, Redis, and file storage" - pass: message: "Default storage class is available" -{{- if .Values.externalDatabase.enabled }} +{{- if not .Values.cnpg.enabled }} - postgresql: checkName: "External PostgreSQL Database Health" collectorName: external-postgresql diff --git a/charts/openhands/templates/troubleshoot/support-bundle.yaml b/charts/openhands/templates/troubleshoot/support-bundle.yaml index 00f1ce68..2e685a98 100644 --- a/charts/openhands/templates/troubleshoot/support-bundle.yaml +++ b/charts/openhands/templates/troubleshoot/support-bundle.yaml @@ -52,14 +52,13 @@ spec: - app=openhands-mcp limits: maxAge: 720h - {{- if .Values.postgresql.enabled }} - # PostgreSQL logs (Bitnami chart) + {{- if .Values.cnpg.enabled }} + # PostgreSQL logs (CNPG) - logs: - name: app/{{ .Release.Name }}-postgresql/logs + name: app/oh-main-postgresql/logs namespace: {{ .Release.Namespace }} selector: - - app.kubernetes.io/name=postgresql - - app.kubernetes.io/instance={{ .Release.Name }} + - cnpg.io/cluster=oh-main-postgresql limits: maxAge: 168h {{- end }} @@ -126,15 +125,15 @@ spec: namespace: ingress-nginx limits: maxAge: 168h - {{- if .Values.postgresql.enabled }} + {{- if .Values.cnpg.enabled }} - postgresql: collectorName: postgresql - uri: postgresql://postgres:@{{ .Release.Name }}-postgresql:5432/openhands?sslmode=disable + uri: postgresql://{{ .Values.database.user }}:@{{ .Values.database.host }}:{{ .Values.database.port }}/{{ .Values.database.name }}?sslmode=disable tls: disabled: true password: - secretName: {{ .Release.Name }}-postgresql - secretKey: postgres-password + secretName: {{ .Values.database.secretName }} + secretKey: {{ .Values.database.secretKey }} {{- end }} {{- if .Values.redis.enabled }} - redis: @@ -217,17 +216,17 @@ spec: when: ">= 1" message: "OpenHands Runtime API deployment is ready" {{- end }} - {{- if .Values.postgresql.enabled }} + {{- if .Values.cnpg.enabled }} - statefulsetStatus: - name: {{ .Release.Name }}-postgresql + name: oh-main-postgresql-1 namespace: {{ .Release.Namespace }} outcomes: - fail: when: "< 1" - message: "OpenHands PostgreSQL statefulset is not ready" + message: "OpenHands PostgreSQL (CNPG) is not ready" - pass: when: ">= 1" - message: "OpenHands PostgreSQL statefulset is ready" + message: "OpenHands PostgreSQL (CNPG) is ready" {{- end }} {{- if .Values.redis.enabled }} - statefulsetStatus: @@ -263,7 +262,7 @@ spec: - pass: when: ">= 1" message: "Ingress NGINX controller deployment is ready" - {{- if .Values.postgresql.enabled }} + {{- if .Values.cnpg.enabled }} - postgresql: checkName: "PostgreSQL Database Health" collectorName: postgresql @@ -274,9 +273,6 @@ spec: - fail: when: "version == \"\"" message: "PostgreSQL version could not be determined" - - warn: - when: "version < 12.0.0" - message: "PostgreSQL version is older than recommended (12.0.0+)" - pass: when: "connected == true" message: "PostgreSQL database is healthy" diff --git a/charts/openhands/values.yaml b/charts/openhands/values.yaml index a152b232..bae37bbf 100644 --- a/charts/openhands/values.yaml +++ b/charts/openhands/values.yaml @@ -27,11 +27,6 @@ datadog: debuggingRoutes: enabled: false -databaseMigrations: - waitForDatabase: true - createDatabases: false - migrate: true - deployment: replicas: 1 resources: @@ -314,7 +309,7 @@ keycloak: postgresql: enabled: false externalDatabase: - host: oh-main-postgresql + host: oh-main-postgresql-rw database: bitnami_keycloak existingSecret: postgres-password existingSecretUserKey: username @@ -331,7 +326,7 @@ keycloak: image: repository: bitnamilegacy/keycloak waitForDb: - image: "bitnamilegacy/postgresql:latest" + image: "postgres:16" initContainers: - name: wait-for-db # The Bitnami Keycloak subchart renders initContainers through common.tplvalues.render, @@ -393,7 +388,7 @@ langfuse: existingSecretKey: password postgresql: deploy: false - host: oh-main-postgresql + host: oh-main-postgresql-rw auth: username: postgres database: postgres_langfuse @@ -425,7 +420,7 @@ litellm-helm: deployStandalone: false useExisting: true database: litellm - endpoint: "oh-main-postgresql" + endpoint: "oh-main-postgresql-rw" secret: name: postgres-password usernameKey: username @@ -494,28 +489,34 @@ minio: memory: 512Mi cpu: 100m -postgresql: - enabled: true - auth: - username: postgres - existingSecret: postgres-password - primary: - initdb: - scriptsConfigMap: "" - persistence: - enabled: false - # Add the following if using Karpenter with persistence - # podAnnotations: - # karpenter.sh/do-not-evict: "true" - service: - ports: - postgresql: 5432 - image: - repository: bitnamilegacy/postgresql +# PostgreSQL database configuration +database: + # Hostname of the PostgreSQL server + host: "oh-main-postgresql-rw" + # Port of the PostgreSQL server + port: "5432" + # Database user + user: "postgres" + # Database name + name: "openhands" + # Name of the Kubernetes secret containing the database password + secretName: "postgres-password" + # Key within the secret that holds the password + secretKey: "password" + # Wait for the database to be ready before starting the application + waitForDatabase: true + # Create the database if it does not exist + createDatabases: false + # Run database migrations on startup + migrate: true -externalDatabase: - enabled: false - existingSecret: postgres-password +# CloudNative-PG embedded PostgreSQL cluster +cnpg: + enabled: true + instances: 1 + storage: + size: 10Gi + storageClass: "" redis: enabled: true @@ -601,17 +602,10 @@ runtime-api: - root - --user-id - "0" - databaseMigrations: + database: waitForDatabase: true createDatabases: false migrate: true - postgresql: - auth: - username: postgres - existingSecret: postgres-password - externalDatabase: - enabled: false - existingSecret: postgres-password ingress: enabled: false # REQUIRED: Update to a hostname in a DNS domain you own @@ -621,7 +615,7 @@ runtime-api: cert-manager.io/cluster-issuer: letsencrypt-production tls: true env: - DB_HOST: oh-main-postgresql + DB_HOST: oh-main-postgresql-rw DB_USER: postgres DB_NAME: runtime_api_db K8S_NAMESPACE: "openhands" @@ -714,6 +708,8 @@ automation: # Secret containing the automation database password secretName: "automation-db-secret" secretKey: "db-password" + # Wait for the database to be ready before starting the application + waitForDatabase: true # Create database and user in an existing PostgreSQL instance # When true, runs an init container to create the database and user # Useful when sharing a PostgreSQL instance with other services diff --git a/charts/runtime-api/Chart.lock b/charts/runtime-api/Chart.lock index 82ee7a07..3d4e25bd 100644 --- a/charts/runtime-api/Chart.lock +++ b/charts/runtime-api/Chart.lock @@ -1,9 +1,6 @@ dependencies: -- name: postgresql - repository: https://charts.bitnami.com/bitnami - version: 15.5.38 - name: helm-release-pruner repository: https://charts.fairwinds.com/stable version: 3.3.0 -digest: sha256:9f911cd2f97b7cbaa03b13b538f1ee44e0fb589f40c797c71ccc032e3a669ba5 -generated: "2026-03-05T14:27:07.142687-05:00" +digest: sha256:17ba46bc56d903ec8100cfc6ba09b16db5ee1e1e28cdf2a7b953c17a3a5610aa +generated: "2026-04-03T15:12:10.702816-04:00" diff --git a/charts/runtime-api/Chart.yaml b/charts/runtime-api/Chart.yaml index 7f28ee29..eaa9f795 100644 --- a/charts/runtime-api/Chart.yaml +++ b/charts/runtime-api/Chart.yaml @@ -1,13 +1,9 @@ apiVersion: v2 name: runtime-api description: A Helm chart for the FastAPI application -version: 0.2.7 # Change this to trigger a new helm chart version being published +version: 0.3.0 # Change this to trigger a new helm chart version being published appVersion: "1.0.0" dependencies: - - name: postgresql - version: 15.x.x - repository: https://charts.bitnami.com/bitnami - condition: postgresql.enabled - name: helm-release-pruner version: 3.3.0 repository: https://charts.fairwinds.com/stable diff --git a/charts/runtime-api/templates/_env.yaml b/charts/runtime-api/templates/_env.yaml index ef68b5be..8b04eac1 100644 --- a/charts/runtime-api/templates/_env.yaml +++ b/charts/runtime-api/templates/_env.yaml @@ -3,6 +3,14 @@ - name: {{ $key }} value: {{ $value | quote }} {{- end }} +- name: DB_HOST + value: {{ .Values.database.host | quote }} +- name: DB_PORT + value: {{ .Values.database.port | quote }} +- name: DB_USER + value: {{ .Values.database.user | quote }} +- name: DB_NAME + value: {{ .Values.database.name | quote }} - name: RUNTIME_DEAD_SECONDS value: {{ printf "%.0f" .Values.cleanup.dead_seconds | quote }} {{- if .Values.runtimeInSameCluster }} @@ -36,26 +44,9 @@ - name: DD_TRACE_SAMPLING_RULES value: '[{"resource": "GET /health", "sample_rate": 0.0}, {"resource": "GET /internal/metrics", "sample_rate": 0.0}]' {{- end }} -{{- if .Values.postgresql.enabled }} -- name: DB_HOST - value: "{{ .Release.Name }}-postgresql" -- name: DB_USER - value: "{{ .Values.postgresql.auth.username }}" -- name: DB_NAME - value: "{{ .Values.postgresql.auth.database }}" -{{- else if .Values.database.create }} # should only be true for AWS deploys -- name: DB_HOST - value: "{{.Values.database.host}}" -- name: DB_PORT - value: "{{.Values.database.port}}" -- name: DB_USER - value: "{{.Values.database.new_user}}" -- name: DB_NAME - value: "{{.Values.database.name}}" -{{- end }} - name: DB_PASS valueFrom: secretKeyRef: - name: {{ .Values.postgresql.auth.existingSecret }} - key: password + name: {{ .Values.database.secretName }} + key: {{ .Values.database.secretKey }} {{- end }} diff --git a/charts/runtime-api/templates/_helpers.tpl b/charts/runtime-api/templates/_helpers.tpl index d8f19983..c378532c 100644 --- a/charts/runtime-api/templates/_helpers.tpl +++ b/charts/runtime-api/templates/_helpers.tpl @@ -54,53 +54,33 @@ app.kubernetes.io/instance: {{ .Release.Name }} PostgreSQL host */}} {{- define "runtime-api.postgresql.host" -}} -{{- if .Values.postgresql.enabled }} -{{- printf "%s-%s" .Release.Name "postgresql" | trunc 63 | trimSuffix "-" -}} -{{- else }} {{- .Values.database.host -}} -{{- end }} {{- end -}} {{/* PostgreSQL username */}} {{- define "runtime-api.postgresql.username" -}} -{{- if .Values.postgresql.enabled }} -{{- .Values.postgresql.auth.username -}} -{{- else }} {{- .Values.database.user -}} -{{- end }} {{- end -}} {{/* PostgreSQL database */}} {{- define "runtime-api.postgresql.database" -}} -{{- if .Values.postgresql.enabled }} -{{- .Values.postgresql.auth.database -}} -{{- else }} {{- .Values.database.name -}} -{{- end }} {{- end -}} {{/* PostgreSQL secret name */}} {{- define "runtime-api.postgresql.secretName" -}} -{{- if .Values.postgresql.enabled }} -{{- printf "%s-%s" .Release.Name "postgresql" -}} -{{- else }} -{{- include "runtime-api.fullname" . -}} -{{- end }} +{{- .Values.database.secretName -}} {{- end -}} {{/* PostgreSQL secret key */}} {{- define "runtime-api.postgresql.secretKey" -}} -{{- if .Values.postgresql.enabled }} -{{- printf "postgres-password" -}} -{{- else }} -{{- printf "db-password" -}} -{{- end }} +{{- .Values.database.secretKey -}} {{- end -}} diff --git a/charts/runtime-api/templates/_init-containers.yaml b/charts/runtime-api/templates/_init-containers.yaml index 1a0f24d4..f0496d0f 100644 --- a/charts/runtime-api/templates/_init-containers.yaml +++ b/charts/runtime-api/templates/_init-containers.yaml @@ -1,7 +1,7 @@ {{- define "runtime-api.dbInitContainers" }} -{{- if .Values.databaseMigrations.waitForDatabase }} +{{- if .Values.database.waitForDatabase }} - name: wait-for-db - image: "bitnamilegacy/postgresql:latest" + image: "postgres:16" command: ['sh', '-c'] args: - | @@ -16,9 +16,9 @@ env: {{- include "runtime-api.env" . | nindent 4 }} {{- end }} -{{- if .Values.databaseMigrations.createDatabases }} +{{- if .Values.database.createDatabases }} - name: create-db - image: "bitnamilegacy/postgresql:latest" + image: "postgres:16" command: ['sh', '-c'] args: - | @@ -31,7 +31,7 @@ env: {{- include "runtime-api.env" . | nindent 4 }} {{- end }} -{{- if .Values.databaseMigrations.migrate }} +{{- if .Values.database.migrate }} - name: migrate-db image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" command: ["alembic", "upgrade", "head"] diff --git a/charts/runtime-api/templates/db-cleanup-cronjob.yaml b/charts/runtime-api/templates/db-cleanup-cronjob.yaml index 1b2c026b..4fd8e034 100644 --- a/charts/runtime-api/templates/db-cleanup-cronjob.yaml +++ b/charts/runtime-api/templates/db-cleanup-cronjob.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.dbCleanup.enabled (or .Values.postgresql.enabled .Values.database.secretName) }} +{{- if .Values.dbCleanup.enabled }} apiVersion: batch/v1 kind: CronJob metadata: diff --git a/charts/runtime-api/templates/troubleshoot/support-bundle.yaml b/charts/runtime-api/templates/troubleshoot/support-bundle.yaml index 3198cb00..09f6b3d6 100644 --- a/charts/runtime-api/templates/troubleshoot/support-bundle.yaml +++ b/charts/runtime-api/templates/troubleshoot/support-bundle.yaml @@ -14,25 +14,6 @@ spec: - app.kubernetes.io/instance={{ .Release.Name }} limits: maxAge: 720h - {{- if .Values.postgresql.enabled }} - # PostgreSQL logs (Bitnami chart) - - logs: - name: app/{{ .Release.Name }}-postgresql/logs - namespace: {{ .Release.Namespace }} - selector: - - app.kubernetes.io/name=postgresql - - app.kubernetes.io/instance={{ .Release.Name }} - limits: - maxAge: 168h - - postgresql: - collectorName: postgresql - uri: postgresql://postgres:@{{ include "runtime-api.postgresql.host" . }}:5432/{{ .Values.postgresql.auth.database | default "runtime_api" }}?sslmode=disable - tls: - disabled: true - password: - secretName: {{ .Release.Name }}-postgresql - secretKey: postgres-password - {{- end }} analyzers: {{- include "runtime.troubleshoot.analyzers.shared" . | nindent 4 }} - deploymentStatus: name: {{ include "runtime-api.fullname" . }} @@ -44,32 +25,4 @@ spec: - pass: when: ">= 1" message: "Runtime API deployment is ready" - {{- if .Values.postgresql.enabled }} - - statefulsetStatus: - name: {{ .Release.Name }}-postgresql - namespace: {{ .Release.Namespace }} - outcomes: - - fail: - when: "< 1" - message: "Runtime API PostgreSQL statefulset is not ready" - - pass: - when: ">= 1" - message: "Runtime API PostgreSQL statefulset is ready" - - postgresql: - checkName: "Runtime API PostgreSQL Database Health" - collectorName: postgresql - outcomes: - - fail: - when: "connected == false" - message: "Cannot connect to Runtime API PostgreSQL database" - - fail: - when: "version == \"\"" - message: "Runtime API PostgreSQL version could not be determined" - - warn: - when: "version < 12.0.0" - message: "Runtime API PostgreSQL version is older than recommended (12.0.0+)" - - pass: - when: "connected == true" - message: "Runtime API PostgreSQL database is healthy" - {{- end }} {{- end -}} diff --git a/charts/runtime-api/values.yaml b/charts/runtime-api/values.yaml index a1456d83..22935786 100644 --- a/charts/runtime-api/values.yaml +++ b/charts/runtime-api/values.yaml @@ -3,11 +3,6 @@ fullnameOverride: "" replicaCount: 1 -databaseMigrations: - waitForDatabase: true - createDatabases: false - migrate: true - image: repository: ghcr.io/openhands/runtime-api tag: sha-7857be8 @@ -73,37 +68,36 @@ tolerations: [] affinity: {} -postgresql: - enabled: false - isFeatureDeploy: false - primary: - persistence: - enabled: false - auth: - username: postgres - password: "" # This should be set externally for security reasons - existingSecret: postgres-password - database: runtime_api_db - service: - ports: - postgresql: 5432 - image: - repository: bitnamilegacy/postgresql - -externalDatabase: - enabled: false - existingSecret: postgres-password - -# External database configuration (used when postgresql.enabled=false) +# PostgreSQL database configuration database: - create: false # Will only be true for AWS as it can't create the DB in terraform - secretName: runtime-api-db-credentials # Secret containing external database credentials + # Hostname of the PostgreSQL server + host: "oh-main-postgresql-rw" + # Port of the PostgreSQL server + port: "5432" + # Database user + user: "postgres" + # Database name + name: "runtime_api_db" + # Name of the Kubernetes secret containing the database password + secretName: "postgres-password" + # Key within the secret that holds the password + secretKey: "password" + # Wait for the database to be ready before starting the application + waitForDatabase: true + # Create the database if it does not exist + createDatabases: false + # Run database migrations on startup + migrate: true + # Create database user if it does not exist + create: false + # Name of the secret containing credentials for user creation + createJobSecretName: "runtime-api-db-credentials" poolSize: - api: 5 # Pool size for API deployment (default) - cronjobs: 2 # Pool size for cronjobs (default) + api: 5 + cronjobs: 2 maxOverflow: - api: 10 # Max overflow for API deployment (default) - cronjobs: 5 # Max overflow for cronjobs (default) + api: 10 + cronjobs: 5 helm-release-pruner: enabled: false @@ -217,8 +211,3 @@ datadog: replicated: enabled: false -global: - security: - # This allows using the bitnamilegacy image repo. - # See: https://github.com/bitnami/containers/issues/83267 - allowInsecureImages: true diff --git a/docs/cnpg-migration-guide.md b/docs/cnpg-migration-guide.md new file mode 100644 index 00000000..76e21215 --- /dev/null +++ b/docs/cnpg-migration-guide.md @@ -0,0 +1,317 @@ +# Migration Guide: Bitnami PostgreSQL to CloudNative-PG (CNPG) + +This guide covers migrating the embedded PostgreSQL from the Bitnami subchart to CloudNative-PG (CNPG) with zero data loss. This applies to deployments using the embedded PostgreSQL (`postgresql.enabled: true` in the old chart). + +> **Downtime**: The dump (Step 1) runs while the application is live. Downtime begins when you scale down workloads (Step 3) and ends when the final helm upgrade brings everything back up (Step 6). + +## Prerequisites + +- `kubectl` access to the cluster +- `helm` v3 +- Current chart version: openhands `0.3.x` (Bitnami PostgreSQL) +- Target chart version: openhands `0.4.0` (CNPG) + +## Step 1: Dump All Databases + +### 1a. Set variables + +```bash +NAMESPACE=openhands # adjust if different +``` + +### 1b. Create a PVC for the dump + +Size this larger than your database. Check current usage with: + +```bash +kubectl exec -n $NAMESPACE \ + $(kubectl get pods -n $NAMESPACE -l app.kubernetes.io/name=postgresql -o jsonpath='{.items[0].metadata.name}') \ + -- psql -U postgres -c "SELECT pg_size_pretty(sum(pg_database_size(datname))) FROM pg_database;" +``` + +```bash +kubectl apply -n $NAMESPACE -f - <<'EOF' +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pg-migration-dump +spec: + accessModes: [ReadWriteOnce] + resources: + requests: + storage: 50Gi # adjust based on database size +EOF +``` + +### 1c. Run the dump + +```bash +kubectl apply -n $NAMESPACE -f - <<'EOF' +apiVersion: batch/v1 +kind: Job +metadata: + name: pg-migration-dump +spec: + backoffLimit: 0 + template: + spec: + restartPolicy: Never + volumes: + - name: dump + persistentVolumeClaim: + claimName: pg-migration-dump + containers: + - name: dump + image: postgres:17 + volumeMounts: + - name: dump + mountPath: /dump + env: + - name: PGHOST + value: oh-main-postgresql + - name: PGUSER + value: postgres + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: postgres-password + key: password + command: ["sh", "-c"] + args: + - pg_dumpall --clean --if-exists > /dump/all.sql && ls -lh /dump/all.sql +EOF +``` + +### 1d. Verify + +```bash +kubectl wait --for=condition=Complete job/pg-migration-dump -n $NAMESPACE --timeout=3600s +kubectl logs job/pg-migration-dump -n $NAMESPACE +``` + +The logs should show the dump file size. Once confirmed, clean up the job: + +```bash +kubectl delete job pg-migration-dump -n $NAMESPACE +``` + +## Step 2: Install the CNPG Operator + +```bash +helm repo add cnpg https://cloudnative-pg.github.io/charts +helm repo update + +helm install cnpg-operator cnpg/cloudnative-pg \ + -n cnpg-system --create-namespace + +kubectl wait --for=condition=Available deployment/cnpg-operator-cloudnative-pg \ + -n cnpg-system --timeout=120s +``` + +## Step 3: Scale Down All Workloads + +Scale everything to zero so nothing writes to the database during the migration. + +```bash +kubectl scale deployment -n $NAMESPACE --all --replicas=0 +kubectl scale statefulset -n $NAMESPACE --all --replicas=0 +kubectl patch cronjob -n $NAMESPACE --type=merge -p '{"spec":{"suspend":true}}' --all +``` + +Wait until no pods remain: + +```bash +kubectl get pods -n $NAMESPACE +``` + +## Step 4: Upgrade the OpenHands Chart (replicas=0) + +### 4a. Update your values file + +**Remove** these sections: + +```yaml +postgresql: + enabled: true + auth: + username: postgres + existingSecret: postgres-password + # ... + +externalDatabase: + enabled: false + existingSecret: postgres-password + +databaseMigrations: + waitForDatabase: true + createDatabases: false + migrate: true +``` + +**Add** these sections: + +```yaml +database: + host: "oh-main-postgresql-rw" + port: "5432" + user: "postgres" + name: "openhands" + secretName: "postgres-password" + secretKey: "password" + waitForDatabase: true + createDatabases: true + migrate: true + +cnpg: + enabled: true + imageName: "ghcr.io/cloudnative-pg/postgresql:17" + instances: 1 + storage: + size: 10Gi + # storageClass: "" # set if you need a specific storage class +``` + +**Update `runtime-api`**: Remove the old `databaseMigrations`, `postgresql`, and `externalDatabase` keys. Also remove `DB_HOST` from `runtime-api.env` if present. Add: + +```yaml +runtime-api: + database: + waitForDatabase: true + createDatabases: false + migrate: true +``` + +**Update hostname references** from `oh-main-postgresql` to `oh-main-postgresql-rw`: + +```yaml +keycloak: + externalDatabase: + host: oh-main-postgresql-rw + +litellm-helm: + db: + endpoint: oh-main-postgresql-rw +``` + +### 4b. Run the helm upgrade with replicas held at zero + +```bash +helm upgrade openhands oci://ghcr.io/all-hands-ai/helm-charts/openhands --version \ + -n $NAMESPACE \ + -f your-values.yaml \ + --set deployment.replicas=0 \ + --set runtime-api.replicaCount=0 \ + --set automation.deployment.replicas=0 \ + --set keycloak.replicaCount=0 \ + --timeout 600s +``` + +Scale down anything the `--set` overrides didn't cover (e.g. LiteLLM): + +```bash +kubectl scale deployment -n $NAMESPACE --all --replicas=0 +kubectl scale statefulset -n $NAMESPACE --all --replicas=0 +``` + +### 4c. Wait for the CNPG cluster + +```bash +kubectl wait --for=condition=Ready cluster/oh-main-postgresql \ + -n $NAMESPACE --timeout=300s +``` + +## Step 5: Restore the Database Dump + +```bash +kubectl apply -n $NAMESPACE -f - <<'EOF' +apiVersion: batch/v1 +kind: Job +metadata: + name: pg-migration-restore +spec: + backoffLimit: 0 + template: + spec: + restartPolicy: Never + volumes: + - name: dump + persistentVolumeClaim: + claimName: pg-migration-dump + containers: + - name: restore + image: postgres:17 + volumeMounts: + - name: dump + mountPath: /dump + env: + - name: PGHOST + value: oh-main-postgresql-rw + - name: PGUSER + value: postgres + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: postgres-password + key: password + command: ["sh", "-c"] + args: + - psql -f /dump/all.sql +EOF +``` + +```bash +kubectl wait --for=condition=Complete job/pg-migration-restore -n $NAMESPACE --timeout=7200s +kubectl logs job/pg-migration-restore -n $NAMESPACE +``` + +You will see some harmless errors like `role "postgres" already exists`. This is expected. + +Clean up: + +```bash +kubectl delete job pg-migration-restore -n $NAMESPACE +kubectl delete pvc pg-migration-dump -n $NAMESPACE +``` + +## Step 6: Bring the Application Back Up + +Run the upgrade again **without** the `--set *.replicas=0` overrides: + +```bash +helm upgrade openhands oci://ghcr.io/all-hands-ai/helm-charts/openhands --version \ + -n $NAMESPACE \ + -f your-values.yaml \ + --wait --timeout 600s +``` + +Database migrations run automatically on startup. + +## Verification + +1. **CNPG cluster health**: + ```bash + kubectl get cluster oh-main-postgresql -n $NAMESPACE + ``` + Status should show `Cluster in healthy state`. + +2. **Databases present**: + ```bash + kubectl exec -n $NAMESPACE oh-main-postgresql-1 -- psql -U postgres -c '\l' + ``` + +3. **Application access**: Log in to the OpenHands UI and verify authentication works and existing conversations are visible. + +## Rollback + +The old Bitnami PostgreSQL PVC is preserved during migration. + +1. `helm rollback openhands` to the previous revision +2. Uninstall the CNPG operator + +## Cleanup + +Once you've verified the migration is successful and no longer need the rollback option: + +```bash +kubectl delete pvc data-oh-main-postgresql-0 -n $NAMESPACE +``` diff --git a/replicated/application.yaml b/replicated/application.yaml index aede3aa2..6d5f341a 100644 --- a/replicated/application.yaml +++ b/replicated/application.yaml @@ -29,9 +29,8 @@ spec: - openhands/statefulset/keycloak - openhands/service/keycloak - # postgres - - '{{repl if ConfigOptionEquals "postgres_type" "embedded_postgres"}}openhands/statefulset/openhands-postgresql{{repl end}}' - - '{{repl if ConfigOptionEquals "postgres_type" "embedded_postgres"}}openhands/service/openhands-postgresql{{repl end}}' + # postgres (CNPG) + - '{{repl if ConfigOptionEquals "postgres_type" "embedded_postgres"}}openhands/pod/oh-main-postgresql-1{{repl end}}' # redis - openhands/statefulset/openhands-redis-master diff --git a/replicated/infra.yaml b/replicated/infra.yaml new file mode 100644 index 00000000..5a2fafdd --- /dev/null +++ b/replicated/infra.yaml @@ -0,0 +1,30 @@ +apiVersion: kots.io/v1beta2 +kind: HelmChart +metadata: + name: infra +spec: + chart: + name: infra + releaseName: infra + namespace: openhands + weight: 5 + helmUpgradeFlags: ["--wait", "--timeout", "300s"] + values: + cloudnative-pg: + enabled: true + image: + repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/cloudnative-pg/cloudnative-pg' + imagePullSecrets: + - name: '{{repl ImagePullSecretName }}' + + optionalValues: + - when: '{{repl HasLocalRegistry }}' + recursiveMerge: true + values: + cloudnative-pg: + image: + repository: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/cloudnative-pg' + + builder: + cloudnative-pg: + enabled: true diff --git a/replicated/openhands.yaml b/replicated/openhands.yaml index 7c5b2f3c..f121520d 100644 --- a/replicated/openhands.yaml +++ b/replicated/openhands.yaml @@ -83,7 +83,7 @@ spec: certificate: | {{repl ConfigOptionData "tls_certificate" | nindent 14}} externalDatabase: - host: '{{repl if ConfigOptionEquals "postgres_type" "external_postgres"}}{{repl ConfigOption "external_postgres_host"}}{{repl else}}oh-main-postgresql{{repl end}}' + host: '{{repl if ConfigOptionEquals "postgres_type" "external_postgres"}}{{repl ConfigOption "external_postgres_host"}}{{repl else}}oh-main-postgresql-rw{{repl end}}' existingSecret: postgres-password existingSecretUserKey: username existingSecretPasswordKey: password @@ -93,7 +93,7 @@ spec: image: repository: 'proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/keycloak-config-cli' waitForDb: - image: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/postgresql:latest' + image: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/library/postgres:16' litellm: enabled: true @@ -103,7 +103,7 @@ spec: enabled: true db: # TODO: should the fallback be openhands-postgresql here? - endpoint: '{{repl if ConfigOptionEquals "postgres_type" "external_postgres"}}{{repl ConfigOption "external_postgres_host"}}{{repl else}}oh-main-postgresql{{repl end}}' + endpoint: '{{repl if ConfigOptionEquals "postgres_type" "external_postgres"}}{{repl ConfigOption "external_postgres_host"}}{{repl else}}oh-main-postgresql-rw{{repl end}}' secret: name: postgres-password usernameKey: username @@ -165,7 +165,7 @@ spec: idle_seconds: repl{{ ConfigOption "sandbox_idle_seconds" }} dead_seconds: repl{{ ConfigOption "sandbox_dead_seconds" }} env: - DB_HOST: '{{repl if ConfigOptionEquals "postgres_type" "external_postgres"}}{{repl ConfigOption "external_postgres_host"}}{{repl else}}oh-main-postgresql{{repl end}}' + DB_HOST: '{{repl if ConfigOptionEquals "postgres_type" "external_postgres"}}{{repl ConfigOption "external_postgres_host"}}{{repl else}}oh-main-postgresql-rw{{repl end}}' DB_USER: '{{repl if ConfigOptionEquals "postgres_type" "external_postgres"}}{{repl ConfigOption "external_postgres_username"}}{{repl else}}postgres{{repl end}}' DB_NAME: "runtime_api_db" RUNTIME_BASE_URL: '{{repl if ConfigOptionEquals "hostname_mode" "derive"}}runtime.{{repl ConfigOption "base_domain"}}{{repl else}}{{repl ConfigOption "runtime_base_hostname"}}{{repl end}}' @@ -219,7 +219,7 @@ spec: kubernetes.io/ingress.class: traefik sandbox: apiHostname: 'http://openhands-runtime-api:5000' - postgresql: + cnpg: enabled: repl{{ ConfigOptionEquals "postgres_type" "embedded_postgres" }} redis: enabled: true @@ -266,21 +266,18 @@ spec: runtime-api: databaseMigrations: createDatabases: true - postgresql: + cnpg: enabled: true - auth: - username: '{{repl ConfigOption "postgres_username"}}' - password: '{{repl ConfigOption "postgres_password" | Base64Encode }}' - postgresPassword: '{{repl ConfigOption "postgres_password" | Base64Encode }}' - database: '{{repl ConfigOption "postgres_database"}}' - persistence: - enabled: true + username: '{{repl ConfigOption "postgres_username"}}' + storage: + size: 10Gi + storageClass: "openebs-hostpath" - when: '{{repl ConfigOptionEquals "postgres_type" "external_postgres" }}' recursiveMerge: true values: databaseMigrations: createDatabases: repl{{ ConfigOptionEquals "external_postgres_create_databases" "1" }} - postgresql: + cnpg: enabled: false externalDatabase: host: '{{repl ConfigOption "external_postgres_host"}}' @@ -317,13 +314,8 @@ spec: - when: '{{repl ConfigOptionEquals "postgres_type" "embedded_postgres" }}' recursiveMerge: true values: - postgresql: - image: - repository: 'proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/postgresql' - keycloak: - postgresql: - image: - repository: 'proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/postgresql' + cnpg: + imageName: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/cloudnative-pg/postgresql:16' - when: '{{repl ConfigOptionEquals "langfuse_enabled" "1" }}' recursiveMerge: true values: @@ -393,10 +385,9 @@ spec: image: repository: '{{repl LocalRegistryNamespace }}/keycloak-config-cli' waitForDb: - image: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/postgresql:latest' - postgresql: - image: - repository: '{{repl LocalRegistryNamespace }}/postgresql' + image: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/postgres:16' + cnpg: + imageName: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/postgresql:16' redis: image: repository: '{{repl LocalRegistryNamespace }}/redis' @@ -528,8 +519,6 @@ spec: enabled: true minio: enabled: true - postgresql: - enabled: true redis: enabled: true runtime-api: diff --git a/replicated/secrets.yaml b/replicated/secrets.yaml index dcca99d5..c53c71d0 100644 --- a/replicated/secrets.yaml +++ b/replicated/secrets.yaml @@ -26,7 +26,7 @@ spec: # Database configuration # TODO: is this the correct hostname fallback for embedded postgres? - postgres_host: '{{repl if ConfigOptionEquals "postgres_type" "external_postgres"}}{{repl ConfigOption "external_postgres_host"}}{{repl else}}oh-main-postgresql{{repl end}}' + postgres_host: '{{repl if ConfigOptionEquals "postgres_type" "external_postgres"}}{{repl ConfigOption "external_postgres_host"}}{{repl else}}oh-main-postgresql-rw{{repl end}}' postgres_username: '{{repl if ConfigOptionEquals "postgres_type" "external_postgres"}}{{repl ConfigOption "external_postgres_username"}}{{repl else}}{{repl ConfigOption "postgres_username"}}{{repl end}}' postgres_database: '{{repl if ConfigOptionEquals "postgres_type" "external_postgres"}}{{repl ConfigOption "external_postgres_database"}}{{repl else}}{{repl ConfigOption "postgres_database"}}{{repl end}}' postgres_password: '{{repl if ConfigOptionEquals "postgres_type" "external_postgres"}}{{repl ConfigOption "external_postgres_password"}}{{repl else}}{{repl ConfigOption "postgres_password"}}{{repl end}}'