runC的checkpoint功能模块源码分析

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和第三方库

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352