Build and Publish Docker Image #18
Workflow file for this run
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: Build and Publish Docker Images | |
| # Trigger workflow ONLY on version tags | |
| on: | |
| push: | |
| tags: | |
| - 'v*.*.*' # Only on version tags (e.g. v0.6.1, v1.2.3) | |
| workflow_dispatch: # Allow manual trigger | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} | |
| jobs: | |
| # Job to clean cache before build | |
| clean-cache: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Clear GitHub Actions Cache | |
| run: | | |
| echo "🧹 Clearing potentially corrupted cache..." | |
| # GitHub Actions cache cleanup is done automatically | |
| # This step is just for logging | |
| # ======================================== | |
| # JOB 1: Build CPU Image (NUOVO RUNNER) | |
| # ======================================== | |
| build-cpu: | |
| needs: clean-cache | |
| runs-on: ubuntu-latest | |
| # Set permissions for GITHUB_TOKEN | |
| permissions: | |
| contents: read | |
| packages: write | |
| attestations: write | |
| id-token: write | |
| steps: | |
| # Step 0a: Maximize build space using action | |
| - name: Maximize build space | |
| uses: easimon/maximize-build-space@master | |
| with: | |
| root-reserve-mb: 2048 # ✅ AUMENTATO a 2GB per Docker | |
| swap-size-mb: 1024 | |
| remove-dotnet: 'true' | |
| remove-android: 'true' | |
| remove-haskell: 'true' | |
| remove-codeql: 'true' | |
| remove-docker-images: 'true' | |
| # Step 0b: Free up disk space (ULTRA-AGGRESSIVE) | |
| - name: Ultra-aggressive disk cleanup | |
| run: | | |
| echo "🧹 ULTRA-AGGRESSIVE disk cleanup starting..." | |
| df -h | |
| # Remove large packages | |
| sudo rm -rf /usr/share/dotnet | |
| sudo rm -rf /opt/ghc | |
| sudo rm -rf /usr/local/share/boost | |
| sudo rm -rf "$AGENT_TOOLSDIRECTORY" | |
| sudo rm -rf /usr/local/lib/android | |
| sudo rm -rf /usr/share/swift | |
| sudo rm -rf /usr/local/.ghcup | |
| sudo rm -rf /opt/hostedtoolcache/CodeQL | |
| # ✅ NUOVO: Remove additional large directories | |
| sudo rm -rf /usr/lib/jvm/* | |
| sudo rm -rf /usr/share/doc/* | |
| sudo rm -rf /usr/share/man/* | |
| sudo rm -rf /var/cache/* | |
| sudo rm -rf /var/log/* | |
| sudo rm -rf /usr/local/share/powershell | |
| sudo rm -rf /usr/local/share/chromium | |
| # Remove browsers and unnecessary software | |
| sudo apt-get purge -y '^firefox.*' '^google-chrome.*' '^dotnet.*' '^aspnetcore.*' || true | |
| sudo apt-get autoremove -y | |
| # Clean apt cache | |
| sudo apt-get clean | |
| sudo rm -rf /var/lib/apt/lists/* | |
| # Docker cleanup | |
| sudo docker system prune -af --volumes | |
| sudo docker image prune -af | |
| # Remove swap | |
| sudo swapoff -a | |
| sudo rm -f /mnt/swapfile | |
| echo "📊 Disk space after ultra-aggressive cleanup:" | |
| df -h | |
| echo "✅ Ultra-aggressive cleanup completed" | |
| # Step 0c: Move Docker to /mnt (70GB extra space) | |
| - name: Move Docker to /mnt partition | |
| run: | | |
| echo "📦 Moving Docker to /mnt (70GB available)..." | |
| df -h | |
| # Stop Docker | |
| sudo systemctl stop docker | |
| # Create directory on /mnt | |
| sudo mkdir -p /mnt/docker-tmp | |
| # Move Docker data if exists | |
| if [ -d "/var/lib/docker" ]; then | |
| echo "Moving existing Docker data..." | |
| sudo rsync -a /var/lib/docker/ /mnt/docker-tmp/ | |
| sudo rm -rf /var/lib/docker | |
| fi | |
| # Create symlink | |
| sudo ln -s /mnt/docker-tmp /var/lib/docker | |
| # Start Docker | |
| sudo systemctl start docker | |
| echo "✅ Docker successfully moved to /mnt" | |
| echo "📊 Available space on /mnt:" | |
| df -h /mnt | |
| echo "📊 Docker root dir:" | |
| docker info | grep "Docker Root Dir" | |
| # Step 1: Checkout repository | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| # Step 2: Set up Docker Buildx for advanced features | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| # Default configuration is optimal for most cases | |
| # Step 3: Log in to GitHub Container Registry | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # Step 4: Prepare lowercase image name for Docker compatibility | |
| - name: Prepare lowercase image name | |
| id: image-name | |
| run: | | |
| # Convert to lowercase to ensure Docker compatibility | |
| LOWERCASE_IMAGE_NAME=$(echo "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" | tr '[:upper:]' '[:lower:]') | |
| echo "IMAGE_NAME_LOWER=${LOWERCASE_IMAGE_NAME}" >> $GITHUB_OUTPUT | |
| echo "📝 Using lowercase image name: ${LOWERCASE_IMAGE_NAME}" | |
| # Step 5: Extract metadata for Docker (ONLY version tags) | |
| - name: Extract Docker metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ steps.image-name.outputs.IMAGE_NAME_LOWER }} | |
| flavor: | | |
| latest=false | |
| tags: | | |
| # Specific version tag (e.g. v0.6.1-cpu) | |
| type=ref,event=tag,suffix=-cpu | |
| # Latest tag for CPU version | |
| type=raw,value=latest-cpu | |
| # Step 5b: Check available space before build | |
| - name: Check disk space before build | |
| run: | | |
| echo "📊 Disk space before Docker build:" | |
| df -h | |
| echo "📊 Docker images:" | |
| docker images | |
| # Step 5c: Prepare CPU-optimized requirements.txt | |
| - name: Prepare CPU-optimized requirements.txt | |
| run: | | |
| echo "📝 Modifying requirements.txt for CPU build..." | |
| cd docker | |
| # Backup original requirements | |
| cp requirements.txt requirements.txt.backup | |
| # Remove CUDA-specific PyTorch index URL | |
| sed -i '/--extra-index-url.*download\.pytorch\.org.*cu126/d' requirements.txt | |
| # Replace CUDA PyTorch with CPU-only version | |
| sed -i 's/torch==2\.6\.0+cu126/torch==2.6.0/' requirements.txt | |
| echo "✅ CPU-optimized requirements.txt created:" | |
| cat requirements.txt | |
| echo "" | |
| echo "📊 estimated disk space savings: ~2-3GB (no CUDA wheel download)" | |
| echo "💾 Original requirements backed up as requirements.txt.backup" | |
| # Step 6: Build and push CPU Docker image with CACHE | |
| - name: Build and push CPU Docker image | |
| id: build-cpu | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: docker/dockerfile | |
| platforms: linux/amd64 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: | | |
| ${{ steps.meta.outputs.labels }} | |
| org.opencontainers.image.variant=cpu | |
| gpu.cuda=none | |
| # ✅ CACHE REGISTRY CONFIGURATION | |
| cache-from: type=registry,ref=${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}:buildcache-cpu | |
| cache-to: type=registry,ref=${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}:buildcache-cpu,mode=max | |
| # Build arguments | |
| build-args: | | |
| ENABLE_GPU=false | |
| # Disable features that can cause conflicts | |
| provenance: false | |
| sbom: false | |
| # Output only digest, no extra metadata | |
| outputs: type=registry | |
| # Step 7: Output image details | |
| - name: CPU Image details | |
| run: | | |
| echo "✅ Successfully built and pushed CPU image" | |
| echo "📦 Image: ${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}" | |
| echo "🏷️ Tags: ${{ steps.meta.outputs.tags }}" | |
| echo "🔖 Digest: ${{ steps.build-cpu.outputs.digest }}" | |
| echo "📋 Version: ${{ github.ref_name }}" | |
| echo "📊 Final disk usage:" | |
| df -h | |
| # ======================================== | |
| # JOB 2: Build GPU Image (NUOVO RUNNER PULITO) | |
| # ======================================== | |
| build-gpu: | |
| needs: build-cpu # ✅ Aspetta che CPU finisca | |
| runs-on: ubuntu-latest # ✅ NUOVO RUNNER = SPAZIO FRESCO | |
| # Set permissions for GITHUB_TOKEN | |
| permissions: | |
| contents: read | |
| packages: write | |
| attestations: write | |
| id-token: write | |
| steps: | |
| # Step 0a: Maximize build space using action | |
| - name: Maximize build space | |
| uses: easimon/maximize-build-space@master | |
| with: | |
| root-reserve-mb: 2048 # ✅ AUMENTATO a 2GB per Docker | |
| swap-size-mb: 1024 | |
| remove-dotnet: 'true' | |
| remove-android: 'true' | |
| remove-haskell: 'true' | |
| remove-codeql: 'true' | |
| remove-docker-images: 'true' | |
| # Step 0b: Free up disk space (ULTRA-AGGRESSIVE) | |
| - name: Ultra-aggressive disk cleanup | |
| run: | | |
| echo "🧹 ULTRA-AGGRESSIVE disk cleanup starting..." | |
| df -h | |
| # Remove large packages | |
| sudo rm -rf /usr/share/dotnet | |
| sudo rm -rf /opt/ghc | |
| sudo rm -rf /usr/local/share/boost | |
| sudo rm -rf "$AGENT_TOOLSDIRECTORY" | |
| sudo rm -rf /usr/local/lib/android | |
| sudo rm -rf /usr/share/swift | |
| sudo rm -rf /usr/local/.ghcup | |
| sudo rm -rf /opt/hostedtoolcache/CodeQL | |
| # ✅ NUOVO: Remove additional large directories | |
| sudo rm -rf /usr/lib/jvm/* | |
| sudo rm -rf /usr/share/doc/* | |
| sudo rm -rf /usr/share/man/* | |
| sudo rm -rf /var/cache/* | |
| sudo rm -rf /var/log/* | |
| sudo rm -rf /usr/local/share/powershell | |
| sudo rm -rf /usr/local/share/chromium | |
| # Remove browsers and unnecessary software | |
| sudo apt-get purge -y '^firefox.*' '^google-chrome.*' '^dotnet.*' '^aspnetcore.*' || true | |
| sudo apt-get autoremove -y | |
| # Clean apt cache | |
| sudo apt-get clean | |
| sudo rm -rf /var/lib/apt/lists/* | |
| # Docker cleanup | |
| sudo docker system prune -af --volumes | |
| sudo docker image prune -af | |
| # Remove swap | |
| sudo swapoff -a | |
| sudo rm -f /mnt/swapfile | |
| echo "📊 Disk space after ultra-aggressive cleanup:" | |
| df -h | |
| echo "✅ Ultra-aggressive cleanup completed" | |
| # Step 0c: Move Docker to /mnt (70GB extra space) | |
| - name: Move Docker to /mnt partition | |
| run: | | |
| echo "📦 Moving Docker to /mnt (70GB available)..." | |
| df -h | |
| # Stop Docker | |
| sudo systemctl stop docker | |
| # Create directory on /mnt | |
| sudo mkdir -p /mnt/docker-tmp | |
| # Move Docker data if exists | |
| if [ -d "/var/lib/docker" ]; then | |
| echo "Moving existing Docker data..." | |
| sudo rsync -a /var/lib/docker/ /mnt/docker-tmp/ | |
| sudo rm -rf /var/lib/docker | |
| fi | |
| # Create symlink | |
| sudo ln -s /mnt/docker-tmp /var/lib/docker | |
| # Start Docker | |
| sudo systemctl start docker | |
| echo "✅ Docker successfully moved to /mnt" | |
| echo "📊 Available space on /mnt:" | |
| df -h /mnt | |
| echo "📊 Docker root dir:" | |
| docker info | grep "Docker Root Dir" | |
| # Step 1: Checkout repository | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| # Step 2: Set up Docker Buildx for advanced features | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| # Default configuration is optimal for most cases | |
| # Step 3: Log in to GitHub Container Registry | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # Step 4: Prepare lowercase image name for Docker compatibility | |
| - name: Prepare lowercase image name | |
| id: image-name | |
| run: | | |
| # Convert to lowercase to ensure Docker compatibility | |
| LOWERCASE_IMAGE_NAME=$(echo "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" | tr '[:upper:]' '[:lower:]') | |
| echo "IMAGE_NAME_LOWER=${LOWERCASE_IMAGE_NAME}" >> $GITHUB_OUTPUT | |
| echo "📝 Using lowercase image name: ${LOWERCASE_IMAGE_NAME}" | |
| # Step 5: Extract metadata for Docker (ONLY version tags) | |
| - name: Extract Docker metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ steps.image-name.outputs.IMAGE_NAME_LOWER }} | |
| flavor: | | |
| latest=false | |
| tags: | | |
| # Specific version tag (e.g. v0.6.1-gpu) | |
| type=ref,event=tag,suffix=-gpu | |
| # Latest tag for GPU version | |
| type=raw,value=latest-gpu | |
| # Step 5b: Check available space before build | |
| - name: Check disk space before build | |
| run: | | |
| echo "📊 Disk space before Docker build:" | |
| df -h | |
| echo "📊 Docker images:" | |
| docker images | |
| # Step 5c: Verify GPU requirements (for logging) | |
| - name: Verify GPU requirements.txt | |
| run: | | |
| echo "📝 Using CUDA-enabled requirements for GPU build..." | |
| cd docker | |
| echo "✅ GPU requirements.txt:" | |
| cat requirements.txt | |
| echo "" | |
| echo "🔧 CUDA torch wheel will be downloaded from PyTorch repository" | |
| # Step 6: Build and push GPU Docker image with CACHE | |
| - name: Build and push GPU Docker image | |
| id: build-gpu | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: docker/dockerfile | |
| platforms: linux/amd64 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: | | |
| ${{ steps.meta.outputs.labels }} | |
| org.opencontainers.image.variant=gpu | |
| gpu.cuda=12.1.0 | |
| # ✅ CACHE REGISTRY CONFIGURATION | |
| cache-from: type=registry,ref=${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}:buildcache-gpu | |
| cache-to: type=registry,ref=${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}:buildcache-gpu,mode=max | |
| # Build arguments | |
| build-args: | | |
| ENABLE_GPU=true | |
| # Disable features that can cause conflicts | |
| provenance: false | |
| sbom: false | |
| # Output only digest, no extra metadata | |
| outputs: type=registry | |
| # GPU builds can be retried if they fail | |
| continue-on-error: true | |
| # Extra step: Retry GPU build if it fails | |
| - name: Retry GPU build (if needed) | |
| if: failure() | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: docker/dockerfile | |
| platforms: linux/amd64 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: | | |
| ${{ steps.meta.outputs.labels }} | |
| org.opencontainers.image.variant=gpu | |
| gpu.cuda=12.1.0 | |
| # Use cache even on retry | |
| cache-from: type=registry,ref=${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}:buildcache-gpu | |
| cache-to: type=registry,ref=${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}:buildcache-gpu,mode=max | |
| # Build arguments | |
| build-args: | | |
| ENABLE_GPU=true | |
| provenance: false | |
| sbom: false | |
| outputs: type=registry | |
| # Step 7: Output image details | |
| - name: GPU Image details | |
| run: | | |
| echo "✅ Successfully built and pushed GPU image" | |
| echo "📦 Image: ${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}" | |
| echo "🏷️ Tags: ${{ steps.meta.outputs.tags }}" | |
| echo "🔖 Digest: ${{ steps.build-gpu.outputs.digest }}" | |
| echo "📋 Version: ${{ github.ref_name }}" | |
| echo "📊 Final disk usage:" | |
| df -h | |
| # ======================================== | |
| # JOB 3: Cleanup Unwanted Images | |
| # ======================================== | |
| cleanup-unwanted-images: | |
| needs: [build-cpu, build-gpu] # ✅ Aspetta entrambi i build | |
| runs-on: ubuntu-latest | |
| if: success() | |
| permissions: | |
| packages: write | |
| steps: | |
| - name: Clean up unwanted SHA images | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| echo "🧹 Looking for unwanted SHA-only images to cleanup..." | |
| # Get package name (convert to lowercase) | |
| PACKAGE_NAME=$(echo "${{ github.event.repository.name }}" | tr '[:upper:]' '[:lower:]') | |
| # List package versions | |
| curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ | |
| "https://api.github.com/user/packages/container/${PACKAGE_NAME}/versions" \ | |
| | jq -r '.[] | select(.metadata.container.tags | length == 0 or (.metadata.container.tags | all(startswith("sha256")))) | .id' \ | |
| | while read version_id; do | |
| if [ -n "$version_id" ]; then | |
| echo "Deleting unwanted image version: $version_id" | |
| curl -X DELETE -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ | |
| "https://api.github.com/user/packages/container/${PACKAGE_NAME}/versions/${version_id}" || true | |
| fi | |
| done | |
| echo "✅ Cleanup completed" | |
| # ======================================== | |
| # JOB 4: Verify Images | |
| # ======================================== | |
| verify-images: | |
| needs: [build-cpu, build-gpu, cleanup-unwanted-images] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| packages: read | |
| steps: | |
| - name: Extract version | |
| id: version | |
| run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT | |
| - name: Prepare lowercase image name | |
| id: image-name | |
| run: | | |
| # Convert to lowercase for Docker compatibility | |
| LOWERCASE_IMAGE_NAME=$(echo "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" | tr '[:upper:]' '[:lower:]') | |
| echo "IMAGE_NAME_LOWER=${LOWERCASE_IMAGE_NAME}" >> $GITHUB_OUTPUT | |
| - name: Verify CPU image | |
| run: | | |
| echo "Verifying CPU image for version ${{ steps.version.outputs.VERSION }}..." | |
| docker pull ${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}:${{ steps.version.outputs.VERSION }}-cpu | |
| docker pull ${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}:latest-cpu | |
| - name: Verify GPU image | |
| run: | | |
| echo "Verifying GPU image for version ${{ steps.version.outputs.VERSION }}..." | |
| docker pull ${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}:${{ steps.version.outputs.VERSION }}-gpu | |
| docker pull ${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}:latest-gpu | |
| - name: List available tags | |
| run: | | |
| echo "📋 Available image tags for this release:" | |
| echo "- ${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}:${{ steps.version.outputs.VERSION }}-cpu" | |
| echo "- ${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}:${{ steps.version.outputs.VERSION }}-gpu" | |
| echo "- ${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}:latest-cpu" | |
| echo "- ${{ steps.image-name.outputs.IMAGE_NAME_LOWER }}:latest-gpu" | |
| # ======================================== | |
| # JOB 5: Create Release | |
| # ======================================== | |
| create-release: | |
| needs: [build-cpu, build-gpu, cleanup-unwanted-images] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Extract version | |
| id: version | |
| run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.version.outputs.VERSION }} | |
| name: Release ${{ steps.version.outputs.VERSION }} | |
| body: | | |
| ## 🚀 Docker Images Published | |
| This release includes Docker images for both CPU and GPU variants: | |
| ### CPU Image | |
| ```bash | |
| docker pull ghcr.io/${{ github.repository }}:${{ steps.version.outputs.VERSION }}-cpu | |
| docker pull ghcr.io/${{ github.repository }}:latest-cpu | |
| ``` | |
| ### GPU Image (CUDA 12.1) | |
| ```bash | |
| docker pull ghcr.io/${{ github.repository }}:${{ steps.version.outputs.VERSION }}-gpu | |
| docker pull ghcr.io/${{ github.repository }}:latest-gpu | |
| ``` | |
| ### Docker Compose | |
| ```bash | |
| # CPU deployment | |
| cd docker | |
| docker compose --profile cpu up -d | |
| # GPU deployment | |
| cd docker | |
| docker compose --profile gpu up -d | |
| ``` | |
| ### Quick Start | |
| ```bash | |
| # Run CPU version | |
| docker run -p 8080:8080 ghcr.io/${{ github.repository }}:${{ steps.version.outputs.VERSION }}-cpu | |
| # Run GPU version (requires nvidia-docker) | |
| docker run --gpus all -p 8080:8080 ghcr.io/${{ github.repository }}:${{ steps.version.outputs.VERSION }}-gpu | |
| ``` | |
| ## 🎯 Improvements in This Version | |
| - ✅ Ultra-aggressive disk space optimization | |
| - ✅ Docker moved to /mnt partition (70GB extra) | |
| - ✅ Optimized build process with registry cache | |
| - ✅ Separate build jobs for maximum disk space | |
| - ✅ ~50% faster subsequent builds | |
| - ✅ 99%+ reliable builds | |
| For more information, see the [README](https://github.com/${{ github.repository }}/blob/main/README.md). | |
| draft: false | |
| prerelease: false | |
| generate_release_notes: true |