Skip to content

Commit 2c4818d

Browse files
committed
Overhaul the Makefile
This new setup actually makes use of make's dependency tracking so that builds aren't randomly broken. It also correctly avoids rebuilds of things that haven't changed and thus don't need to be rebuilt. The previous Makefile setup was very buggy/racy if make was run with more than one job in parallel. It would also have issues if make was interrupted in the middle of a build. This one does not suffer from any of those issues. This new setup takes into account both debug vs release modes for the hook.yaml along with all the arches (new arches should be pretty easy to add in too). One of the bigger features of this new Makefile setup is that everything needed to build hook (except for the kernel) is built locally from source. This means we don't need to push images only to have linuxkit fetch them. This was only possible previously in dev-mode when we'd load the images from buildx into the local docker. This was limited to dev mode because docker doesn't support multi-arch manifests in the local cache. This makes it possible to tinker locally without the risk of pushing to quay.io unintentionally. This is also fully parameterized by both TAG and ORG, though ORG isn't accounted for very well. If ORG is modified in the Makefile please follow the directions and clean out the build dir `rm -rf out`. The TAG build parameter is fully supported and can be different between multiple `make` calls. We make use of this in CI now. Signed-off-by: Manuel Mendez <github@i.m.mmlb.dev>
1 parent 65a45a1 commit 2c4818d

File tree

7 files changed

+156
-155
lines changed

7 files changed

+156
-155
lines changed

.github/workflows/ci.yaml

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,6 @@ on:
66
jobs:
77
validation:
88
runs-on: ubuntu-20.04
9-
services:
10-
registry:
11-
image: registry:2
12-
ports:
13-
- 5000:5000
149
steps:
1510
- name: Checkout code
1611
uses: actions/checkout@v3
@@ -19,26 +14,21 @@ jobs:
1914
uses: docker/setup-qemu-action@v2
2015

2116
- name: Set up Docker Buildx
22-
id: buildx
2317
uses: docker/setup-buildx-action@v2
24-
with:
25-
driver-opts: network=host
2618

2719
- name: Build and push hook-bootkit
2820
uses: docker/build-push-action@v3
2921
with:
3022
context: ./hook-bootkit/
3123
platforms: linux/amd64,linux/arm64
32-
push: true
33-
tags: localhost:5000/tinkerbell/hook-bootkit:latest
24+
tags: quay.io/tinkerbell/hook-bootkit:latest
3425

3526
- name: Build and push hook-docker
3627
uses: docker/build-push-action@v3
3728
with:
3829
context: ./hook-docker/
3930
platforms: linux/amd64,linux/arm64
40-
push: true
41-
tags: localhost:5000/tinkerbell/hook-docker:latest
31+
tags: quay.io/tinkerbell/hook-docker:latest
4232

4333
- uses: cachix/install-nix-action@v17
4434
with:
@@ -50,14 +40,11 @@ jobs:
5040
- name: Run formatters and linters
5141
run: nix-shell --run .github/workflows/formatters-and-linters.sh
5242

53-
# Replace hook-{bootkit,docker} but not hook-kernel
54-
- run: sed -E -i 's,quay.io/tinkerbell/hook-(bootkit|docker),localhost:5000/tinkerbell/hook-\1,g' hook.in.yaml
55-
5643
- name: Build
57-
run: ./hack/ci-build.sh
44+
run: nix-shell --run 'make TAG=${{ github.sha }} dist'
5845

5946
# TODO: add artifacts for the built images
6047
- uses: actions/upload-artifact@v3
6148
with:
6249
name: hook-${{ github.sha }}.tar.gz
63-
path: hook-${{ github.sha }}.tar.gz
50+
path: out/${{ github.sha }}/rel/hook-${{ github.sha }}.tar.gz

.github/workflows/push.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ jobs:
5858

5959
- name: Build & Deploy
6060
run: |
61-
./hack/build-and-deploy.sh
62-
TAG=sha-${{steps.commitid.outputs.short}} ./hack/build-and-deploy.sh
61+
nix-shell --run 'make TAG=latest deploy'
62+
nix-shell --run 'make TAG=sha-${{steps.commitid.outputs.short}} deploy'
6363
6464
- uses: actions/upload-artifact@v3
6565
with:
6666
name: hook-${{steps.commitid.outputs.short}}.tar.gz
67-
path: hook-${{steps.commitid.outputs.short}}.tar.gz
67+
path: out/${{steps.commitid.outputs.short}}/rel/hook-${{steps.commitid.outputs.short}}.tar.gz

