Skip to content

Instantly share code, notes, and snippets.

@pavel-rossinsky
Last active February 16, 2025 10:46
Show Gist options
  • Save pavel-rossinsky/8e9903f5bba124f6c862b09cde24613a to your computer and use it in GitHub Desktop.
Save pavel-rossinsky/8e9903f5bba124f6c862b09cde24613a to your computer and use it in GitHub Desktop.
Cleanup Old Docker Images in GHCR

πŸš€ GitHub Actions Workflow: Build, Push & Cleanup GHCR Docker Images

This GitHub Actions workflow automates building, pushing, and cleaning up Docker images in GitHub Container Registry (GHCR).

πŸ“œ Workflow Steps

  1. Triggers on

    • Pushes to the master branch.
    • Pull requests to master.
    • Manual workflow dispatch.
  2. Key Workflow Steps

    • βœ… Checkout the repository.
    • βœ… Convert repo name to lowercase.
    • βœ… Log in to GitHub Container Registry (GHCR).
    • βœ… Build & push a Docker image.
    • βœ… Cleanup old images, keeping only the latest 3 versions.
    • βœ… Fail the workflow if cleanup is unsuccessful.

πŸ“Œ Usage

  • Place this YAML file in .github/workflows/build-and-cleanup.yml.
  • Ensure the GitHub Actions runner (ubuntu-latest) is configured.
  • Requires GHCR authentication via secrets.GITHUB_TOKEN.

πŸ“Œ Requirements

  • A repository using GitHub Container Registry (GHCR).
  • GitHub Actions runner.
  • GitHub Token with packages:delete permissions.
name: Build and Push Docker Image
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Convert Repository Name to Lowercase
run: echo "REPO_NAME=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Docker Image
run: |
docker build -t ghcr.io/${{ env.REPO_NAME }}:latest .
- name: Push Docker Image to GHCR
if: github.event_name != 'pull_request'
run: |
docker push ghcr.io/${{ env.REPO_NAME }}:latest
- name: Cleanup Old Docker Images in GHCR
if: github.event_name != 'pull_request'
run: |
REPO=$(echo "${{ github.repository }}" | awk -F'/' '{print $2}')
# Reverses the sorted list to get newest to oldest (descending order)
VERSIONS=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/orgs/${{ github.repository_owner }}/packages/container/$REPO/versions" |
jq -r 'sort_by(.created_at) | reverse | .[].id')
COUNT=0
for ID in $VERSIONS; do
COUNT=$((COUNT + 1))
if [[ $COUNT -gt 3 ]]; then
echo "Deleting old image version ID: $ID"
curl -X DELETE -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/orgs/${{ github.repository_owner }}/packages/container/$REPO/versions/$ID"
fi
done
echo "Verifying the remaining images."
REMAINING_VERSIONS=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/orgs/${{ github.repository_owner }}/packages/container/$REPO/versions" |
jq -r '.[].id' | wc -l)
if [[ "$REMAINING_VERSIONS" -gt 3 ]]; then
echo "Error: Expected a maximum of 3 images, but found $REMAINING_VERSIONS. Exiting."
exit 1
fi
echo "Cleanup successful. Exactly 3 images remain."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment