Skip to content

Add minikube image commands for pull and tag and push #12326

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions cmd/minikube/cmd/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,24 @@ $ minikube image unload image busybox
},
}

var pullImageCmd = &cobra.Command{
Use: "pull",
Short: "Pull images",
Example: `
$ minikube image pull busybox
`,
Run: func(cmd *cobra.Command, args []string) {
profile, err := config.LoadProfile(viper.GetString(config.ProfileName))
if err != nil {
exit.Error(reason.Usage, "loading profile", err)
}

if err := machine.PullImages(args, profile); err != nil {
exit.Error(reason.GuestImagePull, "Failed to pull images", err)
}
},
}

func createTar(dir string) (string, error) {
tar, err := docker.CreateTarStream(dir, dockerFile)
if err != nil {
Expand Down Expand Up @@ -245,18 +263,61 @@ $ minikube image ls
},
}

var tagImageCmd = &cobra.Command{
Use: "tag",
Short: "Tag images",
Example: `
$ minikube image tag source target
`,
Aliases: []string{"list"},
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
exit.Message(reason.Usage, "Please provide source and target image")
}
profile, err := config.LoadProfile(viper.GetString(config.ProfileName))
if err != nil {
exit.Error(reason.Usage, "loading profile", err)
}

if err := machine.TagImage(profile, args[0], args[1]); err != nil {
exit.Error(reason.GuestImageTag, "Failed to tag images", err)
}
},
}

var pushImageCmd = &cobra.Command{
Use: "push",
Short: "Push images",
Example: `
$ minikube image push busybox
`,
Run: func(cmd *cobra.Command, args []string) {
profile, err := config.LoadProfile(viper.GetString(config.ProfileName))
if err != nil {
exit.Error(reason.Usage, "loading profile", err)
}

if err := machine.PushImages(args, profile); err != nil {
exit.Error(reason.GuestImagePush, "Failed to push images", err)
}
},
}

func init() {
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")
loadImageCmd.Flags().BoolVar(&overwrite, "overwrite", true, "Overwrite image even if same image:tag name exists")
imageCmd.AddCommand(loadImageCmd)
imageCmd.AddCommand(removeImageCmd)
imageCmd.AddCommand(pullImageCmd)
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)
imageCmd.AddCommand(tagImageCmd)
imageCmd.AddCommand(pushImageCmd)
}
19 changes: 19 additions & 0 deletions pkg/minikube/cruntime/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,16 @@ func (r *Containerd) RemoveImage(name string) error {
return removeCRIImage(r.Runner, name)
}

// TagImage tags an image in this runtime
func (r *Containerd) TagImage(source string, target string) error {
klog.Infof("Tagging image %s: %s", source, target)
c := exec.Command("sudo", "ctr", "-n=k8s.io", "images", "tag", source, target)
if _, err := r.Runner.RunCmd(c); err != nil {
return errors.Wrapf(err, "ctr images tag")
}
return nil
}

