Deploying on Kubernetes
A Helm chart installs the platform as one pod with a persistent volume. Read Deploying dpndncY first: the model (two ports, one replica, one volume) applies unchanged.
#What you need
- Kubernetes 1.25 or later, and Helm 3.
- A default
StorageClass, or one you name. The pod needs oneReadWriteOncevolume of 10 GB or more. - An ingress controller with a certificate source (for example ingress-nginx with cert-manager), and two DNS names, for example
dpndncy.example.com(console) andapi.dpndncy.example.com(API). - The pod requests 250m CPU and 512 Mi, and is limited to 2 CPUs and 2 Gi. Raise the limits for large scans.
#Install
Create a values file. This is a complete, working example:
# values-dpndncy.yaml
config:
publicUrl: https://dpndncy.example.com # the address people open
enableBootstrapSuperadmin: "true" # creates the first operator; switch off after first sign-in
secret:
appSecret: "<output of: openssl rand -hex 32>"
superadminEmail: [email protected]
superadminPassword: "<a long password>"
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: dpndncy.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: dpndncy-tls
hosts: [dpndncy.example.com]
# The API for the CLI, CI pipelines and runtime agents, on its own hostname.
api:
enabled: true
host: api.dpndncy.example.com
tls:
- secretName: dpndncy-api-tls
hosts: [api.dpndncy.example.com]
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/proxy-body-size: "256m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"Install from the registry (use the version of the release you want):
helm install dpndncy oci://ghcr.io/dpndncy-sca/charts/dpndncy \
--version <chart-version> \
--namespace dpndncy --create-namespace \
-f values-dpndncy.yamlOr from the chart repository on dpndncy.com, which needs no registry login (the image still has to be pullable, see Getting the software):
helm repo add dpndncy https://dpndncy.com/charts
helm install dpndncy dpndncy/dpndncy --version 2.9.0 \
--namespace dpndncy --create-namespace \
-f values-dpndncy.yamlOr from a checkout: helm install dpndncy ./helm -n dpndncy --create-namespace -f values-dpndncy.yaml.
Watch it start, then sign in at the console address with superadminEmail:
kubectl -n dpndncy rollout status deploy/dpndncy
kubectl -n dpndncy logs deploy/dpndncy --tail=50Continue with "Setting up a new workplace" in Deploying dpndncY. After your first sign-in, switch the bootstrap off so a pod restart cannot reset the operator password:
helm upgrade dpndncy ./helm -n dpndncy -f values-dpndncy.yaml --set config.enableBootstrapSuperadmin=false#The settings that matter
| Value | Meaning |
|---|---|
config.publicUrl |
The address people open. Required (or enable the ingress with a host, from which it is derived). It becomes CORS_ORIGIN, APP_URL and NEXT_PUBLIC_APP_ORIGIN, and decides secure cookies (https) and proxy trust. The chart refuses to render without it, because the backend would otherwise exit at start-up |
config.apiUrl |
The API address, if it is not one of the ingress hosts |
ingress.api.* |
The second hostname for the API. Without a path to port 3001, only browsers can reach the platform |
secret.appSecret |
Signs sessions and API tokens. Required. Keep it stable |
secret.existingSecret |
Name of a Secret you manage yourself (see below) |
persistence.size, .storageClass, .existingClaim |
The data volume, mounted at /app/data |
image.tag |
stable by default. Pin a version to control upgrades |
resources |
CPU and memory |
config.airgapped |
"true" for sites with no internet (Running dpndncY without internet access (air-gapped)) |
For a quick look without an ingress, set config.publicUrl=http://localhost:3000 and use kubectl port-forward svc/dpndncy 3000:80 -n dpndncy. The API is on the same service at port 3001.
#Keeping secrets out of values files
Create a Secret and point the chart at it. The keys are the environment variable names:
kubectl -n dpndncy create secret generic dpndncy-secrets \
--from-literal=APP_SECRET="$(openssl rand -hex 32)" \
[email protected] \
--from-literal=SUPERADMIN_PASSWORD='<a long password>'secret:
existingSecret: dpndncy-secretsOptional keys: NVD_API_KEY, GITHUB_TOKEN, SMTP_USER, SMTP_PASS, OIDC_*. Any other setting can be added with extraEnv (plain values) or extraEnvFrom (from a Secret or ConfigMap).
#One replica, by design
The chart uses the Recreate strategy and does not allow autoscaling: the database is one SQLite file, and two pods must never write it. During an upgrade the old pod stops before the new one starts, so there is a short outage while the new pod comes up.
#Upgrading
helm upgrade dpndncy oci://ghcr.io/dpndncy-sca/charts/dpndncy --version <new-version> \
-n dpndncy -f values-dpndncy.yamlA new version can migrate the database. Take a backup first (Running dpndncY). Rolling back the chart does not roll back a migrated database; restore the backup too.
#Runtime agent (optional)
The runtime agent watches CI build pods at the kernel level and reports what they did. Enable it as a DaemonSet:
runtimeAgent:
enabled: true
mode: observe # observe, learn, or enforce
tenantId: "<tenant id>"
token: "<API token of a user in that tenant>"It talks to the API service inside the cluster by default. Details and modes are in the runtime agent documentation at https://dpndncy.com/docs/runtime. It runs privileged, so review the chart's RBAC and your cluster policy first.
#Troubleshooting
| Symptom | Cause and fix |
|---|---|
helm install fails with "Set config.publicUrl ..." |
Intended. Set config.publicUrl, or enable the ingress with a host |
Pod in CrashLoopBackOff, log says CORS_ORIGIN missing or APP_SECRET ... missing |
Use the chart's values rather than hand-made manifests. With existingSecret, the Secret must contain APP_SECRET |
Pod Pending |
No volume could be bound. Check kubectl get pvc -n dpndncy and the StorageClass |
| Console loads, pipelines get 404 | The pipeline is calling the console address. Use the API address (ingress.api.host) |
| Sign-in fails with "request could not be verified" | config.publicUrl does not match the address in the browser |
| Large uploads fail with 413 | Raise proxy-body-size on the API ingress (annotation above) |
| Scans cut off after a minute | Raise the proxy read and send timeouts on the API ingress |
| Everyone is signed out after a pod restart | Expected: browser sessions end whenever the server restarts. API tokens keep working |
#Verification status
The chart is linted and rendered in CI on every change, including a case that must refuse to render. The container itself is built and run through a startup, upload, persistence and recovery test in CI. Try the install in a test namespace before production, as you would with any chart.