Roll Back from 8gcr to Harbor OSS
We are sad to see you go, but you will have your reasons. Here is how to move a self-managed installation from 8gcr images back to upstream Harbor OSS images.
This guide covers a same-version swap: you keep running the Harbor release you are on and only change which images serve it, for example 8gcr v2.16.x to goharbor on the same v2.16.x. It is not a Harbor version downgrade. Harbor does not migrate schemas downwards, so a version downgrade needs a restore from backup instead. Nothing in the database has to change for Harbor OSS to start, so the swap is the whole job. What is left to decide is what happens to the four tables 8gcr added.
Back up PostgreSQL before you change any image or any row in schema_migrations, and confirm the backup restores. Every step below is reversible from a good backup and awkward without one.
What 8gcr Adds to the Database
8gcr stores its extra configuration in four tables of its own. Everything else, including projects, repositories, artifacts, tags, users, robot accounts, quotas, replication rules and system configuration, lives in the ordinary Harbor tables that both products share.
| Table | What it holds |
|---|---|
branding | Product name, logo, colors and login page branding |
identity_providers | Federated identity provider configuration |
robot_identity_providers | Links between robot accounts and federated identity providers |
claim_rules | Claim mapping rules for federated identity providers |
Harbor OSS has no code that reads or writes these four tables. Left in place, they sit unused and Harbor OSS behaves as though they were not there.
Which Option to Choose
| Option 1: keep the tables | Option 2: drop the tables | |
|---|---|---|
| Recommended | Yes | Only if you are sure |
| Branding and identity provider config | Preserved in the database | Deleted permanently |
| Returning to 8gcr later | Old configuration comes back | Set everything up again |
| Extra work during rollback | None | One DROP TABLE statement |
| Left in the database | Four unused tables | Nothing |
Option 1 costs nothing. The four tables are small, Harbor OSS ignores them, and keeping them is what lets a later return to 8gcr pick up where you left off.
Take Option 2 only if you have decided you are not coming back, or if a policy requires you to remove data that a product you no longer run wrote to your database.
Before You Start
Pick the upstream Harbor OSS version. Stay on the
v2.16.xline and get as close to your current patch as upstream publishes. 8gcr patch numbers run ahead of upstream’s, so the newestgoharborv2.16.xmay be a lower patch than the 8gcr release you are on. Step 1 covers what that costs you.Confirm the tag exists, on Docker Hub or in your own mirror. The rest of this guide calls it
HARBOR_VERSION:export HARBOR_VERSION=v2.16.xBack up PostgreSQL and Redis, and snapshot any persistent volumes. Restore the PostgreSQL dump into a scratch database and check it opens. A backup you have not restored is a guess.
Save your current Helm values:
helm get values <release-name> -n <namespace> -o yaml.Stop writes to the registry or announce a maintenance window.
Step 1: Check the Schema Migration Marker
Harbor records the highest database migration it has applied in the schema_migrations table. At startup, Harbor core asks golang-migrate to continue from that number. If the recorded number is not among the migration files shipped inside the image, the migration fails and core exits:
[FATAL] [/core/main.go:195]: failed to migrate the database, error:
no migration found for version 182: read down for version 182 .: file does not existUnder Helm this can surface in the preinstall or preupgrade hook job rather than in the core pod, because that job runs core in migrate mode.
Most installations never see it. 8gcr 2.15.8 moved the four tables out of the numbered migration sequence into an authoritative schema, reconciled on every startup, and rewinds the marker the retired numbered migrations left behind. Every 2.16 installation is past that point, so schema_migrations already holds an upstream number and this step is a no-op.
Run the check anyway; it is the first thing to look at if core does not come up. Installations whose last 8gcr release was 2.15.7 or earlier applied the four tables as numbered migrations 0181 and 0182, and upstream Harbor has since reused both numbers for unrelated work, so the recorded number means something different to the upstream image than it did to 8gcr.
Read the recorded version:
SELECT version, dirty FROM schema_migrations;Read the highest migration the upstream image ships:
docker run --rm --entrypoint sh goharbor/harbor-core:"${HARBOR_VERSION}" \
-c 'ls /harbor/migrations/postgresql | tail -1'The filename is prefixed with the migration number, for example 0190_2.16.0_schema.up.sql means 190. Compare the two numbers:
- Recorded version is less than or equal to the number from the image. Nothing to do. Skip to Step 2.
- Recorded version is greater. Set it to the number from the image, and only then:
UPDATE schema_migrations
SET version = <upstream_migration_version>, dirty = false;Confirm your PostgreSQL backup restores before you run that UPDATE. Read the number off the image, as above; do not copy one out of this page. It differs between patch releases: on the 2.15 line, upstream Harbor 2.15.0 ships migrations up to 180 while 2.15.3 and later ship up to 181.
That UPDATE changes one row. It does not touch the four 8gcr tables, and it does not touch any Harbor data.
Step 2: Switch the Images Back to Harbor OSS
Replace every 8gcr image reference in your Helm values with the upstream goharbor image at the same Harbor version. Core matters most, because core runs the migration and serves the API, but leaving any other component on an 8gcr image means you have not finished rolling back.
helm upgrade harbor harbor/harbor \
--namespace harbor \
--reuse-values \
--set core.image.repository=goharbor/harbor-core \
--set core.image.tag="${HARBOR_VERSION}" \
--set portal.image.repository=goharbor/harbor-portal \
--set portal.image.tag="${HARBOR_VERSION}" \
--set jobservice.image.repository=goharbor/harbor-jobservice \
--set jobservice.image.tag="${HARBOR_VERSION}" \
--set registry.controller.image.repository=goharbor/harbor-registryctl \
--set registry.controller.image.tag="${HARBOR_VERSION}" \
--set exporter.image.repository=goharbor/harbor-exporter \
--set exporter.image.tag="${HARBOR_VERSION}" \
--wait --timeout 12mCheck your values for any of the remaining components and reset those too:
| Helm value | Upstream repository |
|---|---|
nginx.image.repository | goharbor/nginx-photon |
portal.image.repository | goharbor/harbor-portal |
core.image.repository | goharbor/harbor-core |
jobservice.image.repository | goharbor/harbor-jobservice |
registry.registry.image.repository | goharbor/registry-photon |
registry.controller.image.repository | goharbor/harbor-registryctl |
trivy.image.repository | goharbor/trivy-adapter-photon |
database.internal.image.repository | goharbor/harbor-db |
redis.internal.image.repository | goharbor/redis-photon |
exporter.image.repository | goharbor/harbor-exporter |
For Docker Compose installations, run the upstream installer for your target version against your existing harbor.yml instead of editing image tags by hand.
Step 3: Verify the Rollback
kubectl rollout status deployment/harbor-core -n harbor
kubectl get pods -n harbor
helm status harbor -n harborThen exercise the registry:
- Log in to the portal as a system administrator.
- Pull an existing image by tag and by digest.
- Push a test image to a non-production project.
- Confirm your projects, users, robot accounts and replication rules are all still listed.
The 8gcr features are gone at this point, which is the intended outcome. The portal shows default Harbor branding, and the federated identity provider screens are no longer in the product. Robot accounts that authenticated through a federated identity provider can no longer do so; give them secrets, or plan for that before you cut over.
If core will not start, read its logs first. A no migration found for version line means Step 1 is still outstanding. Anything else, restore the backups you took in Before You Start.
Step 4, Option 2 Only: Drop the 8gcr Tables
Skip this section if you chose Option 1.
This is permanent. Your branding, identity providers, claim rules and robot account bindings are deleted. Nothing in Harbor OSS can recreate them, and reinstalling 8gcr afterwards gives you an empty configuration. Dump the four tables first.
Wait until Harbor OSS is running and verified, so you are not debugging two changes at once. To keep a copy:
pg_dump -t branding -t identity_providers -t robot_identity_providers -t claim_rules \
-d registry > 8gcr-tables.sqlThen drop them. claim_rules and robot_identity_providers both have foreign keys into identity_providers, so drop the children first, as in this single statement:
DROP TABLE IF EXISTS claim_rules, robot_identity_providers, identity_providers, branding CASCADE;Coming Back to 8gcr Later
This is what Option 1 buys you. 8gcr creates its four tables idempotently at startup: if they already exist, it uses them as they are. Deploying 8gcr images again over the same database gives you your branding and federated identity provider configuration back, with nothing to re-enter.
Two details to expect when you return:
- Robot account bindings follow the robot accounts.
robot_identity_providersrows are removed with the robot they point at, so any robot you deleted while running Harbor OSS is no longer bound to an identity provider. The identity providers and their claim rules are untouched. - Anything you changed in the portal while on Harbor OSS stays changed. The preserved tables hold only what 8gcr managed.
Upstream Harbor upgrades in the meantime do not touch the four tables. They are not part of the upstream schema, so upstream migrations neither read nor rewrite them.
What You End Up With
After Option 1:
- Harbor OSS runs on the upstream images, starting clean with no migration errors.
- Projects, repositories, artifacts, tags, users, robot accounts, quotas, replication rules and system configuration are all intact.
- The four 8gcr tables are still in the database, holding your old configuration, unused by Harbor OSS.
- Reinstalling 8gcr later restores that configuration as it was.
After Option 2, the same, except the four tables and the configuration in them are gone.