一般在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 启动流程分析的更多相关文章

  1. u-boot启动流程分析(2)_板级(board)部分

    转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global dat ...

  2. u-boot启动流程分析(1)_平台相关部分

    转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的“board—>machine—>arch—> ...

  3. Cocos2d-x3.3RC0的Android编译Activity启动流程分析

    本文将从引擎源代码Jni分析Cocos2d-x3.3RC0的Android Activity的启动流程,以下是具体分析. 1.引擎源代码Jni.部分Java层和C++层代码分析 watermark/2 ...

  4. Netty 拆包粘包和服务启动流程分析

    Netty 拆包粘包和服务启动流程分析 通过本章学习,笔者希望你能掌握EventLoopGroup的工作流程,ServerBootstrap的启动流程,ChannelPipeline是如何操作管理Ch ...

  5. Uboot启动流程分析(转载)

    最近一段时间一直在做uboot移植相关的工作,需要将uboot-2016-7移植到单位设计的ARMv7的处理器上.正好元旦放假三天闲来无事,有段完整的时间来整理下最近的工作成果.之前在学习uboot时 ...

  6. Storm集群启动流程分析

    Storm集群启动流程分析 程序员 1.客户端运行storm nimbus时,会调用storm的python脚本,该脚本中为每个命令编写了一个方法,每个方法都可以生成一条相应的Java命令. 命令格式 ...

  7. 【转】Netty 拆包粘包和服务启动流程分析

    原文:https://www.cnblogs.com/itdragon/archive/2018/01/29/8365694.html Netty 拆包粘包和服务启动流程分析 通过本章学习,笔者希望你 ...

  8. ubuntu为什么没有/etc/inittab文件? 深究ubuntu的启动流程分析

    Linux 内核启动 init ,init进程ID是1,是所有进程的父进程,所有进程由它控制. Ubuntu 的启动由upstart控制,自9.10后不再使用/etc/event.d目录的配置文件,改 ...

  9. imx6 uboot启动流程分析

    参考http://blog.csdn.net/skyflying2012/article/details/25804209 这里以imx6平台为例,分析uboot启动流程对于任何程序,入口函数是在链接 ...

  10. GEF入门实例_总结_04_Eclipse插件启动流程分析

    一.前言 本文承接上一节:GEF入门实例_总结_03_显示菜单和工具栏 注意到app目录下的6个类文件. 这6个文件对RCP应用程序而言非常重要,可能我们现在对这几个文件的理解还是云里雾里,这一节我们 ...

随机推荐

  1. 当kfreebsd 用户遇见openSUSE系统

    openSuse的系统工具集覆盖了四大主流桌面环境,是针对每一种桌面环境定制的独立的桌面体验.

  2. 树状数组--K.Bro Sorting

    题目网址: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=110064#problem/D Description Matt’s frie ...

  3. 搭建angularjs API文档站点

    提供一个国内可以访问的 angularjs API文档站点 http://i.frllk.com/ 文档直接在 github 上下载的: https://github.com/angular-cn/n ...

  4. 请用fontAwesome代替网页icon小图标

    1. 引言 网页小图标到处可见,如果一个网页都是干巴巴的文字和图片,而没有小图标,会显得非常简陋.下面的小图标,你是不是会经常用到? 你可能说——“我们用的都是彩色的,不是黑白的”——别着急,下面会讲 ...

  5. Win10 FaceAPI小demo开发问题汇总

    Win10 FaceAPI小demo开发问题汇总 最近使用微软牛津计划做一个小demo,使用FaceAPI做一个小应用,实现刷脸的功能.开发的过程中用到几个问题,具体如下: Stream 与IRand ...

  6. Java中的继承与组合(转载)

    本文主要说明Java中继承与组合的概念,以及它们之间的联系与区别.首先文章会给出一小段代码示例,用于展示到底什么是继承.然后演示如何通过“组合”来改进这种继承的设计机制.最后总结这两者的应用场景,即到 ...

  7. Force.com微信开发系列(四)申请Access Token及自定义菜单之创建菜单

    在微信接口开发中,许多服务的使用都离不开Access Token,Access Token相当于打开这些服务的钥匙,正常情况下会在7200秒内失效,重复获取将导致上次获取的Token失效,本文将首先介 ...

  8. Android项目实战(七):Dialog主题Activity实现自定义对话框效果

    想必大家都用过Dialog主题的Activity吧,用它来显示自定义对话框效果绝对是一个非常不错的选择. 即把activity交互界面以Dialog的形式展现出来,Dialog主题的Activity大 ...

  9. UISlider显示进度(并且实现图片缩放)

    图片展示效果如下: 其他没什么好说的,直接上代码: RootView.h: #import <UIKit/UIKit.h> @interface RootView : UIView @pr ...

  10. Spring(八)SSH整合简述

    一.Spring与Struts2的整合 1.1.整合步骤 1.2.配置web.xml 1.3.配置spring配置文件applicationContext.xml 1.4.配置struts配置文件 1 ...