Deploy on Kubernetes using Helm
The supported method for deploying Anchore Enterprise on Kubernetes is with Helm. The Anchore Enterprise Helm Chart includes configuration options for a full Enterprise deployment.
About the Helm Chart
The chart is split into global and service-specific configurations for the core features, as well as global and service-specific configurations for the optional Anchore Enterprise services.
- The
anchoreConfigsection of the values file contains the application configuration for Anchore Enterprise. This includes the database connection information, credentials, and other application settings. - Anchore Enterprise services run as Kubernetes deployments when installed with the Helm chart. Each service has its own section in the values file for making customizations and configuring the Kubernetes deployment spec.
For a description of each service component, see Anchore Enterprise Service Overview.
pg_cron extension before deploying. See Provision the Database below. Redis, used by the Enterprise UI, is still deployed by the chart.Prerequisites
Before deploying, ensure you have the following in place:
| Requirement | Details |
|---|---|
| Kubernetes | Any CNCF-certified Kubernetes within the chart’s supported range. The chart declares this in its kubeVersion constraint (1.23–1.36 at the time of writing). |
| Helm | v3.8 or above |
kubectl | Configured for your target cluster |
| Anchore Enterprise license | A valid license.yaml file |
| Docker Hub credentials | Access to pull the anchore/enterprise and anchore/enterprise-ui images. Contact Anchore Support to obtain access. |
| PostgreSQL | An external PostgreSQL 17+ database with the pg_cron extension enabled. See Requirements. |
| Docker or Podman | Docker Engine 28+ or Podman 6.0+ to build the CNPG image if needed** |
See the chart prerequisites in the README for the most current details.
Provision the Database
Anchore Enterprise 6.x requires a customer-managed PostgreSQL 17 database with the pg_cron extension installed and enabled, cron.use_background_workers turned on, and USAGE on the cron schema granted to the Anchore database user. Provision this database before installing the chart. There are two common approaches:
Managed PostgreSQL service (recommended for production) — Use a cloud-provider managed database such as Amazon RDS, Google Cloud SQL, or Azure Database for PostgreSQL. Each cloud-provider deployment guide includes the provider-specific steps to enable
pg_cron:In-cluster PostgreSQL with an operator — Run PostgreSQL inside the cluster with an operator such as CloudNativePG (CNPG). See Run PostgreSQL In-Cluster with CloudNativePG below.
pg_cron extension is not included in the default PostgreSQL container images. When running PostgreSQL in-cluster, you must build and host a PostgreSQL 17 image that includes pg_cron.Run PostgreSQL In-Cluster with CloudNativePG
CloudNativePG is a Kubernetes operator that manages the full lifecycle of PostgreSQL clusters. This is a good option for teams who want to run PostgreSQL in-cluster while still getting operator-managed reliability. For production, Anchore still recommends a managed database service.
Build a PostgreSQL 17 image that includes
pg_cron. The default CNPG images do not ship withpg_cron, so build and push your own:FROM ghcr.io/cloudnative-pg/postgresql:17 USER root RUN apt-get update && \ apt-get install -y --no-install-recommends postgresql-17-cron && \ rm -rf /var/lib/apt/lists/* USER postgresdocker build -t <YOUR_REGISTRY>/postgresql-pgcron:17 . docker push <YOUR_REGISTRY>/postgresql-pgcron:17Use the CNPG base image (ghcr.io/cloudnative-pg/postgresql) rather than the genericpostgresimage. The CNPG image includes the tooling the operator expects for lifecycle management, backups, and WAL archiving. This image is your responsibility to maintain and is not an Anchore-supported artifact.If you are unable to build with APT resources please reach out to Anchore Customer Success for alternative solutions.Install the CNPG operator (once per cluster):
helm repo add cnpg https://cloudnative-pg.github.io/charts helm repo update helm install cnpg cnpg/cloudnative-pg --namespace cnpg-system --create-namespaceCreate the PostgreSQL cluster. Create
cnpg-cluster.yaml, referencing your custom image. Thepostgresql.parametersandresourcesbelow are starting points — size them to your instance memory and workload, and see Database Tuning for the parameters Anchore recommends adjusting in production:apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: anchore-pg namespace: anchore spec: instances: 1 imageName: <YOUR_REGISTRY>/postgresql-pgcron:17 postgresql: shared_preload_libraries: - pg_cron parameters: # These are starting points — size them to your instance/pod memory and workload. # See the Database Tuning guidance on the Requirements page for details and defaults. max_connections: "2000" # each Anchore pod opens ~30-100 connections; size for your replica count (minimum 500) shared_buffers: "4GB" # PostgreSQL's dedicated cache; ~25% of the pod's memory (requires restart) effective_cache_size: "12GB" # planner hint for total cache available (~50-75% of memory); not an allocation work_mem: "32MB" # memory per sort/hash operation (default 4MB); larger SBOMs/policies benefit. # Allocated per operation, so peak ~= work_mem x concurrent operations — raise gradually maintenance_work_mem: "512MB" # memory for VACUUM, index builds, and similar maintenance min_wal_size: "2GB" # WAL floor max_wal_size: "8GB" # larger WAL reduces checkpoint frequency under heavy write/analysis load random_page_cost: "1.1" # lower for SSD/NVMe (gp3/io1) so the planner favors index scans; leave 4.0 for spinning disks autovacuum_max_workers: "5" # more autovacuum workers for write-heavy deployments (requires restart) autovacuum_vacuum_cost_limit: "3000" # let autovacuum do more before pausing; reduces table bloat (reload, no restart) "cron.database_name": "anchore" # database pg_cron runs its jobs in "cron.use_background_workers": "on" # required by Anchore Enterprise bootstrap: initdb: database: anchore owner: anchore postInitApplicationSQL: - "CREATE EXTENSION IF NOT EXISTS pg_cron;" - "GRANT USAGE ON SCHEMA cron TO anchore;" - "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA cron TO anchore;" - "GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA cron TO anchore;" storage: size: 100Gi # storageClass: gp3 # set for your environment resources: requests: memory: "16Gi" cpu: "4" limits: memory: "32Gi" # No CPU limit is set intentionally. Anchore does not recommend a CPU limit on the # database — CPU throttling under load causes query latency spikes. Use requests to # guarantee capacity, and size requests/limits to your workload.kubectl create namespace anchore kubectl apply -f cnpg-cluster.yaml kubectl get cluster anchore-pg -n anchore -wVerify
pg_cronis installed and running:kubectl exec -it anchore-pg-1 -n anchore -- \ psql -U anchore -d anchore -c "SELECT * FROM pg_extension WHERE extname = 'pg_cron';" kubectl exec -it anchore-pg-1 -n anchore -- \ psql -U anchore -d anchore -c "SHOW cron.use_background_workers;"CNPG automatically creates a secret named
anchore-pg-appcontaining the database credentials, and exposes a read-write service (anchore-pg-rw) that always points to the current primary. Use the-rwservice as the database endpoint for Anchore Enterprise.
Cluster resource (for example, kubectl delete cluster anchore-pg) permanently destroys the associated PVCs and all data, because CNPG sets owner references on the PVCs. To remove a cluster without losing data, use a StorageClass with reclaimPolicy: Retain, kubectl cnpg destroy –keep-pvc, or declarative hibernation. See the CNPG documentation for details.Install the Chart
This guide covers deploying Anchore Enterprise with the default configuration against your external database. Refer to the Configuration section of the chart README for additional guidance on production deployments.
Create the namespace:
export NAMESPACE=anchore kubectl create namespace ${NAMESPACE}Create a Kubernetes secret for the license file:
export NAMESPACE=anchore export LICENSE_PATH="license.yaml" kubectl create secret generic anchore-enterprise-license --from-file=license.yaml=${LICENSE_PATH} -n ${NAMESPACE}Create a Kubernetes secret for Docker Hub credentials. These credentials are required for authenticated access to the private Anchore Enterprise repositories on Docker Hub. Contact Anchore Support to obtain access.
export NAMESPACE=anchore export DOCKERHUB_PASSWORD="password" export DOCKERHUB_USER="username" export DOCKERHUB_EMAIL="[email protected]" kubectl create secret docker-registry anchore-enterprise-pullcreds --docker-server=docker.io --docker-username=${DOCKERHUB_USER} --docker-password=${DOCKERHUB_PASSWORD} --docker-email=${DOCKERHUB_EMAIL} -n ${NAMESPACE}Create a custom values file named
anchore_values.yamlto override chart parameters. There are two ways to provide the database connection details: directly in the values file, or via pre-created Kubernetes secrets. Choose one approach.Option A: Credentials in the values file. The chart creates the necessary Kubernetes secrets for you from these values.
licenseSecretName: anchore-enterprise-license imagePullSecretName: anchore-enterprise-pullcreds postgresql: externalEndpoint: <DB_HOSTNAME> # e.g. anchore-pg-rw.anchore.svc for CNPG, or your RDS endpoint auth: username: <DB_USERNAME> password: <DB_PASSWORD> database: <DB_NAME> port: 5432 ## Optional: connect to the database over TLS. This requires mounting the ## database CA certificate via certStoreSecretName. # certStoreSecretName: anchore-certs # anchoreConfig: # database: # ssl: true # sslMode: verify-full # sslRootCertFileName: <CA_CERT_KEY>Option B: Using existing Kubernetes secrets. For environments where credentials should not be stored in values files (for example, GitOps workflows), create the secrets manually and reference them. See the Existing Secrets section of the chart README for the full secret format. Your values file then references them:
useExistingSecrets: true existingSecretName: anchore-enterprise-env licenseSecretName: anchore-enterprise-license imagePullSecretName: anchore-enterprise-pullcreds ui: existingSecretName: anchore-enterprise-ui-envDefault passwords are specified in the chart and must be changed before deploying. The password for theadminuser is set via theanchoreConfig.default_admin_passwordparameter in your customanchore_values.yamlfile. This value is only used during initial creation of the admin user; the password can be changed post-installation via the UI.Add the chart repository and deploy Anchore Enterprise:
TheRELEASEvariable should not contain any dots.export NAMESPACE=anchore export RELEASE=anchore helm repo add anchore https://charts.anchore.io helm install ${RELEASE} -n ${NAMESPACE} anchore/enterprise -f anchore_values.yamlUpon completion, check the pod status. Each pod should reflect
READY 1/1andSTATUS Running:kubectl get pods -n ${NAMESPACE}Example output:
NAME READY STATUS RESTARTS AGE anchore-enterprise-analyzer-85495d6cbf-dlszv 1/1 Running 2 (166m ago) 23h anchore-enterprise-api-59ff4565cd-kbsj4 1/1 Running 2 (166m ago) 23h anchore-enterprise-catalog-7b5d45dc86-qmctl 1/1 Running 2 (166m ago) 23h anchore-enterprise-componentcatalog-84ddcbbf96-9nz7k 1/1 Running 2 (166m ago) 23h anchore-enterprise-datasyncer-86546b85b-nmz2f 1/1 Running 2 (166m ago) 23h anchore-enterprise-notifications-689cc6489-6gr4n 1/1 Running 2 (166m ago) 23h anchore-enterprise-policy-64c65bc79-jf8gh 1/1 Running 2 (166m ago) 23h anchore-enterprise-reports-6cccd54c4b-qxsp8 1/1 Running 2 (166m ago) 23h anchore-enterprise-reportsworker-6cc54fcc5f-vcqsq 1/1 Running 2 (166m ago) 23h anchore-enterprise-simplequeue-597bb9494b-2dvr7 1/1 Running 2 (166m ago) 23h anchore-enterprise-ui-6d6795d8c4-4466t 1/1 Running 2 (166m ago) 23h anchore-ui-redis-master-0 1/1 Running 0 23hThere are 11 Anchore Enterprise pods plus the chart-managed Redis pod (
anchore-ui-redis-master-0). PostgreSQL is not listed because it runs externally.
Post-Installation Steps
Anchore Enterprise takes some time to initialize. After the bootstrap phase, it begins a vulnerability feed sync. Image analysis will show zero vulnerabilities and the UI will show errors until the sync is complete. The initial sync typically completes in minutes rather than hours, though low network throughput or high latency to the Anchore Data Service can extend it. The sync process takes place in the background; while it is in progress, anchorectl can be installed and the commands below can be used to check system status.
Export the required parameters to invoke anchorectl:
export NAMESPACE=anchore
export RELEASE=anchore
export ANCHORECTL_URL=http://localhost:8228
export ANCHORECTL_USERNAME="admin"
export ANCHORECTL_PASSWORD="<default_admin_password>"
Port-forward API and UI traffic to the associated pods. Run each command in a separate terminal window in the background:
kubectl port-forward -n ${NAMESPACE} svc/${RELEASE}-enterprise-api 8228:8228 --address 0.0.0.0 --request-timeout=0 &
kubectl port-forward -n ${NAMESPACE} svc/${RELEASE}-enterprise-ui 3000:80 --address 0.0.0.0 --request-timeout=0 &
Gather the status of Anchore Enterprise services:
anchorectl system status
Example output:
✔ Status system
┌───────────────────┬──────────────────────────────────────────────────────┬───────────────────────────────────────────────────────────────────────────┬──────┬────────────────┬────────────┬──────────────┐
│ SERVICE │ HOST ID │ URL │ UP │ STATUS MESSAGE │ DB VERSION │ CODE VERSION │
├───────────────────┼──────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────┼──────┼────────────────┼────────────┼──────────────┤
│ catalog │ anchore-enterprise-catalog-7b5d45dc86-qmctl │ http://anchore-enterprise-catalog.anchore.svc.cluster.local:8082 │ true │ available │ 6010 │ 6.1.0 │
│ component_catalog │ anchore-enterprise-componentcatalog-84ddcbbf96-9nz7k │ http://anchore-enterprise-componentcatalog.anchore.svc.cluster.local:8228 │ true │ available │ 6010 │ 6.1.0 │
│ notifications │ anchore-enterprise-notifications-689cc6489-6gr4n │ http://anchore-enterprise-notifications.anchore.svc.cluster.local:8668 │ true │ available │ 6010 │ 6.1.0 │
│ data_syncer │ anchore-enterprise-datasyncer-86546b85b-nmz2f │ http://anchore-enterprise-datasyncer.anchore.svc.cluster.local:8778 │ true │ available │ 6010 │ 6.1.0 │
│ simplequeue │ anchore-enterprise-simplequeue-597bb9494b-2dvr7 │ http://anchore-enterprise-simplequeue.anchore.svc.cluster.local:8083 │ true │ available │ 6010 │ 6.1.0 │
│ policy_engine │ anchore-enterprise-policy-64c65bc79-jf8gh │ http://anchore-enterprise-policy.anchore.svc.cluster.local:8087 │ true │ available │ 6010 │ 6.1.0 │
│ reports_worker │ anchore-enterprise-reportsworker-6cc54fcc5f-vcqsq │ http://anchore-enterprise-reportsworker.anchore.svc.cluster.local:8559 │ true │ available │ 6010 │ 6.1.0 │
│ reports │ anchore-enterprise-reports-6cccd54c4b-qxsp8 │ http://anchore-enterprise-reports.anchore.svc.cluster.local:8558 │ true │ available │ 6010 │ 6.1.0 │
│ analyzer │ anchore-enterprise-analyzer-85495d6cbf-dlszv │ http://anchore-enterprise-analyzer.anchore.svc.cluster.local:8084 │ true │ available │ 6010 │ 6.1.0 │
│ apiext │ anchore-enterprise-api-59ff4565cd-kbsj4 │ http://anchore-enterprise-api.anchore.svc.cluster.local:8228 │ true │ available │ 6010 │ 6.1.0 │
└───────────────────┴──────────────────────────────────────────────────────┴───────────────────────────────────────────────────────────────────────────┴──────┴────────────────┴────────────┴──────────────┘
anchorectl, see Using Environment Variables.helm list -n ${NAMESPACE}.Next Steps
Now that you have Anchore Enterprise running, you can begin learning more about Anchore Enterprise architecture, concepts, and usage.
Last modified August 11, 2026