I've had a minimum cost paid dockerhub subscription for a long while - just to be able to have private repositories.
I received an e-mail bumping that from $5 to $11 a month - and adding a lot of stuff I don't want or need.
So - let's try moving stuff to github's container repository - ghcr.io.
Updating build scripts
Existing dockerhub setup
All the code was built on github already.
First - dockerhub username and PAT token were added as secrets to the github repository.
Then - the build action looked like this:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to dockerhub
uses: docker/login-action@v3
with:
username: $DOCKERHUB_USERNAME
password: $DOCKERHUB_TOKEN
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ github.repository_owner }}/<project_name>:latest
Updates to move to ghcr
The changes required to move it to ghcr were minimal - since ghcr is already well integrated with github actions.
First - add permissions so that github can write packages:
permissions:
contents: read
packages: write
Then update the login and build steps:
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: |
ghcr.io/${{ github.repository_owner }}/<project_name>:latest
labels: |
org.opencontainers.image.source=https://github.com/${{ github.repository }}
Other changes
I did make one other improvement - when tagging a built image with a new tag - I used to do a docker pull, docker tag, docker push.
Now - it's using docker image tools - for example:
docker buildx imagetools create \
--tag ghcr.io/${{ github.repository_owner }}/<project_name>:staging \
ghcr.io/${{ github.repository_owner }}/<project_name>:latest
Tidy up
Finally - I just had to remove the old dockerhub secrets from the repository.
Pulling images
To pull private images from ghcr.io - you need to create a PAT token with the read:packages
scope.
Testing locally
echo $GHCR_PAT | docker login ghcr.io -u <github-username> --password-stdin
docker pull ghcr.io/<github-username>/<project_name>:latest
Updating ansible
I deploy simple docker images using ansible to some servers.
Login
Replace the dockerhub_password
secret with a ghcr_pat
secret in the ansible vault.
Then - update the login task:
Old:
- name: Login to dockerhub
community.docker.docker_login:
username: "{{ dockerhub_username }}"
password: "{{ dockerhub_password }}"
New:
- name: Login to GHCR
community.docker.docker_login:
registry_url: ghcr.io
username: "{{ github_username }}"
password: "{{ ghcr_pat }}"
Deployment
Simply change the image from <dockerhub_username>/<project_name>:latest
to ghcr.io/<github_username>/<project_name>:latest
Updating flux
In flux - I have secrets for registry credentials. These are deployed using sealed secrets.
Simple update - first - generate a new version of the secret:
kubectl create secret docker-registry regcred \
--namespace <namespace> \
--docker-server=ghcr.io \
--docker-username=<github_username> \
--docker-password='<PAT token with package:read>' \
--dry-run=client -o yaml > regcred.yaml
Then seal it:
kubeseal --format=yaml -cert=path/to/pub-sealed-secrets.pem < regcred.yaml > regcred-sealed.yaml
Remember NOT to commit the unsealed version.
Then - update the image in the deployment to use ghcr.io/<github_username>/<project_name>:latest