一、golang操作docker操作镜像

最近,由于业务上面的需要,需要构建镜像,在查了一些资料之后,将构建镜像、push镜像、pull镜像总结了一下,尤其在构建镜像的时候我们需要注意的点比较多,下面直接放代码

// 1.Docker docker client
type Docker struct {
	*client.Client
}
//  2.init docker client
func NewDockerClient() *Docker {

	cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
	if err != nil {
		return nil
	}
	return &Docker{
		cli,
	}
}
// Images get images from
func (d *Docker) Images(opt types.ImageListOptions) ([]types.ImageSummary, error) {
	return d.ImageList(context.TODO(), opt)
}

//PushImage--> pull image to harbor仓库
func (d *Docker) PushImage(image string) error {
	authConfig := types.AuthConfig{
		Username: setting.HarborSetting.User, //harbor用户名 (这一块我是读的配置文件,需要的可以进行修改)
		Password: setting.HarborSetting.Pwd,  //harbor 密码
	}
	encodedJSON, err := json.Marshal(authConfig)
	if err != nil {
		return err
	}
	authStr := base64.URLEncoding.EncodeToString(encodedJSON)
	out, err := d.ImagePush(context.TODO(), image, types.ImagePushOptions{RegistryAuth: authStr})
	if err != nil {
		return err
	}

	body, err := ioutil.ReadAll(out)
	if err != nil {
		return err
	}
	fmt.Sprintf("Push docker image output: %v", string(body))

	if strings.Contains(string(body), "error") {
		return fmt.Errorf("push image to docker error")
	}


	return nil
}
//PullImage pull image
func (d *Docker) PullImage(name string) error {
	resp, err := d.ImagePull(context.TODO(), name, types.ImagePullOptions{})

	if err != nil {
		return err
	}
	_, err = io.Copy(ioutil.Discard, resp)
	if err != nil {
		return err
	}
	return nil
}

// RemoveImage remove image 这里需要注意的一点就是移除了镜像之后,
//会出现<none>:<none>的标签,这个是因为下载的镜像是分层的,所以删除会导致
func (d *Docker) RemoveImage(name string) error {
	_, err := d.ImageRemove(context.TODO(), name, types.ImageRemoveOptions{})
	return err
}
//RemoveDanglingImages remove dangling images  <none>
func (d *Docker) RemoveDanglingImages() error {
	opt := types.ImageListOptions{
		Filters: filters.NewArgs(filters.Arg("dangling", "true")),
	}

	images, err := d.Images(opt)
	if err != nil {
		return err
	}

	errIDs := []string{}

	for _, image := range images {
		fmt.Printf("image.ID: %v\n", image.ID)
		if err := d.RemoveImage(image.ID); err != nil {
			errIDs = append(errIDs, image.ID[7:19])
		}
	}

	if len(errIDs) > 1 {
		return fmt.Errorf("can not remove ids\n%s", errIDs)
	}

	return nil
}
// SaveImage save image to tar file
func (d *Docker) SaveImage(ids []string, path string) error {
	file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
	if err != nil {
		return err
	}
	defer file.Close()

	out, err := d.ImageSave(context.TODO(), ids)
	if err != nil {
		return err
	}

	if _, err = io.Copy(file, out); err != nil {
		return err
	}

	return nil
}
// LoadImage load image from tar file
func (d *Docker) LoadImage(path string) error {
	file, err := os.Open(path)
	if err != nil {
		return err
	}
	defer file.Close()

	_, err = d.ImageLoad(context.TODO(), file, true)
	return err
}
// ImportImage import image
func (d *Docker) ImportImage(name, tag, path string) error {
	file, err := os.Open(path)
	if err != nil {
		return err
	}
	defer file.Close()

	source := types.ImageImportSource{
		Source:     file,
		SourceName: "-",
	}

	opt := types.ImageImportOptions{
		Tag: tag,
	}

	_, err = d.ImageImport(context.TODO(), source, name, opt)

	return err
}
// SearchImage search images
func (d *Docker) SearchImage(name string) ([]registry.SearchResult, error) {

	return d.ImageSearch(context.TODO(), name, types.ImageSearchOptions{Limit: 100})
}

