Skip to content

Commit

Permalink
neonvm-builder: arm images (#1116)
Browse files Browse the repository at this point in the history
Modify neonvm-builder to support building images with both amd64 or
arm64 architectures.
Change busybox loader to use public image busybox:1.35.0-musl instead of
downloading busybox from busybox.net
Parametrize vector url to be architecture specific.
Has no cross-build support, produced image architecture is the same as
host machine architecture.

#1081

---------

Signed-off-by: Misha Sakhnov <[email protected]>
  • Loading branch information
mikhail-sakhnov authored Dec 10, 2024
1 parent 9299d53 commit 5b1fb31
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 22 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/build-test-vm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ env:
IMG_POSTGRES_16_BULLSEYE: "neondatabase/vm-postgres-16-bullseye"
# using image built in the same workflow
IMG_DAEMON: "neondatabase/neonvm-daemon"
TARGET_ARCH: "amd64"

defaults:
run:
Expand Down Expand Up @@ -87,7 +88,7 @@ jobs:

- name: build ${{ needs.tags.outputs.vm-postgres-16-bullseye }}
run: |
./bin/vm-builder -src postgres:16-bullseye -spec tests/e2e/image-spec.yaml -dst ${{ needs.tags.outputs.vm-postgres-16-bullseye }} -daemon-image ${{ needs.tags.outputs.daemon }}
./bin/vm-builder -src postgres:16-bullseye -spec tests/e2e/image-spec.yaml -dst ${{ needs.tags.outputs.vm-postgres-16-bullseye }} -daemon-image ${{ needs.tags.outputs.daemon }} -target-arch linux/${TARGET_ARCH}
- name: docker push ${{ needs.tags.outputs.vm-postgres-16-bullseye }}
run: |
docker push ${{ needs.tags.outputs.vm-postgres-16-bullseye }}
13 changes: 8 additions & 5 deletions .github/workflows/vm-example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ on:
- ".github/workflows/vm-example.yaml"
workflow_dispatch: # adds ability to run this manually

env:
TARGET_ARCH: amd64

jobs:
vm-example:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -37,26 +40,26 @@ jobs:
password: ${{ secrets.NEON_DOCKERHUB_PASSWORD }}

- name: build vm-alpine:3.16
run: bin/vm-builder -src alpine:3.16 -dst neondatabase/vm-alpine:3.16
run: bin/vm-builder -src alpine:3.16 -dst neondatabase/vm-alpine:3.16 -target-arch linux/${TARGET_ARCH}
- name: push vm-alpine:3.16
run: docker push -q neondatabase/vm-alpine:3.16

- name: build vm-ubuntu:22.04
run: bin/vm-builder -src ubuntu:22.04 -dst neondatabase/vm-ubuntu:22.04
run: bin/vm-builder -src ubuntu:22.04 -dst neondatabase/vm-ubuntu:22.04 -target-arch linux/${TARGET_ARCH}
- name: push vm-ubuntu:22.04
run: docker push -q neondatabase/vm-ubuntu:22.04

- name: build vm-debian:11
run: bin/vm-builder -src debian:11 -dst neondatabase/vm-debian:11
run: bin/vm-builder -src debian:11 -dst neondatabase/vm-debian:11 -target-arch linux/${TARGET_ARCH}
- name: push vm-debian:11
run: docker push -q neondatabase/vm-debian:11

- name: build vm-postgres:14-alpine
run: bin/vm-builder -src postgres:14-alpine -dst neondatabase/vm-postgres:14-alpine
run: bin/vm-builder -src postgres:14-alpine -dst neondatabase/vm-postgres:14-alpine -target-arch linux/${TARGET_ARCH}
- name: push vm-postgres:14-alpine
run: docker push -q neondatabase/vm-postgres:14-alpine

- name: build vm-postgres:15-alpine
run: bin/vm-builder -src postgres:15-alpine -dst neondatabase/vm-postgres:15-alpine
run: bin/vm-builder -src postgres:15-alpine -dst neondatabase/vm-postgres:15-alpine -target-arch linux/${TARGET_ARCH}
- name: push vm-postgres:15-alpine
run: docker push -q neondatabase/vm-postgres:15-alpine
21 changes: 16 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ GOOS ?= $(shell go env GOOS)
# The target architecture for linux kernel. Possible values: amd64 or arm64.
# Any other supported by linux kernel architecture could be added by introducing new build step into neonvm/hack/kernel/Dockerfile.kernel-builder
KERNEL_TARGET_ARCH ?= amd64

TARGET_ARCH ?= amd64
# Get the currently used golang base path
GOPATH=$(shell go env GOPATH)
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
Expand Down Expand Up @@ -196,6 +196,7 @@ docker-build-runner: docker-build-go-base ## Build docker image for NeonVM runne
docker-build-daemon: docker-build-go-base ## Build docker image for NeonVM daemon.
docker build \
--tag $(IMG_DAEMON) \
--build-arg TARGET_ARCH=$(TARGET_ARCH) \
--file neonvm-daemon/Dockerfile \
.

Expand Down Expand Up @@ -228,11 +229,11 @@ docker-build-scheduler: docker-build-go-base ## Build docker image for (autoscal

.PHONY: docker-build-examples
docker-build-examples: bin/vm-builder ## Build docker images for testing VMs
./bin/vm-builder -src postgres:15-bullseye -dst $(E2E_TESTS_VM_IMG) -spec tests/e2e/image-spec.yaml
./bin/vm-builder -src postgres:15-bullseye -dst $(E2E_TESTS_VM_IMG) -spec tests/e2e/image-spec.yaml -target-arch linux/$(TARGET_ARCH)

.PHONY: docker-build-pg16-disk-test
docker-build-pg16-disk-test: bin/vm-builder ## Build a VM image for testing
./bin/vm-builder -src alpine:3.19 -dst $(PG16_DISK_TEST_IMG) -spec vm-examples/pg16-disk-test/image-spec.yaml
./bin/vm-builder -src alpine:3.19 -dst $(PG16_DISK_TEST_IMG) -spec vm-examples/pg16-disk-test/image-spec.yaml -target-arch linux/$(TARGET_ARCH)

#.PHONY: docker-push
#docker-push: ## Push docker image with the controller.
Expand Down Expand Up @@ -394,6 +395,10 @@ load-example-vms: check-local-context kubectl kind k3d ## Load the testing VM im
.PHONY: example-vms
example-vms: docker-build-examples load-example-vms ## Build and push the testing VM images to the kind/k3d cluster.

.PHONY: example-vms-arm64
example-vms-arm64: TARGET_ARCH=arm64
example-vms-arm64: example-vms

.PHONY: load-pg16-disk-test
load-pg16-disk-test: check-local-context kubectl kind k3d ## Load the pg16-disk-test VM image to the kind/k3d cluster.
@if [ $$($(KUBECTL) config current-context) = k3d-$(CLUSTER_NAME) ]; then $(K3D) image import $(PG16_DISK_TEST_IMG) --cluster $(CLUSTER_NAME) --mode direct; fi
Expand Down Expand Up @@ -493,7 +498,13 @@ CODE_GENERATOR_VERSION ?= v0.28.12
KUTTL ?= $(LOCALBIN)/kuttl
# k8s deps @ 1.28.3
KUTTL_VERSION ?= v0.16.0

ifeq ($(GOARCH), arm64)
KUTTL_ARCH = arm64
else ifeq ($(GOARCH), amd64)
KUTTL_ARCH = x86_64
else
$(error Unsupported architecture: $(GOARCH))
endif
KUBECTL ?= $(LOCALBIN)/kubectl
KUBECTL_VERSION ?= v1.29.10

Expand Down Expand Up @@ -535,7 +546,7 @@ $(KUBECTL): $(LOCALBIN)
.PHONY: kuttl
kuttl: $(KUTTL) ## Download kuttl locally if necessary.
$(KUTTL): $(LOCALBIN)
@test -s $(LOCALBIN)/kuttl || { curl -sfSLo $(KUTTL) https://github.com/kudobuilder/kuttl/releases/download/$(KUTTL_VERSION)/kubectl-kuttl_$(subst v,,$(KUTTL_VERSION))_$(GOOS)_$(shell uname -m) && chmod +x $(KUTTL); }
test -s $(LOCALBIN)/kuttl || { curl -sfSLo $(KUTTL) https://github.com/kudobuilder/kuttl/releases/download/$(KUTTL_VERSION)/kubectl-kuttl_$(subst v,,$(KUTTL_VERSION))_$(GOOS)_$(KUTTL_ARCH) && chmod +x $(KUTTL); }

.PHONY: k3d
k3d: $(K3D) ## Download k3d locally if necessary.
Expand Down
19 changes: 12 additions & 7 deletions vm-builder/files/Dockerfile.img
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ USER root

FROM {{.NeonvmDaemonImage}} AS neonvm-daemon-loader

FROM busybox:1.35.0-musl AS busybox-loader

FROM alpine:3.19 AS vm-runtime
ARG TARGET_ARCH
RUN set -e && mkdir -p /neonvm/bin /neonvm/runtime /neonvm/config
# add busybox
ENV BUSYBOX_VERSION 1.35.0
COPY --from=busybox-loader /bin/busybox /neonvm/bin/busybox

RUN set -e \
&& mkdir -p /neonvm/bin /neonvm/runtime /neonvm/config \
&& wget -q https://busybox.net/downloads/binaries/${BUSYBOX_VERSION}-x86_64-linux-musl/busybox -O /neonvm/bin/busybox \
&& chmod +x /neonvm/bin/busybox \
&& /neonvm/bin/busybox --install -s /neonvm/bin
chmod +x /neonvm/bin/busybox \
&& /neonvm/bin/busybox --install -s /neonvm/bin

COPY helper.move-bins.sh /helper.move-bins.sh

Expand Down Expand Up @@ -49,8 +52,10 @@ RUN set -e \

# Install vector.dev binary
RUN set -e \
&& wget https://packages.timber.io/vector/0.26.0/vector-0.26.0-x86_64-unknown-linux-musl.tar.gz -O - \
| tar xzvf - --strip-components 3 -C /neonvm/bin/ ./vector-x86_64-unknown-linux-musl/bin/vector
&& ARCH=$( [ "$TARGET_ARCH" = "linux/arm64" ] && echo "aarch64" || echo "x86_64") \
&& wget https://packages.timber.io/vector/0.26.0/vector-${ARCH}-unknown-linux-musl.tar.gz -O - \
| tar xzvf - --strip-components 3 -C /neonvm/bin/ ./vector-${ARCH}-unknown-linux-musl/bin/vector


# chrony
RUN set -e \
Expand Down
2 changes: 1 addition & 1 deletion vm-builder/files/inittab
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
{{ range .InittabCommands }}
::{{.SysvInitAction}}:su -p {{.CommandUser}} -c {{.ShellEscapedCommand}}
{{ end }}
ttyS0::respawn:/neonvm/bin/agetty --8bits --local-line --noissue --noclear --noreset --host console --login-program /neonvm/bin/login --login-pause --autologin root 115200 ttyS0 linux
{{ .AgettyTTY }}::respawn:/neonvm/bin/agetty --8bits --local-line --noissue --noclear --noreset --host console --login-program /neonvm/bin/login --login-pause --autologin root 115200 {{ .AgettyTTY }} linux
::shutdown:/neonvm/bin/vmshutdown
38 changes: 35 additions & 3 deletions vm-builder/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ var (
configSshd string
)

const (
targetArchLinuxAmd64 = "linux/amd64"
targetArchLinuxArm64 = "linux/arm64"
)

var (
Version string
NeonvmDaemonImage string
Expand All @@ -72,6 +77,7 @@ var (
version = flag.Bool("version", false, `Print vm-builder version`)

daemonImageFlag = flag.String("daemon-image", "", `Specify the neonvm-daemon image: --daemon-image=neonvm-daemon:dev`)
targetArch = flag.String("target-arch", "", fmt.Sprintf("Target architecture: --arch %s | %s", targetArchLinuxAmd64, targetArchLinuxArm64))
)

func AddTemplatedFileToTar(tw *tar.Writer, tmplArgs any, filename string, tmplString string) error {
Expand All @@ -84,7 +90,6 @@ func AddTemplatedFileToTar(tw *tar.Writer, tmplArgs any, filename string, tmplSt
if err = tmpl.Execute(&buf, tmplArgs); err != nil {
return fmt.Errorf("failed to execute template for %q: %w", filename, err)
}

return addFileToTar(tw, filename, buf.Bytes())
}

Expand Down Expand Up @@ -117,6 +122,7 @@ type TemplatesContext struct {
SpecBuild string
SpecMerge string
InittabCommands []inittabCommand
AgettyTTY string
ShutdownHook string
}

Expand All @@ -129,18 +135,28 @@ type inittabCommand struct {
func main() {
flag.Parse()
var dstIm string

if *version {
fmt.Println(Version)
os.Exit(0)
}

if len(*daemonImageFlag) == 0 && len(NeonvmDaemonImage) == 0 {
log.Println("neonvm-daemon image not set, needs to be explicitly passed in, or compiled with -ldflags '-X main.NeonvmDaemonImage=...'")
flag.PrintDefaults()
os.Exit(1)
}

if targetArch == nil || *targetArch == "" {
log.Println("Target architecture not set, see usage info:")
flag.PrintDefaults()
os.Exit(1)
}

if *targetArch != targetArchLinuxAmd64 && *targetArch != targetArchLinuxArm64 {
log.Fatalf("Unsupported target architecture: %q", *targetArch)
flag.PrintDefaults()
return
}

neonvmDaemonImage := NeonvmDaemonImage
if len(*daemonImageFlag) != 0 {
neonvmDaemonImage = *daemonImageFlag
Expand Down Expand Up @@ -292,6 +308,7 @@ func main() {
SpecMerge: "", // overridden below if spec != nil
InittabCommands: nil, // overridden below if spec != nil
ShutdownHook: "", // overridden below if spec != nil
AgettyTTY: getAgettyTTY(*targetArch),
}

if len(imageSpec.Config.User) != 0 {
Expand Down Expand Up @@ -366,6 +383,7 @@ func main() {

buildArgs := make(map[string]*string)
buildArgs["DISK_SIZE"] = size
buildArgs["TARGET_ARCH"] = targetArch
opt := types.ImageBuildOptions{
AuthConfigs: authConfigs,
Tags: []string{dstIm},
Expand All @@ -376,6 +394,7 @@ func main() {
Dockerfile: "Dockerfile",
Remove: true,
ForceRemove: true,
Platform: *targetArch,
}
buildResp, err := cli.ImageBuild(ctx, tarBuffer, opt)
if err != nil {
Expand Down Expand Up @@ -541,3 +560,16 @@ func (f file) validate() []error {

return errs
}

// getAgettyTTY returns the tty device name for agetty based on the target architecture.
func getAgettyTTY(targetArch string) string {
switch targetArch {
case targetArchLinuxAmd64:
return "ttyS0"
case targetArchLinuxArm64:
return "ttyAMA0"
default:
log.Fatalf("Unsupported target architecture: %q", targetArch)
return ""
}
}

0 comments on commit 5b1fb31

Please sign in to comment.