-
Notifications
You must be signed in to change notification settings - Fork 0
300 lines (275 loc) · 14.4 KB
/
Copy pathbuild.yml
File metadata and controls
300 lines (275 loc) · 14.4 KB
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
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
---
# Single-job sequential build: base + K3s share local containers-storage so
# the K3s `FROM ${BASE_IMAGE}` resolves without a registry round-trip. This
# shape is the right answer for 2 images with a parent-child relationship.
#
# When you add a third leaf flavor (RKE2, MicroK8s, multi-arch, alternate
# kernel streams, …), refactor to two jobs:
# 1) build_base (one runner, pushes by digest)
# 2) build_variants (matrix over flavors, pins base by @digest)
# Full copy-paste-ready recipe + pitfalls:
# docs/ci-build-matrix-refactor.md
name: Build container image
on:
pull_request:
branches:
- main
schedule:
- cron: '05 10 * * *' # 10:05am UTC everyday
push:
branches:
- main
paths-ignore:
- '**/README.md'
workflow_dispatch:
env:
IMAGE_DESC: "My Customized Universal Blue Image"
IMAGE_KEYWORDS: "bootc,ublue,universal-blue"
IMAGE_LOGO_URL: "https://avatars.githubusercontent.com/u/120078124?s=200&v=4" # Put your own image here for a fancy profile on https://artifacthub.io/!
IMAGE_NAME: "${{ github.event.repository.name }}" # output image name, usually same as repo name
IMAGE_REGISTRY: "ghcr.io/${{ github.repository_owner }}" # do not edit
DEFAULT_TAG: "stable"
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true
jobs:
build_push:
name: Build and push image
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
id-token: write
steps:
- name: Prepare environment
run: |
# Lowercase the image uri
echo "IMAGE_REGISTRY=${IMAGE_REGISTRY,,}" >> ${GITHUB_ENV}
echo "IMAGE_NAME=${IMAGE_NAME,,}" >> ${GITHUB_ENV}
# These stage versions are pinned by https://github.com/renovatebot/renovate
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
# This is optional, but if you see that your builds are way too big for the runners, you can enable this by uncommenting the following lines:
# - name: Maximize build space
# uses: ublue-os/remove-unwanted-software@517622d6452028f266b7ba4cc9a123b5f58a6b53 # v7
# with:
# remove-codeql: true
- name: Mount BTRFS for podman storage
id: container-storage-action
uses: ublue-os/container-storage-action@911baca08baf30c8654933e9e9723cb399892140 # main
# Fallback to the remove-unwanted-software-action if github doesn't allocate enough space
# See: https://github.com/ublue-os/container-storage-action/pull/11
continue-on-error: true
with:
target-dir: /var/lib/containers
mount-opts: compress-force=zstd:2
- name: Get current date
id: date
run: |
# This generates a timestamp like what is defined on the ArtifactHub documentation
# E.G: 2022-02-08T15:38:15Z'
# https://artifacthub.io/docs/topics/repositories/container-images/
# https://linux.die.net/man/1/date
echo "date=$(date -u +%Y\-%m\-%d\T%H\:%M\:%S\Z)" >> $GITHUB_OUTPUT
# Image metadata for https://artifacthub.io/ - This is optional but is highly recommended so we all can get a index of all the custom images
# The metadata by itself is not going to do anything, you choose if you want your image to be on ArtifactHub or not.
- name: Image Metadata (base)
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5
id: metadata
with:
# This generates all the tags for your image, you can add custom tags here too!
# Default tags are "$DEFAULT_TAG" and "$DEFAULT_TAG.$date".
tags: |
type=raw,value=${{ env.DEFAULT_TAG }}
type=raw,value=${{ env.DEFAULT_TAG }}.{{date 'YYYYMMDD'}}
type=raw,value={{date 'YYYYMMDD'}}
type=sha,enable=${{ github.event_name == 'pull_request' }}
type=ref,event=pr
labels: |
io.artifacthub.package.readme-url=https://raw.githubusercontent.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/${{ github.sha }}/README.md
org.opencontainers.image.created=${{ steps.date.outputs.date }}
org.opencontainers.image.description=${{ env.IMAGE_DESC }}
org.opencontainers.image.documentation=https://raw.githubusercontent.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/${{ github.sha }}/README.md
org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/blob/${{ github.sha }}/Containerfile
org.opencontainers.image.title=${{ env.IMAGE_NAME }}
org.opencontainers.image.url=https://github.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/tree/${{ github.sha }}
org.opencontainers.image.vendor=${{ github.repository_owner }}
org.opencontainers.image.version=${{ env.DEFAULT_TAG }}.{{date 'YYYYMMDD'}}
io.artifacthub.package.deprecated=false
io.artifacthub.package.keywords=${{ env.IMAGE_KEYWORDS }}
io.artifacthub.package.license=Apache-2.0
io.artifacthub.package.logo-url=${{ env.IMAGE_LOGO_URL }}
io.artifacthub.package.prerelease=false
containers.bootc=1
sep-tags: " "
sep-annotations: " "
# Same shape as the base metadata, but with title/source/url pointing at
# the K3s flavor so downstream tools (ArtifactHub, OCI inspectors,
# `bootc status`) report the correct image identity.
- name: Image Metadata (K3s)
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5
id: metadata_k3s
with:
tags: |
type=raw,value=${{ env.DEFAULT_TAG }}
type=raw,value=${{ env.DEFAULT_TAG }}.{{date 'YYYYMMDD'}}
type=raw,value={{date 'YYYYMMDD'}}
type=sha,enable=${{ github.event_name == 'pull_request' }}
type=ref,event=pr
labels: |
io.artifacthub.package.readme-url=https://raw.githubusercontent.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/${{ github.sha }}/README.md
org.opencontainers.image.created=${{ steps.date.outputs.date }}
org.opencontainers.image.description=${{ env.IMAGE_DESC }} (K3s flavor)
org.opencontainers.image.documentation=https://raw.githubusercontent.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/${{ github.sha }}/docs/k3s-rancher-vms.md
org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/blob/${{ github.sha }}/Containerfile.k3s
org.opencontainers.image.title=${{ env.IMAGE_NAME }}-k3s
org.opencontainers.image.url=https://github.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}/tree/${{ github.sha }}
org.opencontainers.image.vendor=${{ github.repository_owner }}
org.opencontainers.image.version=${{ env.DEFAULT_TAG }}.{{date 'YYYYMMDD'}}
io.artifacthub.package.deprecated=false
io.artifacthub.package.keywords=${{ env.IMAGE_KEYWORDS }},k3s,kubernetes
io.artifacthub.package.license=Apache-2.0
io.artifacthub.package.logo-url=${{ env.IMAGE_LOGO_URL }}
io.artifacthub.package.prerelease=false
containers.bootc=1
sep-tags: " "
sep-annotations: " "
- name: Build Image
id: build_image
uses: redhat-actions/buildah-build@7a95fa7ee0f02d552a32753e7414641a04307056 # v2
with:
containerfiles: |
./Containerfile
# Postfix image name with -custom to make it a little more descriptive
# Syntax: https://docs.github.com/en/actions/learn-github-actions/expressions#format
image: ${{ env.IMAGE_NAME }}
tags: ${{ env.DEFAULT_TAG }}
labels: ${{ steps.metadata.outputs.labels }}
oci: false
# Tag for registry
- name: Tag for registry
run: |
for tag in ${{ steps.metadata.outputs.tags }}; do
podman tag ${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }} ${{ env.IMAGE_NAME }}:$tag
done
# Build the K3s flavor on top of the freshly-built base. buildah picks
# up `localhost/<image>:stable` from local containers-storage — no
# registry round-trip needed. Containerfile.k3s honors BASE_IMAGE as
# its FROM, so we just point at the local tag.
- name: Build K3s flavor image
id: build_image_k3s
uses: redhat-actions/buildah-build@7a95fa7ee0f02d552a32753e7414641a04307056 # v2
with:
containerfiles: |
./Containerfile.k3s
image: ${{ env.IMAGE_NAME }}-k3s
tags: ${{ env.DEFAULT_TAG }}
labels: ${{ steps.metadata_k3s.outputs.labels }}
build-args: |
BASE_IMAGE=localhost/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}
oci: false
- name: Tag K3s flavor for registry
run: |
for tag in ${{ steps.metadata.outputs.tags }}; do
podman tag ${{ env.IMAGE_NAME }}-k3s:${{ env.DEFAULT_TAG }} ${{ env.IMAGE_NAME }}-k3s:$tag
done
# SBOM (OPTIONAL): Software Bill of Materials generation using Syft
# Creates a detailed inventory of all software components in the image for supply chain security.
# To enable:
# 1. Uncomment the "Setup Syft" step below
# 2. Uncomment the "Generate SBOM" step below
# 3. If using image signing, also uncomment the "Add SBOM Attestation" step further down
# Documentation: https://github.com/anchore/syft
# - name: Setup Syft
# id: setup-syft
# uses: anchore/sbom-action/download-syft@8e94d75ddd33f69f691467e42275782e4bfefe84 # v0.20.9
# with:
# syft-version: v1.20.0
#
# - name: Generate SBOM
# id: generate-sbom
# env:
# IMAGE: ${{ env.IMAGE_NAME }}
# DEFAULT_TAG: ${{ env.DEFAULT_TAG }}
# SYFT_CMD: ${{ steps.setup-syft.outputs.cmd }}
# run: |
# OUTPUT_PATH="$(mktemp -d)/sbom.json"
# export SYFT_PARALLELISM=$(($(nproc)*2))
# $SYFT_CMD ${IMAGE}:${DEFAULT_TAG} -o spdx-json=${OUTPUT_PATH}
# echo "OUTPUT_PATH=${OUTPUT_PATH}" >> $GITHUB_OUTPUT
# These `if` statements are so that pull requests for your custom images do not make it publish any packages under your name without you knowing
# They also check if the runner is on the default branch so that things like the merge queue (if you enable it), are going to work
- name: Login to GitHub Container Registry
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push To GHCR (base)
uses: redhat-actions/push-to-registry@5ed88d269cf581ea9ef6dd6806d01562096bee9c # v2
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
id: push
env:
REGISTRY_USER: ${{ github.actor }}
REGISTRY_PASSWORD: ${{ github.token }}
with:
registry: ${{ env.IMAGE_REGISTRY }}
image: ${{ env.IMAGE_NAME }}
tags: ${{ steps.metadata.outputs.tags }}
username: ${{ env.REGISTRY_USER }}
password: ${{ env.REGISTRY_PASSWORD }}
- name: Push To GHCR (K3s flavor)
uses: redhat-actions/push-to-registry@5ed88d269cf581ea9ef6dd6806d01562096bee9c # v2
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
id: push_k3s
env:
REGISTRY_USER: ${{ github.actor }}
REGISTRY_PASSWORD: ${{ github.token }}
with:
registry: ${{ env.IMAGE_REGISTRY }}
image: ${{ env.IMAGE_NAME }}-k3s
tags: ${{ steps.metadata.outputs.tags }}
username: ${{ env.REGISTRY_USER }}
password: ${{ env.REGISTRY_PASSWORD }}
# Image signing with Cosign. Signs every tag of both flavors using the
# repository's SIGNING_SECRET. The corresponding public key (cosign.pub)
# is baked into the image by build/10-build.sh, so consumers verify these
# signatures on `bootc upgrade`/`switch` by default — no per-VM setup.
- name: Install Cosign
uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
- name: Sign container images
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
env:
COSIGN_EXPERIMENTAL: false
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}
run: |
for image in "${{ env.IMAGE_NAME }}" "${{ env.IMAGE_NAME }}-k3s"; do
FULL="${{ env.IMAGE_REGISTRY }}/${image}"
for tag in ${{ steps.metadata.outputs.tags }}; do
echo ">>> cosign sign ${FULL}:${tag}"
cosign sign -y --key env://COSIGN_PRIVATE_KEY "${FULL}:${tag}"
done
done
# OPTIONAL: SBOM Attestation
# Attaches SBOM (Software Bill of Materials) to your signed image for supply chain security.
# Requires image signing to be enabled first (see above).
# To enable:
# 1. First enable image signing (see above section)
# 2. Uncomment the "Add SBOM Attestation" step below
# Documentation: https://slsa.dev/spec/v1.0/requirements#provenance-available
# - name: Add SBOM Attestation
# if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
# env:
# IMAGE: ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}
# DIGEST: ${{ steps.push.outputs.digest }}
# COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}
# SBOM_OUTPUT: ${{ steps.generate-sbom.outputs.OUTPUT_PATH }}
# run: |
# cd "$(dirname "$SBOM_OUTPUT")"
# cosign attest -y \
# --predicate "$(basename "$SBOM_OUTPUT")" \
# --type spdxjson \
# --key env://COSIGN_PRIVATE_KEY \
# "${IMAGE}@${DIGEST}"