Skip to content

Commit 9f8ffd5

Browse files
authored
feat: publish container image to Docker Hub for discoverability (#102)
* feat: publish container image to Docker Hub for discoverability Add Docker Hub as a second push target in the release workflow. GHCR remains the primary registry for all docs, Helm defaults, and install manifests (no rate limits on public packages). Changes: - Add Docker Hub login and image tags to release workflow - Sign Docker Hub image with cosign (same keyless flow) - Add dockerhub-readme job to sync docker/README.md on release - Create docker/README.md with Docker Hub-specific content - Add Docker Hub pulls badge to README.md - Add Docker Hub availability note to installation docs - Document Docker Hub in the release process Requires DOCKERHUB_USERNAME and DOCKERHUB_TOKEN secrets to be configured before the next release. Closes #12 Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca> * ci: exclude hub.docker.com from link checker Docker Hub rate-limits and blocks automated link checks, causing false 404s in CI. The Docker Hub repo URL is validated by pull tests after each release instead. Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca> --------- Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
1 parent 351bc6a commit 9f8ffd5

6 files changed

Lines changed: 123 additions & 3 deletions

File tree

.github/workflows/release.yaml

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ jobs:
5151
username: ${{ github.actor }}
5252
password: ${{ secrets.GITHUB_TOKEN }}
5353

54+
- name: Login to Docker Hub
55+
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
56+
with:
57+
username: ${{ secrets.DOCKERHUB_USERNAME }}
58+
password: ${{ secrets.DOCKERHUB_TOKEN }}
59+
5460
- name: Set up Docker Buildx
5561
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
5662

@@ -82,6 +88,8 @@ jobs:
8288
tags: |
8389
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
8490
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
91+
docker.io/attuneio/attune:${{ github.ref_name }}
92+
docker.io/attuneio/attune:latest
8593
build-args: |
8694
VERSION=${{ github.ref_name }}
8795
COMMIT=${{ github.sha }}
@@ -94,12 +102,18 @@ jobs:
94102
- name: Install cosign
95103
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
96104

97-
- name: Sign container image
105+
- name: Sign GHCR image
98106
shell: bash -Eeuo pipefail -x {0}
99107
run: |
100108
cosign sign --yes \
101109
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
102110
111+
- name: Sign Docker Hub image
112+
shell: bash -Eeuo pipefail -x {0}
113+
run: |
114+
cosign sign --yes \
115+
docker.io/attuneio/attune@${{ steps.build.outputs.digest }}
116+
103117
- name: Attest container image
104118
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
105119
with:
@@ -219,3 +233,24 @@ jobs:
219233
registry-username: ${{ github.actor }}
220234
secrets:
221235
registry-password: ${{ secrets.GITHUB_TOKEN }}
236+
237+
# Sync docker/README.md to the Docker Hub repository description.
238+
dockerhub-readme:
239+
name: Docker Hub README
240+
runs-on: ubuntu-latest
241+
timeout-minutes: 5
242+
needs: [release]
243+
steps:
244+
- uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
245+
with:
246+
egress-policy: audit
247+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
248+
249+
- name: Update Docker Hub description
250+
uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5.0.0
251+
with:
252+
username: ${{ secrets.DOCKERHUB_USERNAME }}
253+
password: ${{ secrets.DOCKERHUB_TOKEN }}
254+
repository: attuneio/attune
255+
readme-filepath: docker/README.md
256+
short-description: "Safe, in-place Kubernetes pod resource right-sizing. VPA done right."

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
[![Go Version](https://img.shields.io/badge/go-1.26-blue)](go.mod)
1010
[![License](https://img.shields.io/badge/license-Apache%202.0-blue)](LICENSE)
1111
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/12998/badge)](https://www.bestpractices.dev/projects/12998)
12+
[![Docker Hub](https://img.shields.io/docker/pulls/attuneio/attune)](https://hub.docker.com/r/attuneio/attune)
1213

1314
**Safe, in-place Kubernetes pod resource right-sizing. VPA done right.**
1415

docker/README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Attune
2+
3+
Safe, in-place Kubernetes pod resource right-sizing. VPA done right.
4+
5+
## Quick reference
6+
7+
- **Source**: [github.com/attune-io/attune](https://github.com/attune-io/attune)
8+
- **Documentation**: [github.com/attune-io/attune#documentation](https://github.com/attune-io/attune#documentation)
9+
- **Issues**: [github.com/attune-io/attune/issues](https://github.com/attune-io/attune/issues)
10+
- **License**: Apache 2.0
11+
12+
## What is Attune?
13+
14+
Attune is a Kubernetes operator that automatically right-sizes pod resource
15+
requests and limits using In-Place Pod Resize (beta in Kubernetes 1.33+, alpha
16+
with feature gate in 1.32). No pod restarts, no HPA conflicts, no outages.
17+
18+
## Supported tags
19+
20+
- `latest` - latest stable release
21+
- `vX.Y.Z` - specific version (e.g., `v0.1.1`)
22+
23+
## Supported architectures
24+
25+
- `linux/amd64`
26+
- `linux/arm64`
27+
28+
## How to use this image
29+
30+
> **Recommended registry**: For production use, pull from GHCR to avoid
31+
> Docker Hub rate limits:
32+
> ```bash
33+
> ghcr.io/attune-io/attune:latest
34+
> ```
35+
36+
### Install with Helm (recommended)
37+
38+
```bash
39+
helm install attune oci://ghcr.io/attune-io/charts/attune \
40+
--namespace attune-system --create-namespace
41+
```
42+
43+
### Pull from Docker Hub
44+
45+
```bash
46+
docker pull attuneio/attune:latest
47+
```
48+
49+
### Verify image signature
50+
51+
All images are signed with cosign (keyless, Sigstore):
52+
53+
```bash
54+
cosign verify \
55+
--certificate-identity-regexp="https://github.com/attune-io/attune" \
56+
--certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
57+
attuneio/attune:latest
58+
```
59+
60+
## Security
61+
62+
- Runs as non-root (UID 65532)
63+
- Distroless base image (no shell, no package manager)
64+
- Signed with cosign + SLSA Level 3 provenance
65+
- Trivy-scanned on every release
66+
67+
## Source
68+
69+
[https://github.com/attune-io/attune](https://github.com/attune-io/attune)

docs/contributing/releasing.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,16 @@ cosign verify \
5353
ghcr.io/attune-io/attune:v0.2.0
5454
```
5555

56-
### 5. Helm chart publishing
56+
### 5. Docker Hub publishing
57+
58+
The release workflow also pushes the same multi-arch image to Docker Hub
59+
at `docker.io/attuneio/attune`. The Docker Hub README is synced from
60+
`docker/README.md` on each release.
61+
62+
Both the GHCR and Docker Hub images share the same digest and are
63+
cosign-signed independently.
64+
65+
### 6. Helm chart publishing
5766

5867
The Helm chart is published as an OCI artifact to `ghcr.io/attune-io/charts/attune`.
5968

@@ -71,7 +80,7 @@ helm package charts/attune
7180
helm push attune-0.2.0.tgz oci://ghcr.io/attune-io/charts
7281
```
7382

74-
### 6. Static install manifest
83+
### 7. Static install manifest
7584

7685
Generate the combined install manifest for users who do not use Helm:
7786

docs/getting-started/installation.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ helm install attune \
3939
(`prometheus-server`, `prometheus-kube-prometheus-prometheus`) in
4040
common namespaces.
4141

42+
!!! info "Also available on Docker Hub"
43+
The container image is also published to Docker Hub at
44+
`docker.io/attuneio/attune` for discoverability. For production
45+
use, GHCR is recommended (no rate limits on public packages).
46+
4247
### Upgrading
4348

4449
!!! important "CRDs are not updated by `helm upgrade`"

lychee.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ exclude = [
44
"0\\.0\\.0\\.0",
55
"example\\.com",
66
"medium\\.com",
7+
"hub\\.docker\\.com",
78
]
89
exclude_loopback = true
910
max_concurrency = 8

0 commit comments

Comments
 (0)