Skip to content

Instantly share code, notes, and snippets.

@txoof
Last active April 23, 2026 12:08
Show Gist options
  • Select an option

  • Save txoof/57f4cabc0cc09121454bd624a60d0968 to your computer and use it in GitHub Desktop.

Select an option

Save txoof/57f4cabc0cc09121454bd624a60d0968 to your computer and use it in GitHub Desktop.
Publishing a Docker Image to GHCR as a Team

Publishing a Docker Image to GHCR as a Team

A step-by-step guide for team members to authenticate with GitHub Container Registry (GHCR) and push Docker images to the organisation namespace.

Prerequisites

  • Docker Desktop installed and running
  • A GitHub account that is a member of BredaUniversityADSAI
  • A Dockerfile at the project root
  • The project cloned locally

1. Create a Personal Access Token (PAT)

Each team member needs their own PAT. Do not share tokens.

  1. Go to GitHub -> Settings -> Developer Settings -> Personal Access Tokens -> Tokens (classic)
  2. Click "Generate new token (classic)"
  3. Give it a name, e.g. ghcr-push
  4. Set an expiration date
  5. Check the write:packages scope
  6. Click "Generate token"
  7. Copy the token immediately — GitHub will not show it again

2. Create a .env File

Create a .env file at the project root:

GITHUB_PAT=your_token_here
GITHUB_USERNAME=bredauniversityadsai
GITHUB_PERSONAL_USERNAME=your_personal_github_username

Add .env to .gitignore immediately:

echo ".env" >> .gitignore

Never commit the .env file. Your PAT is a secret.


3. Authenticate with GHCR

Bash

source .env
echo $GITHUB_PAT | docker login ghcr.io -u $GITHUB_PERSONAL_USERNAME --password-stdin

CMD

for /f "tokens=1,2 delims==" %i in (.env) do set %i=%j
echo %GITHUB_PAT% | docker login ghcr.io -u %GITHUB_PERSONAL_USERNAME% --password-stdin

PowerShell

Get-Content .env | ForEach-Object { $k, $v = $_ -split '=', 2; Set-Item "env:$k" $v }
$env:GITHUB_PAT | docker login ghcr.io -u $env:GITHUB_PERSONAL_USERNAME --password-stdin

Git Bash

source .env
echo $GITHUB_PAT | docker login ghcr.io -u $GITHUB_PERSONAL_USERNAME --password-stdin

You should see Login Succeeded.


4. Build and Push the Image

Build for all platforms and push to the org namespace in one step:

Bash

source .env
docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 \
  -t ghcr.io/$GITHUB_USERNAME/thalianacv:latest \
  --push .

CMD

for /f "tokens=1,2 delims==" %i in (.env) do set %i=%j
echo %GITHUB_PAT% | docker login ghcr.io -u %GITHUB_PERSONAL_USERNAME% --password-stdin
docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/%GITHUB_USERNAME%/thalianacv:latest --push .

PowerShell

Get-Content .env | ForEach-Object { $k, $v = $_ -split '=', 2; Set-Item "env:$k" $v }
$env:GITHUB_PAT | docker login ghcr.io -u $env:GITHUB_PERSONAL_USERNAME --password-stdin
docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/$env:GITHUB_USERNAME/thalianacv:latest --push .

Git Bash

source .env
echo $GITHUB_PAT | docker login ghcr.io -u $GITHUB_PERSONAL_USERNAME --password-stdin
docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 \
  -t ghcr.io/$GITHUB_USERNAME/thalianacv:latest \
  --push .

Platform coverage:

Platform Covers
linux/amd64 Intel/AMD Linux, Windows (Docker Desktop), Intel Macs
linux/arm64 Apple Silicon Macs (M1/M2/M3/M4)

The --push flag builds and pushes directly to GHCR. No separate push step is needed.


5. Verify the Push

Go to:

https://github.com/orgs/BredaUniversityADSAI/packages

You should see thalianacv listed. Click on it to confirm both linux/amd64 and linux/arm64 are present.


6. Package Visibility

Packages published to the org namespace are private by default. A lecturer or org Owner needs to make the package public before teammates can pull it without authenticating.

This is a one-time step. If the package is still private, contact your lecturer.


7. Pull and Run the Image

Once the package is public, anyone with Docker Desktop can run it with two commands:

curl -O https://raw.githubusercontent.com/BredaUniversityADSAI/2025-26d-fai2-adsai-group-computervision8/main/docker-compose.yml
docker compose up

Docker pulls the image automatically. No Python, Poetry, or repo clone needed.


8. Automate with the Makefile

The project Makefile wraps the build and push steps. From the project root:

make docker-build    # build for all platforms and push to GHCR
make release-patch   # bump patch version, commit, push to git, build and push container
make release-minor   # bump minor version, also publishes to PyPI
make release-major   # bump major version, also publishes to PyPI

Check all available commands:

make help

Troubleshooting

"no matching manifest for linux/amd64"

The image was built for a single platform. Rebuild using the docker buildx command above with both --platform linux/amd64,linux/arm64.

"500 Internal Server Error" during push

This is an intermittent GHCR issue. Re-run the push command — it resolves on retry.

"tag does not exist" when pushing

The docker-push Makefile target requires a locally tagged image. Use docker-build instead, which builds and pushes directly via buildx.

"denied" or "403" during push

Your PAT may not have write:packages scope, or it may have expired. Generate a new token at https://github.com/settings/tokens and update your .env file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment