当runv需要启动一个容器的时候,首先需要启动containrd,作为该容器的daemon。因此,启动containerd的相关代码也是从runv/start.go开始。最终,启动containerd的命令行参数如下所示:

runv --kernel /var/lib/hyper/kernel --initrd /var/lib/hyper/hyper-initrd.img --default_cpus 1 --default_memory 128 containerd 
--solo-namespaced --containerd-dir /run/runv-namespace-457712864 --state-dir /run/runv --listen /run/runv-namespace-457712864/namespaced.sock

  

1、runv/containerd/containerd.go

Action: func(context *cli.Context)

(1)、对各个flag进行加载,包括driver, kernel, initrd,template,stateDir等等,上面的命令行都描述得很清晰了

(2)、调用hypervisor.HDriver, err = driverloader.Probe(driver)加载hypervisor的驱动,一般为qemu

(3)、调用f = factory.NewFromConfigs(kernel, initrd, nil)获得一个工厂实例

(4)、调用sv, err := supervisor.New(stateDir, containerdDir, f, context.GlobalInt("default_cpus"), context.GlobalInt("default_memory")),获得一个supervisor实例

(5)、如果指定了solo-namespaced参数,则调用go namespaceShare(sv, containerdDir, stateDir)

(6)、创建daemon,调用daemon(sv, context.String("listen"))

(7)、如果指定了solo-namespaced,则进行清除工作,os.RemoveAll(containerdDir)

2、runv/driverloader_linux.go

func Probe(driver string) (hypervisor.HypervisorDriver, error)

该函数针对不同的driver做初始化操作,这里我们只对driver为qemu的情况进行讨论,因此直接调用qd := qemu.InitDriver(),并且return qd。而qemu的InitDriver的操作很简单,仅仅是找到qemu的绝对路径,然后return &QemuDriver{executable: cmd.,}。

3、runv/factory/factory.go

func NewFromConfigs(kernel, initrd string, configs []FactoryConfig) Factory

因为在初始化的过程中configs为nil,因此仅仅只是调用return single.New(direct.New(1000000, 1000000, kernel, initrd))。其中direct.New返回了一个base.Factory,首先构建一个hypervisor.BootConfig的实例,b := hypervisor.BootConfig{CPU: cpu, Memory: mem, HotAddCpuMem: true, Kernel: kernel, Initrd: initrd}, 在包装一下b,return &directFactory{config: b}。而single.New(b base.Factory)仅仅只是返回 Factory{Factory: b}

Supervisor结构如下所示:

type Supervisor struct {

  StateDir    string
  Factory    factory.Factory
  defaultCpus  int
  defaultMemory int   Events    SvEvents   sync.RWMutex   containers  map[string]*Container }

  

4、runv/supervisor/supervisor.go

func New(stateDir, eventLogDir string, f factory.Factory, defaultCpus int , defaultMemory int) (*Supervisor, error)

首先创建stateDir目录和eventLogDir目录,接着填充数据结构Supervisor, sv := &Supervisor{...}。创建sv.Events.subscribers = make(map[chan Event]struct{})。接着go sv.reaper(),最后,return sv, sv.Events.setupEventLog(eventLogDir) // eventLogDir其实就是containerdDir。例如,/run/runv-namespace-457712864

5、runv/containerd/containerd.go

func namaspaceShare(sv *supervisor.Supervisor, namespace, state string)

该函数主要通过从events := sv.Events.Events(time.Time{})接收来的事件来对容器进行计数

(1)、当接收到的事件e的Type为EventContainerStart时,调用os.Symlink(namespace, filepath.Join(state, e.Id, "namespace")),链接两个容器的namespace,最后,containerCount++

(2)、当接收到的事件e的Type为EventExit并且e.Pid为init时,containerCount--,当containerCount为0时,调用syscall.Kill(0, syscall.SIGQUIT)(注:kill的pid为0,表示向进程组所在的所有进程发送信号)。最后,containerd的reaper接收到syscall.SIGQUIT时,退出。

6、runv/containerd/containerd.go

func daemon(sv *supervisor.Supervisor, address)

