Skip to content

Commit

Permalink
Merge pull request #11164 from afbjorklund/build-rebase
Browse files Browse the repository at this point in the history
Add re-implementation of the build command
  • Loading branch information
medyagh authored Apr 25, 2021
2 parents f854a08 + 4d0c0c6 commit 41bbb4f
Show file tree
Hide file tree
Showing 15 changed files with 731 additions and 26 deletions.
89 changes: 83 additions & 6 deletions cmd/minikube/cmd/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ package cmd
import (
"io"
"io/ioutil"
"net/url"
"os"
"path/filepath"
"runtime"
"strings"

"github.com/spf13/cobra"
Expand All @@ -29,6 +32,7 @@ import (
"k8s.io/minikube/pkg/minikube/image"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/reason"
docker "k8s.io/minikube/third_party/go-dockerclient"
)

// imageCmd represents the image command
Expand All @@ -38,9 +42,14 @@ var imageCmd = &cobra.Command{
}

var (
pull bool
imgDaemon bool
imgRemote bool
pull bool
imgDaemon bool
imgRemote bool
tag string
push bool
dockerFile string
buildEnv []string
buildOpt []string
)

func saveFile(r io.Reader) (string, error) {
Expand Down Expand Up @@ -69,7 +78,7 @@ var loadImageCmd = &cobra.Command{
if len(args) == 0 {
exit.Message(reason.Usage, "Please provide an image in your local daemon to load into minikube via <minikube image load IMAGE_NAME>")
}
// Cache and load images into docker daemon
// Cache and load images into container runtime
profile, err := config.LoadProfile(viper.GetString(config.ProfileName))
if err != nil {
exit.Error(reason.Usage, "loading profile", err)
Expand Down Expand Up @@ -155,6 +164,67 @@ $ minikube image unload image busybox
},
}

func createTar(dir string) (string, error) {
tar, err := docker.CreateTarStream(dir, dockerFile)
if err != nil {
return "", err
}
return saveFile(tar)
}

// buildImageCmd represents the image build command
var buildImageCmd = &cobra.Command{
Use: "build PATH | URL | -",
Short: "Build a container image in minikube",
Long: "Build a container image, using the container runtime.",
Example: `minikube image build .`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) < 1 {
exit.Message(reason.Usage, "Please provide a path or url to build")
}
// Build images into container runtime
profile, err := config.LoadProfile(viper.GetString(config.ProfileName))
if err != nil {
exit.Error(reason.Usage, "loading profile", err)
}

img := args[0]
var tmp string
if img == "-" {
tmp, err = saveFile(os.Stdin)
if err != nil {
exit.Error(reason.GuestImageBuild, "Failed to save stdin", err)
}
img = tmp
} else {
// If it is an URL, pass it as-is
u, err := url.Parse(img)
local := err == nil && u.Scheme == "" && u.Host == ""
if runtime.GOOS == "windows" && filepath.VolumeName(img) != "" {
local = true
}
if local {
// If it's a directory, tar it
info, err := os.Stat(img)
if err == nil && info.IsDir() {
tmp, err := createTar(img)
if err != nil {
exit.Error(reason.GuestImageBuild, "Failed to save dir", err)
}
img = tmp
}
// Otherwise, assume it's a tar
}
}
if err := machine.BuildImage(img, dockerFile, tag, push, buildEnv, buildOpt, []*config.Profile{profile}); err != nil {
exit.Error(reason.GuestImageBuild, "Failed to build image", err)
}
if tmp != "" {
os.Remove(tmp)
}
},
}

var listImageCmd = &cobra.Command{
Use: "list",
Short: "List images",
Expand All @@ -167,17 +237,24 @@ $ minikube image list
if err != nil {
exit.Error(reason.Usage, "loading profile", err)
}

if err := machine.ListImages(profile); err != nil {
exit.Error(reason.GuestImageList, "Failed to list images", err)
}
},
}

