The GitHub Container Registry allows you to publish or host private and public Docker images. You can find out everything you need to know in this tutorial.
With its registry service GitHub Packages, GitHub provides a way for developers to host their own Docker images directly in GitHub. In my opinion, the name of GitHub is somewhat misleading: the umbrella term for the service is GitHub Packages. It contains a number of registries. These include the Docker Registry, which has been renamed the Container Registry in order to host all types of containers.
Why not use Docker Hub? 🐋
The Docker Hub is the first port of call when it comes to Docker images – no question about it. In the free version, however, only one private image is available to each account and the number of pulls (200 pulls per 6 hours) is also limited. And this is where the GitHub Container Registry comes into play! 🙂
Push Docker Images into the GitHub Registry
To create a Docker image, we need a Docker image, which we have to create with a Dockerfile. You can create such a Dockerfile using the docker init command, for example. Once the file is available, we can build the image:
docker build -t frontend .
In the next step, we need to log in to the GitHub Container Registry. To do this, we need a personal access token from GitHub.
Generate Personal Access Token (PAT)
To generate a new PAT, navigate to GitHub Settings > Developer seettings > Personal access tokens > Tokens (classic) and create a new token. You must select “write:packages” and** “read:packages”** as the scope. You can adjust the duration of the token to your project or set it to unlimited.
You should save the token, e.g. in your password manager. If you lose the token, you will have to regenerate it.
Now open a terminal on your computer and set your PAT in a variable (replace <YOUR_PAT>
with your token):
# Set PAT into a variable
export GH_PAT=<YOUR_PAT>
To log in to the GitHub Container Registry (ghcr.io), use the following command (replace <USERNAME>
with your GitHub username).
# Login to the GitHub Container Registry using your PAT
echo $GH_PAT | docker login ghcr.io -u <USERNAME> --password-stdin
If the PAT and your user name were correct, you should receive the message “Login Succeeded”.
Next, we tag the image so that it also ends up in the correct registry. Replace <USERNAME>
with your GitHub username, <IMAGE_NAME>
with the desired name of the image and <TAG>
with the desired tag (default: latest
)
# Tag the builded docker image
docker tag frontend ghcr.io/<USERNAME>/<IMAGE_NAME>:<TAG>
Now we can push the image into the registry. Here you have to replace the same variables as when tagging:
docker push ghcr.io/<USERNAME>/<IMAGE_NAME>:<TAG>
If you have done everything correctly, you should receive such an output or no error message 😉
Congratulations! You have successfully pushed your first Docker image to the GitHub registry! 🎉
On this page you now have further options, such as changing the visibility or deleting the image.
Pulling GitHub Docker Images
Of course, you can now also use your Docker images from the registry. The path is the same as for pushing:
docker pull ghcr.io/<USERNAME>/<IMAGE_NAME>:<TAG>
GitHub Actions Workflow for Docker Images in the GitHub Registry
Pushing Docker images manually is daft! That’s why there are CI/CD pipelines that we can implement with GitHub Actions, for example. For certain events, e.g. a new commit, we can automatically build the Docker image and publish it in the registry. In the following example, a Docker image is built and published when the frontend branch is pushed. Building and publishing is already done after the “Build and push Docker image” step. However, I have left the last two steps in for the sake of completeness, as this is a workflow of one of my projects and you may also have a use case for it 😉
In your GitHub repository, you can simply create a file under .github/workflows/cd.yml
.
name: Continuous Deployment - Frontend
on:
push:
branches: ['frontend']
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push-image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
id: push
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Install SSH client
run: sudo apt-get update && sudo apt-get install -y openssh-client
- name: Deploy to VM
env:
SSH_HOST: ${{ vars.SSH_HOST }}
SSH_USER: ${{ secrets.SSH_USER }}
SERVER_SSH_KEY: ${{ secrets.SERVER_SSH_KEY }}
IMAGE_TAG: ${{ steps.meta.outputs.tags }}
run: |
echo "${{ env.SERVER_SSH_KEY }}" > key.pem
chmod 600 key.pem
ssh -i key.pem -o StrictHostKeyChecking=no ${{ env.SSH_USER }}@${{ env.SSH_HOST }} << 'EOF'
docker login ${{ env.REGISTRY }} -u ${{ github.actor }} -p ${{ secrets.MY_PERSONAL_PAT }}
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
cd ~
docker compose down frontend
docker compose up -d frontend
EOF
# Clean up the private key.pem
rm key.pem
And don’t forget: Create the used secrets and variables in the repository settings. In this case:
-
Secrets:
- MY_PERSONAL_PAT
- SERVER_SSH_KEY
- SSH_USER
-
Variables:
- SSH_HOST
GitHub Container Registry: Conclusion
That’s it! Building and publishing Docker images in the GitHub Docker Registry or GitHub Container Registry is very similar to Docker Hub. Only the login via the GitHub PAT is a little more complicated, but also offers advantages in terms of authorisation management, etc. Will you be using the GitHub Packages Registry in the future?
Top comments (0)