Prepare for OCI publishing of helm charts to docker hub - #814
Conversation
There was a problem hiding this comment.
Pull request overview
This PR prepares the Solr Operator project for publishing Helm charts as OCI artifacts to Docker Hub, addressing issue #813 which aims to modernize the chart distribution mechanism.
Changes:
- Adds a GitHub Actions workflow for publishing Helm charts to Docker Hub's OCI registry with validation and verification steps
- Updates documentation across all README files to include OCI registry installation instructions alongside traditional HTTPS repository methods
- Integrates OCI publishing into the release wizard process as a new step after traditional Helm chart publishing
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 19 comments.
Show a summary per file
| File | Description |
|---|---|
| .github/workflows/publish-helm-oci.yaml | New workflow for publishing charts to OCI registry with URL validation, checksum verification, and dry-run support |
| helm/solr/README.md | Adds OCI registry installation and upgrade examples with traditional methods as alternatives |
| helm/solr-operator/README.md | Restructures installation section to prioritize OCI registry approach with detailed instructions for both methods |
| hack/release/wizard/releaseWizard.yaml | Adds new release task for OCI publishing with step-by-step instructions and verification commands |
| README.md | Updates main README to highlight OCI registry installation as the recommended approach |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
This would be awesome! And since the CRDs are in the apache release archives, I think we can do-away with the nightlies reliance all-together! The copilot suggestions seem to be true, that it is the "apache" oci repo that we are pushing to, and it will use the name in the charts. Also I would love to not include "chart" in the name if at all possible. Obviously there might be overlap issues with the docker image (at least for the Solr-operator, not necessarily solr itself), so if not possible that's ok, but it'll be much cleaner (and keeping the same name as previous versions) if we just keep it "solr" and "solr-operator" |
|
Yes, ideally we'd have a sub-folder |
|
I'm actually not confident there will be a conflict. I just tried it out on https://hub.docker.com/repository/docker/houstonputman/solr-operator/general So at least that issue should be solved. |
|
And the versions will never overlap because the images have versions that start with |
|
I love the idea of automating everything, but currently the release manager has to push to docker-hub anyways. Why not just have them also push the helm chart to docker hub? The GitHub action is quite complex. And eventually we can automate the docker build and push at the same time as automating the helm build and push. |
Hmm, I hate the idea of mixing different artifact types on the same OCI path. If I do a list operation on the OCI I'd need to filter on the "^v" each time to just see the versions. I'm leaning towards publishing helm charts on GHCR for this reason. It's a no-brainer to set it up.
Mainly so not all RMs need to obtain the secret docker-hub credentials which are stored as secrets by INFRA in docker. But also good to have all these steps automated. We could use similar workflow for pushing the operator image? |
Yeah, I had assumed that the oci tools (like ORAS) would do a much better job of differentiating artifact types for you. Apparently they do almost nothing, so unless you are looking at the tags in DockerHub, it's very confusing. I would love to have everything in one place, but I'm not against putting the charts in GHCR right now, and it doesn't stop us in the future putting them in both GHCR and DockerHub if ORAS makes differentiating the two better.
Fair enough, I guess this is a good thing to start with, then we can expand to the image (which will be harder since multi-image build is pretty resource intensive) |
Validate url Validate checksum
Docker Hub only supports a single namespace level, so 'helm push' (which
appends the chart name from Chart.yaml) can only produce apache/solr and
apache/solr-operator there. That burns the apache/solr name on a chart
rather than a future Solr server image, and mixes chart tags with image
tags in one tag list. The previous target, apache/solr-operator-chart,
would have resolved to a three-level path and failed at push.
ghcr.io supports nested paths, so the charts go to
ghcr.io/apache/solr-operator/helm/{solr,solr-operator}, keeping the chart
name 'solr' while leaving apache/solr free everywhere. Public ghcr.io
packages are anonymously pullable, so no credentials are needed to install.
Workflow changes beyond the registry switch:
- Keep the downloaded basenames. The .sha512 and .prov files reference the
chart's original filename, so renaming to solr.tgz broke 'sha512sum -c'.
- Download and push the .prov file, so 'helm install --verify' works
against the OCI copy.
- Verify the detached GPG signatures against the Solr KEYS file. The
checksums alone come from the same host as the charts.
- Authenticate with the built-in GITHUB_TOKEN rather than Docker Hub secrets.
- After pushing, log out and pull both charts back anonymously, checking
they are byte-identical to the released artifacts. ghcr.io creates
packages as private, and this is what catches that.
- Pass inputs through the environment and pin azure/setup-helm to a SHA.
Charts are published to both the OCI registry and the deprecated HTTPS
repository throughout the 0.x releases. Starting with v1.0.0 they will be
published to the OCI registry only.
test_cluster.sh gains an -o flag to smoke test the published OCI artifacts.
Claude-Session: https://claude.ai/code/session_017UoVFe4S1qkbw4KurD77Fi
|
@HoustonPutman I've rebased this on main and reworked it — proposing this as the resolution to our earlier discussion about where the charts should live. You were right that Docker Hub can host both images and charts in one repo, with the The chart keeps its natural name I verified the mechanics against my own namespace first: nested paths work, and a public package is anonymously pullable with no On the transition, I propose we cross-publish: every 0.x release goes to both the OCI registry and One thing needing INFRA either way: ghcr.io creates new packages as private, and there's genuinely no self-service path — Does the GHCR path layout look right to you, and are you happy with 1.0.0 as the cutover? |

