diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d0a57031b245adb484280053874b12727acd06e2..aea0ed8b396fb671e80b18da29d10cc5ce7458a8 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,6 +1,8 @@
-Docker:
-  image: jonasled.dev/infra/docker-build:latest
+build:
   stage: build
-  needs: []
+  image:
+    name: gcr.io/kaniko-project/executor:v1.23.2-debug
+    entrypoint: [ "" ]
   script:
-  - build-image.sh
+  - CI_COMMIT_BRANCH=$(echo "$CI_COMMIT_BRANCH" | sed 's/\//-/g')
+  - /kaniko/executor --context "${CI_PROJECT_DIR}" --dockerfile "${CI_PROJECT_DIR}/Dockerfile" --destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_BRANCH}"
diff --git a/Dockerfile b/Dockerfile
index 0870fd3cac0e9bb21afbc4485683a1bea7e6b5b1..2590b4d4eb9a6aa7cecc177d8a9fc88ab42f9ea8 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,9 +1,49 @@
-FROM alpine:3.21
-ENV S6_LOGGING=
+
+ARG ALPINE_VERSION=3.21.2
+FROM mplatform/manifest-tool:v2.1.9 AS manifest-tool
+FROM --platform=$BUILDPLATFORM public.ecr.aws/docker/library/golang:1.23.4-alpine AS kaniko-base
+ARG KANIKO_VERSION=v1.23.2
+RUN apk add --no-cache bash git make && \
+    git clone -b ${KANIKO_VERSION} https://github.com/GoogleContainerTools/kaniko /kanikosrc
+WORKDIR /kanikosrc
+
+FROM kaniko-base AS kaniko-amd64
+ENV GOOS=linux \
+    GOARCH=amd64
+RUN make out/executor && \
+    make out/warmer
+FROM kaniko-base AS kaniko-arm64
+ENV GOOS=linux \
+    GOARCH=arm64
+RUN make out/executor && \
+    make out/warmer
+
+FROM public.ecr.aws/docker/library/alpine:$ALPINE_VERSION AS rootfs
+ARG ALPINE_VERSION=3.21.2
+RUN wget https://dl-cdn.alpinelinux.org/alpine/v3.21/releases/x86_64/alpine-minirootfs-${ALPINE_VERSION}-x86_64.tar.gz -O alpine-amd64.tar.gz && \
+    wget https://dl-cdn.alpinelinux.org/alpine/v3.21/releases/aarch64/alpine-minirootfs-${ALPINE_VERSION}-aarch64.tar.gz -O alpine-arm64.tar.gz && \
+    mkdir -p /build/amd64 /build/arm64 && \
+    tar -xzf alpine-amd64.tar.gz -C /build/amd64 && \
+    tar -xzf alpine-arm64.tar.gz -C /build/arm64 && \
+    mkdir /build/amd64/var/run/proot /build/arm64/var/run/proot
+
+FROM --platform=$BUILDPLATFORM public.ecr.aws/docker/library/golang:1.23.4-alpine AS helper-tool
+COPY helper/ ./
+RUN CGO_ENABLED=0 go build -ldflags "-w -s" -o /build-image
+
+FROM public.ecr.aws/docker/library/alpine:$ALPINE_VERSION
+ENV KANIKO_DIR=/kaniko \
+    PROOT_DONT_POLLUTE_ROOTFS=1 \
+    PROOT_TMP_DIR=/var/run/proot
 RUN sed -i 's|dl-cdn.alpinelinux.org/alpine|alpine.jonasled.de|g' /etc/apk/repositories && \
-    apk add --no-cache docker buildkit buildctl docker-cli-buildx docker-cli-compose \
-    qemu jq git s6-overlay
-COPY /files/ /
+    echo "@testing https://alpine.jonasled.de/edge/testing" >> /etc/apk/repositories && \
+    apk add --no-cache git jq proot@testing qemu qemu-aarch64 && \
+    mkdir /var/run/proot /root/.docker
+
+COPY --from=rootfs /build /build
+COPY --from=kaniko-amd64 /kanikosrc/out /build/amd64/kaniko
+COPY --from=kaniko-arm64 /kanikosrc/out /build/arm64/kaniko
+COPY --from=manifest-tool /manifest-tool /usr/local/bin/manifest-tool
+COPY --from=helper-tool /build-image /usr/local/bin/build-image
 WORKDIR /app
