经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Go语言 » 查看文章
containerd 源码分析:创建 container(三)
来源:cnblogs  作者:lubanseven  时间:2024/6/5 9:24:24  对本文有异议

文接 containerd 源码分析:创建 container(二)

1.2.2.2 启动 task

上节介绍了创建 task,task 创建之后将返回 response 给 ctr。接着,ctr 调用 task.Start 启动容器。

  1. // containerd/client/task.go
  2. func (t *task) Start(ctx context.Context) error {
  3. r, err := t.client.TaskService().Start(ctx, &tasks.StartRequest{
  4. ContainerID: t.id,
  5. })
  6. if err != nil {
  7. ...
  8. }
  9. t.pid = r.Pid
  10. return nil
  11. }
  12. // containerd/api/services/tasks/v1/tasks_grpc.pb.go
  13. func (c *tasksClient) Start(ctx context.Context, in *StartRequest, opts ...grpc.CallOption) (*StartResponse, error) {
  14. out := new(StartResponse)
  15. err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Start", in, out, opts...)
  16. if err != nil {
  17. return nil, err
  18. }
  19. return out, nil
  20. }

ctr 调用 contaienrd/containerd.services.tasks.v1.Tasks/Start 接口创建 task。进入 containerd 查看提供该服务的插件:

  1. // containerd/plugins/services/tasks/service.go
  2. func (s *service) Start(ctx context.Context, r *api.StartRequest) (*api.StartResponse, error) {
  3. return s.local.Start(ctx, r)
  4. }
  5. // containerd/plugins/services/tasks/local.go
  6. func (l *local) Start(ctx context.Context, r *api.StartRequest, _ ...grpc.CallOption) (*api.StartResponse, error) {
  7. t, err := l.getTask(ctx, r.ContainerID)
  8. if err != nil {
  9. return nil, err
  10. }
  11. p := runtime.Process(t)
  12. if r.ExecID != "" {
  13. if p, err = t.Process(ctx, r.ExecID); err != nil {
  14. return nil, errdefs.ToGRPC(err)
  15. }
  16. }
  17. // 启动 task: shimTask.Start
  18. if err := p.Start(ctx); err != nil {
  19. return nil, errdefs.ToGRPC(err)
  20. }
  21. state, err := p.State(ctx)
  22. if err != nil {
  23. return nil, errdefs.ToGRPC(err)
  24. }
  25. return &api.StartResponse{
  26. Pid: state.Pid,
  27. }, nil
  28. }
  29. // containerd/core/runtime/v2/shim.go
  30. func (s *shimTask) Start(ctx context.Context) error {
  31. _, err := s.task.Start(ctx, &task.StartRequest{
  32. ID: s.ID(),
  33. })
  34. if err != nil {
  35. return errdefs.FromGRPC(err)
  36. }
  37. return nil
  38. }
  39. // containerd/api/runtime/task/v2/shim_ttrpc.pb.go
  40. func (c *taskClient) Start(ctx context.Context, req *StartRequest) (*StartResponse, error) {
  41. var resp StartResponse
  42. if err := c.client.Call(ctx, "containerd.task.v2.Task", "Start", req, &resp); err != nil {
  43. return nil, err
  44. }
  45. return &resp, nil
  46. }

经过 containerd 各个插件的层层调用,最终走到 containerd.task.v2.Task.Start ttrpc 服务。提供 containerd.task.v2.Task.Start 服务的是 containerd-shim-runc-v2

  1. // containerd/cmd/containerd-shim-runc-v2/task/service.go
  2. // Start a process
  3. func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.StartResponse, error) {
  4. // 根据 task 的 StartRequest 获得 container 的 metadata
  5. container, err := s.getContainer(r.ID)
  6. if err != nil {
  7. return nil, err
  8. }
  9. ...
  10. p, err := container.Start(ctx, r)
  11. if err != nil {
  12. handleStarted(container, p)
  13. return nil, errdefs.ToGRPC(err)
  14. }
  15. ...
  16. }

调用 Container.Start 启动容器进程:

  1. // containerd/cmd/containerd-shim-runc-v2/runc/container.go
  2. // Start a container process
  3. func (c *Container) Start(ctx context.Context, r *task.StartRequest) (process.Process, error) {
  4. p, err := c.Process(r.ExecID)
  5. if err != nil {
  6. return nil, err
  7. }
  8. if err := p.Start(ctx); err != nil {
  9. return p, err
  10. }
  11. ...
  12. }

Container.Start 调用 Process.Start 启动容器进程。启动容器后 runc init 将退出,将容器的主进程交由 runc init 的父进程 shim:

  1. # ps -ef | grep 138915
  2. root 138915 1 0 15:52 ? 00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace default -id nginx1 -address /run/containerd/containerd.sock
  3. root 138934 138915 0 15:52 ? 00:00:00 nginx: master process nginx -g daemon off;

通过这样的处理,容器进程就和 containerd 没关系了,容器不再受 containerd 的影响,仅和它的 shim 有关系,被 shim 管理,这也是为什么要引入 shim 的原因。

1.3 containerd

从上述 containerd 创建 container 的分析可以看出,containerd 中插件之间的调用是分层的。contianerd 架构如下:

image

containerd 创建 container 的示意图如下:

image

ctr 创建的 container 的交互流程图如下:

image

2. 小结

containerd 源码分析系列文章介绍了 contianerd 是如何创建 container 的,完整了从 kubernetes 到容器创建这一条线。



原文链接:https://www.cnblogs.com/xingzheanan/p/18231621

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号