A GitHub Action that builds and pushes Docker images to a registry with intelligent caching. If an image with the specified tag already exists in the registry, the build and push process will be skipped, saving time and resources.
- 🚀 Smart Build Skipping: Automatically skips build and push if the image already exists in the registry
- 🔐 Registry Authentication: Supports authentication with various Docker registries
- 📦 Flexible Configuration: Customizable Dockerfile names and project paths
- ⚙️ Custom Build Arguments: Pass additional arguments to the docker build command
- 🌍 Environment Variables: Pass environment variables to the docker build process
- ✅ Comprehensive Outputs: Provides detailed information about the build process
- 🛡️ Error Handling: Robust error handling with clear error messages
- 🎯 Optimized Performance: Uses Docker manifest inspection for efficient image existence checks
name: Build and Push Docker Image
on:
push:
branches: [main]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build and Push Docker Image
uses: relab-services/docker-build-push@v1
with:
project-path: './my-app'
dockerfile-name: 'Dockerfile'
image-name: 'my-app'
version: 'v1.0.0'
registry-url: 'ghcr.io/${{ github.repository_owner }}'
registry-username: ${{ github.repository_owner }}
registry-password: ${{ secrets.GITHUB_TOKEN }}name: Build and Deploy
on:
push:
branches: [main]
jobs:
build-and-push:
runs-on: ubuntu-latest
outputs:
image: ${{ steps.docker.outputs.image }}
tag: ${{ steps.docker.outputs.tag }}
href: ${{ steps.docker.outputs.href }}
skipped: ${{ steps.docker.outputs.skipped }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build and Push Docker Image
id: docker
uses: relab-services/docker-build-push@v1
with:
project-path: './app'
image-name: 'my-app'
version: 'v1.0.0'
registry-url: 'ghcr.io/${{ github.repository_owner }}'
registry-username: ${{ github.repository_owner }}
registry-password: ${{ secrets.GITHUB_TOKEN }}
- name: Info
if: steps.docker.outputs.skipped == 'false'
run: |
echo "Pushed ${{ steps.docker.outputs.href }}"
# Your deployment logic herename: Build with Custom Arguments
on:
push:
branches: [main]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build and Push Docker Image with Build Args
uses: relab-services/docker-build-push@v1
with:
project-path: './my-app'
image-name: 'my-app'
version: 'v1.0.0'
registry-url: 'ghcr.io/${{ github.repository_owner }}'
registry-username: ${{ github.repository_owner }}
registry-password: ${{ secrets.GITHUB_TOKEN }}
args:
'--build-arg NODE_ENV=production --build-arg
API_URL=https://api.example.com --no-cache'name: Multi-Stage Build with Arguments
on:
push:
branches: [main]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build Production Image
uses: relab-services/docker-build-push@v1
with:
project-path: './app'
image-name: 'my-app'
version: 'v1.0.0'
registry-url: 'ghcr.io/${{ github.repository_owner }}'
registry-username: ${{ github.repository_owner }}
registry-password: ${{ secrets.GITHUB_TOKEN }}
args: |
--build-arg NODE_ENV=production
--build-arg BUILD_DATE=${{ github.event.head_commit.timestamp }}
--build-arg VCS_REF=${{ github.sha }}
--target production
--no-cacheEnvironment variables are automatically available to the docker build process
when you use the action's env section:
name: Build with Environment Variables
on:
push:
branches: [main]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build Docker Image with Environment Variables
uses: relab-services/docker-build-push@v1
with:
project-path: './app'
image-name: 'my-app'
version: 'v1.0.0'
registry-url: 'ghcr.io/${{ github.repository_owner }}'
registry-username: ${{ github.repository_owner }}
registry-password: ${{ secrets.GITHUB_TOKEN }}
args: |
--build-arg PROJECT=${{ matrix.project.name }}
--build-arg COMMIT_SHA=${{ github.sha }}
--build-arg TURBO_TEAM=${{ vars.TURBO_TEAM }}
--secret id=turbo_token,env=TURBO_TOKEN
--secret id=turbo_remote_cache_signature_key,env=TURBO_REMOTE_CACHE_SIGNATURE_KEY
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_REMOTE_CACHE_SIGNATURE_KEY:
${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}name: Build without Pulling Latest
on:
push:
branches: [main]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build Docker Image (Skip Latest Pull)
uses: relab-services/docker-build-push@v1
with:
project-path: './app'
image-name: 'my-app'
version: 'v1.0.0'
registry-url: 'ghcr.io/${{ github.repository_owner }}'
registry-username: ${{ github.repository_owner }}
registry-password: ${{ secrets.GITHUB_TOKEN }}
pull-latest: false # Skip pulling the latest image| Input | Description | Required | Default |
|---|---|---|---|
project-path |
Path to the project directory containing the Dockerfile | ✅ | - |
image-name |
Name of the Docker image | ✅ | - |
version |
Version tag for the Docker image | ✅ | - |
registry-url |
Docker registry URL (e.g., ghcr.io, docker.io, your-registry.com) |
✅ | - |
registry-username |
Docker registry username | ✅ | - |
registry-password |
Docker registry password or token | ✅ | - |
dockerfile-name |
Name of the Dockerfile | ❌ | Dockerfile |
args |
Additional arguments to pass to the docker build command | ❌ | '' |
pull-latest |
Whether to pull the latest image before building | ❌ | true |
| Output | Description |
|---|---|
image |
Docker image name that was built/pushed |
tag |
Docker image tag that was built/pushed |
href |
Full Docker image name with tag (image-name:image-tag) |
skipped |
Whether the build was skipped because image already exists (true/false) |
- Docker Engine Setup: Ensures Docker is available and sets up Docker Buildx
- Registry Authentication: Logs into the specified Docker registry
- Image Existence Check: Uses
docker manifest inspectto check if the image already exists - Conditional Build:
- If image exists: Skips build and push, returns
skipped: true - If image doesn't exist: Proceeds with build and push
- If image exists: Skips build and push, returns
- Latest Image Pull (optional): Pulls the latest version of the image if
pull-latestis set totrue(default behavior) - Build Process: Builds the Docker image using the specified Dockerfile
- Push Process: Tags and pushes the image to the registry
- Output Generation: Provides comprehensive outputs for downstream steps
version: ${{ github.ref_name }} # For tags like v1.0.0
# or
version: ${{ github.sha }} # For commit-based versions- name: Deploy only if built
if: steps.docker.outputs.skipped == 'false'
run: |
echo "New image built: ${{ steps.docker.outputs.href }}"
# Deploy the new imagestrategy:
matrix:
service: [api, web, worker]
include:
- service: api
dockerfile: Dockerfile.api
- service: web
dockerfile: Dockerfile.web
- service: worker
dockerfile: Dockerfile.worker# For production builds
args: '--build-arg NODE_ENV=production --build-arg API_URL=https://api.prod.com'
# For development builds
args: '--build-arg NODE_ENV=development --build-arg API_URL=https://api.dev.com'
# For multi-stage builds
args: '--target production --build-arg BUILD_DATE=${{ github.event.head_commit.timestamp }}'# Pass environment variables via the action's env section
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_REMOTE_CACHE_SIGNATURE_KEY:
${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
# Use them in build arguments
args: |
--secret id=turbo_token,env=TURBO_TOKEN
--secret id=turbo_remote_cache_signature_key,env=TURBO_REMOTE_CACHE_SIGNATURE_KEY
--build-arg NPM_TOKEN=$NPM_TOKENEnvironment variables are useful for:
- Passing secrets to Docker build secrets
- Providing tokens for private registries
- Setting build-time configuration values
- Enabling secure access to external services during build
The action automatically benefits from Docker's layer caching when building images.
# Pull latest image (default behavior) - useful for base image updates
pull-latest: true
# Skip pulling latest - useful for faster builds or when you want to use local cache
pull-latest: falseWhen to use pull-latest: false:
- You want faster builds by using local Docker cache
- You're building in an environment with limited bandwidth
- You want to ensure reproducible builds using only local images
- You're building from a private registry where pulling latest might fail
-
Authentication Failed
- Verify registry credentials are correct
- Check if the registry URL is properly formatted
- Ensure the user has push permissions
-
Dockerfile Not Found
- Verify the
project-pathpoints to the correct directory - Check if the
dockerfile-namematches the actual filename - Ensure the Dockerfile exists in the specified path
- Verify the
-
Build Failed
- Check Dockerfile syntax and dependencies
- Verify all required files are present in the build context
- Review build logs for specific error messages
-
Environment Variables Not Available
- Check that environment variable names don't contain spaces or special characters
- Ensure secrets are properly configured in your repository settings
- Verify the action's
envsection is properly formatted - Review build logs to confirm environment variables are being passed correctly
This project is licensed under the MIT License - see the LICENSE file for details.