首先创建一个reaper, s := make(chan os.Signal, 2048),signal.Notify(s, syscall.SIGCHLD, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT)。之后,调用server, err := startServer(address, sv)启动server。最后,处理来自s的信号,若信号为syscall.SIGCHLD只调用osutils.Reap()进行简单的处理,其他信号则直接调用server.Stop()关闭containerd

7、runv/containerd/containerd.go

func startServer(address string, sv *supervisor.Supervisor) (*grpc.Server, error)

该函数主要用于创建grpc server

(1)、l, err := net.Listen(defautlListenType, address)

(2)、types.RegisterAPIServer(s, server.NewServer(sv))

(3)、go func() { s.server(l) }()

-------------------------------------------------------------------------- containerd 对 event的处理---------------------------------------------------------

1、runv/supervisor/supervisor.go

func (sv *Supervisor) reaper()

首先调用events := sv.Events.Events(time.Time{})获得一个channel,用于获取container最新的状态。之后,调用一个for循环,从events中得到事件e,当e.Type 为EventExit时,调用go sv.reap(e.ID, e.PID)

2、runv/supervisor/supervisor.go

func (sv *Supervisor) reap(container, processId string)

根据container和processId,调用go p.reap(),删除c.ownerPod.Processes中和c.Processes对应的processId, 如果c中的Process为0了,则调用go c.reap(),再依次删除c.ownerPod.Containers和sv.Containers中的container。最后,若c.ownerPod.Containers为0了,则调用go c.ownerPod.reap()

3、runv/supervisor/supervisor.go

func (se *SvEvents) setupEventLog(logDir string) error

首先调用se.readEventLog(logDir),将events.log中的内容都读取到se.eventLog中,接着调用events := se.Events(time.Time{})获取events的channel,最后将channel中读取的event写入events.log中并且也添加到se.eventLog中。其实这个函数所做的工作,就是将events.log中原有的log添加到se.eventLog中,并且将新的event添加到se.eventLog和events.log中。

4、runv/supervisor/supervisor.go

// notifySubscribers will send the provided event to the external subscriber of the events channel,就是向se.subscriber中注册的各个channel发送event

func (se *SvEvents) notifySubscribers(e Event)

仅仅只是一个简单的for循环,遍历subscribers:

for sub := range se.subscribers{

  select{

  // do a non-blocking send for the channel (non-blocking是指,如果sub<-e阻塞,就直接default?)

  case sub <- e:

  default:

    glog.Infof("containerd: event not sent to the subscriber")

  }

}

-------------------------------------------------------------------- process, container, pod的reap 操作 --------------------------------------------------------------------------------------

1、runv/supervisor/process.go

func (p *Process) reap()

该函数只是简单的调用p.closeStdin而已

2、runv/supervisor/process.go

func (p *Process) closeStdin() error

当p.stdinCloser不为空时,调用p.stdinCloser.Close(),最后将p.stdinCloser置为nil即可

3、runv/supervisor/container.go

func (c *Container) reap()

首先,containerShareDir := filepath.Join(hypervisor.BaseDir, c.ownerPod.vm.Id, hypervisor.ShareDirTag, c.Id),然后将containerShareDir中的rootfs umount,最后,删除containerShareDir和filepath.Join(c.ownerPod.sv.StateDir, c.Id)

4、runv/supervisor/hyperpod.go

func (hp *HyperPod) reap()

首先调用Response := hp.vm.StopPod(hp.podStatus),接着调用hp.stopNsListener(),最后删除目录filepath.Join(hypervisor.BaseDir, hp.vm.Id)

