-
-
Notifications
You must be signed in to change notification settings - Fork 34
231 lines (209 loc) · 9.39 KB
/
reusable-docker-build.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
---
name: Docker Build and Push
on:
# REUSABLE WORKFLOW with INPUTS
# to keep this workflow simple, assumptions are made:
# - only able to push to Docker Hub and/or GHCR (GHCR by default)
# - adds a comment to PRs of tags and label metadata
# - you want to use GitHub cache for buildx image layers
# - Builds on PR with tag of `pr-NUMBER` (same tag each PR push)
# - Builds on push to default_branch will have a unique tag of `stable-YYYYMMDD-SHA`
# - Builds on push to default_branch will have a reusable tag of `latest` (useful for easy human testing, not servers)
# - Builds on a tag push with semver will also have a reusable tag of `latest` and also a semver tag
# - Defaults to only linux/amd64 platform builds, but can build for others in parallel
workflow_call:
# allow reuse of this workflow in other repos
inputs:
comment-enable:
description: Create a PR comment with image tags and labels
required: false
default: true
type: boolean
context:
description: Docker context (path) to start build from
# To set to a subdir, use format of "{{defaultContext}}:mysubdir"
required: false
type: string
dockerhub-enable:
description: Log into Docker Hub
required: false
default: false
type: boolean
file:
description: Dockerfile to build, relative to context path
required: false
type: string
flavor-rules:
# https://github.com/marketplace/actions/docker-metadata-action#flavor-input
description: Three rules to (optionally) set for tag-rules, latest, prefix, and suffix
required: false
type: string
# will tag latest on a git tag push, or if you add a type=semver or type=match tag-rules
# NOTE: if you are seeing `latest` retagged when you don't expect it, set this latest=false
default: |
latest=auto
ghcr-enable:
description: Log into GHCR
required: false
default: true
type: boolean
image-names:
description: A list of the account/repo names for docker build to push to
required: false
type: string
# this is cool because you can add multiple names to different registries
# and docker-build-push step will push to all of them
default: |
ghcr.io/${{ github.repository }}
platforms:
description: Platforms to build for
required: false
type: string
# common ones: linux/amd64,linux/arm64,linux/arm/v7
default: linux/amd64
push:
description: Push image to registry(s)
required: false
type: boolean
default: true
tag-rules:
# https://github.com/marketplace/actions/docker-metadata-action#tags-input
description: Use docker-metadata action to create tags from a key-value pair list in CSV format
required: false
type: string
# this ruleset will create one or more tags for each image in image-names
# some fire in pr-only, some in push/merge-only
# I still recommend reusable `latest` tag for human-friendly testing (not servers)
# I like a full tag for prod images that reads something like `stable-<date>-<commit>`
# Tags starting with `gha-<run_id>` are unique to each PR commit, and used to test fresh images # rules with is_default_branch only create the tag if it's a push/merge to default branch
# priority attribute is used to sort tags in the final list. The higher the value,
# the higher the priority. The first tag in the list (higher priority) will be used as
# the image version for generated OCI label and version output.
default: |
type=raw,value=stable-{{date 'YYYYMMDD'}}-{{sha}},enable={{is_default_branch}},priority=300
type=ref,event=tag,priority=200
type=raw,value=latest,enable={{is_default_branch}},priority=100
type=raw,value=gha-${{ github.run_id }},enable=${{github.event_name == 'pull_request'}},priority=200
type=ref,event=pr,priority=100
target:
description: Build stage to target
required: false
type: string
secrets:
dockerhub-username:
description: Docker Hub username
required: false
dockerhub-token:
description: Docker Hub token
required: false
outputs:
image-tag:
description: "single-use image tag for GHA runs"
value: ${{ jobs.build-image.outputs.image-tag }}
# set permissions here for what's required to run this Reusable Workflow
# However, permisions are set in the GITHUB_TOKEN by the **calling** workflow
# Calling permissions must be equal to or greater than these reusable permissions for it to work
# https://docs.github.com/en/actions/using-workflows/reusing-workflows#supported-keywords-for-jobs-that-call-a-reusable-workflow
permissions:
contents: read
packages: write # needed to push docker image to ghcr.io
pull-requests: write # needed to create and update comments in PRs
jobs:
build-image:
name: Build+Push
runs-on: ubuntu-latest
outputs:
# only outputs the unique gha- image tag that's unique to each GHA run
image-tag: ${{ steps.image-tag.outputs.image-tag }}
steps:
# we need qemu and buildx so we can build multiple platforms later
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v3.2.0
# BuildKit (used with `docker buildx`) is the best way to build images
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3.8.0
- name: Login to DockerHub
if: inputs.dockerhub-enable
uses: docker/login-action@v3.3.0
with:
username: ${{ secrets.dockerhub-username }}
password: ${{ secrets.dockerhub-token }}
- name: Login to GHCR
if: inputs.ghcr-enable
uses: docker/login-action@v3.3.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker meta
id: docker_meta
uses: docker/metadata-action@v5.6.1
with:
# list of Docker images to use as base name for tags
images: ${{ inputs.image-names }}
flavor: ${{ inputs.flavor-rules }}
tags: ${{ inputs.tag-rules }}
# this will build the images, once per platform,
# then push to one or more registries (based on image list above in docker_meta)
# NOTE: this will not push if a PR is from a fork, where secrets are not available
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
- name: Docker Build and Push
id: build_image
uses: docker/build-push-action@v6.10.0
with:
platforms: ${{ inputs.platforms }}
context: ${{ inputs.context }}
file: ${{ inputs.file }}
target: ${{ inputs.target }}
builder: ${{ steps.buildx.outputs.name }}
# it uses github cache API for faster builds:
# https://github.com/docker/build-push-action/blob/master/docs/advanced/cache.md#cache-backend-api
cache-from: type=gha
cache-to: type=gha,mode=max
push: ${{ inputs.push }}
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
# add attestations for provenance and sbom (bleeding edge BuildKit features)
# NOTE: for now, this reults in `unknown/unknown` images in all registries but Hub
# https://docs.docker.com/build/attestations/attestation-storage/
provenance: true
sbom: true
# If PR, put image tags in the PR comments
# from https://github.com/marketplace/actions/create-or-update-comment
- name: Find comment for image tags
uses: peter-evans/find-comment@v3.1.0
if: github.event_name == 'pull_request' && inputs.comment-enable
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: 'github-actions[bot]'
body-includes: Docker image tag(s) pushed
# If PR, put image tags in the PR comments
- name: Create or update comment for image tags
uses: peter-evans/create-or-update-comment@v4.0.0
if: github.event_name == 'pull_request' && inputs.comment-enable
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body: |
Docker image tag(s) pushed:
```text
${{ steps.docker_meta.outputs.tags }}
```
Labels added to images:
```text
${{ steps.docker_meta.outputs.labels }}
```
edit-mode: replace
# for dependent jobs, we need to output the unique tag for this GHA run
# based on the docker_meta tag priority rules, the highest priority tag
# will be sent to this output
# this step output is sent to job output, which is sent to workflow output
# use this tag in another job with needs.<job-name>.outputs.image-tag
- name: Find the primary image tag we just pushed, and output it
id: image-tag
run: |
# shellcheck disable=SC2086
echo "image-tag=${{ steps.docker_meta.outputs.version }}" >> $GITHUB_OUTPUT