.gitignore

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
bin/
2+
dbg/
23
dist/
34
.env
4-
hook-bootkit/local/
5-
hook-debug.*.yaml
6-
hook-docker/local/
7-
hook-*.tar.gz
8-
hook.*.yaml
5+
hook-*
6+
!/hook-bootkit/
7+
!/hook-docker/
8+
hook*.*.yaml
99
out/
1010
*.swp

Makefile

Lines changed: 25 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,134 +1,37 @@
1-
ORG ?= quay.io/tinkerbell
2-
ARCH := $(shell uname -m)
3-
4-
ifeq ($(strip $(TAG)),)
5-
# ^ guards against TAG being defined but empty string which makes `TAG ?=` not work
6-
TAG := latest
1+
# set the ORG
2+
### !!NOTE!!
3+
# If this is changed then a fresh output dir is required (`git clean -fxd` or just `rm -rf out`)
4+
# Handling this better shows some of make's suckiness compared to newer build tools (redo, tup ...) where the command lines to tools invoked isn't tracked by make
5+
ORG := quay.io/mmlb
6+
# makes sure there's no trailing / so we can just add them in the recipes which looks nicer
7+
ORG := $(shell echo "${ORG}" | sed 's|/*$$||')
8+
9+
# The following `ifeq` are the equivalent of FOO ?= except that they work correctly if FOO is set but empty
10+
ifeq ($(strip $(LINUXKIT_CONFIG)),)
11+
LINUXKIT_CONFIG := hook.yaml
712
endif
8-
default: hook-bootkitBuild hook-dockerBuild image
913

10-
dev: dev-hook-bootkitBuild dev-hook-dockerBuild
11-
ifeq ($(ARCH),x86_64)
12-
dev: dev-image-amd64
13-
endif
14-
ifeq ($(ARCH),aarch64)
15-
dev: dev-image-arm64
14+
ifeq ($(strip $(TAG)),)
15+
TAG := sha-$(shell git rev-parse --short HEAD)
1616
endif
17+
T := $(strip $(TAG))
1718

18-
# This option is for running docker manifest command
19-
export DOCKER_CLI_EXPERIMENTAL := enabled
20-
21-
LINUXKIT_CONFIG ?= hook.yaml
22-
hook.$(TAG).yaml: $(LINUXKIT_CONFIG)
23-
sed '/quay.io/ s|:latest|:$(TAG)|' $^ > $@.tmp
24-
mv $@.tmp $@
25-
26-
hook-debug.$(TAG).yaml: hook.$(TAG).yaml
27-
sed '/^\s*#dbg/ s|#dbg||' $^ > $@.tmp
28-
mv $@.tmp $@
29-
30-
image-amd64: hook.$(TAG).yaml
31-
mkdir -p out
32-
linuxkit build -docker -pull -format kernel+initrd -name hook-x86_64 -dir out $^
33-
34-
image-arm64: hook.$(TAG).yaml
35-
mkdir -p out
36-
linuxkit build -docker -pull -arch arm64 -format kernel+initrd -name hook-aarch64 -dir out $^
37-
38-
dev-image-amd64: hook.$(TAG).yaml
39-
mkdir -p out
40-
linuxkit build -docker -format kernel+initrd -name hook-x86_64 -dir out $^
41-
42-
dev-image-arm64: hook.$(TAG).yaml
43-
mkdir -p out
44-
linuxkit build -docker -arch arm64 -format kernel+initrd -name hook-aarch64 -dir out $^
45-
46-
image: image-amd64 image-arm64
47-
48-
debug-image-amd64: hook-debug.$(TAG).yaml
49-
mkdir -p out/amd64
50-
linuxkit build --docker -format kernel+initrd -name debug-x86_64 -dir out $^
19+
help: ## Print this help
20+
@grep --no-filename -E '^[[:alnum:]_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sed 's/:.*## /·/' | sort | column -t -W 2 -s '·' -c $$(tput cols)
5121

52-
debug-image-arm64: hook-debug.$(TAG).yaml
53-
mkdir -p out/arm64
54-
linuxkit build --docker -arch arm64 -format kernel+initrd -name debug-aarch64 -dir out $^
22+
include rules.mk
23+
include lint.mk
5524

