Split dockerfile generation in multiple steps

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
This commit is contained in:
Dimitris Karakasilis
2023-10-05 09:41:27 +03:00
parent 781cffa3d8
commit 0ee6ef666c
4 changed files with 88 additions and 62 deletions

View File

@@ -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"]

View File

@@ -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

View File

@@ -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

View File

@@ -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
}