vlambda博客
学习文章列表

ctr container create 流程源码分析

1. ctr

cmd/ctr/commands/containers目录找到createCommand, 一直跟踪下去,都是在处理参数和调用新的Create函数。

https://github.com/containerd/containerd/blob/v1.6.0/cmd/ctr/commands/containers/containers.go#L85

var createCommand = cli.Command{
    ...
    Action: func(context *cli.Context) error {
        ...
        _, err = run.NewContainer(ctx, client, context)
        ...
    },
}

https://github.com/containerd/containerd/blob/v1.6.0/cmd/ctr/commands/run/run_unix.go#L347

func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli.Context) (containerd.Container, error) {
    ...
    return client.NewContainer(ctx, id, cOpts...)
}

https://github.com/containerd/containerd/blob/v1.6.0/client.go#L289

func (*Client) NewContainer(ctx context.Context, id string, opts ...NewContainerOpts) (Container, error) {
    ...
    r, err := c.ContainerService().Create(ctx, container)
    ...
}

https://github.com/containerd/containerd/blob/v1.6.0/containerstore.go#L110

func (*remoteContainers) Create(ctx context.Context, container containers.Container) (containers.Container, error) {
    created, err := r.client.Create(ctx, &containersapi.CreateContainerRequest{
        Container: containerToProto(&container),
    })
    ...
}

直到调用GRPC,由服务端执行containerd.services.containers.v1.Containers服务的Create方法。

https://github.com/containerd/containerd/blob/v1.6.0/api/services/containers/v1/containers.pb.go#L729

func (*containersClient) Create(ctx context.Context, in *CreateContainerRequest, opts ...grpc.CallOption) (*CreateContainerResponse, error) {
    out := new(CreateContainerResponse)
    err := c.cc.Invoke(ctx, "/containerd.services.containers.v1.Containers/Create", in, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}

2. containerd

搜索containerd.services.containers.v1.Containers关键字,可以找到该服务定义于_Containers_serviceDesc。调用其Create方法时会调用_Containers_Create_Handler

https://github.com/containerd/containerd/blob/v1.6.0/api/services/containers/v1/containers.pb.go#L904

var _Containers_serviceDesc = grpc.ServiceDesc{
    ServiceName: "containerd.services.containers.v1.Containers",
    HandlerType: (*ContainersServer)(nil),
    Methods: []grpc.MethodDesc{
        ...
        {
            MethodName: "Create",
            Handler:    _Containers_Create_Handler,
        },
        ...
    },
    ...
    Metadata: "github.com/containerd/containerd/api/services/containers/v1/containers.proto",
}

该服务由github.com/containerd/containerd/services/containers下的service实现并注册。

https://github.com/containerd/containerd/blob/v1.6.0/services/containers/service.go#L63

func (*service) Register(server *grpc.Server) error {
    api.RegisterContainersServer(server, s)
    return nil
}

https://github.com/containerd/containerd/blob/v1.6.0/api/services/containers/v1/containers.pb.go#L790

func RegisterContainersServer(*grpc.Server, srv ContainersServer) {
    s.RegisterService(&_Containers_serviceDesc, srv)
}

因此,_Containers_Create_Handler中调用的srv,和srv.Create方法,要查看github.com/containerd/containerd/services/containers下的service的实现。

https://github.com/containerd/containerd/blob/v1.6.0/api/services/containers/v1/containers.pb.go#L850

func _Containers_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
    in := new(CreateContainerRequest)
    if err := dec(in); err != nil {
        return nil, err
    }
    if interceptor == nil {
        return srv.(ContainersServer).Create(ctx, in)
    }
    info := &grpc.UnaryServerInfo{
        Server:     srv,
        FullMethod: "/containerd.services.containers.v1.Containers/Create",
    }
    handler := func(ctx context.Context, req interface{}) (interface{}, error) {
        return srv.(ContainersServer).Create(ctx, req.(*CreateContainerRequest))
    }
    return interceptor(ctx, in, info, handler)
}

https://github.com/containerd/containerd/blob/v1.6.0/services/containers/service.go#L99

func (*service) Create(ctx context.Context, req *api.CreateContainerRequest) (*api.CreateContainerResponse, error) {
    return s.local.Create(ctx, req)
}

https://github.com/containerd/containerd/blob/v1.6.0/services/containers/local.go#L116

func (*local) Create(ctx context.Context, req *api.CreateContainerRequest, _ ...grpc.CallOption) (*api.CreateContainerResponse, error) {
    var resp api.CreateContainerResponse

    if err := l.withStoreUpdate(ctx, func(ctx context.Context) error {
        container := containerFromProto(&req.Container)

        created, err := l.Store.Create(ctx, container)
        if err != nil {
            return err
        }

        resp.Container = containerToProto(&created)

        return nil
    }); err != nil {
        return &resp, errdefs.ToGRPC(err)
    }
    ...
    return &resp, nil
}

containerStore.Create将container数据写入到数据库中。

https://github.com/containerd/containerd/blob/v1.6.0/metadata/containers.go#L117

func (*containerStore) Create(ctx context.Context, container containers.Container) (containers.Container, error) {
    ...
    if err := update(ctx, s.db, func(tx *bolt.Tx) error {
        bkt, err := createContainersBucket(tx, namespace)
        if err != nil {
            return err
        }

        cbkt, err := bkt.CreateBucket([]byte(container.ID))
        ...
        if err := writeContainer(cbkt, &container); err != nil {
            return fmt.Errorf("failed to write container %q: %w", container.ID, err)
        }

        return nil
    }); err != nil {
        return containers.Container{}, err
    }

    return container, nil
}