runv containerd 流程分析的更多相关文章

  1. runv kill 流程分析

    1.runv/kill.go Action: func(context *cli.Context) 该函数做的工作很简单,就是通过grpc客户端,发送一个grpc请求而已,如下: c.Signal(n ...

  2. runv start container 流程分析

    1.runv/start.go func startContainer(context *cli.Context, container, address string, config *spec.Sp ...

  3. 8、Struts2 运行流程分析

    1.流程分析: 请求发送给 StrutsPrepareAndExecuteFilter StrutsPrepareAndExecuteFilter 询问 ActionMapper: 该请求是否是一个 ...

  4. freeswitch呼叫流程分析

    今天翻文档时发现之前整理的关于freeswitch呼叫相关的内容,写成博文分享出来也方便我以后查阅. 整体结构图 FreeswitchCore 模块加载过程 freeswitch主程序初始化时会从mo ...

  5. u-boot 流程分析

    u-boot 介绍: 对于计算机来说 , 从一开始上机通电是无法直接启动操作系统的 , 这中间需要一个引导过程 , 嵌入式Linux系统同样离不开引导程序 ,  这个启动程序就叫启动加载程序(Boot ...

  6. thttpd和cgilua安装与运行流程分析

    安装 参考如下博文安装thttpd软件 http://blog.csdn.net/21aspnet/article/details/7045845 http://blog.csdn.net/drago ...

  7. 【转】Hostapd工作流程分析

    [转]Hostapd工作流程分析 转自:http://blog.chinaunix.net/uid-30081165-id-5290531.html Hostapd是一个运行在用户态的守护进程,可以通 ...

  8. u-boot中nandflash初始化流程分析(转)

    u-boot中nandflash初始化流程分析(转) 原文地址http://zhuairlunjj.blog.163.com/blog/static/80050945201092011249136/ ...

  9. Android7.0 Phone应用源码分析(二) phone来电流程分析

    接上篇博文:Android7.0 Phone应用源码分析(一) phone拨号流程分析 今天我们再来分析下Android7.0 的phone的来电流程 1.1TelephonyFramework 当有 ...

随机推荐

  1. IIS在默认情况并不支持对PUT和DELETE请求的支持

    IIS在默认情况并不支持对PUT和DELETE请求的支持: IIS拒绝PUT和DELETE请求是由默认注册的一个名为:“WebDAVModule”的自定义HttpModule导致的.WebDAV的全称 ...

  2. Ogre2.1 灯光与阴影

    Ogre2.1大量光源渲染 Ogre2.1不是采用现在大部分引擎所用的延迟渲染,而是采用一种前向渲染的改进技术,理论基本来自于Forward+,见如下. http://www.klayge.org/? ...

  3. [翻译]:SQL死锁-阻塞探测

    到了这篇,才是真正动手解决问题的时候,有了死锁之后就要分析死锁的原因,具体就是需要定位到具体的SQL语句上.那么如何发现产生死锁的问题本质呢?下面这篇讲的非常细了,还提到了不少实用的SQL,但对我个人 ...

  4. SharpGL学习笔记(十二) 光源例子:解决光源场景中的常见问题

    笔者学到光源这一节,遇到的问题就比较多了,收集了一些如下所述: (1) 导入的3ds模型,如果没有材质光照效果很奇怪.如下图 (2) 导入的3ds模型,有材质,灯光效果发暗,材质偏色,效果也很奇怪. ...

  5. js argument实参集合与局部变量、参数关系

    形参 形式上传递的参数 function fn1(a,b,c) {//a,b,c就是形参 实参 实际传递的参数 fn1 (1,2,5);//1,2,5就是实参 argument 定义: 实参的集合 用 ...

  6. Oauth笔记

    上周的工作有安全验证这一块,但不懂,只知道有几个关键字Oauth.secret-key .token.签名等.今天就查下资料做笔记. Oauth是什么 不依靠用户账号和密码就能获得访问资源权限 本质: ...

  7. WampServer搭建php环境可能遇到的问题

    WampServer搭建php环境可能遇到的问题 1.安装时报错,缺少 MSVCR100.dll 文件 这是因为wampServer安装时用到的vc库没有更新,要安装更新之后再进行安装,因为之前安装的 ...

  8. ASP.NET中UEditor使用

    ASP.NET中UEditor使用 0.ueditor简介 UEditor是由百度WEB前端研发部开发的所见即所得的开源富文本编辑器,具有轻量.可定制.用户体验优秀等特点.开源基于BSD协议,所有源代 ...

  9. margin:0 auto;不能居中的原因

    原因: 1.没有设置本身元素和父元素的宽度 2.本身元素使用了绝对定位和浮动 2.没声明DOCTYPE

  10. access的逻辑类型

    Alter TABLE [表名] ADD [新增字段] BOOLEAN或者Alter TABLE [表名] ADD [新增字段] YESNO 或者Alter TABLE [表名] ADD [新增字段] ...