From 0ee6ef666c324e1138f3dcc9246c9f2d10d0c7f3 Mon Sep 17 00:00:00 2001 From: Dimitris Karakasilis Date: Thu, 5 Oct 2023 09:41:27 +0300 Subject: [PATCH] Split dockerfile generation in multiple steps Signed-off-by: Dimitris Karakasilis --- Dockerfile | 33 +++++++----------- cmd/dockerfile.go | 4 +-- pkg/action/converter.go | 39 ++------------------- pkg/action/dockerfile.go | 74 +++++++++++++++++++++++++++++++++++++--- 4 files changed, 88 insertions(+), 62 deletions(-) diff --git a/Dockerfile b/Dockerfile index fc535e4..77dc5e7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,26 +1,19 @@ -ARG GO_VERSION=1.20-alpine3.18 -FROM golang:$GO_VERSION AS builder -WORKDIR /build -COPY . . +FROM ubuntu:latest as base +FROM busybox as builder -ENV CGO_ENABLED=0 -RUN go mod download -# Set arg/env after go mod download, otherwise we invalidate the cached layers due to the commit changing easily -ARG ENKI_VERSION -ARG ENKI_COMMIT -ENV ENKI_VERSION=${ENKI_VERSION} -ENV ENKI_COMMIT=${ENKI_COMMIT} -RUN go build \ - -ldflags "-w -s \ - -X github.com/kairos-io/enki/internal/version.version=$ENKI_VERSION \ - -X github.com/kairos-io/enki/internal/version.gitCommit=$ENKI_COMMIT" \ - -o /enki +COPY --from=base . /rootfs -FROM gcr.io/kaniko-project/executor:latest +FROM rootfs +# Additional os specific things -COPY --from=builder /enki /enki +RUN echo "nameserver 8.8.8.8" > /rootfs/etc/resolv.conf +RUN cat /rootfs/etc/resolv.conf -ENTRYPOINT ["/enki"] +FROM scratch as rootfs + +COPY --from=builder /rootfs/ . + +FROM rootfs +# Additional os specific things -CMD ["convert"] diff --git a/cmd/dockerfile.go b/cmd/dockerfile.go index dfee54f..fccb1e5 100644 --- a/cmd/dockerfile.go +++ b/cmd/dockerfile.go @@ -16,9 +16,9 @@ func NewDockerfileCmd() *cobra.Command { Long: "Create a dockerfile that builds a Kairos image from the provided one\n\n" + "The base image can be specified either as a directory where the image has been extracted or as an image uri.\n" + "This is best effort. Enki will try to detect the distribution and add the necessary bits to convert it to a Kairos image", - Args: cobra.ExactArgs(3), PreRunE: func(cmd *cobra.Command, args []string) error { - return CheckRoot() // TODO: Do we need root? + //return CheckRoot() // TODO: Do we need root? + return nil }, RunE: func(cmd *cobra.Command, args []string) error { // Set this after parsing of the flags, so it fails on parsing and prints usage properly diff --git a/pkg/action/converter.go b/pkg/action/converter.go index d162bc5..3583858 100644 --- a/pkg/action/converter.go +++ b/pkg/action/converter.go @@ -55,9 +55,10 @@ func NewConverterAction(rootfsPath, resultPath, imageName string, runner Runner) // E.g. // CGO_ENABLED=0 go build -ldflags '-extldflags "-static"' -o build/enki && docker run -it -e PATH=/kaniko -v /tmp -v /home/dimitris/workspace/kairos/osbuilder/tmp/rootfs/:/context -v "$PWD/build/enki":/enki -v $PWD:/build --rm --entrypoint "/enki" gcr.io/kaniko-project/executor:latest convert /context func (ca *ConverterAction) Run() (err error) { - dockerfile, err := ca.createDockerfile() + da := NewDockerfileAction(ca.rootFSPath, "") + dockerfile, err := da.Run() if err != nil { - return + return err } defer os.Remove(dockerfile) @@ -75,40 +76,6 @@ func (ca *ConverterAction) Run() (err error) { return } -func (ca *ConverterAction) createDockerfile() (string, error) { - f, err := os.CreateTemp("", "") - if err != nil { - return "", err - } - defer f.Close() - - // write data to the temporary file - data := []byte(` -FROM busybox as builder -RUN mkdir /rootfs -COPY . /rootfs/. - -RUN echo "nameserver 8.8.8.8" > /rootfs/etc/resolv.conf -RUN cat /rootfs/etc/resolv.conf - -FROM scratch as rootfs - -COPY --from=builder /rootfs/ . - -FROM rootfs - -# TODO: Do more clever things -RUN apt-get update && apt-get install -y curl -`) - - if _, err := f.Write(data); err != nil { - os.Remove(f.Name()) - return "", err - } - - return f.Name(), nil -} - // https://github.com/GoogleContainerTools/kaniko/issues/1007 // Create a .dockerignore in the rootfs directory to skip these: // https://github.com/GoogleContainerTools/kaniko/pull/1724/files#diff-1e90758e2fb0f26bdbfe7a40aafc4b4796cbf808842703e52e16c1f36b8da7dcR89 diff --git a/pkg/action/dockerfile.go b/pkg/action/dockerfile.go index cbab407..8930a9f 100644 --- a/pkg/action/dockerfile.go +++ b/pkg/action/dockerfile.go @@ -1,6 +1,9 @@ package action -import "errors" +import ( + "errors" + "fmt" +) // ConverterAction is the action that converts a non-kairos image to a Kairos one. // The conversion happens in a best-effort manner. It's not guaranteed that @@ -21,9 +24,72 @@ func NewDockerfileAction(rootfsPath, baseImageURI string) *DockerfileAction { } func (a *DockerfileAction) Run() (dockerfile string, err error) { - if a.rootFSPath != "" && a.baseImageURI != "" { - return "", errors.New("only one of 'rootfs-dir' and 'base-image-uri' should be defined") + if err := a.Validate(); err != nil { + return "", err } - return "", nil + dockerfile = "" + dockerfile += a.baseImageSection() + dockerfile += a.dnsSection() + dockerfile += a.footerSection() + dockerfile += a.osSpecificSection() + + return dockerfile, nil +} + +func (a *DockerfileAction) baseImageSection() string { + result := "" + if a.baseImageURI != "" { + return fmt.Sprintf(` +FROM %s as base +FROM busybox as builder + +COPY --from=base . /rootfs + +FROM rootfs +# Additional os specific things +`, a.baseImageURI) + } + + result = fmt.Sprintf(` +FROM busybox as builder +RUN mkdir /rootfs +COPY %s /rootfs/. + +FROM rootfs +# Additional os specific things +`, a.rootFSPath) + + return result +} + +func (a *DockerfileAction) dnsSection() string { + return ` +RUN echo "nameserver 8.8.8.8" > /rootfs/etc/resolv.conf +RUN cat /rootfs/etc/resolv.conf +` +} + +func (a *DockerfileAction) footerSection() string { + return ` +FROM scratch as rootfs + +COPY --from=builder /rootfs/ . +` +} + +func (a *DockerfileAction) osSpecificSection() string { + return ` +FROM rootfs +# Additional os specific things +` +} + +func (a *DockerfileAction) Validate() error { + if a.rootFSPath != "" && a.baseImageURI != "" || + a.rootFSPath == "" && a.baseImageURI == "" { + return errors.New("exactly one of 'rootfs-dir' and 'base-image-uri' should be defined") + } + + return nil }