dpndncY

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 one ReadWriteOnce volume 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) and api.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.yaml

Or 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.yaml

Or 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=50

Continue 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-secrets

Optional 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.yaml

A 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.