Fixes #813
Publishes the Helm charts as OCI artifacts, alongside the existing HTTPS chart repository.
Where
No
helm repo add, and no credentials — public ghcr.io packages are anonymously pullable.Why GHCR and not Docker Hub
helm pushappends the chart name fromChart.yamlto the target path, and Docker Hub only supports a single namespace level. So on Docker Hub the only legal target isoci://docker.io/apache, givingapache/solrandapache/solr-operator. That would:apache/solrfor a chart, rather than leaving it for a future Solr server image, andapache/solr-operator.(The earlier
oci://docker.io/apache/solr-operator-chartin this PR would have resolved to a three-level path and simply failed at push — thanks Copilot.)ghcr.io supports nested paths, so namespacing the charts under
solr-operator/helm/keeps the chart namesolrwhile leavingapache/solrfree everywhere. Noteghcr.io/apache/*is one namespace shared by every ASF project, hence the repo-name prefix — the same thing Airflow does withghcr.io/apache/airflow/....Deprecation plan
Charts are published to both the OCI registry and
https://solr.apache.org/chartsthroughout the 0.x releases. Starting withv1.0.0, charts are published to the OCI registry only. Documented in the upgrade notes and both chart READMEs.What's in the workflow
workflow_dispatchwith the two chart URLs fromdist.apache.organd adry-runflag. It never builds a chart — it re-publishes a verified copy of one that has already been released and voted on. Also used to backfill older versions..sha512and.provfiles reference the chart's real filename, so the previous rename tosolr.tgzbrokesha512sum -c..provfile, sohelm install --verifyworks against the OCI copy. No release-tooling change needed —build_helm.shalready runshelm package --sign.KEYSfile. The checksums come from the same host as the charts, so on their own they only prove the download wasn't corrupted.GITHUB_TOKEN+permissions: packages: write. No secrets to configure.azure/setup-helmis pinned to a SHA.Other changes
running-the-operator,local-tutorial,upgrade-notes) lead with OCI, keeping the HTTPS repo documented as deprecated.publish_helm_charts_ocitodo after the existing HTTPS publish step.test_cluster.shgains-o OCI_REGISTRYto smoke test the published OCI artifacts after a release. CRDs still come fromLOCATION, since they aren't part of the OCI artifacts.Verified
Pre-flight against
ghcr.io/janhoy/*, before proposing theapachepaths:helm show chart, and ahelm pullthat is byte-identical to the pushed artifact, all with nohelm registry login.ghcr.io/janhoy/solr-operator,ghcr.io/janhoy/solr-operator/helm/solr-operatorandghcr.io/janhoy/solr-operator/helm/solrall resolve simultaneously. So nesting the charts undersolr-operator/does not consumeghcr.io/apache/solr-operator— it stays free for a future operator image.401 unauthorizedat the token endpoint — which is exactly the failure the workflow's post-push anonymous re-pull is there to catch.Needs INFRA
ghcr.io creates new packages as private. There is no self-service path to change that:
.asf.yamlhas no packages/registry feature,selfserve.apache.orgdoesn't offer it, and there's no REST endpoint (PATCH /user/packages/container/...404s) — it's web-UI only. So an INFRA ticket is needed to make the two packages public, once per chart name; later versions inherit the visibility.ghcr.io/apache/airflow/...is existing precedent.Not in this PR
artifacthub.io/packages/helm/apache-solr/...URL, so it's better done as part of the v1.0.0 cutover — dual publishing keeps the current entry accurate meanwhile.hack/test-upgrade.shpins v0.2.6/v0.2.8, which exist in neitherdistnorarchive.apache.org(the archive starts at v0.3.0), so it can't be converted. Follow-up issue.