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 (c *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 (r *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 (c *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 (s *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(s *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 (s *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 (l *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 (s *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
}