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 anchoreConfig section 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.

Prerequisites

Before deploying, ensure you have the following in place:

RequirementDetails
KubernetesAny 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).
Helmv3.8 or above
kubectlConfigured for your target cluster
Anchore Enterprise licenseA valid license.yaml file
Docker Hub credentialsAccess to pull the anchore/enterprise and anchore/enterprise-ui images. Contact Anchore Support to obtain access.
PostgreSQLAn external PostgreSQL 17+ database with the pg_cron extension enabled. See Requirements.
Docker or PodmanDocker 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:

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.

  1. Build a PostgreSQL 17 image that includes pg_cron. The default CNPG images do not ship with pg_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 postgres
    
    docker build -t <YOUR_REGISTRY>/postgresql-pgcron:17 .
    docker push <YOUR_REGISTRY>/postgresql-pgcron:17
    
  2. 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-namespace
    
  3. Create the PostgreSQL cluster. Create cnpg-cluster.yaml, referencing your custom image. The postgresql.parameters and resources below 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 -w
    
  4. Verify pg_cron is 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-app containing the database credentials, and exposes a read-write service (anchore-pg-rw) that always points to the current primary. Use the -rw service as the database endpoint for Anchore Enterprise.

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.

  1. Create the namespace:

    export NAMESPACE=anchore
    
    kubectl create namespace ${NAMESPACE}
    
  2. 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}
    
  3. 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}
    
  4. Create a custom values file named anchore_values.yaml to 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-env
    
  5. Add the chart repository and deploy Anchore Enterprise:

    export NAMESPACE=anchore
    export RELEASE=anchore
    
    helm repo add anchore https://charts.anchore.io
    helm install ${RELEASE} -n ${NAMESPACE} anchore/enterprise -f anchore_values.yaml
    

    Upon completion, check the pod status. Each pod should reflect READY 1/1 and STATUS 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              23h
    

    There 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        │
└───────────────────┴──────────────────────────────────────────────────────┴───────────────────────────────────────────────────────────────────────────┴──────┴────────────────┴────────────┴──────────────┘

Next Steps

Now that you have Anchore Enterprise running, you can begin learning more about Anchore Enterprise architecture, concepts, and usage.

  • To learn more about Anchore Enterprise, go to Overview
  • To learn more about Anchore Enterprise Concepts, go to Concepts
Last modified August 11, 2026