-CMD ["/init"]
-EXPOSE 2375
\ No newline at end of file
+CMD [ "/usr/local/bin/build-image" ]
\ No newline at end of file
diff --git a/Readme.md b/Readme.md
index a0d7b64690a7eaa226dd113ae476638d09413007..6c5d8f907e8671cb96f37c9cbea78ccaff644853 100644
--- a/Readme.md
+++ b/Readme.md
@@ -1,3 +1,3 @@
-# Docker Build Container
+# Docker Build Container using kaniko
 
-This repos contains the base image, used for all build jobs, building a container image.
\ No newline at end of file
+Currently only native arch builds are possible
\ No newline at end of file
diff --git a/files/etc/docker/daemon.json b/files/etc/docker/daemon.json
deleted file mode 100644
index b5da9362b99b0b7fd28473485e79b50c4922b6de..0000000000000000000000000000000000000000
--- a/files/etc/docker/daemon.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "features": {
-      "containerd-snapshotter": true,
-      "buildkit": true
-    },
-    "hosts": [
-      "tcp://0.0.0.0:2375",
-      "unix:///var/run/docker.sock"
-    ],
-    "max-concurrent-downloads": 20,
-    "max-concurrent-uploads": 20
-  }
\ No newline at end of file
diff --git a/files/etc/s6-overlay/s6-rc.d/buildcontext/dependencies.d/docker b/files/etc/s6-overlay/s6-rc.d/buildcontext/dependencies.d/docker
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/files/etc/s6-overlay/s6-rc.d/buildcontext/type b/files/etc/s6-overlay/s6-rc.d/buildcontext/type
deleted file mode 100644
index 3d92b15f2d56c7753feb51fd035d8c490de86bd7..0000000000000000000000000000000000000000
--- a/files/etc/s6-overlay/s6-rc.d/buildcontext/type
+++ /dev/null
@@ -1 +0,0 @@
-oneshot
\ No newline at end of file
diff --git a/files/etc/s6-overlay/s6-rc.d/buildcontext/up b/files/etc/s6-overlay/s6-rc.d/buildcontext/up
deleted file mode 100644
index 825664d95e8e5c36743cdb81261b7bc24882c640..0000000000000000000000000000000000000000
--- a/files/etc/s6-overlay/s6-rc.d/buildcontext/up
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/ash
-while ! docker info >/dev/null 2>&1; do
-    echo "Waiting for Docker to start..."
-    sleep 1
-done
-echo "creating build context"
-docker buildx use default
\ No newline at end of file
diff --git a/files/etc/s6-overlay/s6-rc.d/buildkit/run b/files/etc/s6-overlay/s6-rc.d/buildkit/run
deleted file mode 100644
index 0b6214b0003a8541819a91b9f04a4ab0a8a66377..0000000000000000000000000000000000000000
--- a/files/etc/s6-overlay/s6-rc.d/buildkit/run
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/ash
-buildkitd
\ No newline at end of file
diff --git a/files/etc/s6-overlay/s6-rc.d/buildkit/type b/files/etc/s6-overlay/s6-rc.d/buildkit/type
deleted file mode 100644
index 1780f9f44efd7a9a5240468e2d3d851ae5b7a471..0000000000000000000000000000000000000000
--- a/files/etc/s6-overlay/s6-rc.d/buildkit/type
+++ /dev/null
@@ -1 +0,0 @@
-longrun
\ No newline at end of file
diff --git a/files/etc/s6-overlay/s6-rc.d/docker/run b/files/etc/s6-overlay/s6-rc.d/docker/run
deleted file mode 100644
index 584de9a390f977ec328f67a9e9a909d484439b1c..0000000000000000000000000000000000000000
--- a/files/etc/s6-overlay/s6-rc.d/docker/run
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/ash
-dockerd --tls=false
\ No newline at end of file
diff --git a/files/etc/s6-overlay/s6-rc.d/docker/type b/files/etc/s6-overlay/s6-rc.d/docker/type
deleted file mode 100644
index 1780f9f44efd7a9a5240468e2d3d851ae5b7a471..0000000000000000000000000000000000000000
--- a/files/etc/s6-overlay/s6-rc.d/docker/type
+++ /dev/null
@@ -1 +0,0 @@
-longrun
\ No newline at end of file
diff --git a/files/etc/s6-overlay/s6-rc.d/user/contents.d/buildcontext b/files/etc/s6-overlay/s6-rc.d/user/contents.d/buildcontext
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/files/etc/s6-overlay/s6-rc.d/user/contents.d/docker b/files/etc/s6-overlay/s6-rc.d/user/contents.d/docker
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/files/usr/local/bin/build-image.sh b/files/usr/local/bin/build-image.sh
deleted file mode 100755
index 8e920ffbe4b28ff0c8424bb1625c3c22d651763c..0000000000000000000000000000000000000000
--- a/files/usr/local/bin/build-image.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/ash
-
-if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
-    DEFAULT_IMAGE_TAG="latest"
-else
-    DEFAULT_IMAGE_TAG="$CI_COMMIT_REF_SLUG"
-fi
-create-build-context.sh
-wait-for-docker.sh
-
-IMAGE="${IMAGE_NAME:=$CI_REGISTRY_IMAGE}:${IMAGE_TAG:=$DEFAULT_IMAGE_TAG}"
-docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
-echo "Building docker image $IMAGE for ${ARCHITECTURES:="linux/arm64,linux/amd64"}"
-
-docker buildx build --platform "${ARCHITECTURES:="linux/arm64,linux/amd64"}" --push --provenance false --tag "$IMAGE" .
-export IMAGE_HASH=$(docker buildx imagetools inspect "$IMAGE" --format "{{json .Manifest}}" | jq .digest)
-echo "Image Hash: $IMAGE_HASH"
-echo "$IMAGE_HASH" >> image-hash.txt
diff --git a/files/usr/local/bin/create-build-context.sh b/files/usr/local/bin/create-build-context.sh
deleted file mode 100755
index 5306567669a9eb9995b5233c1e577ab3c43841f3..0000000000000000000000000000000000000000
--- a/files/usr/local/bin/create-build-context.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/ash
-#!/bin/sh
-
-# Host to check
-HOSTNAME="docker"
-
-# Check if the host "docker" can be resolved
-if getent hosts "$HOSTNAME" >/dev/null 2>&1; then
-    docker context create remote-docker --docker "host=tcp://$HOSTNAME:2375"
-    docker context use remote-docker
-    docker buildx use remote-docker
-    echo "Switched to the remote Docker context."
-
-else
-    docker buildx use default
-fi
diff --git a/files/usr/local/bin/detect-default-image-tag.sh b/files/usr/local/bin/detect-default-image-tag.sh
deleted file mode 100755
index 0e1d7bd5d42dc6f7c5a9bb6dffcb94eeb800eed0..0000000000000000000000000000000000000000
--- a/files/usr/local/bin/detect-default-image-tag.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/ash
-if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
-    echo "latest"
-else
-    echo "$CI_COMMIT_REF_SLUG"
-fi
diff --git a/files/usr/local/bin/wait-for-docker.sh b/files/usr/local/bin/wait-for-docker.sh
deleted file mode 100755
index dabb27a8e75dc63b13906102e543481069de35d0..0000000000000000000000000000000000000000
--- a/files/usr/local/bin/wait-for-docker.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-while ! docker info >/dev/null 2>&1; do
-    echo "Waiting for Docker daemon..."
-    sleep 1
-done
-docker buildx use default
\ No newline at end of file
diff --git a/helper/cmd.go b/helper/cmd.go
new file mode 100644
index 0000000000000000000000000000000000000000..a57481e7c4a977fcd2c46446898c631c97e01031
--- /dev/null
+++ b/helper/cmd.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"os"
+	"os/exec"
+)
+
+func executeCmd(command string) {
+	cmd := exec.Command("/bin/sh", "-c", command)
+
+	// Get the command's stdout and stderr pipes
+	stdout, err := cmd.StdoutPipe()
+	if err != nil {
+		fmt.Println("Error:", err)
+		return
+	}
+	stderr, err := cmd.StderrPipe()
+	if err != nil {
+		fmt.Println("Error:", err)
+		return
+	}
+
+	// Start the command in the background
+	err = cmd.Start()
+	if err != nil {
+		fmt.Println("Error starting command:", err)
+		return
+	}
+
+	// Create a scanner to read stdout and stderr
+	go printOutput(stdout)
+	go printOutput(stderr)
+
+	// Wait for the command to finish
+	err = cmd.Wait()
+	if err != nil {
+		fmt.Println("Error waiting for command to finish:", err)
+		os.Exit(1)
+		return
+	}
+
+}
+
+func printOutput(pipe io.Reader) {
+	scanner := bufio.NewScanner(pipe)
+	for scanner.Scan() {
+		fmt.Println(scanner.Text())
+	}
+	if err := scanner.Err(); err != nil {
+		fmt.Println("Error reading output:", err)
+	}
+}
diff --git a/helper/go.mod b/helper/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..4567926bfa758d28fc0f81def8e965b45a7ac222
--- /dev/null
+++ b/helper/go.mod
@@ -0,0 +1,5 @@
+module jonasled.dev/infra/docker-build/helper
+
+go 1.23.4
+
+require gopkg.in/yaml.v2 v2.4.0
diff --git a/helper/go.sum b/helper/go.sum
new file mode 100644
index 0000000000000000000000000000000000000000..dd0bc19f1fe3e536098c0fd769c96042bf9ebc73
--- /dev/null
+++ b/helper/go.sum
@@ -0,0 +1,4 @@
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
diff --git a/helper/helper.go b/helper/helper.go
new file mode 100644
index 0000000000000000000000000000000000000000..53a0c9c154078b740917b4e4493f686e86f8c127
--- /dev/null
+++ b/helper/helper.go
@@ -0,0 +1,67 @@
+package main
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+func getImageTag() string {
+	imageTag := os.Getenv("CI_COMMIT_REF_SLUG")
+	if os.Getenv("CI_COMMIT_BRANCH") == os.Getenv("CI_DEFAULT_BRANCH") {
+		imageTag = "latest"
+	}
+	if os.Getenv("IMAGE_TAG") != "" {
+		imageTag = os.Getenv("IMAGE_TAG")
+	}
+	return imageTag
+}
+
+func getImageName() string {
+	if os.Getenv("IMAGE_NAME") != "" {
+		return os.Getenv("IMAGE_NAME")
+	}
+	return os.Getenv("CI_REGISTRY_IMAGE")
+}
+
+func getDockerfilePath() string {
+	dockerfilePath := "Dockerfile"
+	if os.Getenv("DOCKERFILE_PATH") != "" {
+		dockerfilePath = os.Getenv("DOCKERFILE_PATH")
+	}
+	cwd, _ := os.Getwd()
+	return filepath.Join(cwd, dockerfilePath)
+}
+
+func getArchitectures() []string {
+	if os.Getenv("ARCHITECTURES") != "" {
+		return strings.Split(os.Getenv("ARCHITECTURES"), ",")
+	}
+	return []string{
+		"amd64",
+		"arm64",
+	}
+}
+
+func getSingleArchImageName() string {
+	if os.Getenv("SINGLEARCH_IMAGE_NAME") == "" {
+		return "single-arch"
+	}
+	return os.Getenv("SINGLEARCH_IMAGE_NAME")
+}
+
+func getImageDigest() (string, error) {
+	filePath := "./image.txt"
+	content, err := os.ReadFile(filePath)
+	if err != nil {
+		return "", fmt.Errorf("failed to read file: %w", err)
+	}
+
+	err = os.Remove(filePath)
+	if err != nil {
+		return "", fmt.Errorf("failed to delete file: %w", err)
+	}
+
+	return strings.TrimSpace(string(content)), nil
+}
diff --git a/helper/main.go b/helper/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..a2ddd874e8f3dba2540e5f7c0e6f499c557dcc8c
--- /dev/null
+++ b/helper/main.go
@@ -0,0 +1,88 @@
+package main
+
+import (
+	"fmt"
+	"os"
+
+	"gopkg.in/yaml.v2"
+)
+
+var manifestConfig ManifestToolConfig
+
+func main() {
+	var imageDigest string
+	for _, arch := range getArchitectures() {
+		switch arch {
+		case "amd64":
+			imageDigest = buildAmd64()
+		case "arm64":
+			imageDigest = buildArm64()
+		default:
+			fmt.Println("Unknown architecture: ", arch)
+			continue
+		}
+		manifest := ManifestToolManifest{
+			Image: imageDigest,
+			Platform: ManifestToolPlatform{
+				OS:           "linux",
+				Architecture: arch,
+			},
+		}
+		manifestConfig.Manifests = append(manifestConfig.Manifests, manifest)
+	}
+	buildManifest()
+}
+
+func buildAmd64() string {
+	fmt.Println("Building image for amd64")
+	buildCmd := fmt.Sprintf("proot --bind=\"$(pwd)\" -S /build/amd64 /kaniko/executor --context \"$(pwd)\" --ignore-path=/tmp/ --skip-unused-stages --reproducible --use-new-run --force --dockerfile \"%s\" --destination \"%s/%s:%s-amd64\" --image-name-with-digest-file \"$(pwd)/image.txt\"",
+		getDockerfilePath(),
+		getImageName(),
+		getSingleArchImageName(),
+		getImageTag())
+	fmt.Println("Assembled build command: ", buildCmd)
+	executeCmd(buildCmd)
+	imageDigest, err := getImageDigest()
+	if err != nil {
+		fmt.Println("Failed to get image digest for AMD64 platform")
+		os.Exit(1)
+	}
+	return imageDigest
+}
+
+func buildArm64() string {
+	fmt.Println("Building image for arm64")
+	buildCmd := fmt.Sprintf("proot -q qemu-aarch64 --bind=\"$(pwd)\" -S /build/arm64 /kaniko/executor --context \"$(pwd)\" --ignore-path=/tmp/ --skip-unused-stages --reproducible --use-new-run --force --dockerfile \"%s\" --destination \"%s/%s:%s-arm64\" --image-name-with-digest-file \"$(pwd)/image.txt\"",
+		getDockerfilePath(),
+		getImageName(),
+		getSingleArchImageName(),
+		getImageTag())
+	fmt.Println("Assembled build command: ", buildCmd)
+	executeCmd(buildCmd)
+	imageDigest, err := getImageDigest()
+	if err != nil {
+		fmt.Println("Failed to get image digest for AMD64 platform")
+		os.Exit(1)
+	}
+	return imageDigest
+}
+
+func buildManifest() {
+	executeCmd("mkdir -p ~/.docker")
+	executeCmd("echo \"{\\\"auths\\\":{\\\"${CI_REGISTRY}\\\": {\\\"auth\\\": \\\"$(printf \"%s:%s\" \"${CI_REGISTRY_USER}\" \"${CI_REGISTRY_PASSWORD}\" | base64 | tr -d '\\n')\\\"}}}\" > ~/.docker/config.json")
+
+	fmt.Println("Writing Image manifest config")
+	manifestConfig.Image = getImageName() + ":" + getImageTag()
+	yamlData, err := yaml.Marshal(&manifestConfig)
+	if err != nil {
+		fmt.Println("Failed converting struct to yaml: ", err.Error())
+		os.Exit(1)
+	}
+	err = os.WriteFile("./imagemanifest.yaml", yamlData, 0644)
+	if err != nil {
+		fmt.Println("Failed writing manifest yaml: ", err.Error())
+		os.Exit(1)
+	}
+	fmt.Println("Generating and uploading manifest")
+	executeCmd("manifest-tool push from-spec ./imagemanifest.yaml")
+}
diff --git a/helper/manifestStruct.go b/helper/manifestStruct.go
new file mode 100644
index 0000000000000000000000000000000000000000..68ed7cb858a3ee66f76c550b765150dc39a891d3
--- /dev/null
+++ b/helper/manifestStruct.go
@@ -0,0 +1,17 @@
+package main
+
+type ManifestToolPlatform struct {
+	Architecture string `yaml:"architecture"`
+	OS           string `yaml:"os"`
+}
+
+type ManifestToolManifest struct {
+	Image    string               `yaml:"image"`
+	Platform ManifestToolPlatform `yaml:"platform"`
+}
+
+type ManifestToolConfig struct {
+	Image     string                 `yaml:"image"`
+	Tags      []string               `yaml:"tags"`
+	Manifests []ManifestToolManifest `yaml:"manifests"`
+}