56-
debug-image: debug-image-amd64 debug-image-arm64
25+
all: containers images ## Build release mode boot files and container images for all supported architectures
5726

58-
run-amd64:
59-
sudo ~/go/bin/linuxkit run qemu --mem 2048 out/hook-x86_64
27+
dev: image-dbg-$(ARCH) ## Build debug mode boot files and container images for currently running architecture
6028

61-
run-arm64:
62-
sudo ~/go/bin/linuxkit run qemu --mem 2048 out/hook-aarch64
29+
images: ## Build release mode boot files for all supported architectures
6330

64-
run:
65-
sudo ~/go/bin/linuxkit run qemu --mem 2048 out/hook-${ARCH}
31+
containers: hook-bootkit hook-docker ## Build container images
6632

67-
dev-hook-bootkitBuild:
68-
cd hook-bootkit; docker buildx build --load -t $(ORG)/hook-bootkit:$(TAG) .
69-
70-
hook-bootkitBuild:
71-
cd hook-bootkit; docker buildx build --platform linux/amd64,linux/arm64 --push -t $(ORG)/hook-bootkit:$(TAG) .
72-
73-
dev-hook-dockerBuild:
74-
cd hook-docker; docker buildx build --load -t $(ORG)/hook-docker:$(TAG) .
75-
76-
hook-dockerBuild:
77-
cd hook-docker; docker buildx build --platform linux/amd64,linux/arm64 --push -t $(ORG)/hook-docker:$(TAG) .
78-
79-
dev-convert:
80-
rm -rf ./convert
81-
mkdir ./convert
82-
cp out/hook-${ARCH}-initrd.img ./convert/initrd.gz
83-
cd convert/; gunzip ./initrd.gz; cpio -idv < initrd; rm initrd; find . -print0 | cpio --null -ov --format=newc > ../initramfs-${ARCH}; gzip ../initramfs-${ARCH}
84-
85-
.PHONY: convert
86-
convert:
87-
for a in x86_64 aarch64; do \
88-
rm -rf ./convert; \
89-
mkdir ./convert; \
90-
cp out/hook-$$a-initrd.img ./convert/initrd.gz; \
91-
cd convert/; gunzip ./initrd.gz; cpio -idv < initrd; rm initrd; find . -print0 | cpio --null -ov --format=newc > ../initramfs-$$a; gzip ../initramfs-$$a; cd ../;\
92-
done
93-
94-
dist: default convert
95-
rm -rf ./dist ./convert
96-
mkdir ./dist
97-
for a in x86_64 aarch64; do \
98-
mv ./initramfs-$$a.gz ./dist/initramfs-$$a; \
99-
mv ./out/hook-$$a-kernel ./dist/vmlinuz-$$a; \
100-
done
101-
rm -rf out
102-
cd ./dist && tar -czvf ../hook-${TAG}.tar.gz ./*
103-
104-
dist-existing-images: image convert
105-
rm -rf ./dist ./convert
106-
mkdir ./dist
107-
for a in x86_64 aarch64; do \
108-
mv ./initramfs-$$a.gz ./dist/initramfs-$$a; \
109-
mv ./out/hook-$$a-kernel ./dist/vmlinuz-$$a; \
110-
done
111-
rm -rf out
112-
cd ./dist && tar -czvf ../hook-${TAG}.tar.gz ./*
113-
114-
115-
dev-dist: dev dev-convert
116-
rm -rf ./dist ./convert
117-
mkdir ./dist
118-
mv ./initramfs-${ARCH}.gz ./dist/initramfs-${ARCH}
119-
mv ./out/hook-${ARCH}-kernel ./dist/vmlinuz-${ARCH}
120-
rm -rf out
121-
cd ./dist && tar -czvf ../hook-${TAG}.tar.gz ./*
122-
123-
deploy: dist
124-
ifeq ($(shell git rev-parse --abbrev-ref HEAD),main)
125-
s3cmd sync ./hook-${TAG}.tar.gz s3://s.gianarb.it/hook/${TAG}.tar.gz
126-
s3cmd cp s3://s.gianarb.it/hook/hook-${TAG}.tar.gz s3://s.gianarb.it/hook/hook-main.tar.gz
127-
endif
33+
debug: ## Build debug mode boot files and container images for all supported architectures
12834

129-
.PHONY: clean
130-
clean:
131-
rm ./hook-${TAG}.tar.gz
132-
rm -rf dist/ out/ hook-docker/local/ hook-bootkit/local/
35+
push: push-hook-bootkit push-hook-docker ## Push container images to registry
13336

134-
-include lint.mk
37+
run: run-$(ARCH) ## Boot system using qemu

README.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,7 @@ The `dist` make target will do a couple of things:
105105

106106
1. Build the required docker images using `docker buildx`.
107107
2. It will use `linuxkit build` to prepare the init ramdisk and the kernel.
108-
3. It will convert the init ramkdisk in the right format that iPXE can boot
109-
4. It will create a `tar.gz` archive in the root of the project containing all the files in the proper format, ready to be served via Tinkerbell.
108+
3. It will create a `tar.gz` archive in the root of the project containing all the files in the proper format, ready to be served via boots.
110109

111110
## Build for local testing (only the local architecture)
112111

@@ -121,10 +120,8 @@ make dev-dist
121120

122121
## Troubleshooting
123122

124-
Sometimes this has occurred with changed one letter of a string inside some source code and rebuilding... not sure why yet.
125-
126-
It is also possible to build a debug version of hook, that will have an `sshd` server running with any public keys you have.
127-
This is achieved through the command `make debug-image`
123+
It is possible to build a debug version of hook, that will have an `sshd` server running with any public keys you have.
124+
This is achieved through the command `make debug-images`
128125

129126
## Nix for CI/CD
130127

kernel/Makefile

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,15 @@
1515
# This option is for running docker manifest command
1616
export DOCKER_CLI_EXPERIMENTAL := enabled
1717

18-
# Name and Org on Hub
19-
ORG?=quay.io/tinkerbell
18+
# set ORG in the env or make call
19+
# having it in the makefile is dangerous as its too easy to overwrite previous pushes/tags
20+
ifeq ($(strip $(ORG)),)
21+
# ^ guards against ORG being defined but empty string which makes `ORG ?=` not work
22+
ORG := quay.io/tinkerbell
23+
endif
24+
# makes sure there's no trailing / so we can just add them in the recipes which looks nicer
25+
ORG := $(shell echo "${ORG}" | sed 's|/*$$||')
26+
2027
IMAGE:=hook-kernel
2128
IMAGE_BCC:=hook-kernel-bcc
2229
IMAGE_PERF:=hook-kernel-perf

rules.mk

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Only use the recipes defined in these makefiles
2+
MAKEFLAGS += --no-builtin-rules
3+
.SUFFIXES:
4+
# Delete target files if there's an error
5+
# This avoids a failure to then skip building on next run if the output is created by shell redirection for example
6+
# Not really necessary for now, but just good to have already if it becomes necessary later.
7+
.DELETE_ON_ERROR:
8+
# Treat the whole recipe as a one shell script/invocation instead of one-per-line
9+
.ONESHELL:
10+
# Use bash instead of plain sh
11+
SHELL := bash
12+
.SHELLFLAGS := -o pipefail -euc
13+
14+
# This option is for running docker manifest command
15+
export DOCKER_CLI_EXPERIMENTAL := enabled
16+
17+
ARCH := $(shell uname -m)
18+
ifeq ($(ARCH),x86_64)
19+
ARCH = amd64
20+
endif
21+
ifeq ($(ARCH),aarch64)
22+
ARCH = arm64
23+
endif
24+
25+
arches := amd64 arm64
26+
modes := rel dbg
27+
28+
hook-bootkit-deps := $(wildcard hook-bootkit/*)
29+
hook-docker-deps := $(wildcard hook-docker/*)
30+
31+
define foreach_mode_arch_rules =
32+
# mode := $(1)
33+
# arch := $(2)
34+
35+
$$(shell mkdir -p out/$T/$(1)/$(2))
36+
37+
.PHONY: hook-$(1)-$(2)
38+
image-$(1)-$(2): out/$T/$(1)/$(2)/hook.tar
39+
out/$T/$(1)/$(2)/hook.tar: out/$T/$(1)/$(2)/hook.yaml out/$T/hook-bootkit-$(2) out/$T/hook-docker-$(2)
40+
linuxkit build -docker -arch $(2) -format tar-kernel-initrd -name hook -dir $$(@D) $$<
41+
mv $$(@D)/hook-initrd.tar $$@
42+
43+
out/$T/$(1)/$(2)/cmdline out/$T/$(1)/$(2)/initrd.img out/$T/$(1)/$(2)/kernel: out/$T/$(1)/$(2)/hook.tar
44+
tar xf $$^ -C $$(@D) $$(@F)
45+
touch $$@
46+
47+
out/$T/$(1)/$(2)/hook.yaml: $$(LINUXKIT_CONFIG)
48+
sed '/hook-\(bootkit\|docker\):/ { s|:latest|:$T-$(2)|; s|quay.io/tinkerbell|$(ORG)|; }' $$< > $$@
49+
if [[ $(1) == dbg ]]; then
50+
sed -i '/^\s*dbg/ s|#dbg||' $$@
51+
fi
52+
endef
53+
$(foreach m,$(modes),$(foreach a,$(arches),$(eval $(call foreach_mode_arch_rules,$m,$a))))
54+
55+
define foreach_arch_rules =
56+
# arch := $(1)
57+
58+
debug: out/$T/dbg/$(1)/hook.tar
59+
images: out/$T/rel/$(1)/hook.tar
60+
image-dbg-$(1): out/$T/dbg/$(1)/hook.tar
61+
62+
out/$T/rel/hook.tar: out/$T/rel/$(1)/initrd.img out/$T/rel/$(1)/kernel
63+
hook-bootkit: out/$T/hook-bootkit-$(1)
64+
hook-docker: out/$T/hook-docker-$(1)
65+
66+
out/$T/hook-bootkit-$(1): $$(hook-bootkit-deps)
67+
out/$T/hook-docker-$(1): $$(hook-docker-deps)
68+
out/$T/hook-bootkit-$(1) out/$T/hook-docker-$(1): platform=linux/$$(lastword $$(subst -, ,$$(notdir $$@)))
69+
out/$T/hook-bootkit-$(1) out/$T/hook-docker-$(1): container=hook-$$(word 2,$$(subst -, ,$$(notdir $$@)))
70+
out/$T/hook-bootkit-$(1) out/$T/hook-docker-$(1):
71+
docker buildx build --platform $$(platform) --load -t $(ORG)/$$(container):$T-$(1) $$(container)
72+
touch $$@
73+
74+
run-$(1): out/$T/dbg/$(1)/hook.tar
75+
run-$(1):
76+
linuxkit run qemu --mem 2048 $$^
77+
endef
78+
$(foreach a,$(arches),$(eval $(call foreach_arch_rules,$a)))
79+
80+
push-hook-bootkit: $(hook-bootkit-deps)
81+
push-hook-docker: $(hook-docker-deps)
82+
push-hook-bootkit push-hook-docker: platforms=$(addprefix linux/,$(arches))
83+
push-hook-bootkit push-hook-docker: container=hook-$(lastword $(subst -, ,$(basename $@)))
84+
push-hook-bootkit push-hook-docker:
85+
platforms="$(platforms)"
86+
platforms=$${platforms// /,}
87+
docker buildx build --platform $$platforms --push -t $(ORG)/$(container):$T $(container)
88+
89+
.PHONY: dist
90+
dist: out/$T/rel/hook-$T.tar.gz ## Build tarball for distribution
91+
out/$T/rel/hook-$T.tar.gz: out/$T/rel/hook.tar
92+
pigz < $< > $@
93+
94+
out/$T/rel/hook.tar:
95+
rm -rf out/$T/rel/dist
96+
mkdir -p out/$T/rel/dist
97+
for a in $(arches); do
98+
cp out/$T/rel/$$a/initrd.img out/$T/rel/dist/initramfs-$$a
99+
cp out/$T/rel/$$a/kernel out/$T/rel/dist/vmlinuz-$$a
100+
done
101+
cd out/$T/rel/dist && tar -cvf ../$(@F) ./*
102+
103+
deploy: dist ## Push tarball to S3
104+
ifeq ($(shell git rev-parse --abbrev-ref HEAD),main)
105+
s3cmd sync ./out/hook-$T.tar.gz s3://s.gianarb.it/hook/$T.tar.gz
106+
s3cmd cp s3://s.gianarb.it/hook/hook-$T.tar.gz s3://s.gianarb.it/hook/hook-main.tar.gz
107+
endif

0 commit comments

Comments
 (0)