美文网首页
runC的checkpoint功能模块源码分析

runC的checkpoint功能模块源码分析

作者: 之江数字孪生与数据智能 | 来源:发表于2020-08-29 18:14 被阅读0次

runC是什么?

RunC 是一个轻量级的工具,它是用来运行容器的,只用来做这一件事,并且这一件事要做好。我们可以认为它就是个命令行小工具,可以不用通过 docker 引擎,直接运行容器。事实上,runC 是标准化的产物,它根据 OCI 标准来创建和运行容器。而 OCI(Open Container Initiative)组织,旨在围绕容器格式和运行时制定一个开放的工业化标准。

概述

本文对runC的checkpoint功能模块源码进行分析,主要包括:

  1. 梳理checkpoint功能模块源码的调用流程;
  2. 梳理checkpoint功能模块源码中用到的struct、method和第三方库;
  3. 梳理checkpoint功能模块源码中涉及的专业知识(需要学习的部分);

checkpoint功能模块源码的调用流程

runC源码入口为:

runc/main.go

func main() {
    app := cli.NewApp()
    app.Name = "runc"
    app.Usage = usage
        ...

        app.Flags = []cli.Flag{
        ...
    }
    app.Commands = []cli.Command{
        checkpointCommand,
        ...
    }
    ...
}

由main()函数可知,checkpointCommand是checkpoint功能模块的入口,进入checkpointCommand定义:

runc/checkpoint.go

var checkpointCommand = cli.Command{
    ...
    Flags: []cli.Flag{
        ...
    },
    Action: func(context *cli.Context) error {
        ...
        container, err := getContainer(context)
        ...
        
        options := criuOptions(context)
        ...
        return container.Checkpoint(options)
    },
}

由checkpointCommand定义可知,checkpointCommand核心内容由Flags和Action组成,Flags中各个flag的作用通过定义可以一目了然,接下来深入分析Action中定义的函数。

Action函数

由checkpointCommand定义可知,Action函数核心内容包括:container, err := getContainer(context) 、options := criuOptions(context)和container.Checkpoint(options)三个函数调用,接下来逐个函数深入分析。

container, err := getContainer(context)

函数getContainer(...)的作用是获取需要checkpoint的容器实例,进入函数getContainer(...)的定义:

runc/utils_linux.go

func getContainer(context *cli.Context) (libcontainer.Container, error) {
    ...
    factory, err := loadFactory(context)
    ...
    return factory.Load(id)
}

由getContainer(...)函数的定义可知,其作用是通过从状态加载指定的容器实例并返回,整个过程是由factory, err := loadFactory(context)和factory.Load(id)联合完成的,接下来对它们的实现进行深入分析。

factory, err := loadFactory(context)

进入loadFactory(context)函数定义:

runc/utils_linux.go

func loadFactory(context *cli.Context) (libcontainer.Factory, error) {
    ...
    return libcontainer.New(abs, cgroupManager, intelRdtManager,
        libcontainer.CriuPath(context.GlobalString("criu")),
        libcontainer.NewuidmapPath(newuidmap),
        libcontainer.NewgidmapPath(newgidmap))
}

由 loadFactory(...)函数的定义可知,该函数的主要作用就是根据指定配置创建一个容器实例并返回,该功能主要由libcontainer.New(...)函数完成,进入其定义:

runc/libcontainer/factory_linux.go

func New(root string, options ...func(*LinuxFactory) error) (Factory, error) {
    ...
    l := &LinuxFactory{
        Root:      root,
        InitPath:  "/proc/self/exe",
        InitArgs:  []string{os.Args[0], "init"},
        Validator: validate.New(),
        CriuPath:  "criu",
    }
    ...
    return l, nil
}

由New(...)函数的定义可知,创建factory实例最终是由struct LinuxFactory{...}(runc/libcontainer/factory_linux.go)来实现的,该struct实现了Factory interface {...}(runc/libcontainer/factory_linux.go)。

factory.Load(id)

进入factory.Load(id)函数定义:

runc/libcontainer/factory_linux.go

func (l *LinuxFactory) Load(id string) (Container, error) {
    ...
    c := &linuxContainer{
        ...
    }
    c.state = &loadedState{c: c}
    ...
    return c, nil
}

由factory.Load(id)函数的定义可知,创建容器实例最终是由linuxContainer struct{...}(runc/libcontainer/container_linux.go)来实现的,该struct实现了Container interface {...}(runc/libcontainer/container_linux.go)。

至此,就分析完了getContainer(context)函数的整个实现流程,接下来分析options := criuOptions(context)。

options := criuOptions(context)

函数criuOptions(context)用来获取checkpoint的配置项实例,进入函数 criuOptions(context)的定义:

runc/restore.go

func criuOptions(context *cli.Context) *libcontainer.CriuOpts {
    imagePath := getCheckpointImagePath(context)
    ...
    }
    return &libcontainer.CriuOpts{
        ImagesDirectory:         imagePath,
        WorkDirectory:           context.String("work-path"),
        ParentImage:             context.String("parent-path"),
        LeaveRunning:            context.Bool("leave-running"),
        TcpEstablished:          context.Bool("tcp-established"),
        ExternalUnixConnections: context.Bool("ext-unix-sk"),
        ShellJob:                context.Bool("shell-job"),
        FileLocks:               context.Bool("file-locks"),
        PreDump:                 context.Bool("pre-dump"),
        AutoDedup:               context.Bool("auto-dedup"),
        LazyPages:               context.Bool("lazy-pages"),
        StatusFd:                context.Int("status-fd"),
    }
}

由criuOptions(context)函数定义可知,该函数就是用来获取checkpoint的各配置项,并最终创建一个CriuOpts实例
返回。

container.Checkpoint(options)

函数container.Checkpoint(options)负责执行容器的checkpoint操作,进入其定义:

runc/libcontainer/container_linux.go

func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
    ...
    if err := os.Mkdir(criuOpts.ImagesDirectory, 0700); err != nil && !os.IsExist(err) {
        return err
    }
    ...
        rpcOpts := criurpc.CriuOpts{
        ...
    }

    c.handleCriuConfigurationFile(&rpcOpts)

    ...
    var t criurpc.CriuReqType
    if criuOpts.PreDump {
        ...
    } else {
        ...
    }

    if criuOpts.LazyPages {
        ...
    }

    req := &criurpc.CriuReq{
        Type: &t,
        Opts: &rpcOpts,
    }

    // no need to dump all this in pre-dump
    if !criuOpts.PreDump {
        
        ...
    }

    err = c.criuSwrk(nil, req, criuOpts, nil)
    ...
    return nil
}

由container.Checkpoint(options)函数的定义可知,容器实例根据配置项将运行的容器checkpoint出来。

至此,就梳理完了runC的checkpoint功能模块源码的调用流程。

checkpoint功能模块源码中用到的struct、method和第三方库

相关文章

网友评论

      本文标题:runC的checkpoint功能模块源码分析

      本文链接:https://www.haomeiwen.com/subject/uyejsktx.html