//Buildimage build image  image 需要构建的镜像名称
func (d *Docker) Buildimage(warName, image string) error {

	// 1.需要构建的war包上传到docker/web/目录下
	err := file.CopyFile(fmt.Sprintf("/tmp/docker/%s", warName), fmt.Sprintf("docker/web/%s", warName))
	if err != nil {
		return err
	}

	var tags []string
	tags = append(tags, image)
	//打一个docker.tar包
	tarit("docker/", ".") //src:要打包文件的源地址 target:要打包文件的目标地址  (使用相对路径-->相对于main.go)
	//打开刚刚打的tar包
	dockerBuildContext, _ := os.Open("docker.tar") //打开打包的文件,
	defer dockerBuildContext.Close()
	options := types.ImageBuildOptions{
		Dockerfile:     "docker/Dockerfile", //不能是绝对路径 是相对于build context来说的,
		SuppressOutput: false,
		Remove:         true,
		ForceRemove:    true,
		PullParent:     true,
		Tags:           tags, //[]string{"192.168.0.1/harbor/cdisample:v1"}
	}
	buildResponse, err := d.ImageBuild(context.Background(), dockerBuildContext, options)
	fmt.Printf("err build: %v\n", err)
	if err != nil {
		fmt.Printf("%s", err.Error())
		return err
	}
	fmt.Printf("********* %s **********", buildResponse.OSType)
	response, err := ioutil.ReadAll(buildResponse.Body)
	if err != nil {
		fmt.Printf("%s", err.Error())
		return err
	}
	fmt.Println(string(response))
	return nil

}

/*
source:打包的的路径
target:放置打包文件的位置
*/
func tarit(source string, target string) error {
	filename := filepath.Base(source)
	fmt.Println(filename)
	target = filepath.Join(target, fmt.Sprintf("%s.tar", filename))
	//target := fmt.Sprintf("%s.tar", filename)
	fmt.Println(target)
	tarfile, err := os.Create(target)
	if err != nil {
		return err
	}
	fmt.Println(tarfile)
	defer tarfile.Close()

	tarball := tar.NewWriter(tarfile)
	// 这里不要忘记关闭,如果不能成功关闭会造成 tar 包不完整
	// 所以这里在关闭的同时进行判断,可以清楚的知道是否成功关闭
	defer func() {
		if err := tarball.Close(); err != nil {
			utils.ErrPrintln(err)
		}
	}()

	info, err := os.Stat(source)
	if err != nil {
		return nil
	}

	var baseDir string
	if info.IsDir() {
		baseDir = filepath.Base(source)
	}

	return filepath.Walk(source,
		func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			header, err := tar.FileInfoHeader(info, info.Name())
			if err != nil {
				return err
			}
			if baseDir != "" {
				header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
			}

			if err := tarball.WriteHeader(header); err != nil {
				return err
			}

			if info.IsDir() {
				return nil
			}

			file, err := os.Open(path)
			if err != nil {
				return err
			}
			defer file.Close()
			_, err = io.Copy(tarball, file)
			return err
		})
}
  • 关于构建镜像这一块需要注意的点
  • 构建镜像需要将我们需要的文件(包括Dockerfile)打成一个tar包,这里建议名字就使用这个默认的名称就行。
  • types.ImageBuildOptions中Dockerfile需要使用想对路径,而且是相对于build context 的路径来说的。使用绝对路径会报错

在我业务中主要是体现在构建镜像的过程中将临时文件中的war包复制我的docker/web目录下和Dockerfile文件进行一个tar打包。如下所示
在这里插入图片描述

Dockerfile中主要就是将war包添加到我们需要的镜像中,然后构建。
在这里插入图片描述
上面说到了如果是绝对路径会报错的问题,我接下来进行一个模拟。我在当前目录有一个Dockerfile文件和一个wa包进行一个构建。
在这里插入图片描述
Dockerfile文件
在这里插入图片描述

开始构建,发现已经报错,看他报错的提示,说明构建的必须是一个目录。
在这里插入图片描述
,这里报错的原因是ADD 文件的时候也不能使用绝对路径,他添加的文件必须也是相对路径,而且相对于docker build的路径才能够构建成功

下面换成相对路径在重新构建一下,这样就可以构建镜像了。
在这里插入图片描述
使用docker images 查看镜像,发现确实这个镜像已经存在。在这里插入图片描述

二 、删除镜像为标签 none:none 的操作

这两种方式都可以进行删除

docker images|grep none|awk '{print $3 }'|xargs docker rmi
docker rmi -f `docker images | grep none | awk '{print $3}'`

当然可以使用命令docker images prune 进行删除
在这里插入图片描述

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