[WIP] Run kaniko

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
This commit is contained in:
Dimitris Karakasilis 2023-09-01 17:01:05 +03:00
parent d74178362f
commit 427ccc341b
3 changed files with 158 additions and 2 deletions

View File

@ -3,6 +3,16 @@ VERSION 0.7
# renovate: datasource=docker depName=golang
ARG --global GO_VERSION=1.20-alpine3.18
build:
FROM golang:$GO_VERSION
WORKDIR /build
COPY . .
ENV CGO_ENABLED=0
RUN go build -ldflags '-extldflags "-static"'
SAVE ARTIFACT enki AS LOCAL build/enki
test:
FROM golang:$GO_VERSION
RUN apk add rsync gcc musl-dev docker jq

View File

@ -0,0 +1,51 @@
package cmd
import (
"fmt"
"github.com/kairos-io/enki/pkg/action"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/spf13/cobra"
)
// NewBuildISOCmd returns a new instance of the build-iso subcommand and appends it to
// the root command.
func NewConvertCmd() *cobra.Command {
c := &cobra.Command{
Use: "convert rootfs",
Short: "Convert a base image to a Kairos image",
Long: "Convert a base image to a Kairos image\n\n" +
"This is best effort. Enki will try to detect the distribution and add\n" +
"the necessary bits to convert it to a Kairos image",
Args: cobra.ExactArgs(1),
PreRunE: func(cmd *cobra.Command, args []string) error {
return CheckRoot() // TODO: Do we need root?
},
RunE: func(cmd *cobra.Command, args []string) error {
// Set this after parsing of the flags, so it fails on parsing and prints usage properly
cmd.SilenceUsage = true
cmd.SilenceErrors = true // Do not propagate errors down the line, we control them
rootfsDir := args[0]
// TODO: Check if this is really an existing dir (not a file)
fmt.Printf("rootfsDir = %+v\n", rootfsDir)
logger := v1.NewLogger()
convertAction := action.NewConverterAction(rootfsDir)
err := convertAction.Run()
if err != nil {
logger.Errorf(err.Error())
return err
}
return nil
},
}
return c
}
func init() {
rootCmd.AddCommand(NewConvertCmd())
}

View File

@ -1,13 +1,108 @@
package action
import (
"fmt"
"os"
"os/exec"
)
// 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
// any distribution will successfully be converted to a Kairos flavor. See
// the Kairos releases for known-to-work flavors.
// The "input" of this action is a directory where the rootfs is extracted.
// [TBD] The output is the same directory updated to be a Kairos image
type ConverterAction struct {
rootFSPath string
}
func NewConverterAction() *ConverterAction {
return &ConverterAction{}
func NewConverterAction(rootfsPath string) *ConverterAction {
return &ConverterAction{
rootFSPath: rootfsPath,
}
}
// https://github.com/GoogleContainerTools/kaniko/issues/1007
// docker run -it -v $PWD:/work:rw --rm gcr.io/kaniko-project/executor:latest --dockerfile /work/Dockerfile --context dir:///work/rootfs --destination whatever --tar-path /work/image.tar --no-push
// Run assumes the `kaniko` executable is in PATH as it shells out to it.
// The best way to do that is to spin up a container with the upstream
// image (gcr.io/kaniko-project/executor:latest) and mount enki in it.
// E.g.
// docker run -it -v "$PWD/enki":/enki --rm --entrypoint "/enki" gcr.io/kaniko-project/executor:latest
func (ca *ConverterAction) Run() (err error) {
dockerfile, err := ca.createDockerfile()
if err != nil {
return
}
defer os.Remove(dockerfile)
err = ca.addDockerIgnore()
if err != nil {
return
}
defer ca.removeDockerIgnore()
out, err := ca.BuildWithKaniko(dockerfile)
if err != nil {
return fmt.Errorf("%w: %s", err, out)
}
fmt.Printf("out = %+v\n", out)
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 scratch as rootfs
COPY . .
FROM rootfs
# TODO: Do more clever things
RUN 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
func (ca *ConverterAction) addDockerIgnore() error {
return nil
}
func (ca *ConverterAction) removeDockerIgnore() error {
return nil
}
func (ca *ConverterAction) BuildWithKaniko(dockerfile string) (string, error) {
fmt.Printf("ca.rootFSPath = %+v\n", ca.rootFSPath)
cmd := exec.Command("executor",
"--dockerfile", dockerfile,
"--context", ca.rootFSPath,
"--destination", "whatever",
"--tar-path", "image.tar", // TODO: Where do we write? Do we want this extracted to the rootFSPath?
"--no-push",
)
d, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("%w: %s", err, string(d))
}
return string(d), err
}