Problem

Multiple applications deployed on the same server are each downloading dependencies independently, causing slow builds and wasted bandwidth.

Solutions Implemented

1. BuildKit Cache Mounts (HIGHEST IMPACT)

Enable Docker BuildKit and use cache mounts to share package caches across all builds on the same server.

For Next.js/React Apps (pnpm):

Dockerfile
  
# In build stage, replace:RUN pnpm install

# With:RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \
pnpm install --frozen-lockfile

For .NET Apps:

Dockerfile
  
# In build stage, replace:RUN dotnet restore

# With:RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
dotnet restore

2. Jenkins Pipeline Configuration

Update your Jenkinsfile to enable BuildKit:

TypeScript
  
    pipeline {
    agent any
    environment {
        DOCKER_BUILDKIT = '1'
    }
    stages {
        stage('Build') {
            steps {
                sh 'docker build --build-arg BUILDKIT_INLINE_CACHE=1 -t myapp .'
            }
        }
    }
}

3. Docker Daemon Configuration

On your server, edit /etc/docker/daemon.json :

JSON
  
    {"features": {
    "buildkit": true}}

Restart Docker:

Bash
  
    sudo systemctl restart docker

4. Multi-Stage Build Best Practices

✅ Your Dockerfiles already use multi-stage builds

✅ Dependencies are copied before source code

5. Layer Caching Order (Verify)

Ensure this order in all Dockerfiles:

  1. Install package manager (pnpm/dotnet)

  2. Copy package files only (package.json, pnpm-lock.yaml, *.csproj)

  3. Install dependencies (with cache mount)

  4. Copy source code

  5. Build application

Expected Performance Improvements

OptimizationFirst BuildSubsequent BuildsBenefit
Cache MountsSame60-90% fasterShares npm/pnpm/NuGet cache
Layer CachingSame40-70% fasterReuses unchanged layers
CombinedSame70-95% fasterMaximum efficiency

Quick Application Guide

Next.js Apps (pnpm-based):

Optimization Pattern:

Dockerfile
  
    RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \

    pnpm install --frozen-lockfile

Vite/React Apps (pnpm-based):

Same optimization as Next.js

.NET Apps:

Optimization Pattern:

Dockerfile
  
    RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \

    dotnet restore

Implementation Steps

  1. Enable BuildKit (server-level - do this first):

    Bash
          
            echo '{"features": {"buildkit": true}}' | sudo tee /etc/docker/daemon.json
    sudo systemctl restart docker
  2. Update Jenkinsfiles (add to environment):

    Code
          
            environment {
        DOCKER_BUILDKIT = '1'
    }
  3. Update Dockerfiles (for each app):

    • Add --mount=type=cache to install commands

    • Use --frozen-lockfile or --prod=false flags appropriately

  4. Verify Build Logs :

    • Look for CACHED messages in build output

    • Monitor build times improvement

Additional Optimizations

A. Use .dockerignore

Create .dockerignore in each project:

Code
  
    node_modules
.next
.git
*.log
.env.local
dist
build

B. Prune Unused Images Regularly

Add Jenkins job:

Code
  
    stage('Cleanup') {
    steps {
        sh 'docker system prune -af --filter "until=168h"'
    }
}

C. Use Registry Cache (Advanced)

For even faster builds, push cache to Docker registry:

Bash
  
    docker build \
  --cache-from myregistry/app:cache \
  --build-arg BUILDKIT_INLINE_CACHE=1 \
  -t myregistry/app:latest \
  --push .

Monitoring Success

After implementation, track:

Run this to see cache usage:

Bash
  
    docker system df -v