Deploy DevPortal to Kubernetes
This guide walks through deploying DevPortal V2 to a Kubernetes cluster using the veecode-devportal-platform Helm chart. See Plan your setup before proceeding.
For environments where Helm is not available, a no-Helm fallback using raw manifests is documented at the end of this page.
Step 1: Add the Helm repository (optional)
The install and upgrade commands in this guide point straight at the chart repo URL with --repo, so this step isn't required. Add it only if you want a persistent local alias — useful for helm search/helm show values outside of an install:
helm repo add next-charts https://veecode-platform.github.io/next-charts
helm repo update next-charts
helm search repo veecode-devportal-platform
# should show a CHART VERSION / APP VERSION pair, e.g. 0.4.0 / 2.2.0 — check
# https://veecode-platform.github.io/next-charts/index.yaml for the current latest
With the alias in place, swap veecode-devportal-platform --repo https://veecode-platform.github.io/next-charts for next-charts/veecode-devportal-platform in any command below.
Step 2: Create the credentials Secret
Credentials for the presets you select must be in a Kubernetes Secret before helm install. The chart references it via existingSecret.
Never pass production credentials through --set credentials.* — that stores them in the Helm release manifest. Use existingSecret for production.
- GitHub
- GitLab
- Azure
For the github and github-auth presets:
kubectl create secret generic my-devportal-creds \
--namespace platform \
--from-literal=GITHUB_PAT=<personal-access-token> \
--from-literal=GITHUB_ORG=<your-org> \
--from-literal=GITHUB_AUTH_CLIENT_ID=<oauth-client-id> \
--from-literal=GITHUB_AUTH_CLIENT_SECRET=<oauth-client-secret>
For the gitlab preset (identity + integration):
kubectl create secret generic my-devportal-creds \
--namespace platform \
--from-literal=GITLAB_HOST=gitlab.com \
--from-literal=GITLAB_TOKEN=<personal-access-token> \
--from-literal=GITLAB_AUTH_CLIENT_ID=<oauth-app-id> \
--from-literal=GITLAB_AUTH_CLIENT_SECRET=<oauth-app-secret> \
--from-literal=GITLAB_GROUP=<root-group>
For the azure (integration) and azure-auth (identity) presets:
kubectl create secret generic my-devportal-creds \
--namespace platform \
--from-literal=AZURE_DEVOPS_TOKEN=<pat> \
--from-literal=AZURE_DEVOPS_HOST=dev.azure.com \
--from-literal=AZURE_DEVOPS_ORG=<org> \
--from-literal=AZURE_DEVOPS_PROJECT=<project> \
--from-literal=AZURE_AUTH_TENANT_ID=<tenant-id> \
--from-literal=AZURE_AUTH_CLIENT_ID=<client-id> \
--from-literal=AZURE_AUTH_CLIENT_SECRET=<client-secret>
For GitOps workflows, use an external secrets operator (External Secrets Operator, Vault Agent, Sealed Secrets) to populate the Secret from your secrets store.
PostgreSQL credentials (production)
For production deployments using external PostgreSQL (see Step 3), include the database credentials in the same Secret. The chart injects them into backend.database automatically when database.external.enabled=true:
| Key | Description |
|---|---|
PG_HOST | PostgreSQL hostname or endpoint |
PG_PORT | Port — typically 5432 |
PG_USER | Database user |
PG_PASSWORD | Database password |
PG_DATABASE | Database name — backstage is the conventional default |
Add them to your kubectl create secret command above, or patch an existing Secret:
kubectl patch secret my-devportal-creds \
--namespace platform \
--type merge \
--patch '{"stringData":{"PG_HOST":"<host>","PG_PORT":"5432","PG_USER":"<user>","PG_PASSWORD":"<password>","PG_DATABASE":"backstage"}}'
For AWS RDS, prefer a Multi-AZ instance — with PVCs removed the database becomes the single durable dependency.
Step 3: Install the chart
Production (PostgreSQL — recommended)
This is the chart's default posture. database.external.enabled=true injects a backend.database block using the PG_* credentials from your Secret, and with both PVCs off the pod is fully stateless and schedules in any availability zone (the flags below are the defaults, shown explicitly for clarity):
helm install devportal veecode-devportal-platform \
--repo https://veecode-platform.github.io/next-charts \
--namespace platform \
--create-namespace \
--set 'presets={recommended,github,github-auth}' \
--set existingSecret=my-devportal-creds \
--set database.external.enabled=true \
--set persistence.data.enabled=false \
--set persistence.plugins.enabled=false
With stateless pods, replicaCount > 1 is safe for steady-state traffic. Add --set replicaCount=2 for basic HA. Note: the chart uses strategy: Recreate, so upgrades (helm upgrade) still cause a brief downtime window regardless of replica count — all pods are terminated before the new ones start.
Development / minimal (SQLite)
This is an opt-in path — the chart defaults to stateless PostgreSQL and a render-time guard blocks a bare install unless you pick a persistence path. Enable the two PVCs (/app/data and /app/dynamic-plugins-root) explicitly. Suitable for a single-node dev cluster only; an EBS- or RWO-backed PVC pins the pod to one availability zone and is not recommended for production:
helm install devportal veecode-devportal-platform \
--repo https://veecode-platform.github.io/next-charts \
--namespace platform \
--create-namespace \
--set 'presets={recommended,github,github-auth}' \
--set existingSecret=my-devportal-creds \
--set persistence.data.enabled=true \
--set persistence.plugins.enabled=true