前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >docker 1.13中docker system prune的浅析

docker 1.13中docker system prune的浅析

作者头像
nevermosby
发布2020-05-11 16:49:19
5.7K1
发布2020-05-11 16:49:19
举报

docker system prune ,一个 should have 的功能

前一篇文章分析了docker system df的实现,这次分析下与它配套的docker system prune命令,之所以说配套,是因为既然已经检查出了可以被clean的unused data,那就需要do the clean stuff。这个功能,对于用docker时间比较久的同学,必定觉得“早就该出了”,他们肯定像我一样,在没有这个官方命令的时候,用

代码语言:javascript
复制
docker rm `docker ps -a | grep -i 'exited' | awk {'print $1'}`

类似这样的shell命令清理过没有运行的docker container。

docker system prune 运行情况

  1. 下图为运行帮助命令,docker system prune -h后的截图:

有两个选项:

  • --all,意思是删除所有unused镜像,而不单单是dangling状态的镜像
  • --f,意思是跳过确认选择,直接删除

  1. 下图为执行docker system prune并确认删除后的截图:

可以看到罗列出4种会被prune的对象以及其他信息,包括:

  1. stopped containers, 不是运行状态的container
  2. unused volumes,不被任何container引用的volume,所谓dangling volume,一般删除了某个container后,可能会产生这样的volume,可以通过docker rm -v避免这种dangling volume
  3. unused network,不被任何container引用的network
  4. dangling images,不被任何container引用的image
  5. 每个被删除的对象都能看到它的ID,比如container ID、volume ID
  6. 最后有个释放空间大小的summary

跟踪container prune功能,解析docker system prune 代码

相对docker system df的实现,由于prune的目的明确,所以它的代码实现逻辑应该也比较简单:利用df实现的相关逻辑找出目标对象,然后删除它们。

查看了相关的代码,感觉整个调用逻辑很有趣,所以梳理了一个脑图出来,帮助将来理解其他功能模块:

大家有兴趣,可以自己去看看代码,我就简单说明下:

  1. docker命令行是用cobra这个golang库,包括k8s在内的很多golang项目都用这个类库。docker system prune的命令行实现参见:https://github.com/docker/docker/blob/master/cli/command/system/prune.go,截取核心方法的源码,简单解读一下:
代码语言:javascript
复制
// docker system prune command handler
func runPrune(dockerCli *command.DockerCli, options pruneOptions) error {
	var message string

	// 这个选项针对image清理
	// 如果有all标识,就清理所有image,而不单单是dangling
	if options.all {
		message = fmt.Sprintf(warning, allImageDesc)
	} else {
		message = fmt.Sprintf(warning, danglingImageDesc)
	}

	if !options.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), message) {
		return nil
	}

	var spaceReclaimed uint64

	/* 
	分析业务逻辑: 
		首先依次处理没有option的3个清理维度
			- container清理
			- volume清理
			- network清理
	*/   
	/* 
	分析代码写法:
		range后面跟的是初始化的数组,类型是func(看起来像是匿名函数),内容是填充dockerCli这个字段
	*/
	for _, pruneFn := range []func(dockerCli *command.DockerCli, filter opts.FilterOpt) (uint64, string, error){
		prune.RunContainerPrune,
		prune.RunVolumePrune,
		prune.RunNetworkPrune,
	} {
		// 循环体内,是依次执行这3个具有不同dockerCli值的函数
		spc, output, err := pruneFn(dockerCli, options.filter)
		if err != nil {
			return err
		}
		spaceReclaimed += spc
		if output != "" {
			fmt.Fprintln(dockerCli.Out(), output)
		}
	}

    // 由于接受的参数不同,image清理函数被独立执行
	spc, output, err := prune.RunImagePrune(dockerCli, options.all, options.filter)
	if err != nil {
		return err
	}
	if spc > 0 {
		spaceReclaimed += spc
		fmt.Fprintln(dockerCli.Out(), output)
	}

	fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))

	return nil
}

2. 通过跟踪container prune这个功能实现,来解读prune的过程,其他维度类似:

代码语言:javascript
复制
// actual function to do the prune operation for docker container
func (daemon *Daemon) ContainersPrune(pruneFilters filters.Args) (*types.ContainersPruneReport, error) {
	rep := &types.ContainersPruneReport{}

	// 这个方法目的是在于截取请求option当中until字段的值,并系列化成对象,后面会用到。
	// 这里对pruneFilters做的特殊处理,是为了docker image/container prune这些命令,因为他们可以有--filter until=这样的选项
        // 详细可参见:https://github.com/docker/docker/commit/58738cdee327f5de481dcf7d3d377374cbb5f13a
	until, err := getUntilFromPruneFilters(pruneFilters)
	if err != nil {
		return nil, err
	}
	/*
	分析业务逻辑:
		- 拿到本机所有container,包含运行和退出的
		- 遍历每个container是不是在运行,
		- 符合条件的container,就进行删除操作,并记录大小用于统计报告
	*/
	allContainers := daemon.List()
	for _, c := range allContainers {
		if !c.IsRunning() {
			// until字段,从字面意思就是说,会把这个字段指定的时间之后创建的container过滤掉,不做处理
			if !until.IsZero() && c.Created.After(until) {
				continue
			}
			// 获取container的大小
			cSize, _ := daemon.getSize(c)
			// TODO: sets RmLink to true?
			err := daemon.ContainerRm(c.ID, &types.ContainerRmConfig{})
			if err != nil {
				logrus.Warnf("failed to prune container %s: %v", c.ID, err)
				continue
			}
			// 把成功删除的container大小加到最终显示的清理值中去
			if cSize > 0 {
				rep.SpaceReclaimed += uint64(cSize)
			}
			rep.ContainersDeleted = append(rep.ContainersDeleted, c.ID)
		}
	}

	return rep, nil
}

总结

  • docker system prune包含了4种维度的清理
  • 解读了container prune的过程,其实image prune也是个有趣的过程,后续加以解读
  • 整理了某些docker command的前后端调用逻辑。很希望有方法可以截取docker client发出的API,看下它的request body,便于了解细节。目前是通过看docker项目里的测试代码来了解。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年2月8日20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • docker system prune ,一个 should have 的功能
  • docker system prune 运行情况
  • 跟踪container prune功能,解析docker system prune 代码
  • 总结
相关产品与服务
容器镜像服务
容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档