Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 168 additions & 0 deletions .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
name: Docker Build and Push

on:
workflow_call:
inputs:
image-name:
description: "Docker image name (e.g., aligent/my-app)"
type: string
required: true
registry:
description: "Docker registry"
type: string
required: false
default: "docker.io"
context:
description: "Build context path"
type: string
required: false
default: "."
dockerfile:
description: "Path to Dockerfile"
type: string
required: false
default: "Dockerfile"
build-args:
description: "Build arguments (newline-separated KEY=value pairs)"
type: string
required: false
default: ""
platforms:
description: "Target platforms (e.g., linux/amd64,linux/arm64)"
type: string
required: false
default: ""
push:
description: "Push image to registry"
type: boolean
required: false
default: true
tags:
description: "Custom tags configuration for docker/metadata-action"
type: string
required: false
default: |
type=raw,value=latest,enable={{is_default_branch}}
type=sha,prefix=
no-cache:
description: "Disable build cache"
type: boolean
required: false
default: false
cache-from:
description: "Cache source (e.g., type=gha)"
type: string
required: false
default: "type=gha"
cache-to:
description: "Cache destination (e.g., type=gha,mode=max)"
type: string
required: false
default: "type=gha,mode=max"
provenance:
description: "Generate provenance attestation"
type: boolean
required: false
default: false
timeout-minutes:
description: "Job timeout in minutes"
type: number
required: false
default: 60
dockerhub-username:
description: "Docker Hub username (from vars). Required when push: true (default)."
type: string
required: false

secrets:
dockerhub-token:
description: "Docker Hub access token (from secrets). Required when push: true (default)."
required: false
build-secrets:
description: "Docker BuildKit secrets (newline-separated KEY=value pairs)"
required: false
build-args-secrets:
description: "Secret build arguments appended to build-args (newline-separated KEY=value pairs)"
required: false

jobs:
build-and-push:
runs-on: ubuntu-latest
timeout-minutes: ${{ inputs.timeout-minutes }}
permissions:
contents: read

steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false

- name: Set up QEMU
if: inputs.platforms != ''
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0

- name: Log in to Docker Hub
if: inputs.push
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
Comment thread
crispy101 marked this conversation as resolved.
with:
registry: ${{ inputs.registry }}
username: ${{ inputs.dockerhub-username }}
password: ${{ secrets.dockerhub-token }}

- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
with:
images: ${{ inputs.registry }}/${{ inputs.image-name }}
tags: ${{ inputs.tags }}

- name: Prepare build args
id: build-args
run: |
{
echo 'args<<EOF'
echo "$BUILD_ARGS"
echo "$BUILD_ARGS_SECRETS"
echo 'EOF'
} >> "$GITHUB_OUTPUT"
env:
BUILD_ARGS: ${{ inputs.build-args }}
BUILD_ARGS_SECRETS: ${{ secrets.build-args-secrets }}

