GitHub Container Registry: How to push Docker images to GitHub
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 container 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 Container 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?
What did you think of this post?