Repository navigation
217 lines (207 loc) · 8.91 KB
/
Copy pathkernel.yml
File metadata and controls
217 lines (207 loc) · 8.91 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
# Builds the kernel that fctl's firecracker driver boots its sandboxes with,
# for amd64 and arm64, boots it in Firecracker where the runner has KVM, and
# publishes it as ghcr.io/hyperstructure/sandbox-kernel:<kernel/VERSION> and
# :<major>.<minor>: an image whose /vmlinux is the kernel. fctl pins the
# version its hosts pull.
#
# - A push to main that changes kernel/ publishes the version in
# kernel/VERSION when it isn't published yet. A published version is never
# built again: hosts that pinned it keep the kernel they have, so a change
# to how it is built comes with a new version (6.18.59-2 for the same
# Linux release).
# - `gh workflow run kernel.yml` does the same, for a run that failed.
# - Pull requests that change kernel/ build and check it without publishing.
#
# Each architecture builds on its own runner and is pushed by digest, without
# a tag; the last job tags the two as one image. Only main publishes.
name: Kernel
on:
pull_request:
paths:
- kernel/**
- .github/workflows/kernel.yml
push:
branches: [main]
paths:
- kernel/**
- .github/workflows/kernel.yml
workflow_dispatch:
permissions:
contents: read
concurrency:
group: kernel-${{ github.event_name == 'pull_request' && github.ref || 'publish' }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
IMAGE: ghcr.io/hyperstructure/sandbox-kernel
DESCRIPTION: The kernel of fctl's Firecracker sandboxes
SOURCE: https://github.com/hyperstructure/sandbox
jobs:
plan:
name: What to build
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: read
packages: read
outputs:
version: ${{ steps.plan.outputs.version }}
tags: ${{ steps.plan.outputs.tags }}
created: ${{ steps.plan.outputs.created }}
build: ${{ steps.plan.outputs.build }}
push: ${{ steps.plan.outputs.push }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Version and tags
id: plan
env:
EVENT: ${{ github.event_name }}
GH_TOKEN: ${{ github.token }}
run: |
# The Linux release, and a build number when the build changed without one.
version=$(tr -d '[:space:]' < kernel/VERSION)
[[ $version =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$ ]] || { echo "::error::kernel/VERSION says '$version'"; exit 1; }
IFS=. read -r major minor _ <<<"${version%%-*}"
tags="$IMAGE:$version $IMAGE:$major.$minor"
# Only main publishes; pull requests and other branches build and check.
push=no
if [ "$EVENT" != pull_request ] && [ "$GITHUB_REF" = refs/heads/main ]; then push=yes; fi
build=yes why="$IMAGE:$version isn't published yet"
if [ "$push" = yes ]; then
echo "$GH_TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin >/dev/null
# Published: never again. GHCR denies a package it doesn't have
# yet; anything else (a 5xx, the network) stops the run, rather
# than publish over what may be there.
if inspected=$(docker buildx imagetools inspect --raw "$IMAGE:$version" 2>&1); then
build=no why="$IMAGE:$version is published already: a change to how it is built takes a new version in kernel/VERSION"
elif ! grep -qiE "not found|manifest unknown|name unknown|denied" <<<"$inspected"; then
echo "::error::Reading $IMAGE:$version: $inspected"
exit 1
fi
fi
{
echo "version=$version"
echo "tags=$tags"
echo "created=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo "build=$build"
echo "push=$push"
} >> "$GITHUB_OUTPUT"
{
if [ "$build" = no ]; then
echo "Nothing to build: $why."
elif [ "$push" = yes ]; then
echo "Building Linux $version for \`$tags\`: $why."
else
echo "Building Linux $version from \`$GITHUB_REF\`, without publishing it."
fi
} >> "$GITHUB_STEP_SUMMARY"
build:
name: Build (${{ matrix.arch }})
needs: plan
if: needs.plan.outputs.build == 'yes'
strategy:
matrix:
include:
- arch: amd64
runner: ubuntu-24.04
- arch: arm64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
permissions:
contents: read
packages: write
env:
VERSION: ${{ needs.plan.outputs.version }}
CREATED: ${{ needs.plan.outputs.created }}
PUSH: ${{ needs.plan.outputs.push }}
ARCH: ${{ matrix.arch }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Build
run: |
docker buildx create --name kernel --driver docker-container --use >/dev/null
docker buildx build kernel \
--platform "linux/$ARCH" --pull --provenance=false \
--output "type=local,dest=$RUNNER_TEMP/out"
ls -l "$RUNNER_TEMP/out"
- name: Boot it
shell: bash
run: |
# GitHub's x86_64 runners have KVM, for root only.
if [ -e /dev/kvm ]; then sudo chmod 666 /dev/kvm; fi
sudo apt-get install -y --no-install-recommends busybox-static >/dev/null
kernel/check.sh "$RUNNER_TEMP/out/vmlinux" | tee -a "$GITHUB_STEP_SUMMARY"
- name: Push it by digest
id: push
if: needs.plan.outputs.push == 'yes'
env:
GH_TOKEN: ${{ github.token }}
run: |
echo "$GH_TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin >/dev/null
# The same build again, from the builder's cache.
docker buildx build kernel \
--platform "linux/$ARCH" --provenance=false \
--label "org.opencontainers.image.title=sandbox-kernel" \
--label "org.opencontainers.image.description=$DESCRIPTION" \
--label "org.opencontainers.image.url=$SOURCE" \
--label "org.opencontainers.image.source=$SOURCE" \
--label "org.opencontainers.image.licenses=GPL-2.0-only" \
--label "org.opencontainers.image.version=$VERSION" \
--label "org.opencontainers.image.revision=$GITHUB_SHA" \
--label "org.opencontainers.image.created=$CREATED" \
--output "type=image,name=$IMAGE,push-by-digest=true,name-canonical=true,push=true,oci-mediatypes=true" \
--metadata-file "$RUNNER_TEMP/build.json"
digest=$(jq -r '."containerimage.digest"' "$RUNNER_TEMP/build.json")
mkdir -p "$RUNNER_TEMP/digests"
touch "$RUNNER_TEMP/digests/${digest#sha256:}"
- if: needs.plan.outputs.push == 'yes'
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: kernel-digest-${{ matrix.arch }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
publish:
name: Publish
needs: [plan, build]
if: needs.plan.outputs.push == 'yes'
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: read
packages: write
env:
VERSION: ${{ needs.plan.outputs.version }}
CREATED: ${{ needs.plan.outputs.created }}
TAGS: ${{ needs.plan.outputs.tags }}
steps:
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
pattern: kernel-digest-*
path: ${{ runner.temp }}/digests
merge-multiple: true
- name: Tag both architectures as one image
env:
GH_TOKEN: ${{ github.token }}
run: |
echo "$GH_TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin >/dev/null
sources=()
for file in "$RUNNER_TEMP"/digests/*; do sources+=("$IMAGE@sha256:$(basename "$file")"); done
[ "${#sources[@]}" = 2 ] || { echo "::error::expected a digest for each architecture, got ${sources[*]}"; exit 1; }
tags=()
for tag in $TAGS; do tags+=(--tag "$tag"); done
# On the index too: GHCR shows these, and the next runs read the
# commit from them.
docker buildx imagetools create "${tags[@]}" \
--annotation "index:org.opencontainers.image.description=$DESCRIPTION" \
--annotation "index:org.opencontainers.image.source=$SOURCE" \
--annotation "index:org.opencontainers.image.licenses=GPL-2.0-only" \
--annotation "index:org.opencontainers.image.version=$VERSION" \
--annotation "index:org.opencontainers.image.revision=$GITHUB_SHA" \
--annotation "index:org.opencontainers.image.created=$CREATED" \
"${sources[@]}"
docker buildx imagetools inspect "$IMAGE:$VERSION"
{
echo "Published Linux $VERSION as:"
for tag in $TAGS; do echo "- \`$tag\`"; done
} >> "$GITHUB_STEP_SUMMARY"