func init() {
imageCmd.AddCommand(loadImageCmd)
imageCmd.AddCommand(removeImageCmd)
loadImageCmd.Flags().BoolVarP(&pull, "pull", "", false, "Pull the remote image (no caching)")
loadImageCmd.Flags().BoolVar(&imgDaemon, "daemon", false, "Cache image from docker daemon")
loadImageCmd.Flags().BoolVar(&imgRemote, "remote", false, "Cache image from remote registry")
imageCmd.AddCommand(loadImageCmd)
imageCmd.AddCommand(removeImageCmd)
buildImageCmd.Flags().StringVarP(&tag, "tag", "t", "", "Tag to apply to the new image (optional)")
buildImageCmd.Flags().BoolVarP(&push, "push", "", false, "Push the new image (requires tag)")
buildImageCmd.Flags().StringVarP(&dockerFile, "file", "f", "", "Path to the Dockerfile to use (optional)")
buildImageCmd.Flags().StringArrayVar(&buildEnv, "build-env", nil, "Environment variables to pass to the build. (format: key=value)")
buildImageCmd.Flags().StringArrayVar(&buildOpt, "build-opt", nil, "Specify arbitrary flags to pass to the build. (format: key=value)")
imageCmd.AddCommand(buildImageCmd)
imageCmd.AddCommand(listImageCmd)
}
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ require (
github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 // indirect
github.com/docker/cli v0.0.0-20200303162255-7d407207c304 // indirect
github.com/docker/docker v17.12.0-ce-rc1.0.20200916142827-bd33bbf0497b+incompatible
github.com/docker/docker v17.12.0-ce-rc1.0.20210128214336-420b1d36250f+incompatible
github.com/docker/go-units v0.4.0
github.com/docker/machine v0.16.2
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f
Expand Down Expand Up @@ -102,6 +102,7 @@ require (
replace (
git.apache.org/thrift.git => github.com/apache/thrift v0.0.0-20180902110319-2566ecd5d999
github.com/briandowns/spinner => github.com/alonyb/spinner v1.12.7
github.com/docker/docker => github.com/afbjorklund/moby v0.0.0-20210308214533-2fa72faf0e8b
github.com/docker/machine => github.com/machine-drivers/machine v0.7.1-0.20210306082426-fcb2ad5bcb17
github.com/google/go-containerregistry => github.com/afbjorklund/go-containerregistry v0.4.1-0.20210321165649-761f6f9626b1
github.com/samalba/dockerclient => github.com/sayboras/dockerclient v1.0.0
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ github.com/VividCortex/godaemon v0.0.0-20201030160542-15e3f4925a21 h1:Pgxfz/g+Xy
github.com/VividCortex/godaemon v0.0.0-20201030160542-15e3f4925a21/go.mod h1:Y8CJ3IwPIAkMhv/rRUWIlczaeqd9ty9yrl+nc2AbaL4=
github.com/afbjorklund/go-containerregistry v0.4.1-0.20210321165649-761f6f9626b1 h1:AI8EIk8occ3pruhaTpkaQxQGlC1dHx3J9hAtg7t+FLI=
github.com/afbjorklund/go-containerregistry v0.4.1-0.20210321165649-761f6f9626b1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0=
github.com/afbjorklund/moby v0.0.0-20210308214533-2fa72faf0e8b h1:wmyy8gOOzYzMD6SfMs44yCPoOWAAHcjxCio/zQjOlDU=
github.com/afbjorklund/moby v0.0.0-20210308214533-2fa72faf0e8b/go.mod h1:qXUBi22bjTfxOV8XyOI/W1PklPSinepyWoJ6eYSLwwo=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
Expand Down Expand Up @@ -292,10 +294,8 @@ github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TT
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v17.12.0-ce-rc1.0.20181225093023-5ddb1d410a8b+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v17.12.0-ce-rc1.0.20200916142827-bd33bbf0497b+incompatible h1:SiUATuP//KecDjpOK2tvZJgeScYAklvyjfK8JZlU6fo=
github.com/docker/docker v17.12.0-ce-rc1.0.20200916142827-bd33bbf0497b+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v17.12.0-ce-rc1.0.20210128214336-420b1d36250f+incompatible h1:nhVo1udYfMj0Jsw0lnqrTjjf33aLpdgW9Wve9fHVzhQ=
github.com/docker/docker v17.12.0-ce-rc1.0.20210128214336-420b1d36250f+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
Expand Down
105 changes: 105 additions & 0 deletions pkg/minikube/cruntime/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"net/url"
"os"
"os/exec"
"path"
"strings"
Expand Down Expand Up @@ -277,6 +279,109 @@ func (r *Containerd) RemoveImage(name string) error {
return removeCRIImage(r.Runner, name)
}

func gitClone(cr CommandRunner, src string) (string, error) {
// clone to a temporary directory
rr, err := cr.RunCmd(exec.Command("mktemp", "-d"))
if err != nil {
return "", err
}
tmp := strings.TrimSpace(rr.Stdout.String())
cmd := exec.Command("git", "clone", src, tmp)
if _, err := cr.RunCmd(cmd); err != nil {
return "", err
}
return tmp, nil
}

func downloadRemote(cr CommandRunner, src string) (string, error) {
u, err := url.Parse(src)
if err != nil {
return "", err
}
if u.Scheme == "" && u.Host == "" { // regular file, return
return src, nil
}
if u.Scheme == "git" {
return gitClone(cr, src)
}

// download to a temporary file
rr, err := cr.RunCmd(exec.Command("mktemp"))
if err != nil {
return "", err
}
dst := strings.TrimSpace(rr.Stdout.String())
cmd := exec.Command("curl", "-L", "-o", dst, src)
if _, err := cr.RunCmd(cmd); err != nil {
return "", err
}

// extract to a temporary directory
rr, err = cr.RunCmd(exec.Command("mktemp", "-d"))
if err != nil {
return "", err
}
tmp := strings.TrimSpace(rr.Stdout.String())
cmd = exec.Command("tar", "-C", tmp, "-xf", dst)
if _, err := cr.RunCmd(cmd); err != nil {
return "", err
}

return tmp, nil
}

// BuildImage builds an image into this runtime
func (r *Containerd) BuildImage(src string, file string, tag string, push bool, env []string, opts []string) error {
// download url if not already present
dir, err := downloadRemote(r.Runner, src)
if err != nil {
return err
}
if file != "" {
if dir != src {
file = path.Join(dir, file)
}
// copy to standard path for Dockerfile
df := path.Join(dir, "Dockerfile")
if file != df {
cmd := exec.Command("sudo", "cp", "-f", file, df)
if _, err := r.Runner.RunCmd(cmd); err != nil {
return err
}
}
}
klog.Infof("Building image: %s", dir)
extra := ""
if tag != "" {
// add default tag if missing
if !strings.Contains(tag, ":") {
tag += ":latest"
}
extra = fmt.Sprintf(",name=%s", tag)
if push {
extra += ",push=true"
}
}
args := []string{"buildctl", "build",
"--frontend", "dockerfile.v0",
"--local", fmt.Sprintf("context=%s", dir),
"--local", fmt.Sprintf("dockerfile=%s", dir),
"--output", fmt.Sprintf("type=image%s", extra)}
for _, opt := range opts {
args = append(args, "--"+opt)
}
c := exec.Command("sudo", args...)
e := os.Environ()
e = append(e, env...)
c.Env = e
c.Stdout = os.Stdout
c.Stderr = os.Stderr
if _, err := r.Runner.RunCmd(c); err != nil {
return errors.Wrap(err, "buildctl build.")
}
return nil
}

// CGroupDriver returns cgroup driver ("cgroupfs" or "systemd")
func (r *Containerd) CGroupDriver() (string, error) {
info, err := getCRIInfo(r.Runner)
Expand Down
35 changes: 35 additions & 0 deletions pkg/minikube/cruntime/crio.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"encoding/json"
"fmt"
"net"
"os"
"os/exec"
"path"
"strings"
Expand Down Expand Up @@ -197,6 +198,40 @@ func (r *CRIO) RemoveImage(name string) error {
return removeCRIImage(r.Runner, name)
}

// BuildImage builds an image into this runtime
func (r *CRIO) BuildImage(src string, file string, tag string, push bool, env []string, opts []string) error {
klog.Infof("Building image: %s", src)
args := []string{"podman", "build"}
if file != "" {
args = append(args, "-f", file)
}
if tag != "" {
args = append(args, "-t", tag)
}
args = append(args, src)
for _, opt := range opts {
args = append(args, "--"+opt)
}
c := exec.Command("sudo", args...)
e := os.Environ()
e = append(e, env...)
c.Env = e
c.Stdout = os.Stdout
c.Stderr = os.Stderr
if _, err := r.Runner.RunCmd(c); err != nil {
return errors.Wrap(err, "crio build image")
}
if tag != "" && push {
c := exec.Command("sudo", "podman", "push", tag)
c.Stdout = os.Stdout
c.Stderr = os.Stderr
if _, err := r.Runner.RunCmd(c); err != nil {
return errors.Wrap(err, "crio push image")
}
}
return nil
}

// CGroupDriver returns cgroup driver ("cgroupfs" or "systemd")
func (r *CRIO) CGroupDriver() (string, error) {
c := exec.Command("crio", "config")
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/cruntime/cruntime.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ type Manager interface {
LoadImage(string) error
// Pull an image to the runtime from the container registry
PullImage(string) error
// Build an image idempotently into the runtime on a host
BuildImage(string, string, string, bool, []string, []string) error

// ImageExists takes image name and image sha checks if an it exists
ImageExists(string, string) bool
Expand Down
Loading

0 comments on commit 41bbb4f

Please sign in to comment.