- name: Build Docker image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: ${{ inputs.context }}
file: ${{ inputs.context }}/${{ inputs.dockerfile }}
push: false
load: ${{ inputs.platforms == '' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: ${{ steps.build-args.outputs.args }}
platforms: ${{ inputs.platforms || '' }}
no-cache: ${{ inputs.no-cache }}
cache-from: ${{ !inputs.no-cache && inputs.cache-from || '' }}
cache-to: ${{ inputs.cache-to }}
provenance: ${{ inputs.provenance }}
secrets: ${{ secrets.build-secrets }}

- name: Refresh Docker Hub login
if: inputs.push
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with:
registry: ${{ inputs.registry }}
username: ${{ inputs.dockerhub-username }}
password: ${{ secrets.dockerhub-token }}

- name: Push Docker image
Comment thread
AdamJHall marked this conversation as resolved.
if: inputs.push
run: |
echo "$TAGS" | tr ',' '\n' | while read -r tag; do
[ -n "$tag" ] && docker push "$tag"
done
env:
TAGS: ${{ steps.meta.outputs.tags }}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ A collection of GitHub action workflows. Built using the [reusable workflows](ht
| Workflow | Description |
|----------|-------------|
| [AIO App Deployment](docs/aio-app-deployment.md) | Adobe I/O App Builder deployment for standalone apps and NX monorepos |
| [Docker Build and Push](docs/docker-build.md) | Build and push Docker images to Docker Hub with caching, multi-platform, and BuildKit secrets support |
| [AIO Mesh Deployment](docs/aio-mesh-deployment.md) | Adobe I/O API Mesh create/update with provisioning polling |
| [AWS CDK](docs/aws-cdk.md) | Multi-environment infrastructure synthesis, diffs and deployments with automatic package manager detection |
| [Changeset Check](docs/changeset-check.md) | Advisory PR comments when changesets are missing for affected packages |
Expand Down
102 changes: 102 additions & 0 deletions docs/docker-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Docker Build and Push

Build and push Docker images to Docker Hub with support for multi-platform builds, caching, and BuildKit secrets.

#### **Inputs**
| Name | Required | Type | Default | Description |
|-------------------|----------|---------|------------------------------------------------------|--------------------------------------------------|
| image-name | ✅ | string | | Docker image name (e.g., `aligent/my-app`) |
| registry | ❌ | string | `docker.io` | Docker registry |
| context | ❌ | string | `.` | Build context path |
| dockerfile | ❌ | string | `Dockerfile` | Path to Dockerfile |
| build-args | ❌ | string | | Build arguments (newline-separated KEY=value) |
| platforms | ❌ | string | | Target platforms (e.g., `linux/amd64,linux/arm64`) |
| push | ❌ | boolean | `true` | Push image to registry |
| tags | ❌ | string | `type=raw,value=latest,enable={{is_default_branch}}`<br>`type=sha,prefix=` | Custom tags for docker/metadata-action |
| no-cache | ❌ | boolean | `false` | Disable build cache |
| cache-from | ❌ | string | `type=gha` | Cache source |
| cache-to | ❌ | string | `type=gha,mode=max` | Cache destination |
| provenance | ❌ | boolean | `false` | Generate provenance attestation |
| timeout-minutes | ❌ | number | `60` | Job timeout in minutes |
| dockerhub-username| ✅ | string | | Docker Hub username (from vars) |

#### **Secrets**
| Name | Required | Description |
|-------------------|----------|------------------------------------------------------|
| dockerhub-token | ✅ | Docker Hub access token |
| build-secrets | ❌ | Docker BuildKit secrets (newline-separated KEY=value)|
| build-args-secrets| ❌ | Secret build arguments appended to build-args |

#### **Features**

- **Split build and push**: Build and push are separate steps with a fresh Docker Hub login before push, preventing token timeout for long-running builds.
- **Multi-platform support**: Optional QEMU setup for cross-platform builds.
- **GitHub Actions cache**: Uses `type=gha` caching by default for faster builds.
- **BuildKit secrets**: Securely pass secrets during build without exposing them in logs.
- **Flexible tagging**: Uses docker/metadata-action for automatic tag generation.

#### Example Usage

```yaml
name: Build and Push Docker Image

on:
push:
branches: [main]
schedule:
- cron: '0 2 * * *' # Daily at 2am UTC
workflow_dispatch:

jobs:
build-and-push:
uses: aligent/workflows/.github/workflows/docker-build.yml@main
with:
image-name: aligent/my-app
dockerhub-username: ${{ vars.DOCKERHUB_USERNAME }}
build-args: |
BUILD_ENV=production
secrets:
dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }}
```

#### Example with BuildKit Secrets

For builds requiring sensitive data (e.g., API keys during build):

```yaml
jobs:
build-and-push:
uses: aligent/workflows/.github/workflows/docker-build.yml@main
with:
image-name: aligent/my-app
dockerhub-username: ${{ vars.DOCKERHUB_USERNAME }}
timeout-minutes: 360
build-args: |
UPDATE_DB=true
secrets:
dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }}
build-secrets: |
NVD_API_KEY=${{ secrets.NVD_API_KEY }}
```

In your Dockerfile, access the secret:

```dockerfile
RUN --mount=type=secret,id=NVD_API_KEY,mode=0444 \
SECRET_VALUE=$(cat /run/secrets/NVD_API_KEY) && \
# use SECRET_VALUE...
```

#### Example with Multi-Platform Build

```yaml
jobs:
build-and-push:
uses: aligent/workflows/.github/workflows/docker-build.yml@main
with:
image-name: aligent/my-app
dockerhub-username: ${{ vars.DOCKERHUB_USERNAME }}
platforms: linux/amd64,linux/arm64
secrets:
dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }}
```