回顾
runc 比较重要的容器启动流程前面已经基本分析完毕了,今天是最后一章主要分析runc的pause/resume;然后顺带Q一下cgroup;
技术点
-
pause/resume 的作用是挂起与恢复进程组。大致原理主要使用cgroup 的
freeze对进程信号拦截处理;在信号处理的开始挂了一个类似于钩子的东西,把挂起进程交给信号处理来做,freeze框架要做的就是设置一些标志位来指示信号处理要冻结它了,然后设置此进程的信号附着位,这样该进程在返回用户空间的时候就乖乖进入到冻结状态了。 -
下面的链接有 freezer 在linux中设置的方法,freezer 分为3个状态:
THAWEDFREEZINGFROZEN
pause 命令
-
runc/libcontainer/container_linux.go
通过cgroup manager 去管理所有类型的cgroup子系统,而且已经支持cgroupV2版本了;通过一点判定机制选用cgroupV1 还是 cgroupV2
func (c *linuxContainer) Pause() error { c.m.Lock() defer c.m.Unlock() status, err := c.currentStatus() if err != nil { return err } switch status { case Running, Created: // 设置进程的cgroup为 Frozen 冻结进程 if err := c.cgroupManager.Freeze(configs.Frozen); err != nil { return err } return c.state.transition(&pausedState{ c: c, }) } return newGenericError(fmt.Errorf("container not running or created: %s", status), ContainerNotRunning) } -
runc/libcontainer/cgroups/fs/freezer.go
写入cgroup文件
func (s *FreezerGroup) Set(path string, cgroup *configs.Cgroup) error { switch cgroup.Resources.Freezer { case configs.Frozen, configs.Thawed: for { // 最终可以看到是通过写文件进行设置freezer的状态 if err := fscommon.WriteFile(path, "freezer.state", string(cgroup.Resources.Freezer)); err != nil { return err } state, err := s.GetState(path) if err != nil { return err } if state == cgroup.Resources.Freezer { break } time.Sleep(1 * time.Millisecond) } case configs.Undefined: return nil default: return fmt.Errorf("Invalid argument '%s' to freezer.state", string(cgroup.Resources.Freezer)) } return nil }
resume 命令
-
/runc/libcontainer/container_linux.go
设置进程的cgroup为 Thawed 解冻进程, 最终也是调用上面的freezer.go写入文件
func (c *linuxContainer) Resume() error { c.m.Lock() defer c.m.Unlock() status, err := c.currentStatus() if err != nil { return err } if status != Paused { return newGenericError(fmt.Errorf("container not paused"), ContainerNotPaused) } // 设置进程的cgroup为 Thawed 解冻进程, 最终也是调用上面 if err := c.cgroupManager.Freeze(configs.Thawed); err != nil { return err } return c.state.transition(&runningState{ c: c, }) }
cgroups 推荐文章
总结
-
runc的源码分析告一段落,这次写的系列算是自己的一个里程碑;回想起努力搞懂每个小的知识点还是感到小有成就的,而且对自己的golang语言也有所提升;
-
后续计划:
- 202101~03 阅读完《Go语言高级编程》
- 202101 分析 containerd源码 完成
- 202102 编写开始 containerd 源码分析文章
-
明年见,人生路短~~,抓紧时间了~~
加油吧~~~少年 !!!
On the road ~~~