Skip to main content

Working with Docker Workflows

1. Building Docker Images

Option Values Notes
uses docker/build-push-action@v5 GitHub Action for building and pushing Docker images
context . Path to the Dockerfile and build context
tags my-image:latest Tags to apply to the built image
push true Whether to push the image to a registry

Example: Building and pushing a Docker image

name: Build and Push Docker Image
on:
  push:
    branches: [ main ]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
      -
        name: Login to DockerHub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      -
        name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: my-image:latest
Note: Ensure Dockerfile is in the root of your repository or adjust the context accordingly.

2. Tagging Docker Images

Tag Format Description Examples
latest Default tag for the most recent image ghcr.io/myuser/myapp:latest
version Tag with semantic versioning (e.g., v1.0.0) ghcr.io/myuser/myapp:v1.2.3
commit-sha Tag with full commit SHA (e.g., 7d8b3c4) ghcr.io/myuser/myapp:7d8b3c4
branch Tag with branch name (e.g., main) ghcr.io/myuser/myapp:main

Example: Using GitHub Actions to tag Docker images with version

name: Build and Push Docker Image
on:
  push:
    tags:
      - 'v*'
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ghcr.io/myuser/myapp:${{ github.ref_name }}

3. Pushing to Docker Hub

Option Values Notes
uses docker://ghcr.io/owner/repo:tag Image reference for Docker Hub
with.image myapp:latest Name of the Docker image to push
with.tags latest, v1.0 Comma-separated list of tags to push
with.username $GITHUB_ACTOR Username for Docker Hub authentication
with.password ${{ secrets.DOCKER_HUB_TOKEN }} Personal Access Token for Docker Hub

Example: Pushing Docker Image to Docker Hub

