docker-containerd 启动流程分析
一般在docker启动时,containerd的启动命令如下所示:
root 2090 0.0 0.1 292780 11008 ? Ssl 10月22 0:12 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --shim docker-containerd-shim
--metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --runtime docker-runc
1、containerd/containerd/main.go
func daemon(context *cli.Context) error
(1)、首先调用:
sv, err := supervisor.New(
context.String("state-dir"),
context.String("runtime"),
context.String("shim"),
context.String("runtime-args"),
context.String("start-timeout"),
context.Int("retain-count"),
)
(2)、for循环10次,调用w := supervisor.NewWorker(sv, wg),再go w.Start()
(3)、调用sv.Start(),启动supervisor
(4)、调用server, err := startServer(listenParts[0], listenParts[1], sv),启动grpc server
supervisor的数据结构定义如下所示:
// Supervisor represents a container supervisor
type Supervisor struct {
// stateDir is the directory on the system to store container runtime state information
stateDir string
// name of the OCI compatible runtime used to execute containers
runtime string
runtimeArgs []string
shim string
containers map[string]*containerInfo
startTasks chan *startTask
// we need a lock around the subscribers map only because addtions and deletions from
// the map via the API so we cannot really control the currency
subscriberLock sync.RWMutex
subscribers map[chan Event]struct{}
machine Machine
tasks chan Task
monitor *Monitor
eventLog []Event
eventLock sync.Mutex
timeout time.Duration
}
2、containerd/supervisor/supervisor.go
// New returns an initialized Process supervisor
func New(stateDir string, runtimeName, shimName string, runtimeArgs []string, timeout time.Duration, retainCount int) (*Supervisor, error)
(1)、调用machine, err := CollectionMachineInformation(),获取当前宿主机的CPU数和RAM总量
(2)、调用monitor, err := NewMonitor(),启动并返回一个监视器
(3)、填充数据结构Supervisor:
s := &Supervisor{
stateDir: stateDir,
containers: make(map[string]*ContainerInfo),
startTasks: startTasks,
machine: machine,
subscriber: make(map[chan Event]struct{}),
tasks: make(chan Task, defaultBufferSize),
monitor: monitor,
runtime: runtimeName,
runtimeArgs: runtimeArgs,
shim: shimName,
timeout: timeout,
}
(4)、调用setupEventLog(s, retainCount)设置event log
(5)、生成两个goroutine,s.exitHandler()和s.oomHandler()
(6)、最后,调用s.restore(),加载之前已经存在的容器
3、containerd/supervisor/supervisor.go
func (s *Supvervisor) restore() error
(1)、遍历目录s.stateDir(其实就是/var/run/docker/libcontainerd/containerd)
(2)、调用id := d.Name()获取容器id,再调用container, err := runtime.Load(s.stateDir, id, s.shim, s.timeout),load的作用就是加载s.stateDir/id/state.json获取容器实例。之后,再遍历s.stateDir/id/下的pid 文件,加载容器中的process。
(3)、调用processes, err := container.Processes(),加载容器中的process,如果process的状态为running,则调用s.monitorProcess(p)对其进行监控,并对其中不在运行的process进行处理。
4、containerd/supervisor/supervisor.go
// Start is a non-blocking call that runs the supervisor for monitoring container processes and executing new containers
// This event loop is the only thing that is allowed to modify state of containers and processes, therefore it is save to do operations
// in the handlers that modify state of the system or state of the Supervisor
func (s *Supervisor) Start() error
该函数所做的工作很简单,就是启动一个goroutine,再for i := range s.tasks,调用s.handlerTask(i)
Task的数据结构如下所示:
// Task executes an action returning an error chan with either nil or the error from excuting the task
type Task interface {
// ErrorCh returns a channel used to report and error from an async task
ErrorCh() chan error
}
5、containerd/supervisor/supervisor.go
func (s *Supervisor) handleTask(i Task)
该函数根据i的类型,调用相应的处理函数进行处理。例如,i.(type)为*StartTask时,则调用s.start(t),若i.(type)为*DeleteTask时,则调用s.delete(t)。
----------------------------------------------------------------------- worker的工作 -------------------------------------------------------------------------
worker的数据结构如下所示:
type Work interface {
Start()
}
type worker struct {
wg *sync.WaitGroup
s *Supervisor
}
4、containerd/supervisor/worker.go
func NewWorker(s *Supervisor, wg *sync.WaitGroup) Worker
这个函数只是简单地填充数据结构,return &worker{s: s, wg: wg}
5、containerd/supervisor/worker.go
// Start runs a loop in charge of starting new containers
func (w *worker) Start()
(1)、遍历w.s.startTasks,调用process, err := t.container.Start(t.checkPointPath, runtime.NewStdio(t.Stdin, t.Stdout, t.Stderr))
(2)、调用w.s.monitor.MonitorOOM(t.Container)和w.s.monitorProcess(process)对container和process进行监控
(3)、当我们从checkpoint restore一个容器的时候,不需要start process。因此,在t.CheckpointPath == ""的时候,调用process.Start()
(4)、调用ContainerStartTimer.UpdateSince(started),started是当前的时间
(5)、最后,调用t.Err <- nil, t.StartResponse <- StartResponse{Container: t.Container},和w.s.notifySubscribers(Event{Timestamp: time.Now, ID: t.container.ID(), Type: StateStart}),进行消息通知
---------------------------------------------------------------------------- monitor 分析 -----------------------------------------------------------------------
Monitor的数据结构如下所示:
// Monitor represents a runtime.Process monitor
type Monitor struct {
m sync.Mutext
receivers map[int]interface{}
exits chan runtime.Process
ooms chan string
epollFd int
}
1、containerd/supervisor/monitor_linux.go
// NewMonitor starts a new process monitor and returns it
(1)、首先获取一个monitor实例,m := &Monitor{receivers: make(map[int]interface{}), exits: make(chan runtime.Process, 1024), oom: make(chan string, 1024)}
(2)、调用fd, err := archutils.EpollCreate1(0),创建一个epoll fd,接着将fd赋值给m.epollFd
(3)、生成一个goroutine,go m.start()
2、containerd/supervisor/monitor_linux.go
func (m *Monitor) start()
(1)、该函数就是对各种syscall.EpollEvent进行处理,每次通过调用n, err := archutils.EpollWait(m.epollFd, events[:], -1),获取n个EpollEvent。
(2)、再通过fd := int(events[i].Fd),r := m.receivers[fd]找到对应的runtimeProcess或者runtime.OOM。
(3)、最后,t := r.(type),再分别对runtime.Process和runtime.OOM进行处理
3、containerd/supervisor/monitor_linux.go
// Monitor adds a process to the list of the one being monitored
func (m *Monitor) Monitor(p runtime.Process) error
(1)、调用fd := p.ExitFD() ---> ExitFD returns the fd of the exit pipe,再根据fd新建一个event := syscall.EpollEvent{Fd: int32(fd), Events: syscall.EPOLLHUP,}
(2)、调用archutils.EpollCtl(m.epollFd, syscall.EPOLL_CTL_ADD, fd, &event)
(3)、最后,调用EpollFdCounter.Inc(1),m.receivers[fd] = p
docker-containerd 启动流程分析的更多相关文章
- u-boot启动流程分析(2)_板级(board)部分
转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global dat ...
- u-boot启动流程分析(1)_平台相关部分
转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的“board—>machine—>arch—> ...
- Cocos2d-x3.3RC0的Android编译Activity启动流程分析
本文将从引擎源代码Jni分析Cocos2d-x3.3RC0的Android Activity的启动流程,以下是具体分析. 1.引擎源代码Jni.部分Java层和C++层代码分析 watermark/2 ...
- Netty 拆包粘包和服务启动流程分析
Netty 拆包粘包和服务启动流程分析 通过本章学习,笔者希望你能掌握EventLoopGroup的工作流程,ServerBootstrap的启动流程,ChannelPipeline是如何操作管理Ch ...
- Uboot启动流程分析(转载)
最近一段时间一直在做uboot移植相关的工作,需要将uboot-2016-7移植到单位设计的ARMv7的处理器上.正好元旦放假三天闲来无事,有段完整的时间来整理下最近的工作成果.之前在学习uboot时 ...
- Storm集群启动流程分析
Storm集群启动流程分析 程序员 1.客户端运行storm nimbus时,会调用storm的python脚本,该脚本中为每个命令编写了一个方法,每个方法都可以生成一条相应的Java命令. 命令格式 ...
- 【转】Netty 拆包粘包和服务启动流程分析
原文:https://www.cnblogs.com/itdragon/archive/2018/01/29/8365694.html Netty 拆包粘包和服务启动流程分析 通过本章学习,笔者希望你 ...
- ubuntu为什么没有/etc/inittab文件? 深究ubuntu的启动流程分析
Linux 内核启动 init ,init进程ID是1,是所有进程的父进程,所有进程由它控制. Ubuntu 的启动由upstart控制,自9.10后不再使用/etc/event.d目录的配置文件,改 ...
- imx6 uboot启动流程分析
参考http://blog.csdn.net/skyflying2012/article/details/25804209 这里以imx6平台为例,分析uboot启动流程对于任何程序,入口函数是在链接 ...
- GEF入门实例_总结_04_Eclipse插件启动流程分析
一.前言 本文承接上一节:GEF入门实例_总结_03_显示菜单和工具栏 注意到app目录下的6个类文件. 这6个文件对RCP应用程序而言非常重要,可能我们现在对这几个文件的理解还是云里雾里,这一节我们 ...
随机推荐
- Maven创建servlet项目演示(三)
上一节用Maven新建了web项目成功后,本文演示在此基础上应用servlet. 从对tomcat服务器进行配置可的过程中可以知道,tomcat作为servlet容器运行,负责处理客户请求,把请求传送 ...
- JavaScript来实现打开链接页面(转载)
在页面中的链接除了常规的方式以外,如果使用javascript,还有很多种方式,下面是一些使用javascript,打开链接的几种方式: 1.使用window的open方法打开链接,这里可是在制定页面 ...
- RAID选项
RAID:Redundant Array Independent Disk(独立磁盘构成的具有冗余能力的阵列) 最常见的为RAID类型为:0,1,5和10:3和6很少见,但在某些环境中仍然有用. RA ...
- winform(无边框窗体与timer)
一.无边框窗体 1.控制按钮如何制作就是放置可以点击的控件,不局限于使用按钮或是什么别的,只要放置的控件可以点击能触发点击事件就可以了 做的好看一点,就是鼠标移入(pictureBox1_MouseE ...
- 【GOF23设计模式】装饰模式
来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_装饰模式.IO流底层架构.装饰和桥接模式的区别 package com.test.decorator; /** * Com ...
- Android启示录——开始Android旅途
为了明年可以开始进行android程序开发,开始从零开始学习android,仅以此代表第一步开始(*^_^*),开始搭建环境…… 1. 软件下载 http://developer.android.co ...
- 为网站添加ico图标
1.将目标图片装换为.ico格式 在线转换工具:http://www.bitbug.net/ 2.将装换后的图标放入项目文件中,一般命名为favicon 3.在项目文件的index页面中引入 < ...
- andriod CheckBox
<?xml version="1.0" encoding="UTF-8"?> <LinearLayout android:orientatio ...
- iOS开发笔记3:XML/JSON数据解析
这篇主要总结在iOS开发中XML/JSON数据解析过程用到的方法.XML数据解析主要使用SAX方式的NSXMLParser以及DOM方式的GDataXML,JSON数据解析主要使用NSJSONSeri ...
- Android 之 2048 的游戏逻辑分析
继续学习了极客学院的实战路径课程,讲到了2048游戏的编写过程,我在这里作个总结分享给大家(结果会附源代码和我改写后的代码): 这里主要包括两个方面:1.2048界面的绘制 2.2048算法逻辑的 ...