GitHub
Practical guide to GitHub, GHCR and GitHub Actions for deploying applications.
GHCR
GitHub Container Registry (GHCR) is a container registry service that allows you to store and manage Docker images and OCI artifacts directly in GitHub.
1. Generate a Personal Access Token (PAT)
Go to GitHub and generate a PAT with repo and packages permissions.
Log in to GitHub, go to Settings then Developer settings. Under Personal access tokens, choose Tokens (classic) and generate a new token with the selected permissions.
2. Log in to GHCR with Docker
shell
echo "<TOKEN>" | docker login ghcr.io -u <USERNAME> --password-stdin3. Pull and run an image
shell
docker pull ghcr.io/<USERNAME>/<IMAGE_NAME>
docker run -d -p <HOST_PORT>:<CONTAINER_PORT> ghcr.io/<USERNAME>/<IMAGE_NAME>4. Log out of GHCR
shell
docker logout ghcr.ioGitHub Actions
We will use GitHub Actions with GHCR to build and push our images.
Create the .github/workflows/ folders at the root of the project.
Workflows
To build and push Docker images we will use GHCR. For SSH deployment, we will use the GitHub Actions utility appleboy.
GHCR Workflow
yaml
# .github/workflows/ghcr.yaml
name: GitHub Container Registry
on:
push:
branches:
- main
jobs:
ghcr:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
attestations: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set lowercase repository owner
run: echo "REPO_OWNER=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
- name: Build and push Docker image
run: |
docker build -t ghcr.io/${{ env.REPO_OWNER }}/<TAG_NAME>:latest ./<APP_CODE>
docker push ghcr.io/${{ env.REPO_OWNER }}/<TAG_NAME>:latest
- name: Logout from GHCR
run: docker logout ghcr.ioDeploy Workflow
yaml
# .github/workflows/deploy.yaml
deploy:
needs: [ghcr]
runs-on: ubuntu-latest
steps:
- name: Deploy using ssh
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_KEY }}
port: ${{ secrets.SSH_PORT }}
script: |
echo ${{ secrets.GHCR_PAT }} | docker login ghcr.io -u ${{ github.REPOSITORY_OWNER }} --password-stdin
docker pull ghcr.io/${{ env.REPO_OWNER }}/<TAG_NAME>:latest
docker compose -f compose.prod.yaml up -d
docker logout ghcr.ioConfigure on the VPS
Create a compose.prod.yaml file
yaml
# compose.prod.yaml
services:
app:
image: ghcr.io/<REPO_OWNER>/<TAG_NAME>:latest
ports:
- "XXXX:XXXX"