Pull a docker image to local registry using golang

huangapple go评论73阅读模式
英文:

Pull a docker image to local registry using golang

问题

我正在尝试构建一个使用Golang来拉取Docker镜像的自动化工具。

以下是脚本的简化版本:

package dockermgr

import (
	"context"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
)

func getClient() (*client.Client, error) {
	return client.NewClientWithOpts(client.FromEnv)
}

func ImagePull(image models.DockerImage) error {
	// TODO: Is docker daemon running?
	cli, err := getClient()

	if err != nil {
		panic(err)
	}

	defer cli.Close()

	reader, err := cli.ImagePull(
		context.Background(),
		image.GetNameAndTag(),
		types.ImagePullOptions{})

	if err != nil {
		panic(err)
	}

	defer reader.Close()

	return err
}

它似乎成功拉取了镜像,但是当我回到终端并执行docker image list时,我看不到指定的镜像被拉取并保存到本地注册表中。

我想知道它是否调用了自己的Docker守护进程而不是使用本地的守护进程。但是似乎并非如此。如果我尝试暂停本地的Docker守护进程,当我执行这个脚本时,它会重新启动。

那么我漏掉了什么?

英文:

I'm trying to build an automation tool to pull docker images using golang.

Here is the simplified version of the script:

package dockermgr

import (
	"context"


	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
)


func getClient() (*client.Client, error) {

	return client.NewClientWithOpts(client.FromEnv)
}

func ImagePull(image models.DockerImage) error {
	// TODO: Is docker daemon running?
	cli, err := getClient()

	if err != nil {
		panic(err)
	}

	defer cli.Close()

	reader, err := cli.ImagePull(
		context.Background(),
		image.GetNameAndTag(),
		types.ImagePullOptions{})

	if err != nil {
		panic(err)
	}

	defer reader.Close()

	return err

}

It apparently pulls the image, but when I turn back to terminal and execute a docker image list, I can't see the specified image pulled & saved into the local registry.

I wondered if it invokes it's own docker daemon instead of using the local one. But it does not seem to be the case. If I try to pause the local docker daemon, it wakes back up when I execute this.

So what am I missing?

答案1

得分: 2

我最初建议打印PullImage返回的事件,以查看导致问题的错误。后来@SercioSoydanov在评论中提到:
> 如果在读取器被耗尽之前不消耗它,那么在图像拉取操作完成之前,该操作将被中断。

所以我编辑了我的答案,使其更有意义。当返回ImagePull时,并不意味着图像已经被拉取(这不太好,因为至少函数名和文档没有显示出来)。所以问题在于原始实现中程序退出得太快了。一个明显的解决方案是在评论中提到的保持足够的时间来读取所有事件。但由于实现预期的行为与消耗这些事件无关,我添加了另一种更复杂但更有逻辑意义的实现(仅仅是为了作为一个答案)。

该程序会一直等到图像实际被拉取。

func getClient() (*client.Client, error) {
	return client.NewClientWithOpts(client.FromEnv)
}

func main() {
	ImagePull()
}

func ImagePull() error {
	cli, err := getClient()

	if err != nil {
		panic(err)
	}

	defer cli.Close()

	events, err := cli.ImagePull(
		context.Background(),
		"busybox:1.35",
		types.ImagePullOptions{},
	)

	if err != nil {
		panic(err)
	}
	defer events.Close()

	wg := sync.WaitGroup{}
	wg.Add(1)
	go func(wg *sync.WaitGroup) {
		time.Sleep(1 * time.Second)
		list, err := cli.ImageList(context.Background(), types.ImageListOptions{})
		if err != nil {
			panic(err)
		}
		for _, ims := range list {
			for _, tag := range ims.RepoTags {
				if strings.HasPrefix(tag, "busybox:1.35") {
					wg.Done()
				}
			}
		}
	}(&wg)
	wg.Wait()
	return nil
}

英文:

I initially suggested printing the events returned by PullImage to see the error causing the issue. Later @SercioSoydanov mentioned in one of the comments:
> if you don't consume the reader until it's depleted, the Image Pull operation gets interrupted before it can finish

So I edited my answer so it makes more sense. When the ImagePull is returned it doesn't mean the image is pulled (which is not great since at least the function name and the doc doesn't show that). So the issue with the original implementation in the question is that the program exists too soon. One obvious solution is to stick around enough to read all events as mentioned by @SercioSoydanov in comments. But since achieving the expected behaviour has nothing to do with consuming those events I added another implementation which is more complicated but makes more sense logically (just for the sake of being an answer).

The program sticks around till the image is actually pulled.

func getClient() (*client.Client, error) {
	return client.NewClientWithOpts(client.FromEnv)
}

func main() {
	ImagePull()
}

func ImagePull() error {
	cli, err := getClient()

	if err != nil {
		panic(err)
	}

	defer cli.Close()

	events, err := cli.ImagePull(
		context.Background(),
		"busybox:1.35",
		types.ImagePullOptions{},
	)

	if err != nil {
		panic(err)
	}
	defer events.Close()

	wg := sync.WaitGroup{}
	wg.Add(1)
	go func(wg *sync.WaitGroup) {
		time.Sleep(1 * time.Second)
		list, err := cli.ImageList(context.Background(), types.ImageListOptions{})
		if err != nil {
			panic(err)
		}
		for _, ims := range list {
			for _, tag := range ims.RepoTags {
				if strings.HasPrefix(tag, "busybox:1.35") {
					wg.Done()
				}
			}
		}
	}(&wg)
	wg.Wait()
	return nil
}

huangapple
  • 本文由 发表于 2023年2月18日 20:43:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/75493423.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定