Cleanup Container Images #206
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Cleanup Container Images | |
| # Run daily at 2 AM UTC to clean up old container images | |
| on: | |
| schedule: | |
| - cron: '0 2 * * *' # Daily at 2 AM UTC | |
| workflow_dispatch: # Allow manual triggering | |
| inputs: | |
| dry_run: | |
| description: 'Dry run mode (show what would be deleted without actually deleting)' | |
| required: false | |
| default: 'false' | |
| type: boolean | |
| # Set up permissions for Azure authentication | |
| permissions: | |
| id-token: write | |
| contents: read | |
| packages: write | |
| jobs: | |
| cleanup-images: | |
| runs-on: ubuntu-latest | |
| env: | |
| AZURE_CLIENT_ID: ${{ vars.AZURE_CLIENT_ID }} | |
| AZURE_TENANT_ID: ${{ vars.AZURE_TENANT_ID }} | |
| AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }} | |
| AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }} | |
| AZURE_LOCATION: ${{ vars.AZURE_LOCATION }} | |
| steps: | |
| - name: Install Azure CLI | |
| run: | | |
| curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash | |
| - name: Log in with Azure (Federated Credentials) | |
| uses: azure/login@v2 | |
| with: | |
| client-id: ${{ env.AZURE_CLIENT_ID }} | |
| tenant-id: ${{ env.AZURE_TENANT_ID }} | |
| subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }} | |
| - name: Get Azure Container Registry Name | |
| id: get-acr | |
| run: | | |
| # Get the resource group name | |
| rg_name="rg-${{ env.AZURE_ENV_NAME }}" | |
| echo "Resource group: $rg_name" | |
| # Verify the resource group exists | |
| if ! az group show --name "$rg_name" >/dev/null 2>&1; then | |
| echo "Resource group '$rg_name' not found. Skipping cleanup." | |
| echo "acr_name=" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # Get the ACR name from the resource group | |
| acr_name=$(az acr list --resource-group "$rg_name" --query "[0].name" --output tsv 2>/dev/null) | |
| if [ -z "$acr_name" ] || [ "$acr_name" = "null" ]; then | |
| echo "No Azure Container Registry found in resource group '$rg_name'." | |
| echo "acr_name=" >> $GITHUB_OUTPUT | |
| else | |
| echo "Found ACR: $acr_name" | |
| echo "acr_name=$acr_name" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Cleanup Old Container Images | |
| id: cleanup | |
| run: | | |
| acr_name="${{ steps.get-acr.outputs.acr_name }}" | |
| dry_run="${{ github.event.inputs.dry_run || 'false' }}" | |
| if [ -z "$acr_name" ]; then | |
| echo "No Azure Container Registry found. Skipping cleanup." | |
| echo "purged_count=0" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| echo "Starting container image cleanup for ACR: $acr_name" | |
| echo "Retention policy: Keep 5 most recent images per repository" | |
| # Get all repositories in the ACR | |
| repositories=$(az acr repository list --name "$acr_name" --output tsv 2>/dev/null) | |
| if [ -z "$repositories" ]; then | |
| echo "No repositories found in ACR. Nothing to clean up." | |
| echo "purged_count=0" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| echo "Found repositories: $(echo "$repositories" | wc -l)" | |
| # Build the purge command with filters for each repository | |
| PURGE_FILTERS="" | |
| for repo in $repositories; do | |
| PURGE_FILTERS="$PURGE_FILTERS --filter '$repo:.*'" | |
| done | |
| # Construct the purge command and capture the output | |
| PURGE_CMD="acr purge $PURGE_FILTERS --ago 0d --keep 5 --untagged" | |
| if [ "$dry_run" = "true" ]; then | |
| PURGE_CMD="$PURGE_CMD --dry-run" | |
| echo "🔍 DRY RUN MODE: Will show what would be deleted without actually deleting" | |
| fi | |
| echo "Running purge command..." | |
| # Run the purge command and capture output | |
| purge_output=$(az acr run \ | |
| --cmd "$PURGE_CMD" \ | |
| --registry "$acr_name" \ | |
| --timeout 3600 \ | |
| /dev/null) | |
| exit_code=$? | |
| # Count purged images by looking for lines with "Deleted manifest" in the output | |
| purged_count=$(echo "$purge_output" | grep -c "Deleted manifest" || true) | |
| echo "purged_count=$purged_count" >> $GITHUB_OUTPUT | |
| if [ $exit_code -eq 0 ]; then | |
| echo "✅ Cleanup process completed successfully!" | |
| echo "🧹 Images purged: $purged_count" | |
| else | |
| echo "❌ Cleanup process failed with exit code $exit_code" | |
| exit $exit_code | |
| fi | |
| - name: Create Summary | |
| run: | | |
| purged_count="${{ steps.cleanup.outputs.purged_count }}" | |
| dry_run="${{ github.event.inputs.dry_run || 'false' }}" | |
| echo "## Container Registry Cleanup Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "- Registry: \`${{ steps.get-acr.outputs.acr_name }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "- Date: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY | |
| if [ "$dry_run" = "true" ]; then | |
| echo "- Mode: 🔍 **DRY RUN** (no images were actually deleted)" >> $GITHUB_STEP_SUMMARY | |
| echo "- Images that would be purged: **$purged_count**" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "- Mode: ✅ **Production Run**" >> $GITHUB_STEP_SUMMARY | |
| echo "- Images purged: **$purged_count**" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "- Retention Policy: Keep 5 most recent images per repository" >> $GITHUB_STEP_SUMMARY |