Skip to content

Commit 2754495

Browse files
authored
vm-kernel: cache image (#715)
This PR adds caching logic for `neondatabase:vm-kernel` image (it uses the latest git commit sha related to the kernel directory as a cache key) Changes: - All the stuff related to the kernel (Dockerfile + linux-config file) moved to a separate directory `neonvm/hack/kernel` `vm-kernel` workflow: - Gets the last commit sha of `neonvm/hack/kernel` - if an image with such a tag exists — return it to be used in e2e tests. - if the image doesn't exist — build an image and add cache tag for it, return new image for e2e tests - accepts `force-rebuild` parameter, which forces CI to rebuild the image Part of #660
1 parent 8a91e83 commit 2754495

File tree

8 files changed

+140
-43
lines changed

8 files changed

+140
-43
lines changed

.github/workflows/e2e-test.yaml

+6-4
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ on:
2121
env:
2222
PRESERVE_RUNNER_PODS: "true"
2323

24+
defaults:
25+
run:
26+
shell: bash -euo pipefail {0}
27+
2428
jobs:
2529
vm-kernel:
2630
uses: ./.github/workflows/vm-kernel.yaml
2731
with:
28-
push: true
29-
tag: ${{ github.run_id }}
30-
kernel-image-tag-override: ${{ inputs.kernel-image }}
32+
return-image-for-tag: ${{ inputs.kernel-image }}
3133
secrets: inherit
3234

3335
e2e-tests:
@@ -73,7 +75,7 @@ jobs:
7375
run: |
7476
docker pull --quiet $IMAGE
7577
ID=$(docker create $IMAGE true)
76-
docker cp ${ID}:/vmlinuz neonvm/hack/vmlinuz
78+
docker cp ${ID}:/vmlinuz neonvm/hack/kernel/vmlinuz
7779
docker rm -f ${ID}
7880
7981
# our docker builds use the output of 'git describe' for embedding git information

.github/workflows/release.yaml

+1-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ jobs:
2222
vm-kernel:
2323
uses: ./.github/workflows/vm-kernel.yaml
2424
with:
25-
push: true
2625
tag: ${{ github.ref_name }}
2726

2827
release:
@@ -82,7 +81,7 @@ jobs:
8281
run: |
8382
docker pull --quiet $IMAGE
8483
ID=$(docker create $IMAGE true)
85-
docker cp ${ID}:/vmlinuz neonvm/hack/vmlinuz
84+
docker cp ${ID}:/vmlinuz neonvm/hack/kernel/vmlinuz
8685
docker rm -f ${ID}
8786
8887
- name: build and push runner image

.github/workflows/vm-kernel.yaml

+126-31
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,144 @@
11
name: vm-kernel
22

33
on:
4-
schedule:
5-
- cron: '42 4 * * 2' # run once a week
64
workflow_dispatch: # adds ability to run this manually
75
inputs:
8-
push:
9-
description: 'Push to Docker Hub'
10-
type: boolean
11-
default: false
126
tag:
137
description: 'Tag to use for Docker image'
148
type: string
159
required: false
16-
workflow_call:
17-
inputs:
18-
push:
19-
description: 'Push to Docker Hub'
10+
force-rebuild:
11+
description: 'Rebuild the kernel image even if it already exists'
2012
type: boolean
13+
required: false
2114
default: false
15+
workflow_call:
16+
inputs:
2217
tag:
2318
description: 'Tag to use for Docker image'
2419
type: string
2520
required: false
26-
kernel-image-tag-override:
27-
description: 'If set, the workflow return the full image name for this tag'
21+
return-image-for-tag:
22+
description: 'Make workflow to return image for the passed tag without building or tagging anything'
2823
type: string
2924
required: false
3025
default: ''
26+
force-rebuild:
27+
description: 'Rebuild the kernel image even if it already exists. No-op if `return-image-for-tag` is set'
28+
type: boolean
29+
required: false
30+
default: false
3131
outputs:
3232
image:
3333
description: 'vm-kernel Docker image'
34-
value: ${{ jobs.check-kernel-image-override.outputs.image || jobs.vm-kernel.outputs.image }}
34+
value: ${{ jobs.setup-build-vm-kernel-image.outputs.image || jobs.build-vm-kernel-image.outputs.image }}
3535

3636
env:
3737
VM_KERNEL_IMAGE: "neondatabase/vm-kernel"
3838

39+
defaults:
40+
run:
41+
shell: bash -euo pipefail {0}
42+
3943
jobs:
40-
check-kernel-image-override:
44+
setup-build-vm-kernel-image:
4145
outputs:
42-
image: ${{ steps.check-kernel-image-override.outputs.image }}
46+
image: ${{ steps.get-kernel-image.outputs.image }}
47+
last-kernel-sha: ${{ steps.get-last-kernel-commit-sha.outputs.last-kernel-sha }}
4348

4449
runs-on: ubuntu-latest
4550

4651
steps:
47-
- id: check-kernel-image-override
52+
- name: get last kernel commit sha
53+
id: get-last-kernel-commit-sha
54+
env:
55+
COMMIT_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
56+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
57+
run: |
58+
CACHE_TAG=$(
59+
gh api \
60+
-H "Accept: application/vnd.github+json" \
61+
-H "X-GitHub-Api-Version: 2022-11-28" \
62+
--method GET \
63+
--field path=neonvm/hack/kernel \
64+
--field sha=${COMMIT_SHA} \
65+
--field per_page=1 \
66+
--jq ".[0].sha" \
67+
"/repos/${GITHUB_REPOSITORY}/commits"
68+
)
69+
echo "last-kernel-sha=${CACHE_TAG}" >> $GITHUB_OUTPUT
70+
71+
- name: get kernel image
72+
id: get-kernel-image
4873
env:
49-
OVERRIDE_TAG: ${{ inputs.kernel-image-tag-override }}
74+
FORCED_TAG: ${{ inputs.return-image-for-tag }}
75+
FORCE_REBUILD: ${{ inputs.force-rebuild }}
76+
CACHE_TAG: ${{ steps.get-last-kernel-commit-sha.outputs.last-kernel-sha }}
5077
run: |
51-
if [ -n "${OVERRIDE_TAG}" ]; then
52-
DIGEST=$(docker manifest inspect ${VM_KERNEL_IMAGE}:${OVERRIDE_TAG} -v | jq -r '.Descriptor.digest')
53-
IMAGE="${VM_KERNEL_IMAGE}:${OVERRIDE_TAG}@${DIGEST}"
78+
if [ -n "${FORCED_TAG}" ]; then
79+
DIGEST=$(docker manifest inspect ${VM_KERNEL_IMAGE}:${FORCED_TAG} -v | jq -r '.Descriptor.digest')
80+
IMAGE="${VM_KERNEL_IMAGE}:${FORCED_TAG}@${DIGEST}"
81+
elif [ "${FORCE_REBUILD}" == "false" ]; then
82+
CACHE_TAG_DIGEST=$(docker manifest inspect ${VM_KERNEL_IMAGE}:${CACHE_TAG} -v | jq -r '.Descriptor.digest' || true)
83+
if [ -n "${CACHE_TAG_DIGEST}" ]; then
84+
IMAGE="${VM_KERNEL_IMAGE}:${CACHE_TAG}@${CACHE_TAG_DIGEST}"
85+
else
86+
IMAGE=""
87+
fi
5488
else
5589
IMAGE=""
5690
fi
91+
5792
echo "image=${IMAGE}" >> $GITHUB_OUTPUT
5893
59-
vm-kernel:
60-
needs: check-kernel-image-override
61-
if: needs.check-kernel-image-override.outputs.image == ''
94+
- name: check if we need to retag the image
95+
id: check-if-retag-needed
96+
env:
97+
CACHED_IMAGE: ${{ steps.get-kernel-image.outputs.image }}
98+
FORCE_REBUILD: "${{ inputs.force-rebuild }}"
99+
FORCED_TAG: ${{ inputs.return-image-for-tag }}
100+
NEW_TAG: ${{ inputs.tag }}
101+
run: |
102+
if [ -z "${NEW_TAG}" ]; then
103+
# there's no tag provided to retag the image with
104+
RETAG_NEEDED=false
105+
elif [ -z "${CACHED_IMAGE}" ]; then
106+
# there's no image to retag
107+
RETAG_NEEDED=false
108+
elif [ -n "${FORCED_TAG}"]; then
109+
# we're asked to return image for a specific tag, so no need to retag
110+
RETAG_NEEDED=false
111+
elif [ "${FORCE_REBUILD}" == "true" ]; then
112+
# the image is going to be rebuilt anyway, no need to retag it now
113+
RETAG_NEEDED=false
114+
else
115+
RETAG_NEEDED=true
116+
fi
117+
118+
echo "retag-needed=${RETAG_NEEDED}" >> $GITHUB_OUTPUT
119+
120+
- name: login to docker hub
121+
if: steps.check-if-retag-needed.outputs.retag-needed == 'true'
122+
uses: docker/login-action@v2
123+
with:
124+
username: ${{ secrets.NEON_DOCKERHUB_USERNAME }}
125+
password: ${{ secrets.NEON_DOCKERHUB_PASSWORD }}
126+
127+
- name: tag image with new tag
128+
if: steps.check-if-retag-needed.outputs.retag-needed == 'true'
129+
env:
130+
CACHED_IMAGE: ${{ steps.get-kernel-image.outputs.image }}
131+
NEW_TAG: ${{ inputs.tag }}
132+
run: |
133+
docker pull ${CACHED_IMAGE}
134+
docker tag ${CACHED_IMAGE} ${VM_KERNEL_IMAGE}:${NEW_TAG}
135+
docker push ${VM_KERNEL_IMAGE}:${NEW_TAG}
136+
137+
build-vm-kernel-image:
138+
needs: setup-build-vm-kernel-image
139+
if: needs.setup-build-vm-kernel-image.outputs.image == ''
62140
outputs:
63-
image: ${{ fromJSON(steps.build-linux-kernel.outputs.metadata)['image.name'] }}@${{ steps.build-linux-kernel.outputs.digest }}
141+
image: ${{ steps.get-tags.outputs.canonical }}@${{ steps.build-linux-kernel.outputs.digest }}
64142

65143
runs-on: [ self-hosted, gen3, large ]
66144
steps:
@@ -87,25 +165,42 @@ jobs:
87165
- name: get kernel version
88166
id: get-kernel-version
89167
run: |
90-
linux_config=$(ls neonvm/hack/linux-config-*) # returns something like "neonvm/hack/linux-config-6.1.63"
91-
kernel_version=${linux_config##*-} # returns something like "6.1.63"
168+
linux_config=$(ls neonvm/hack/kernel/linux-config-*) # returns something like "neonvm/hack/kernel/linux-config-6.1.63"
169+
kernel_version=${linux_config##*-} # returns something like "6.1.63"
92170
93171
echo VM_KERNEL_VERSION=$kernel_version >> $GITHUB_OUTPUT
94172
173+
- name: get docker tags
174+
id: get-tags
175+
env:
176+
KERNEL_VERSION_TAG: ${{ inputs.tag || steps.get-kernel-version.outputs.VM_KERNEL_VERSION }}
177+
CACHE_TAG: ${{ needs.setup-build-vm-kernel-image.outputs.last-kernel-sha }}
178+
run: |
179+
# A comma-separated list of tags
180+
TAGS="${VM_KERNEL_IMAGE}:${KERNEL_VERSION_TAG}"
181+
TAGS="${VM_KERNEL_IMAGE}:${CACHE_TAG},${TAGS}"
182+
TAGS="${VM_KERNEL_IMAGE}:${GITHUB_RUN_ID},${TAGS}"
183+
184+
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
185+
186+
# `docker/build-push-action@v3` returns all ${TAGS} in metadata ("image.name" field), so it can't be used a image name right away.
187+
# Choose one of them as a "canonical" tag and use it to construct the job output (along with a digest provided by `docker/build-push-action@v3`).
188+
echo "canonical=${VM_KERNEL_IMAGE}:${GITHUB_RUN_ID}" >> $GITHUB_OUTPUT
189+
95190
- name: build linux kernel
96191
id: build-linux-kernel
97192
uses: docker/build-push-action@v3
98193
with:
99194
build-args: KERNEL_VERSION=${{ steps.get-kernel-version.outputs.VM_KERNEL_VERSION }}
100-
context: neonvm/hack
195+
context: neonvm/hack/kernel
101196
platforms: linux/amd64
102197
# Push kernel image only for scheduled builds or if workflow_dispatch/workflow_call input is true
103-
push: ${{ github.event_name == 'schedule' && 'true' || ( inputs.push || 'false' ) }}
198+
push: true
104199
pull: true
105200
no-cache: true
106-
file: neonvm/hack/Dockerfile.kernel-builder
107-
# Tag kernel image with workflow_dispatch/workflow_call input or with the kernel version by default
108-
tags: ${{ env.VM_KERNEL_IMAGE }}:${{ inputs.tag || steps.get-kernel-version.outputs.VM_KERNEL_VERSION }}
201+
file: neonvm/hack/kernel/Dockerfile.kernel-builder
202+
tags: ${{ steps.get-tags.outputs.tags }}
203+
109204
- name: remove custom docker config directory
110205
if: always()
111206
run: |

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@ testbin/*
2525

2626
*.qcow2
2727
neonvm/hack/vmlinuz
28+
neonvm/hack/kernel/vmlinuz
2829

2930
rendered_manifests

Makefile

+5-5
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,8 @@ endif
223223

224224
.PHONY: kernel
225225
kernel: ## Build linux kernel.
226-
rm -f neonvm/hack/vmlinuz; \
227-
linux_config=$$(ls neonvm/hack/linux-config-*) \
226+
rm -f neonvm/hack/vmlinuz neonvm/hack/kernel/vmlinuz; \
227+
linux_config=$$(ls neonvm/hack/kernel/linux-config-*) \
228228
kernel_version=$${linux_config##*-} \
229229
iidfile=$$(mktemp /tmp/iid-XXXXXX); \
230230
trap "rm $$iidfile" EXIT; \
@@ -234,10 +234,10 @@ kernel: ## Build linux kernel.
234234
--pull \
235235
--load \
236236
--iidfile $$iidfile \
237-
--file neonvm/hack/Dockerfile.kernel-builder \
238-
neonvm/hack; \
237+
--file neonvm/hack/kernel/Dockerfile.kernel-builder \
238+
neonvm/hack/kernel; \
239239
id=$$(docker create $$(cat $$iidfile)); \
240-
docker cp $$id:/vmlinuz neonvm/hack/vmlinuz; \
240+
docker cp $$id:/vmlinuz neonvm/hack/kernel/vmlinuz; \
241241
docker rm -f $$id
242242

243243
.PHONY: check-local-context
File renamed without changes.

neonvm/runner/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,6 @@ RUN apk add --no-cache \
4545
cgroup-tools
4646

4747
COPY --from=builder /runner /usr/bin/runner
48-
COPY neonvm/hack/vmlinuz /vm/kernel/vmlinuz
48+
COPY neonvm/hack/kernel/vmlinuz /vm/kernel/vmlinuz
4949

5050
ENTRYPOINT ["/sbin/tini", "--", "runner"]

0 commit comments

Comments
 (0)