func gitClone(cr CommandRunner, src string) (string, error) {
// clone to a temporary directory
rr, err := cr.RunCmd(exec.Command("mktemp", "-d"))
Expand Down Expand Up @@ -412,6 +422,15 @@ func (r *Containerd) BuildImage(src string, file string, tag string, push bool,
return nil
}

// PushImage pushes an image
func (r *Containerd) PushImage(name string) error {
klog.Infof("Pushing image %s: %s", name)
c := exec.Command("sudo", "ctr", "-n=k8s.io", "images", "push", name)
if _, err := r.Runner.RunCmd(c); err != nil {
return errors.Wrapf(err, "ctr images push")
}
return nil
}
func (r *Containerd) initBuildkitDaemon() error {
// if daemon is already running, do nothing
cmd := exec.Command("pgrep", "buildkitd")
Expand Down
20 changes: 20 additions & 0 deletions pkg/minikube/cruntime/crio.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,16 @@ func (r *CRIO) RemoveImage(name string) error {
return removeCRIImage(r.Runner, name)
}

// TagImage tags an image in this runtime
func (r *CRIO) TagImage(source string, target string) error {
klog.Infof("Tagging image %s: %s", source, target)
c := exec.Command("sudo", "podman", "tag", source, target)
if _, err := r.Runner.RunCmd(c); err != nil {
return errors.Wrap(err, "crio tag image")
}
return nil
}

// 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)
Expand Down Expand Up @@ -250,6 +260,16 @@ func (r *CRIO) BuildImage(src string, file string, tag string, push bool, env []
return nil
}

// PushImage pushes an image
func (r *CRIO) PushImage(name string) error {
klog.Infof("Pushing image %s", name)
c := exec.Command("sudo", "podman", "push", name)
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
4 changes: 4 additions & 0 deletions pkg/minikube/cruntime/cruntime.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ type Manager interface {
BuildImage(string, string, string, bool, []string, []string) error
// Save an image from the runtime on a host
SaveImage(string, string) error
// Tag an image
TagImage(string, string) error
// Push an image from the runtime to the container registry
PushImage(string) error

// ImageExists takes image name and image sha checks if an it exists
ImageExists(string, string) bool
Expand Down
20 changes: 20 additions & 0 deletions pkg/minikube/cruntime/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,16 @@ func (r *Docker) RemoveImage(name string) error {
return nil
}

// TagImage tags an image in this runtime
func (r *Docker) TagImage(source string, target string) error {
klog.Infof("Tagging image %s: %s", source, target)
c := exec.Command("docker", "tag", source, target)
if _, err := r.Runner.RunCmd(c); err != nil {
return errors.Wrap(err, "tag image docker.")
}
return nil
}

// BuildImage builds an image into this runtime
func (r *Docker) BuildImage(src string, file string, tag string, push bool, env []string, opts []string) error {
klog.Infof("Building image: %s", src)
Expand Down Expand Up @@ -278,6 +288,16 @@ func (r *Docker) BuildImage(src string, file string, tag string, push bool, env
return nil
}

// PushImage pushes an image
func (r *Docker) PushImage(name string) error {
klog.Infof("Pushing image: %s", name)
c := exec.Command("docker", "push", name)
if _, err := r.Runner.RunCmd(c); err != nil {
return errors.Wrap(err, "push image docker.")
}
return nil
}

// CGroupDriver returns cgroup driver ("cgroupfs" or "systemd")
func (r *Docker) CGroupDriver() (string, error) {
// Note: the server daemon has to be running, for this call to return successfully
Expand Down
138 changes: 138 additions & 0 deletions pkg/minikube/machine/cache_images.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,3 +539,141 @@ func ListImages(profile *config.Profile) error {

return nil
}

// TagImage tags image in all nodes in profile
func TagImage(profile *config.Profile, source string, target string) error {
api, err := NewAPIClient()
if err != nil {
return errors.Wrap(err, "error creating api client")
}
defer api.Close()

succeeded := []string{}
failed := []string{}

pName := profile.Name

c, err := config.Load(pName)
if err != nil {
klog.Errorf("Failed to load profile %q: %v", pName, err)
return errors.Wrapf(err, "error loading config for profile :%v", pName)
}

for _, n := range c.Nodes {
m := config.MachineName(*c, n)

status, err := Status(api, m)
if err != nil {
klog.Warningf("error getting status for %s: %v", m, err)
continue
}

if status == state.Running.String() {
h, err := api.Load(m)
if err != nil {
klog.Warningf("Failed to load machine %q: %v", m, err)
continue
}
runner, err := CommandRunner(h)
if err != nil {
return err
}
cruntime, err := cruntime.New(cruntime.Config{Type: c.KubernetesConfig.ContainerRuntime, Runner: runner})
if err != nil {
return errors.Wrap(err, "error creating container runtime")
}
err = cruntime.TagImage(source, target)
if err != nil {
failed = append(failed, m)
klog.Warningf("Failed to tag image for profile %s %v", pName, err.Error())
continue
}
succeeded = append(succeeded, m)
}
}

klog.Infof("succeeded tagging in: %s", strings.Join(succeeded, " "))
klog.Infof("failed tagging in: %s", strings.Join(failed, " "))
return nil
}

// pushImages pushes images from the container run time
func pushImages(cruntime cruntime.Manager, images []string) error {
klog.Infof("PushImages start: %s", images)
start := time.Now()

defer func() {
klog.Infof("PushImages completed in %s", time.Since(start))
}()

var g errgroup.Group

for _, image := range images {
image := image
g.Go(func() error {
return cruntime.PushImage(image)
})
}
if err := g.Wait(); err != nil {
return errors.Wrap(err, "error pushing images")
}
klog.Infoln("Successfully pushed images")
return nil
}

// PushImages push images on all nodes in profile
func PushImages(images []string, profile *config.Profile) error {
api, err := NewAPIClient()
if err != nil {
return errors.Wrap(err, "error creating api client")
}
defer api.Close()

succeeded := []string{}
failed := []string{}

pName := profile.Name

c, err := config.Load(pName)
if err != nil {
klog.Errorf("Failed to load profile %q: %v", pName, err)
return errors.Wrapf(err, "error loading config for profile :%v", pName)
}

for _, n := range c.Nodes {
m := config.MachineName(*c, n)

status, err := Status(api, m)
if err != nil {
klog.Warningf("error getting status for %s: %v", m, err)
continue
}

if status == state.Running.String() {
h, err := api.Load(m)
if err != nil {
klog.Warningf("Failed to load machine %q: %v", m, err)
continue
}
runner, err := CommandRunner(h)
if err != nil {
return err
}
cruntime, err := cruntime.New(cruntime.Config{Type: c.KubernetesConfig.ContainerRuntime, Runner: runner})
if err != nil {
return errors.Wrap(err, "error creating container runtime")
}
err = pushImages(cruntime, images)
if err != nil {
failed = append(failed, m)
klog.Warningf("Failed to push image for profile %s %v", pName, err.Error())
continue
}
succeeded = append(succeeded, m)
}
}

klog.Infof("succeeded pushing in: %s", strings.Join(succeeded, " "))
klog.Infof("failed pushing in: %s", strings.Join(failed, " "))
return nil
}
6 changes: 6 additions & 0 deletions pkg/minikube/reason/reason.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,14 @@ var (
GuestImageLoad = Kind{ID: "GUEST_IMAGE_LOAD", ExitCode: ExGuestError}
// minikube failed to remove an image
GuestImageRemove = Kind{ID: "GUEST_IMAGE_REMOVE", ExitCode: ExGuestError}
// minikube failed to pull an image
GuestImagePull = Kind{ID: "GUEST_IMAGE_PULL", ExitCode: ExGuestError}
// minikube failed to push an image
GuestImagePush = Kind{ID: "GUEST_IMAGE_PUSH", ExitCode: ExGuestError}
// minikube failed to build an image
GuestImageBuild = Kind{ID: "GUEST_IMAGE_BUILD", ExitCode: ExGuestError}
// minikube failed to tag an image
GuestImageTag = Kind{ID: "GUEST_IMAGE_TAG", ExitCode: ExGuestError}
// minikube failed to load host
GuestLoadHost = Kind{ID: "GUEST_LOAD_HOST", ExitCode: ExGuestError}
// minkube failed to create a mount
Expand Down
Loading