Key idea
Anyone can pull a public image; a private one needs a sign-in. Sign in with a token made for the job, never your account password, and give each machine the least it needs: push for your laptop or CI, pull only for anything that just runs the image.
Public or private
Public is right for open-source images and for these labs, where ComputeSphere pulls your image with no credentials. Private is right for your company's code: the image contains everything the app ships with, so a public image of a private app is a leak.
Each registry has its own default. A new GHCR package starts private. On Docker Hub you choose when you create the repository.
Tokens, not passwords
Both registries sign you in with a personal access token:
- Docker Hub: Account settings, then Personal access tokens. Give it the least access the job needs: read to pull, write to push.
- GHCR: a GitHub personal access token (classic) with
write:packagesto push, orread:packagesto pull. GitHub's fine-grained tokens don't work with GHCR.
A token can be revoked on its own, can be given an expiry date, and does only what its access allows. If one leaks, you revoke one token, not your whole account.
Signing in
docker login can take the token on standard input, the text piped into a command rather than typed after it, so the token never appears in the command or your history:
read -s CR_PAT # paste the token, then Enter; nothing is shown
echo "$CR_PAT" | docker login ghcr.io -u <your-username> --password-stdin
unset CR_PAT # forget the token once you're signed in
read -s CR_PAT waits for you to paste a line and stores it in the shell variable CR_PAT without echoing it (-s is silent). echo pipes it into docker login, and unset removes the variable.
With no registry name, docker login signs in to Docker Hub. It prints Login Succeeded, and from then on docker push and docker pull use those credentials for that registry.
Docker keeps the credentials in your system's credential store (the macOS keychain, for example), with just the registry's name in ~/.docker/config.json. docker logout ghcr.io removes them.
Amazon ECR and other cloud registries
Cloud registries sign in through the cloud's own tools. Amazon ECR, for one, hands out passwords that expire after 12 hours, so anything pulling from it has to renew them. ComputeSphere doesn't renew ECR credentials reliably yet, which is why these lessons use Docker Hub and GHCR.
Check yourself