name: Push Docker Image to Docker Hub
on:
  push:
    branches: [ main ]

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_HUB_USERNAME }}
          password: ${{ secrets.DOCKER_HUB_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: myapp:latest,myapp:v1.0

4. Pushing to GHCR

Option Values Description
uses docker://ghcr.io/owner/repo:tag Reference to the GHCR image
with.image ghcr.io/owner/repo:tag Name of the image to push
with.tags latest, v1.0 Comma-separated list of tags to push

Example: Pushing Docker Image to GHCR

name: Push Docker Image to GHCR
on:
  push:
    branches: [ main ]

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ghcr.io/${{ github.actor }}/my-app:latest
Note: Ensure the GITHUB_TOKEN has write:packages permissions to push images.
Warning: Avoid pushing sensitive data or secrets in Docker images. Use build args or environment variables for configuration.

5. Using Docker Buildx

Option Values Description
uses docker/setup-buildx-action@v3 Sets up Docker Buildx for use in workflows
args --driver docker-container Specifies the driver to use for Buildx
version v0.12.0 Version of Buildx to use (latest stable as of 2026)

Example: Setting up Buildx

steps:
  - name: Set up Docker Buildx
    uses: docker/setup-buildx-action@v3
    with:
      driver: docker-container
      version: v0.12.0
Option Values Description
platform linux/amd64,linux/arm64 Target platforms for the build (comma-separated)
outputs type=registry,registry=ghcr.io,repository=myapp Output configuration for the build (e.g., registry or local)
cache-from type=gha Cache sources for build cache (e.g., GitHub Actions cache)
cache-to type=gha,mode=max Cache destinations for build cache (e.g., GitHub Actions cache)

Example: Building and pushing multi-platform image

steps:
  - name: Set up Docker Buildx
    uses: docker/setup-buildx-action@v3
  - name: Build and push
    uses: docker/build-push-action@v5
    with:
      context: .
      platforms: linux/amd64,linux/arm64
      push: true
      tags: ghcr.io/myuser/myapp:latest
      cache-from: type=gha
      cache-to: type=gha,mode=max
Note: Buildx requires Docker daemon to be running on the runner. Ensure that dockerd is enabled in your workflow if using self-hosted runners.
Warning: When using docker/build-push-action, make sure to set push: true if you want to push the image to a registry. Otherwise, it will only build locally.

6. Using Multi-Stage Builds

Stage Description Use Case Example
FROM node:18 as builder Initial stage for building application dependencies Install Node.js dependencies and build frontend assets
FROM node:18 as builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:18-alpine as runtime Final stage with minimal runtime environment Run the application in a lightweight container
FROM node:18-alpine as runtime
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

Example: Multi-stage Docker Build in GitHub Actions

name: Build and Deploy
on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./Dockerfile
          push: false
          tags: my-app:latest
Note: Multi-stage builds reduce image size and improve security by minimizing the attack surface in production containers.

7. Caching Docker Layers

Example: Using cache action for Docker layers

name: Build and push Docker image
on:
  push:
    branches: [ main ]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/checkout@v4
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      -
        name: Cache Docker layers
        uses: actions/cache@v3
        id: cache
        with:
          path: /tmp/.buildx-cache
          key: ${{ runner.os }}-buildx-${{ github.sha }}
      -
        name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./Dockerfile
          push: false
          tags: my-image:latest
          cache-from: type=local,src=/tmp/.buildx-cache
          cache-to: type=local,dest=/tmp/.buildx-cache
Option Description Values
actions/cache@v3 Cache action to store Docker layers true
path Directory to cache /tmp/.buildx-cache
key Cache key to use for storing and retrieving cache ${{ runner.os }}-buildx-${{ github.sha }}
Note: The cache key should include a unique identifier like github.sha to ensure cache invalidation on code changes.
Warning: Ensure the cache directory is not included in your Docker image to avoid layer caching issues.

8. Using Docker Compose

Option Values Description
services object Defines the services that make up your app's containers
volumes array Defines volumes to be mounted in the containers
networks object Defines custom networks for services to communicate

Example: Basic docker-compose.yml

version: '3.8'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - db
  db:
    image: postgres:13
    volumes:
      - db_data:/var/lib/postgresql/data
volumes:
  db_data:

Example: GitHub Actions workflow using Docker Compose

name: Build and Test with Docker Compose
on:
  push:
    branches: [ main ]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Compose
        run: |
          docker-compose up -d
          sleep 10

      - name: Run tests
        run: |
          docker-compose exec web npm test
Note: Ensure that your docker-compose.yml file is in the root of your repository for GitHub Actions to find it.
Warning: Using docker-compose up in a CI environment might not be ideal for all use cases. Consider using docker-compose run or docker-compose exec for more controlled execution.

9. Running Docker Containers

Option Values Notes
uses docker://image:tag Runs a Docker image as a step
with.args arg1 arg2 Arguments to pass to the container
with.entrypoint /bin/sh Override the default entrypoint
with.working-directory /app Working directory inside the container

Example: Running a Docker Container

steps:
  - name: Run Docker Container
    uses: docker://alpine:latest
    with:
      args: echo "Hello from Alpine"

Example: Using Custom Image with Arguments

steps:
  - name: Run Custom Image
    uses: docker://myapp:latest
    with:
      args: "--verbose --output=/tmp/result.txt"
Note: When using docker://, the image must be available in a registry (e.g., Docker Hub, GitHub Container Registry).

10. Scanning Images for Vulnerabilities

Example: Using Trivy to Scan Docker Images

name: Scan Docker Image
on:
  push:
    branches: [ main ]
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - name: Scan image with Trivy
        uses: aquasecurity/trivy-action@master
        with:
          image-name: 'myapp:latest'
          format: 'sarif'
          output: 'trivy-results.sarif'
Option Values Description
image-name myapp:latest Name of the Docker image to scan
format sarif Output format (e.g., sarif, json)
output trivy-results.sarif File to save scan results
Note: Trivy is a popular open-source vulnerability scanner for container images and filesystems.
Warning: Ensure that the image is pulled or built before scanning to avoid errors.

11. Using Build Arguments

Argument Description Usage
build-arg Build argument to pass to the Docker build command build-arg NAME=value
build-arg-file Path to a file containing build arguments build-arg-file path/to/args.txt

Example: Setting Build Arguments in Workflow

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      -
        name: Build Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./Dockerfile
          build-arg:
            VERSION: 1.0.0
            ENV: production
Note: Build arguments are only available during the build process and are not persisted in the final image.

12. Publishing to Multiple Registries

Registry URL Authentication Notes
Docker Hub https://index.docker.io/v1/ Username + Password or Token Default registry for most Docker images
GitHub Container Registry (GHCR) https://ghcr.io GitHub Personal Access Token (PAT) or GitHub App Token Integrated with GitHub, supports fine-grained permissions
Amazon ECR 123456789012.dkr.ecr.region.amazonaws.com AWS Access Key ID + Secret Access Key or IAM Role Requires AWS CLI or AWS credentials to be configured
Google Container Registry (GCR) gcr.io Service Account Key or gcloud auth application-default login Requires Google Cloud SDK to be installed and authenticated

Example: Publishing to Docker Hub and GHCR

name: Publish Docker Image
on:
  push:
    branches:
      - main

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/checkout@v4
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      -
        name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      -
        name: Login to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      -
        name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            my-dockerhub-username/my-image:latest
            ghcr.io/my-github-username/my-image:latest
Note: When pushing to multiple registries, ensure that each registry's authentication is correctly configured in your GitHub repository secrets.

Was this article helpful?