1 - Migrate using Docker Compose
Migrate a v5.x Docker Compose deployment to v6.1 or later by standing up a new deployment from the v6.1 reference compose file and moving your data into it.
This runbook migrates a running Anchore Enterprise v5.x Docker Compose deployment to v6.1 or later. It assumes the commands are run on the host where the deployment lives. Before you begin, read the migration overview to understand what the migration does and what you need in place.
Rather than editing your existing v5.x docker-compose.yaml file in place, this guide has you start from a clean copy of the v6.1 reference compose file and move your data into it.
The migration has two parts: we safely migrate the underlying PostgreSQL database from PostgreSQL 13 to PostgreSQL 17, and we then move the actual Anchore Enterprise application images from v5.x to v6.1.
Starting from the v6.1 template takes care of both at once — the template already runs PostgreSQL 17, and once your data is restored into it, Anchore Enterprise upgrades its own database schema automatically on first boot.
Something you may already noticed by taking a look at the new v6.1 docker-compose file, is that v6.x adds two new services (component-catalog and db-preflight) along with several new required settings.
Upgrades are only supported from v5.x to v6.1 or later. A v5.x deployment cannot upgrade directly to v6.0.
Migrating a host with no outbound internet access? See
Air-Gapped Migration before you begin — you’ll need to mirror the v6.x compose file, database Dockerfile, and application images to the high side before
Step 4 below.
Prerequisites
Before you begin, make sure you have:
- Confirm the deployment is currently running a supported Anchore Enterprise v5.x release. Check the Recommended Component Versions table in the Release Notes for the version you’re moving from.
- Docker and Docker Compose installed and up to date.
- A valid
license.yaml. - Ensure sufficient disk space exists for database backups, temporary migration files, and the additional PostgreSQL volume — a full second copy of your database’s data directory, plus the export file, at minimum.
- A maintenance window — you will need to stop the deployment and writes to the database before the final export in Step 5 so no data is missed.
Test this procedure in a staging or QA environment before running it against production. The steps below include a downtime window while the database is exported and restored.
Migration Procedure
Step 1: Stop All Services
docker compose down --remove-orphans
This begins the downtime window.
Step 2: Back Up Your Existing Configuration
Before making any changes, back up the existing docker-compose.yaml and, optionally, the Docker volumes. Please file away the backup of the file somewhere safe so that you do not accidentally use/delete it.
cp docker-compose.yaml docker-compose-v5.yaml.bak
Step 3: Set Up a New Deployment Directory
Create a separate directory for the v6.1 deployment. Do not reuse your v5.x deployment directory. This method keeps the two deployments, and their compose projects, independent until you’re ready to retire v5.x.
mkdir anchore-enterprise-v6 && cd anchore-enterprise-v6
Step 4: Download the v6.x Deployment Files
Your new v6.x directory will need a new v6.1 formatted docker-compose.yaml file, your license file which we can copy from the old v5.x directory, and a Dockerfile that we also provide for download from our official documentation site for building the new Postgres 17 Database:
curl -sSfL https://docs.anchore.com/current/docs/deployment/docker_compose/docker-compose.yaml > docker-compose.yaml
curl -sSfL https://docs.anchore.com/current/docs/deployment/docker_compose/Dockerfile.anchore-db > Dockerfile.anchore-db
cp /path/to/your/v5-license.yaml ./license.yaml
The Dockerfile needs to be named ‘Dockerfile.anchore-db’ as it is targeted by name directly from the docker-compose file on build. If you name it something different then it will not get picked up by the build.
Follow Step 4: Configure Secrets in the standard deployment guide to set POSTGRES_PASSWORD, ANCHORE_ADMIN_PASSWORD, ANCHORE_AUTH_SECRET, and ANCHORE_DB_PASSWORD. These are fresh secrets for the new deployment — they do not need to match the values your v5.x deployment used.
You do not need to reconcile the database password with your v5.x deployment after restoring your data. pg_dumpall carries PostgreSQL role passwords over in a format PostgreSQL 17 rejects, but the export/restore in this guide uses pg_dump against a single database (not roles), so the fresh POSTGRES_PASSWORD you set here is never touched by the restore.
At-rest encryption of sensitive database columns (
ANCHORE_DB_ENCRYPTION_KEY_CURRENT) is optional and off by default — leave it commented out and the service starts normally, with those columns stored as plaintext exactly as in v5.x. See
Encrypting Database Secrets at Rest if you want to enable it now or later.
Step 6: Start Only the New Database
docker compose up -d anchore-db
Wait for it to report healthy before continuing:
docker compose ps anchore-db
Step 7: Export the v5.x Database
From your v5.x deployment directory, stop writes and export the database - we are going to export it to our new v6 deployment directory and then from there you can decide where you want to move it to after the migration is complete:
docker compose exec -T anchore-db pg_dump -U postgres -Fc -d postgres -f /tmp/anchore-v5-export.dump
docker compose cp anchore-db:/tmp/anchore-v5-export.dump path/to/v6-deployment/anchore-v5-export.dump
You are going to need enough storage space for this process as mentioned in the Prerequisites earlier. You are probably going to need enough free disk space to store the file at least twice. Once you have completed this guide and the migration has been verified as successful, you can move the old dump file wherever you wish.
Step 8: Restore the Data into the New Database
From your new v6.x deployment directory run the below command to restore data from the export that you previously took from the old database into the new database:
docker compose exec -T anchore-db pg_restore -U postgres -d postgres --clean --if-exists --no-owner < ./anchore-v5-export.dump
–clean –if-exists lets you re-run this command safely if you need to redo the restore — it drops matching objects before recreating them instead of erroring on a non-empty database.
Step 9: Start the Full v6.x Deployment
Again, from inside the new v6.x deployment directory run the below to bring up the full v6 deployment:
Anchore Enterprise performs its own database schema migration in-process on first boot, upgrading your restored v5.x data to the v6.1 schema automatically — no separate migration command is needed.
Step 10: Validate the Upgrade
| Check | Command |
|---|
| All services are healthy | docker compose ps |
| API reports the new version | curl <api-url>/v2/status — confirm "version":"6.1.0" |
| Users can log in | anchorectl account list |
| Historical data is present | anchorectl image list |
| Scans and policy evaluations still function | anchorectl image vulnerabilities <existing-tag> and anchorectl image check <existing-tag> |
Retire the Old v5.x Deployment (Optional)
Once the upgrade is validated and you feel comfortable and confident you won’t need to roll back, you can take the real final (but completely optional!) step of removing the v5.x deployment’s volume backup. Our recommendation is to retain the database dump file, the original compose file, and the volume backup until the upgraded deployment has been fully validated in production.
docker volume rm <your-old-db-volume-name>
Please make sure you are using the correct volume name in the command - it is the old v5 volume name and NOT *the new v6 volume name. If you use the wrong name you may completely wipe all of your data.
Also do not remove the v5.x deployment’s volumes until you’ve confirmed that the migration succeeded and your existing data, images etc. because this and the original v5 docker-compose.yaml file are your only rollback path.
Downtime Expectations
This migration requires application downtime during the database export and restore.Downtime duration depends on database size, disk performance, and system resources.
1.1 - Migrate Air-Gapped using Docker Compose
If the deployment host has no outbound internet access, complete this guide before Step 4: Download the v6.x Deployment Files in the main migration runbook. It mirrors the low-side/high-side process in Air-Gapped Docker Compose deployment — the v6.x reference compose file, database Dockerfile, and application images all need to reach the high side before you can start the new deployment, in addition to the database dump you already have to move as part of the migration itself.
Throughout this guide, the low side is the internet-facing system and the high side is the air-gapped system.
Prepare the Files and Images (low side)
Download the v6.x compose file and database Dockerfile:
curl -sSfL https://docs.anchore.com/current/docs/deployment/docker_compose/docker-compose.yaml > docker-compose.yaml
curl -sSfL https://docs.anchore.com/current/docs/deployment/docker_compose/Dockerfile.anchore-db > Dockerfile.anchore-db
Pull the v6.x application images:
docker pull docker.io/anchore/enterprise:v6.1.0
docker pull docker.io/anchore/enterprise-ui:v6.1.0
docker pull docker.io/redis:7.4.6
Build the database image from Dockerfile.anchore-db:
docker build -f Dockerfile.anchore-db -t anchore:db .
Move the Files and Images to the High Side
Choose one of the following, matching the equivalent step in the Air-Gapped Docker Compose deployment guide:
- Private container registry (recommended) — re-tag, then push directly, or save/transfer/load/push, exactly as described in Option 1, for all four images pulled/built above.
- Local image tarball — for hosts with no registry available, as described in Option 2.
Also transfer docker-compose.yaml, Dockerfile.anchore-db, and your license.yaml to the high side along with the images — you’ll need docker-compose.yaml in Step 4 of the main runbook, and the Dockerfile is kept for reference even though anchore:db is already built.
Point Your Compose File at the Registry (or Local Images)
Update the image: lines in your new docker-compose.yaml exactly as described in Deploy on the High Side on the deployment air-gapped page — point every service referencing docker.io/anchore/enterprise and docker.io/anchore/enterprise-ui at your registry tag or locally loaded image name, replace anchore-db’s build: section with a direct image: <registry>/anchore:db (or image: anchore:db for a local tarball) reference, and update the redis image line the same way.
Run the Migration from the Local Files
Continue with the main migration runbook starting at Step 4, substituting the compose file you just edited for the one Step 4 would otherwise download, and skipping the curl commands there — you already have both files from the low side.
Every other step needs no changes for an air-gapped host:
Because the deployment cannot reach the Anchore Data Service, complete
Air-Gapped Feed Configuration on the new v6.x deployment — disable the Data Syncer’s automatic feed sync and import feed bundles manually with AnchoreCTL — or the migrated deployment will have no vulnerability data.
2 - Migrate on Kubernetes using Helm
Migrate a running Anchore Enterprise v5.x Helm deployment to v6.1 or later, including the move to PostgreSQL 17.
This runbook migrates a running Anchore Enterprise v5.x Helm deployment to v6.1 or later. Before you begin, read the migration overview to understand what the migration does and what you need in place.
The v6.x Helm chart (the enterprise chart v4.1+ to migrate) requires a customer-provided PostgreSQL 17 database with the pg_cron extension. Unlike the v5.x chart, it does not deploy a PostgreSQL instance for you. How much work the migration involves depends on where your v5.x database runs today:
- If your v5.x deployment already uses an external PostgreSQL database, you upgrade that database to PostgreSQL 17, enable
pg_cron, update your values file, and run helm upgrade. No data is moved. Follow Path A. - If your v5.x deployment uses the chart’s bundled (Bitnami) PostgreSQL, that subchart is removed in v6.x. You must migrate your data into a new PostgreSQL 17 database before installing v6.1. Follow Path B.
Upgrades are only supported from v5.x to v6.1 or later. A v5.x deployment cannot upgrade directly to v6.0. Use enterprise chart v4.1+, which ships Anchore Enterprise v6.1.0.
The v6.1 database schema migration is
one-way. Once v6.1 runs against your database, the schema is no longer compatible with v5.x. A database backup taken immediately before the upgrade is your only rollback path. See
Roll Back.
Prerequisites
Complete these steps regardless of which path you follow.
- A running v5.x Helm deployment (v5.0.0 or later) with admin access to its PostgreSQL database.
- A provisioned or upgradeable PostgreSQL 17 database with the
pg_cron extension, cron.use_background_workers enabled, and USAGE on the cron schema granted to the Anchore user. See Requirements. - A CNCF-certified Kubernetes version within the chart’s supported
kubeVersion range (1.23–1.36 at the time of writing), Helm v3.8+, and kubectl configured for the target cluster. - A valid v6.x license. Optionally a database encryption key: at-rest column encryption is off by default and can be enabled now or later, so it is not a prerequisite for migrating. See the migration overview.
- A v6.1 values file built from the
enterprise chart v4.1+. Do not reuse your v5-era values file unchanged — several keys were removed, renamed, or relocated in v6.x. See Values File Changes.
Several steps in this runbook are long-running and hold your terminal — the database dump/restore or import, and the helm upgrade that runs the schema migration can each take from many minutes to hours on large datasets. Run them from a stable host (for example a bastion or jumpbox) inside a persistent session such as screen, tmux, or nohup/at, so a dropped SSH connection or closed laptop does not interrupt the operation.
Set some environment variables used throughout this runbook:
export RELEASE=<your-helm-release-name>
export NAMESPACE=<your-namespace>
Confirm the license and pull-credential secrets already exist in your namespace (they carry over from v5.x):
kubectl get secret anchore-enterprise-license -n ${NAMESPACE}
kubectl get secret anchore-enterprise-pullcreds -n ${NAMESPACE}
Back Up the Database
This step is critical. Because the schema migration is one-way, this backup is your only way back to v5.x.
# Dump from the v5.x database in custom format (adjust host/user/db as needed).
# For the chart's bundled PostgreSQL, exec into the postgres pod:
kubectl exec -it ${RELEASE}-postgresql-0 -n ${NAMESPACE} -- \
pg_dump -U anchore -d anchore -Fc -f /tmp/anchore_backup.dump
# Copy the dump off the pod to durable storage
kubectl cp ${NAMESPACE}/${RELEASE}-postgresql-0:/tmp/anchore_backup.dump ./anchore_backup.dump
Verify the backup is usable, then store it somewhere durable (not on ephemeral pod storage):
ls -lh anchore_backup.dump
pg_restore --list anchore_backup.dump | head -20
Use pg_dump -Fc, never pg_dumpall. On some platforms (for example, OpenShift) a pod’s ephemeral storage is capped; if your database is larger than that cap, run pg_dump directly against the database from a machine with enough disk instead of writing into the pod. Always check the dump size looks reasonable.
For a large database, a logical pg_dump is often impractical — it needs roughly as much free disk as the database size and can take hours. A volume snapshot of the database’s PersistentVolume (for example, an EBS or CSI VolumeSnapshot) is usually a faster, lower-overhead backup. This is especially true when your object store uses the database driver, since the stored objects live in the database and dominate its size.
Path A: Upgrade with an Existing External PostgreSQL
Use this path if your v5.x deployment already connects to an external PostgreSQL database (RDS, Cloud SQL, CNPG, or self-managed). This is the simplest path — your data stays where it is.
Step 1: Upgrade PostgreSQL to 17 and Enable pg_cron
If your database is not already on PostgreSQL 17+, upgrade it first. Take a snapshot before upgrading.
- Amazon RDS: Use the RDS major version upgrade process.
- Google Cloud SQL: Use the in-place major version upgrade.
- CloudNativePG: Update
spec.imageName to a PostgreSQL 17 image that includes pg_cron; the operator performs a rolling restart. - Self-managed: Upgrade using your normal process.
Then enable pg_cron using your platform’s method (see the provider-specific steps in the EKS, GKE, and AKS guides). In every case, finish by creating the extension and granting the Anchore user access to the cron schema:
CREATE EXTENSION IF NOT EXISTS pg_cron;
GRANT USAGE ON SCHEMA cron TO <ANCHORE_DB_USER>;
Step 2: Update Your Values File
Apply the changes in Values File Changes to your existing values file. At minimum, remove postgresql.chartEnabled and any other removed keys, and relocate any settings you previously passed via extraEnv.
Step 3: Run the Upgrade
helm upgrade ${RELEASE} -n ${NAMESPACE} anchore/enterprise -f anchore-values.yaml
The chart runs its database upgrade job (upgradeJob, executed as a pre-upgrade hook) automatically during helm upgrade. It verifies database connectivity, scales down the running v5.x pods, runs the database schema migration, and then starts all services on the v6.1 image. Do not interrupt this process. The Legacy Imported SBOM migration then runs in the background on first boot.
upgradeJob.enabled must be
true (the default). It is what performs the v6.1 database schema migration. With it disabled,
helm upgrade only updates the deployment specs and images — the schema is never migrated — and the services fail to start against a mismatched schema. If the upgrade job fails, check its pod logs and delete the failed job before retrying; see
Services Fail to Start After an Upgrade.
helm upgrade waits on its hooks and defaults to a 5-minute timeout. The v5.x → v6.1 schema upgrade can take longer than that on larger datasets, causing Helm to report a failure while the upgrade job is still running. Extend the timeout to comfortably exceed your expected migration time, for example helm upgrade … –timeout 30m. This applies to the helm upgrade commands throughout this runbook.
Continue to Verify the Migration.
Path B: Migrate Off the Bundled PostgreSQL
Use this path if your v5.x deployment uses the chart’s bundled Bitnami PostgreSQL (postgresql.chartEnabled: true). That subchart is removed in v6.x, and it runs PostgreSQL 13 by default (or another pre-17 version if you overrode the image tag) — so you must move your data to a new PostgreSQL 17 database before installing v6.1.
If your object store uses the database driver (the default), the stored objects live in the database and can dominate its size — tens or hundreds of GB. Moving that much data with
pg_dump/
pg_restore or a CNPG import can take several hours. If you plan to move to an external object store (for example, S3) anyway, doing so
before the migration — with the object store (OSAA) migration — shrinks the database dramatically and shortens the migration window. See
External Object Store and
Migrating the Object Store.
Step 1: Scale Down Anchore Enterprise
Stop all Anchore Enterprise services so no writes occur during the migration. Leave the bundled PostgreSQL pod running.
for deploy in $(kubectl get deploy -n ${NAMESPACE} -l app.kubernetes.io/name=${RELEASE}-enterprise -o name); do
kubectl scale ${deploy} -n ${NAMESPACE} --replicas=0
done
# Verify all Anchore Enterprise pods are gone (the PostgreSQL pod should still be running)
kubectl get pods -n ${NAMESPACE}
Step 2: Provision the PostgreSQL 17 Database
Stand up a new PostgreSQL 17 database with pg_cron enabled, using the same database name as your v5.x database (for example, anchore), and grant the Anchore user USAGE on the cron schema. Use a managed service (see the EKS / GKE / AKS guides) or an in-cluster operator (see Run PostgreSQL In-Cluster with CloudNativePG).
Step 3: Move Your Data
Choose one migration method.
Method A: pg_dump / pg_restore (Any Target)
This works for any PostgreSQL 17 target. Dump from the bundled PostgreSQL pod (you may already have this from Back Up the Database):
kubectl exec -it ${RELEASE}-postgresql-0 -n ${NAMESPACE} -- \
pg_dump -U anchore -d anchore -Fc -f /tmp/anchore_full.dump
kubectl cp ${NAMESPACE}/${RELEASE}-postgresql-0:/tmp/anchore_full.dump ./anchore_full.dump
Restore into the new PostgreSQL 17 database (reachable from where you run this):
pg_restore -h <TARGET_HOST> -U anchore -d anchore \
--no-owner --no-privileges --clean --if-exists \
anchore_full.dump
Verify the tables restored:
psql -h <TARGET_HOST> -U anchore -d anchore -c "\dt" | head -30
Method B: CloudNativePG Bootstrap Import
If your target is CloudNativePG, CNPG can import directly from the running bundled PostgreSQL using its bootstrap.initdb.import feature, so you do not run pg_dump/pg_restore by hand. Follow the CNPG operator and custom-image setup in the main deployment guide, then create a Cluster with an import bootstrap that points its externalClusters source at the ${RELEASE}-postgresql service. The bundled PostgreSQL pod must stay running during the import.
After the import completes, two follow-up tasks are required before the database is usable:
Create the pg_cron extension. A CNPG import bootstrap does not run the cluster’s postInitApplicationSQL, so the pg_cron extension is not created automatically, even though shared_preload_libraries includes pg_cron. Anchore Enterprise v6.x will not start without it. Create it on the imported database manually:
kubectl exec -it anchore-pg-1 -n ${NAMESPACE} -- \
psql -U postgres -d anchore -c \
"CREATE EXTENSION IF NOT EXISTS pg_cron; GRANT USAGE ON SCHEMA cron TO anchore;"
Reset the Anchore role’s password. PostgreSQL 13 may store password hashes in the older md5 format, which PostgreSQL 17 does not accept, leaving every service failing to authenticate. Reset the password on the new database so it is rewritten using scram-sha-256:
kubectl exec -it <new-pg-pod> -n ${NAMESPACE} -- \
psql -U postgres -d anchore -c \
"SET password_encryption = 'scram-sha-256'; ALTER ROLE anchore WITH PASSWORD '<PASSWORD>';"
Step 4: Update Your Values File
Create your v6.1 values file pointing at the new database, applying the changes in Values File Changes. A minimal example:
licenseSecretName: anchore-enterprise-license
imagePullSecretName: anchore-enterprise-pullcreds
postgresql:
externalEndpoint: <NEW_DB_HOST> # e.g. anchore-pg-rw.anchore.svc for CNPG
auth:
username: anchore
password: <PASSWORD>
database: anchore
port: 5432
Step 5: Install v6.x
Choose one of two approaches based on your risk tolerance.
Approach 1 — helm upgrade in place (recommended). Keeps the same release name, service names, and any existing ingress/DNS configuration. Because the v5.x release is already scaled down and the data has moved, upgrade the existing release directly:
helm upgrade ${RELEASE} -n ${NAMESPACE} anchore/enterprise -f anchore-values.yaml
Helm cleans up the old bundled PostgreSQL resources during the upgrade. A PVC may be left behind; remove it once you have verified the new deployment:
kubectl get pvc -n ${NAMESPACE} -l app.kubernetes.io/name=postgresql
# kubectl delete pvc data-${RELEASE}-postgresql-0 -n ${NAMESPACE}
Approach 2 — install as a new release (side-by-side). Keeps the scaled-down v5.x release as a safety net until you are confident. Install with a new release name:
helm install anchore-v6 -n ${NAMESPACE} anchore/enterprise -f anchore-values.yaml
A new release name changes every Kubernetes resource name (services, deployments) to the new prefix. After you verify v6.1 and uninstall the old release, you must update anything that referenced the old service names: ingress rules, DNS/load-balancer targets, CI/CD anchorectl or API URLs, and monitoring scrape targets.
Continue to Verify the Migration.
Values File Changes
Several chart values were removed, renamed, or relocated in v6.x. Review your existing values file against the tables below before running helm upgrade. The chart validates these on install/upgrade and fails fast with a descriptive error if a removed or relocated key is present, so it is safe to iterate.
Removed and Restructured Keys
| v5.x value | Status in v6.x | Action |
|---|
postgresql.chartEnabled | Removed | Delete it. The bundled PostgreSQL subchart no longer exists. |
postgresql.primary.* | Removed | Delete it. Use postgresql.port instead of postgresql.primary.service.ports.postgresql. |
postgresql.image.* | Removed | Delete it. |
startMigrationPod | Removed | Delete it. |
migrationPodImage | Removed | Delete it. |
migrationAnchoreEngineSecretName | Removed | Delete it. |
anchoreConfig.webhooks | Removed | Delete it. |
anchoreConfig.internalServicesSSL.* | Restructured | Replace with anchoreConfig.internal_ssl_verify plus per-service external_tls fields. |
anchoreConfig.<service>.external.enabled | Restructured | Replace with anchoreConfig.<service>.external_hostname, external_port, and external_tls. |
anchoreConfig.reports_worker.runtime_report_generation.use_legacy_loaders_and_queries | Removed | Delete it. |
anchoreConfig.analyzer.configFile.retrieve_files | Renamed | Rename to anchoreConfig.analyzer.configFile.file_contents. |
Object store swift driver | Removed | Only db and s3 are supported. Migrate from Swift to S3 before upgrading. |
In v6.x, a number of settings that were commonly passed as environment variables via extraEnv must be set in their dedicated anchoreConfig value instead. The chart rejects these environment variables and will not install or upgrade until they are moved.
Environment variable (remove from extraEnv) | Set this value instead |
|---|
ANCHORE_LAYER_CACHE_ENABLED | anchoreConfig.analyzer.layer_cache_max_gigabytes |
ANCHORE_LAYER_CACHE_SIZE_GB | anchoreConfig.analyzer.layer_cache_max_gigabytes |
ANCHORE_HINTS_ENABLED | anchoreConfig.analyzer.enable_hints |
ANCHORE_OWNED_PACKAGE_FILTERING_ENABLED | anchoreConfig.analyzer.enable_owned_package_filtering |
ANCHORE_KEEP_IMAGE_ANALYSIS_TMPFILES | anchoreConfig.analyzer.keep_image_analysis_tmpfiles |
ANCHORE_CATALOG_IMAGE_GC_WORKERS | anchoreConfig.catalog.image_gc.max_worker_threads |
ANCHORE_ENTERPRISE_RUNTIME_INVENTORY_TTL_DAYS | anchoreConfig.catalog.runtime_inventory.inventory_ttl_days |
ANCHORE_ENTERPRISE_RUNTIME_INVENTORY_INGEST_OVERWRITE | anchoreConfig.catalog.runtime_inventory.inventory_ingest_overwrite |
ANCHORE_ENTERPRISE_INTEGRATION_HEALTH_REPORTS_TTL_DAYS | anchoreConfig.catalog.integrations.integration_health_report_ttl_days |
ANCHORE_IMPORT_OPERATION_EXPIRATION_DAYS | anchoreConfig.catalog.import_operation_expiration_days |
ANCHORE_POLICY_EVAL_CACHE_TTL_SECONDS | anchoreConfig.policy_engine.policy_evaluation_cache_ttl |
ANCHORE_POLICY_ENGINE_ENABLE_PACKAGE_DB_LOAD | anchoreConfig.policy_engine.enable_package_db_load |
ANCHORE_ENTERPRISE_REPORTS_ENABLE_GRAPHIQL | anchoreConfig.reports.enable_graphiql |
ANCHORE_ENTERPRISE_REPORTS_MAX_ASYNC_EXECUTION_THREADS | anchoreConfig.reports.max_async_execution_threads |
ANCHORE_ENTERPRISE_REPORTS_ASYNC_EXECUTION_TIMEOUT | anchoreConfig.reports.async_execution_timeout |
ANCHORE_ENTERPRISE_REPORTS_ENABLE_DATA_INGRESS | anchoreConfig.reports_worker.enable_data_ingress |
ANCHORE_ENTERPRISE_REPORTS_ENABLE_DATA_EGRESS | anchoreConfig.reports_worker.enable_data_egress |
ANCHORE_ENTERPRISE_REPORTS_DATA_EGRESS_WINDOW | anchoreConfig.reports_worker.data_egress_window |
ANCHORE_ENTERPRISE_REPORTS_DATA_REFRESH_MAX_WORKERS | anchoreConfig.reports_worker.data_refresh_max_workers |
ANCHORE_ENTERPRISE_REPORTS_DATA_LOAD_MAX_WORKERS | anchoreConfig.reports_worker.data_load_max_workers |
ANCHORE_ENTERPRISE_UI_URL | anchoreConfig.notifications.ui_url |
ANCHORE_DATA_SYNC_AUTO_SYNC_ENABLED | anchoreConfig.data_syncer.auto_sync_enabled |
ANCHORE_ADMIN_EMAIL | anchoreConfig.default_admin_email |
ANCHORE_API_DRIVEN_CONFIGURATION_ENABLED | anchoreConfig.api_driven_configuration_enabled |
ANCHORE_ALLOW_ECR_IAM_AUTO | anchoreConfig.allow_awsecr_iam_auto |
ANCHORE_AUTH_PRIVKEY | anchoreConfig.keys.privateKeyFileName |
ANCHORE_AUTH_PUBKEY | anchoreConfig.keys.publicKeyFileName |
ANCHORE_DISABLE_METRICS_AUTH | anchoreConfig.metrics.auth_disabled |
ANCHORE_ENABLE_METRICS | anchoreConfig.metrics.enabled |
ANCHORE_MAX_COMPRESSED_IMAGE_SIZE_MB | anchoreConfig.max_compressed_image_size_mb |
ANCHORE_MAX_IMPORT_CONTENT_SIZE_MB | anchoreConfig.max_import_content_size_mb |
ANCHORE_MAX_IMPORT_SOURCE_SIZE_MB | anchoreConfig.max_source_import_size_mb |
ANCHORE_OAUTH_TOKEN_EXPIRATION | anchoreConfig.user_authentication.oauth.default_token_expiration_seconds |
ANCHORE_OAUTH_REFRESH_TOKEN_EXPIRATION | anchoreConfig.user_authentication.oauth.refresh_token_expiration_seconds |
ANCHORE_SSO_REQUIRES_EXISTING_USERS | anchoreConfig.user_authentication.sso_require_existing_users |
ANCHORE_IMAGE_ANALYZE_TIMEOUT_SECONDS | anchoreConfig.image_analyze_timeout_seconds |
Verify the Migration
After the upgrade, watch the pods come up and confirm system status:
kubectl get pods -n ${NAMESPACE} -w
# Port-forward the API and check status (use the new release name for Path B, Approach 2)
kubectl port-forward svc/${RELEASE}-enterprise-api 8228:8228 -n ${NAMESPACE}
anchorectl system status
anchorectl system feeds list
Confirm that all services report up, that your existing images, policies, and scan results are present, that feed syncs are running, and that the UI is reachable.
The Legacy Imported SBOM migration runs in the background on first boot; your deployment is fully usable while it runs, though migrated SBOMs may not all appear as Apps, App Versions, and Assets until it finishes. Report its progress with anchore-enterprise-manager, which reads the database directly and so must be run from inside a running Anchore Enterprise pod:
kubectl exec -it deploy/${RELEASE}-enterprise-catalog -n ${NAMESPACE} -- bash -c \
'anchore-enterprise-manager --json db --db-connect postgresql://"${ANCHORE_DB_USER}":"${ANCHORE_DB_PASSWORD}"@"${ANCHORE_DB_HOST}":"${ANCHORE_DB_PORT}"/"${ANCHORE_DB_NAME}" legacy-sbom-migration-status'
The database environment variables are already present in every Anchore Enterprise pod, so the connection string above needs no editing. It is quoted for the pod’s shell to expand, not yours.
If your database requires SSL, add –db-use-ssl and an ?sslmode=<mode> suffix to the connection string, matching what the chart’s own upgrade job passes for your anchoreConfig.database.sslMode.
{
"message": "Legacy SBOM Migration is in progress. SBOM mappings migrated so far: 604, SBOM mappings remaining: 549, SBOM mappings failed to migrate: 0",
"migrated": 604,
"remaining": 549,
"state": "in_progress",
"total": 1153,
"failed": 0
}
state reports one of:
state | Meaning |
|---|
not_triggered | No Legacy Imported SBOM migration ran. Expected when the v5.x deployment had no imported SBOMs. |
in_progress | Still working. remaining counts the SBOM mappings left to process. |
complete | Every SBOM mapping migrated, with no failures. |
complete_with_failures | Finished, but failed mappings did not migrate. |
The counts are SBOM mappings — one per SBOM per SBOM Group it belongs to, plus one per empty SBOM Group — not SBOM documents, so the total will exceed your imported SBOM count when SBOMs belong to more than one group. Drop --json to print the message line on its own.
If the migration ends as complete_with_failures, contact Anchore Customer Success via support.anchore.com before retiring your v5.x backup.
Roll Back
Rollback restores the pre-upgrade state from your backup, because the schema migration cannot be reversed.
- Uninstall or scale down the v6.1 release.
- Restore the database backup taken in Back Up the Database into a v5.x-compatible PostgreSQL instance.
- Restart or reinstall the v5.x release pointing at the restored database.
- Verify all services come back up with your pre-upgrade data intact.
Any work done in v6.1 after cutover is lost on rollback, so keep the v6.1 trial period write-light until you commit to it.
Troubleshooting
| Symptom | Likely cause |
|---|
| Pre-upgrade hook fails with a DB connection error | PostgreSQL is unreachable or credentials changed. Check the hook job logs with kubectl get jobs -n ${NAMESPACE} and kubectl logs. |
Helm upgrade fails citing postgresql.chartEnabled | The removed key is still in your values file. Delete it. |
Helm upgrade fails naming an extraEnv variable | A setting must move out of extraEnv. See Settings Moved Out of extraEnv. |
pg_cron errors in pod logs | The extension is not enabled on the target database. Enable it and run CREATE EXTENSION pg_cron;. |
pg_restore errors: role "anchore" does not exist | Create the Anchore user on the target first. |
FATAL: password authentication failed after migrating off PG13 | Reset the role password so it is rewritten as scram-sha-256 (see the password-reset task in Method B). |
| Services are up but data appears missing | You are pointed at the wrong database. Confirm the endpoint and check \dt in psql. |
pg_dump is very slow on a large database | Add -j <N> to pg_dump/pg_restore for parallelism, and run during off-hours. |
2.1 - Migrate Air-Gapped using Helm
If the cluster has no outbound internet access, complete this guide before Back Up the Database in the main migration runbook. It mirrors the low-side/high-side process in Air-Gapped Helm deployment, with one difference: this time kubectlImage must be mirrored too, because the pre-upgrade hook’s migration job actually runs it to scale down the v5.x pods — a fresh install never touches that image.
Throughout this guide, the low side is the internet-facing system and the high side is the air-gapped cluster.
Prepare the Chart and Images (low side)
Add the chart repository and find the current chart version — use enterprise chart v4.1+, which ships Anchore Enterprise v6.1.0 or later:
helm repo add anchore https://charts.anchore.io
helm search repo anchore/enterprise
Download (pull) the chart archive:
export CHART_VERSION="<chart-version-from-above>"
helm pull anchore/enterprise --version ${CHART_VERSION}
Pull the images the migration needs:
docker pull docker.io/anchore/enterprise:v6.1.0
docker pull docker.io/anchore/enterprise-ui:v6.1.0
docker pull docker.io/redis:7.4.6
docker pull docker.io/bitnamilegacy/kubectl:1.30
Unlike a fresh install, mirroring bitnamilegacy/kubectl:1.30 (the chart’s kubectlImage) is required here — the osaaMigrationJob and upgradeJob hooks use it to scale down the v5.x deployments before the schema migration runs.
Move the Chart and Images to the High Side
Choose one of the following, matching the equivalent step in the Air-Gapped Helm deployment guide:
- Private container registry (recommended) — re-tag, then push directly, or save/transfer/load/push, exactly as described in Option 1, but for all four images pulled above.
- Local import onto cluster nodes — for small clusters with no registry available, as described in Option 2.
- Internal Helm repository or GitOps source — push the chart
.tgz to your OCI registry or chart repository as described in Push the Chart to an Internal Helm Repository or GitOps Source.
Also transfer enterprise-${CHART_VERSION}.tgz and the v6.x values file you build in Values File Changes to the high side along with the images.
Point Your Values File at the Registry
Add the registry overrides to your v6.x values file:
image: <registry>/anchore/enterprise:v6.1.0
ui:
image: <registry>/anchore/enterprise-ui:v6.1.0
ui-redis:
image:
registry: <registry>
repository: redis
tag: 7.4.6
pullSecrets:
- anchore-enterprise-pullcreds
kubectlImage: <registry>/bitnamilegacy/kubectl:1.30
Create (or update) the image pull secret to point at your private registry instead of Docker Hub, as described under Deploy on the High Side on the deployment air-gapped page.
Run the Migration from the Local Chart
Whichever path you follow in the migration runbook, complete Back Up the Database first. It needs no changes for an air-gapped cluster — pg_dump/pg_restore run directly against your database and require no internet access. Since you are already staging the chart and images for transfer, store the backup in that same durable storage.
Then substitute the local chart archive — or your internal registry reference — for anchore/enterprise in every helm upgrade/helm install command below.
Path A: Upgrade with an Existing External PostgreSQL
In Step 3: Run the Upgrade:
helm upgrade ${RELEASE} -n ${NAMESPACE} ./enterprise-${CHART_VERSION}.tgz -f anchore-values.yaml --timeout 30m
or, from an internal OCI registry:
helm upgrade ${RELEASE} -n ${NAMESPACE} oci://<registry>/charts/enterprise --version ${CHART_VERSION} -f anchore-values.yaml --timeout 30m
Path B: Migrate Off the Bundled PostgreSQL
Follow Path B through Step 1: Scale Down Anchore Enterprise and Step 2: Provision the PostgreSQL 17 Database as written — provisioning the new database doesn’t depend on the Anchore chart or images.
For Step 3: Move Your Data:
Method A: pg_dump/pg_restore needs no changes — it’s a direct database-to-database copy and does not touch the Anchore chart or images.
Method B: CloudNativePG Bootstrap Import additionally requires the CNPG operator chart, the CNPG operator image, and your custom pg_cron-enabled PostgreSQL image on the high side — none of which are part of the Anchore chart. Mirror all three exactly as described in step 4 of the deployment air-gapped guide (chart repo add/pull, operator image pull, custom image build), and include them in the same tarball you save and transfer in Move the Chart and Images to the High Side above. If you already mirrored these for a prior air-gapped deployment using the same registry, no extra mirroring is needed here.
Also save a cnpg-cluster.yaml on the low side now, same as step 4e in that guide, but using Method B’s bootstrap-import configuration (the bootstrap.initdb.import block pointing externalClusters at ${RELEASE}-postgresql) instead of a plain new cluster — leave imageName as a placeholder until the high side.
On the high side, install the operator from the local chart and point its image at your registry exactly as described in Install CloudNativePG and Provision the Database on the deployment air-gapped page. Then fill in imageName in your transferred cnpg-cluster.yaml and apply it — keeping the bundled v5.x PostgreSQL pod running during the import, per the warning in Method B.
At Step 5: Install v6.x, substitute the local chart archive (or internal registry reference) in whichever approach you choose:
# Approach 1 — helm upgrade in place
helm upgrade ${RELEASE} -n ${NAMESPACE} ./enterprise-${CHART_VERSION}.tgz -f anchore-values.yaml --timeout 30m
# Approach 2 — install as a new release
helm install anchore-v6 -n ${NAMESPACE} ./enterprise-${CHART_VERSION}.tgz -f anchore-values.yaml --timeout 30m
or, from an internal OCI registry, replace ./enterprise-${CHART_VERSION}.tgz with oci://<registry>/charts/enterprise --version ${CHART_VERSION} in either command.