runC config.json文件示例

/run/containerd/io.containerd.runtime.v1.linux/moby/790b6f02b02464bd9301125fb83eee5c9527f411433346dd194b74eb5f096e44/config.json
.
├── config.json
├── init.pid
├── log.json
└── rootfs

简化

  1. {
  2. "ociVersion": "1.0.1-dev",
  3. "process": {
  4. "user": {
  5. "uid": 0,
  6. "gid": 0,
  7. "additionalGids": [
  8. 10
  9. ]
  10. },
  11. "args": [
  12. "sleep",
  13. "24h"
  14. ],
  15. "env": [
  16. "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
  17. "HOSTNAME=790b6f02b024"
  18. ],
  19. "cwd": "/",
  20. "oomScoreAdj": 0
  21. },
  22. "root": {
  23. "path": "/var/lib/docker/aufs/mnt/071238d45a177890efadf9dbd1f66c505808e77e4c3bba6355323081ac269351"
  24. },
  25. "hostname": "790b6f02b024",
  26. "mounts": [
  27. {
  28. "destination": "/proc",
  29. "type": "proc",
  30. "source": "proc",
  31. "options": [
  32. "nosuid",
  33. "noexec",
  34. "nodev"
  35. ]
  36. },
  37. {
  38. "destination": "/dev",
  39. "type": "tmpfs",
  40. "source": "tmpfs",
  41. "options": [
  42. "nosuid",
  43. "strictatime",
  44. "mode=755",
  45. "size=65536k"
  46. ]
  47. },
  48. {
  49. "destination": "/dev/pts",
  50. "type": "devpts",
  51. "source": "devpts",
  52. "options": [
  53. "nosuid",
  54. "noexec",
  55. "newinstance",
  56. "ptmxmode=0666",
  57. "mode=0620",
  58. "gid=5"
  59. ]
  60. },
  61. {
  62. "destination": "/sys",
  63. "type": "sysfs",
  64. "source": "sysfs",
  65. "options": [
  66. "nosuid",
  67. "noexec",
  68. "nodev",
  69. "ro"
  70. ]
  71. },
  72. {
  73. "destination": "/sys/fs/cgroup",
  74. "type": "cgroup",
  75. "source": "cgroup",
  76. "options": [
  77. "ro",
  78. "nosuid",
  79. "noexec",
  80. "nodev"
  81. ]
  82. },
  83. {
  84. "destination": "/dev/mqueue",
  85. "type": "mqueue",
  86. "source": "mqueue",
  87. "options": [
  88. "nosuid",
  89. "noexec",
  90. "nodev"
  91. ]
  92. },
  93. {
  94. "destination": "/etc/resolv.conf",
  95. "type": "bind",
  96. "source": "/var/lib/docker/containers/790b6f02b02464bd9301125fb83eee5c9527f411433346dd194b74eb5f096e44/resolv.conf",
  97. "options": [
  98. "rbind",
  99. "rprivate"
  100. ]
  101. },
  102. {
  103. "destination": "/etc/hostname",
  104. "type": "bind",
  105. "source": "/var/lib/docker/containers/790b6f02b02464bd9301125fb83eee5c9527f411433346dd194b74eb5f096e44/hostname",
  106. "options": [
  107. "rbind",
  108. "rprivate"
  109. ]
  110. },
  111. {
  112. "destination": "/etc/hosts",
  113. "type": "bind",
  114. "source": "/var/lib/docker/containers/790b6f02b02464bd9301125fb83eee5c9527f411433346dd194b74eb5f096e44/hosts",
  115. "options": [
  116. "rbind",
  117. "rprivate"
  118. ]
  119. },
  120. {
  121. "destination": "/dev/shm",
  122. "type": "bind",
  123. "source": "/var/lib/docker/containers/790b6f02b02464bd9301125fb83eee5c9527f411433346dd194b74eb5f096e44/mounts/shm",
  124. "options": [
  125. "rbind",
  126. "rprivate"
  127. ]
  128. }
  129. ],
  130. "hooks": {
  131. "prestart": [
  132. {
  133. "path": "/proc/2325/exe",
  134. "args": [
  135. "libnetwork-setkey",
  136. "790b6f02b02464bd9301125fb83eee5c9527f411433346dd194b74eb5f096e44",
  137. "c2a68d82d6cfefcc3404f3a2ce3a5bba4204f518d27da191ae7f7359619cd6c3"
  138. ]
  139. }
  140. ]
  141. },
  142. "linux": {
  143. "resources": {
  144. "devices": [
  145. {
  146. "allow": false,
  147. "access": "rwm"
  148. },
  149. {
  150. "allow": true,
  151. "type": "c",
  152. "major": 1,
  153. "minor": 5,
  154. "access": "rwm"
  155. },
  156. {
  157. "allow": true,
  158. "type": "c",
  159. "major": 1,
  160. "minor": 3,
  161. "access": "rwm"
  162. },
  163. {
  164. "allow": true,
  165. "type": "c",
  166. "major": 1,
  167. "minor": 9,
  168. "access": "rwm"
  169. },
  170. {
  171. "allow": true,
  172. "type": "c",
  173. "major": 1,
  174. "minor": 8,
  175. "access": "rwm"
  176. },
  177. {
  178. "allow": true,
  179. "type": "c",
  180. "major": 5,
  181. "minor": 0,
  182. "access": "rwm"
  183. },
  184. {
  185. "allow": true,
  186. "type": "c",
  187. "major": 5,
  188. "minor": 1,
  189. "access": "rwm"
  190. },
  191. {
  192. "allow": false,
  193. "type": "c",
  194. "major": 10,
  195. "minor": 229,
  196. "access": "rwm"
  197. }
  198. ],
  199. "memory": {
  200. "disableOOMKiller": false
  201. },
  202. "cpu": {
  203. "shares": 0
  204. },
  205. "pids": {
  206. "limit": 0
  207. },
  208. "blockIO": {
  209. "weight": 0
  210. }
  211. },
  212. "cgroupsPath": "/docker/790b6f02b02464bd9301125fb83eee5c9527f411433346dd194b74eb5f096e44",
  213. "namespaces": [
  214. {
  215. "type": "mount"
  216. },
  217. {
  218. "type": "network"
  219. },
  220. {
  221. "type": "uts"
  222. },
  223. {
  224. "type": "pid"
  225. },
  226. {
  227. "type": "ipc"
  228. }
  229. ],
  230. "maskedPaths": [
  231. "/proc/asound",
  232. "/proc/acpi",
  233. "/proc/kcore",
  234. "/proc/keys",
  235. "/proc/latency_stats",
  236. "/proc/timer_list",
  237. "/proc/timer_stats",
  238. "/proc/sched_debug",
  239. "/proc/scsi",
  240. "/sys/firmware"
  241. ],
  242. "readonlyPaths": [
  243. "/proc/bus",
  244. "/proc/fs",
  245. "/proc/irq",
  246. "/proc/sys",
  247. "/proc/sysrq-trigger"
  248. ]
  249. }
  250. }

1) container.go#container.NewTask

  1. func (c *container) NewTask(ctx context.Context, ioCreate cio.Creator, opts ...NewTaskOpts) (_ Task, err error) {
  2. i, err := ioCreate(c.id)
  3. if err != nil {
  4. return nil, err
  5. }
  6. defer func() {
  7. if err != nil && i != nil {
  8. i.Cancel()
  9. i.Close()
  10. }
  11. }()
  12. cfg := i.Config()
  13. request := &tasks.CreateTaskRequest{
  14. ContainerID: c.id,
  15. Terminal: cfg.Terminal,
  16. Stdin: cfg.Stdin,
  17. Stdout: cfg.Stdout,
  18. Stderr: cfg.Stderr,
  19. }
  20. r, err := c.get(ctx)
  21. if err != nil {
  22. return nil, err
  23. }
  24. if r.SnapshotKey != "" {
  25. if r.Snapshotter == "" {
  26. return nil, errors.Wrapf(errdefs.ErrInvalidArgument, "unable to resolve rootfs mounts without snapshotter on container")
  27. }
  28. // get the rootfs from the snapshotter and add it to the request
  29. mounts, err := c.client.SnapshotService(r.Snapshotter).Mounts(ctx, r.SnapshotKey)
  30. if err != nil {
  31. return nil, err
  32. }
  33. for _, m := range mounts {
  34. request.Rootfs = append(request.Rootfs, &types.Mount{
  35. Type: m.Type,
  36. Source: m.Source,
  37. Options: m.Options,
  38. })
  39. }
  40. }
  41. var info TaskInfo
  42. for _, o := range opts {
  43. if err := o(ctx, c.client, &info); err != nil {
  44. return nil, err
  45. }
  46. }
  47. if info.RootFS != nil {
  48. for _, m := range info.RootFS {
  49. request.Rootfs = append(request.Rootfs, &types.Mount{
  50. Type: m.Type,
  51. Source: m.Source,
  52. Options: m.Options,
  53. })
  54. }
  55. }
  56. if info.Options != nil {
  57. any, err := typeurl.MarshalAny(info.Options)
  58. if err != nil {
  59. return nil, err
  60. }
  61. request.Options = any
  62. }
  63. t := &task{
  64. client: c.client,
  65. io: i,
  66. id: c.id,
  67. }
  68. if info.Checkpoint != nil {
  69. request.Checkpoint = info.Checkpoint
  70. }
  71. // ********************************** NOTICE ********************************** //
  72. response, err := c.client.TaskService().Create(ctx, request)
  73. // ********************************** NOTICE ********************************** //
  74. if err != nil {
  75. return nil, errdefs.FromGRPC(err)
  76. }
  77. t.pid = response.Pid
  78. return t, nil
  79. }

1.1) api/services/tasks/v1/tasks.pb.go#tasksClient.Create

  1. func (c *tasksClient) Create(ctx context.Context, in *CreateTaskRequest, opts ...grpc.CallOption) (*CreateTaskResponse, error) {
  2. out := new(CreateTaskResponse)
  3. err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Create", in, out, c.cc, opts...)
  4. if err != nil {
  5. return nil, err
  6. }
  7. return out, nil
  8. }

1.1.1) services/tasks/local.go#local.Create

  1. func (l *local) Create(ctx context.Context, r *api.CreateTaskRequest, _ ...grpc.CallOption) (*api.CreateTaskResponse, error) {
  2. container, err := l.getContainer(ctx, r.ContainerID)
  3. if err != nil {
  4. return nil, errdefs.ToGRPC(err)
  5. }
  6. checkpointPath, err := getRestorePath(container.Runtime.Name, r.Options)
  7. if err != nil {
  8. return nil, err
  9. }
  10. // jump get checkpointPath from checkpoint image
  11. if checkpointPath != "" && r.Checkpoint != nil {
  12. checkpointPath, err = ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "ctrd-checkpoint")
  13. if err != nil {
  14. return nil, err
  15. }
  16. if r.Checkpoint.MediaType != images.MediaTypeContainerd1Checkpoint {
  17. return nil, fmt.Errorf("unsupported checkpoint type %q", r.Checkpoint.MediaType)
  18. }
  19. reader, err := l.store.ReaderAt(ctx, ocispec.Descriptor{
  20. MediaType: r.Checkpoint.MediaType,
  21. Digest: r.Checkpoint.Digest,
  22. Size: r.Checkpoint.Size_,
  23. })
  24. if err != nil {
  25. return nil, err
  26. }
  27. _, err = archive.Apply(ctx, checkpointPath, content.NewReader(reader))
  28. reader.Close()
  29. if err != nil {
  30. return nil, err
  31. }
  32. }
  33. opts := runtime.CreateOpts{
  34. Spec: container.Spec,
  35. IO: runtime.IO{
  36. Stdin: r.Stdin,
  37. Stdout: r.Stdout,
  38. Stderr: r.Stderr,
  39. Terminal: r.Terminal,
  40. },
  41. Checkpoint: checkpointPath,
  42. Runtime: container.Runtime.Name,
  43. RuntimeOptions: container.Runtime.Options,
  44. TaskOptions: r.Options,
  45. }
  46. for _, m := range r.Rootfs {
  47. opts.Rootfs = append(opts.Rootfs, mount.Mount{
  48. Type: m.Type,
  49. Source: m.Source,
  50. Options: m.Options,
  51. })
  52. }
  53. // linux
  54. // ********************************** NOTICE ********************************** //
  55. rtime, err := l.getRuntime(container.Runtime.Name)
  56. // ********************************** NOTICE ********************************** //
  57. if err != nil {
  58. return nil, err
  59. }
  60. if _, err := rtime.Get(ctx, r.ContainerID); err != runtime.ErrTaskNotExists {
  61. return nil, errdefs.ToGRPC(fmt.Errorf("task %s already exists", r.ContainerID))
  62. }
  63. // ********************************** NOTICE ********************************** //
  64. c, err := rtime.Create(ctx, r.ContainerID, opts)
  65. // ********************************** NOTICE ********************************** //
  66. if err != nil {
  67. return nil, errdefs.ToGRPC(err)
  68. }
  69. // TODO: fast path for getting pid on create
  70. if err := l.monitor.Monitor(c); err != nil {
  71. return nil, errors.Wrap(err, "monitor task")
  72. }
  73. state, err := c.State(ctx)
  74. if err != nil {
  75. log.G(ctx).Error(err)
  76. }
  77. return &api.CreateTaskResponse{
  78. ContainerID: r.ContainerID,
  79. Pid: state.Pid,
  80. }, nil
  81. }

1.1.1.1) runtime/v1/linux/runtime.go#Runtime.Create

  1. // Create a new task
  2. func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts) (_ runtime.Task, err error) {
  3. namespace, err := namespaces.NamespaceRequired(ctx)
  4. if err != nil {
  5. return nil, err
  6. }
  7. if err := identifiers.Validate(id); err != nil {
  8. return nil, errors.Wrapf(err, "invalid task id")
  9. }
  10. ropts, err := r.getRuncOptions(ctx, id)
  11. if err != nil {
  12. return nil, err
  13. }
  14. // ********************************** NOTICE ********************************** //
  15. bundle, err := newBundle(id,
  16. filepath.Join(r.state, namespace),
  17. filepath.Join(r.root, namespace),
  18. opts.Spec.Value)
  19. // ********************************** NOTICE ********************************** //
  20. if err != nil {
  21. return nil, err
  22. }
  23. defer func() {
  24. if err != nil {
  25. bundle.Delete()
  26. }
  27. }()
  28. shimopt := ShimLocal(r.config, r.events)
  29. if !r.config.NoShim {
  30. var cgroup string
  31. if opts.TaskOptions != nil {
  32. v, err := typeurl.UnmarshalAny(opts.TaskOptions)
  33. if err != nil {
  34. return nil, err
  35. }
  36. cgroup = v.(*runctypes.CreateOptions).ShimCgroup
  37. }
  38. exitHandler := func() {
  39. log.G(ctx).WithField("id", id).Info("shim reaped")
  40. t, err := r.tasks.Get(ctx, id)
  41. if err != nil {
  42. // Task was never started or was already successfully deleted
  43. return
  44. }
  45. lc := t.(*Task)
  46. log.G(ctx).WithFields(logrus.Fields{
  47. "id": id,
  48. "namespace": namespace,
  49. }).Warn("cleaning up after killed shim")
  50. if err = r.cleanupAfterDeadShim(context.Background(), bundle, namespace, id, lc.pid); err != nil {
  51. log.G(ctx).WithError(err).WithFields(logrus.Fields{
  52. "id": id,
  53. "namespace": namespace,
  54. }).Warn("failed to clean up after killed shim")
  55. }
  56. }
  57. shimopt = ShimRemote(r.config, r.address, cgroup, exitHandler)
  58. }
  59. // ********************************** NOTICE ********************************** //
  60. s, err := bundle.NewShimClient(ctx, namespace, shimopt, ropts)
  61. // ********************************** NOTICE ********************************** //
  62. if err != nil {
  63. return nil, err
  64. }
  65. defer func() {
  66. if err != nil {
  67. if kerr := s.KillShim(ctx); kerr != nil {
  68. log.G(ctx).WithError(err).Error("failed to kill shim")
  69. }
  70. }
  71. }()
  72. rt := r.config.Runtime
  73. if ropts != nil && ropts.Runtime != "" {
  74. rt = ropts.Runtime
  75. }
  76. sopts := &shim.CreateTaskRequest{
  77. ID: id,
  78. Bundle: bundle.path,
  79. Runtime: rt,
  80. Stdin: opts.IO.Stdin,
  81. Stdout: opts.IO.Stdout,
  82. Stderr: opts.IO.Stderr,
  83. Terminal: opts.IO.Terminal,
  84. Checkpoint: opts.Checkpoint,
  85. Options: opts.TaskOptions,
  86. }
  87. for _, m := range opts.Rootfs {
  88. sopts.Rootfs = append(sopts.Rootfs, &types.Mount{
  89. Type: m.Type,
  90. Source: m.Source,
  91. Options: m.Options,
  92. })
  93. }
  94. // ********************************** NOTICE ********************************** //
  95. cr, err := s.Create(ctx, sopts)
  96. // ********************************** NOTICE ********************************** //
  97. if err != nil {
  98. return nil, errdefs.FromGRPC(err)
  99. }
  100. // ********************************** NOTICE ********************************** //
  101. t, err := newTask(id, namespace, int(cr.Pid), s, r.events, r.tasks, bundle)
  102. // ********************************** NOTICE ********************************** //
  103. if err != nil {
  104. return nil, err
  105. }
  106. if err := r.tasks.Add(ctx, t); err != nil {
  107. return nil, err
  108. }
  109. r.events.Publish(ctx, runtime.TaskCreateEventTopic, &eventstypes.TaskCreate{
  110. ContainerID: sopts.ID,
  111. Bundle: sopts.Bundle,
  112. Rootfs: sopts.Rootfs,
  113. IO: &eventstypes.TaskIO{
  114. Stdin: sopts.Stdin,
  115. Stdout: sopts.Stdout,
  116. Stderr: sopts.Stderr,
  117. Terminal: sopts.Terminal,
  118. },
  119. Checkpoint: sopts.Checkpoint,
  120. Pid: uint32(t.pid),
  121. })
  122. return t, nil
  123. }

—1.1.1.1.1-创建bundle和config.json) runtime/v1/linux/bundle.go#newBundle

  1. // newBundle creates a new bundle on disk at the provided path for the given id
  2. func newBundle(id, path, workDir string, spec []byte) (b *bundle, err error) {
  3. if err := os.MkdirAll(path, 0711); err != nil {
  4. return nil, err
  5. }
  6. path = filepath.Join(path, id)
  7. if err := os.Mkdir(path, 0711); err != nil {
  8. return nil, err
  9. }
  10. defer func() {
  11. if err != nil {
  12. os.RemoveAll(path)
  13. }
  14. }()
  15. workDir = filepath.Join(workDir, id)
  16. if err := os.MkdirAll(workDir, 0711); err != nil {
  17. return nil, err
  18. }
  19. defer func() {
  20. if err != nil {
  21. os.RemoveAll(workDir)
  22. }
  23. }()
  24. if err := os.Mkdir(filepath.Join(path, "rootfs"), 0711); err != nil {
  25. return nil, err
  26. }
  27. err = ioutil.WriteFile(filepath.Join(path, configFilename), spec, 0666)
  28. return &bundle{
  29. id: id,
  30. path: path,
  31. workDir: workDir,
  32. }, err
  33. }

—1.1.1.1.2) runtime/v1/linux/bundle.go#bundle.NewShimClient

  1. // NewShimClient connects to the shim managing the bundle and tasks creating it if needed
  2. func (b *bundle) NewShimClient(ctx context.Context, namespace string, getClientOpts ShimOpt, runcOpts *runctypes.RuncOptions) (*client.Client, error) {
  3. cfg, opt := getClientOpts(b, namespace, runcOpts)
  4. return client.New(ctx, cfg, opt)
  5. }
  6. // getClientOpts
  7. // ShimLocal is a ShimOpt for using an in process shim implementation
  8. func ShimLocal(c *Config, exchange *exchange.Exchange) ShimOpt {
  9. return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) {
  10. return b.shimConfig(ns, c, ropts), client.WithLocal(exchange)
  11. }
  12. }
  13. func (b *bundle) shimConfig(namespace string, c *Config, runcOptions *runctypes.RuncOptions) shim.Config {
  14. var (
  15. criuPath string
  16. runtimeRoot = c.RuntimeRoot
  17. systemdCgroup bool
  18. )
  19. if runcOptions != nil {
  20. criuPath = runcOptions.CriuPath
  21. systemdCgroup = runcOptions.SystemdCgroup
  22. if runcOptions.RuntimeRoot != "" {
  23. runtimeRoot = runcOptions.RuntimeRoot
  24. }
  25. }
  26. return shim.Config{
  27. Path: b.path,
  28. WorkDir: b.workDir,
  29. Namespace: namespace,
  30. Criu: criuPath,
  31. RuntimeRoot: runtimeRoot,
  32. SystemdCgroup: systemdCgroup,
  33. }
  34. }
  35. // WithLocal uses an in process shim
  36. func WithLocal(publisher events.Publisher) func(context.Context, shim.Config) (shimapi.ShimService, io.Closer, error) {
  37. return func(ctx context.Context, config shim.Config) (shimapi.ShimService, io.Closer, error) {
  38. service, err := shim.NewService(config, publisher)
  39. if err != nil {
  40. return nil, nil, err
  41. }
  42. return shim.NewLocal(service), nil, nil
  43. }
  44. }
  45. // NewService returns a new shim service that can be used via GRPC
  46. func NewService(config Config, publisher events.Publisher) (*Service, error) {
  47. if config.Namespace == "" {
  48. return nil, fmt.Errorf("shim namespace cannot be empty")
  49. }
  50. ctx := namespaces.WithNamespace(context.Background(), config.Namespace)
  51. ctx = log.WithLogger(ctx, logrus.WithFields(logrus.Fields{
  52. "namespace": config.Namespace,
  53. "path": config.Path,
  54. "pid": os.Getpid(),
  55. }))
  56. s := &Service{
  57. config: config,
  58. context: ctx,
  59. processes: make(map[string]rproc.Process),
  60. events: make(chan interface{}, 128),
  61. ec: Default.Subscribe(),
  62. }
  63. go s.processExits()
  64. if err := s.initPlatform(); err != nil {
  65. return nil, errors.Wrap(err, "failed to initialized platform behavior")
  66. }
  67. go s.forward(publisher)
  68. return s, nil
  69. }

—1.1.1.1.3) runtime/v1/shim/local.go#local.Create

  1. type ShimService interface {
  2. State(ctx context.Context, req *StateRequest) (*StateResponse, error)
  3. Create(ctx context.Context, req *CreateTaskRequest) (*CreateTaskResponse, error)
  4. Start(ctx context.Context, req *StartRequest) (*StartResponse, error)
  5. Delete(ctx context.Context, req *google_protobuf1.Empty) (*DeleteResponse, error)
  6. DeleteProcess(ctx context.Context, req *DeleteProcessRequest) (*DeleteResponse, error)
  7. ListPids(ctx context.Context, req *ListPidsRequest) (*ListPidsResponse, error)
  8. Pause(ctx context.Context, req *google_protobuf1.Empty) (*google_protobuf1.Empty, error)
  9. Resume(ctx context.Context, req *google_protobuf1.Empty) (*google_protobuf1.Empty, error)
  10. Checkpoint(ctx context.Context, req *CheckpointTaskRequest) (*google_protobuf1.Empty, error)
  11. Kill(ctx context.Context, req *KillRequest) (*google_protobuf1.Empty, error)
  12. Exec(ctx context.Context, req *ExecProcessRequest) (*google_protobuf1.Empty, error)
  13. ResizePty(ctx context.Context, req *ResizePtyRequest) (*google_protobuf1.Empty, error)
  14. CloseIO(ctx context.Context, req *CloseIORequest) (*google_protobuf1.Empty, error)
  15. ShimInfo(ctx context.Context, req *google_protobuf1.Empty) (*ShimInfoResponse, error)
  16. Update(ctx context.Context, req *UpdateTaskRequest) (*google_protobuf1.Empty, error)
  17. Wait(ctx context.Context, req *WaitRequest) (*WaitResponse, error)
  18. }
  1. func (c *local) Create(ctx context.Context, in *shimapi.CreateTaskRequest) (*shimapi.CreateTaskResponse, error) {
  2. return c.s.Create(ctx, in)
  3. }

——1.1.1.1.3.1) runtime/v1/shim/service.go#Service.Create

  1. // Create a new initial process and container with the underlying OCI runtime
  2. func (s *Service) Create(ctx context.Context, r *shimapi.CreateTaskRequest) (_ *shimapi.CreateTaskResponse, err error) {
  3. var mounts []proc.Mount
  4. for _, m := range r.Rootfs {
  5. mounts = append(mounts, proc.Mount{
  6. Type: m.Type,
  7. Source: m.Source,
  8. Target: m.Target,
  9. Options: m.Options,
  10. })
  11. }
  12. config := &proc.CreateConfig{
  13. ID: r.ID,
  14. Bundle: r.Bundle,
  15. Runtime: r.Runtime,
  16. Rootfs: mounts,
  17. Terminal: r.Terminal,
  18. Stdin: r.Stdin,
  19. Stdout: r.Stdout,
  20. Stderr: r.Stderr,
  21. Checkpoint: r.Checkpoint,
  22. ParentCheckpoint: r.ParentCheckpoint,
  23. Options: r.Options,
  24. }
  25. rootfs := filepath.Join(r.Bundle, "rootfs")
  26. defer func() {
  27. if err != nil {
  28. if err2 := mount.UnmountAll(rootfs, 0); err2 != nil {
  29. log.G(ctx).WithError(err2).Warn("Failed to cleanup rootfs mount")
  30. }
  31. }
  32. }()
  33. for _, rm := range mounts {
  34. m := &mount.Mount{
  35. Type: rm.Type,
  36. Source: rm.Source,
  37. Options: rm.Options,
  38. }
  39. if err := m.Mount(rootfs); err != nil {
  40. return nil, errors.Wrapf(err, "failed to mount rootfs component %v", m)
  41. }
  42. }
  43. s.mu.Lock()
  44. defer s.mu.Unlock()
  45. // ********************************** NOTICE ********************************** //
  46. process, err := newInit(
  47. ctx,
  48. s.config.Path,
  49. s.config.WorkDir,
  50. s.config.RuntimeRoot,
  51. s.config.Namespace,
  52. s.config.Criu,
  53. s.config.SystemdCgroup,
  54. s.platform,
  55. config,
  56. )
  57. // ********************************** NOTICE ********************************** //
  58. if err != nil {
  59. return nil, errdefs.ToGRPC(err)
  60. }
  61. // ********************************** NOTICE ********************************** //
  62. if err := process.Create(ctx, config); err != nil {
  63. // ********************************** NOTICE ********************************** //
  64. return nil, errdefs.ToGRPC(err)
  65. }
  66. // save the main task id and bundle to the shim for additional requests
  67. s.id = r.ID
  68. s.bundle = r.Bundle
  69. pid := process.Pid()
  70. s.processes[r.ID] = process
  71. return &shimapi.CreateTaskResponse{
  72. Pid: uint32(pid),
  73. }, nil
  74. }

———1.1.1.1.3.1.1) runtime/v1/shim/service.go#newInit

  1. func newInit(ctx context.Context, path, workDir, runtimeRoot, namespace, criu string, systemdCgroup bool, platform rproc.Platform, r *proc.CreateConfig) (*proc.Init, error) {
  2. var options runctypes.CreateOptions
  3. if r.Options != nil {
  4. v, err := typeurl.UnmarshalAny(r.Options)
  5. if err != nil {
  6. return nil, err
  7. }
  8. options = *v.(*runctypes.CreateOptions)
  9. }
  10. rootfs := filepath.Join(path, "rootfs")
  11. // ********************************** NOTICE ********************************** //
  12. runtime := proc.NewRunc(runtimeRoot, path, namespace, r.Runtime, criu, systemdCgroup)
  13. // ********************************** NOTICE ********************************** //
  14. p := proc.New(r.ID, runtime, rproc.Stdio{
  15. Stdin: r.Stdin,
  16. Stdout: r.Stdout,
  17. Stderr: r.Stderr,
  18. Terminal: r.Terminal,
  19. })
  20. // ********************************** NOTICE ********************************** //
  21. p.Bundle = r.Bundle
  22. p.Platform = platform
  23. p.Rootfs = rootfs
  24. p.WorkDir = workDir
  25. p.IoUID = int(options.IoUid)
  26. p.IoGID = int(options.IoGid)
  27. p.NoPivotRoot = options.NoPivotRoot
  28. p.NoNewKeyring = options.NoNewKeyring
  29. p.CriuWorkPath = options.CriuWorkPath
  30. if p.CriuWorkPath == "" {
  31. // if criu work path not set, use container WorkDir
  32. p.CriuWorkPath = p.WorkDir
  33. }
  34. return p, nil
  35. }
  36. // NewRunc returns a new runc instance for a process
  37. func NewRunc(root, path, namespace, runtime, criu string, systemd bool) *runc.Runc {
  38. if root == "" {
  39. root = RuncRoot
  40. }
  41. return &runc.Runc{
  42. Command: runtime,
  43. Log: filepath.Join(path, "log.json"),
  44. LogFormat: runc.JSON,
  45. PdeathSignal: syscall.SIGKILL,
  46. Root: filepath.Join(root, namespace),
  47. Criu: criu,
  48. SystemdCgroup: systemd,
  49. }
  50. }
  51. // New returns a new process
  52. func New(id string, runtime *runc.Runc, stdio proc.Stdio) *Init {
  53. p := &Init{
  54. id: id,
  55. runtime: runtime,
  56. stdio: stdio,
  57. status: 0,
  58. waitBlock: make(chan struct{}),
  59. }
  60. p.initState = &createdState{p: p}
  61. return p
  62. }

———1.1.1.1.3.1.2) runtime/v1/linux/proc/init.go#Init.Create

  1. // Create the process with the provided config
  2. func (p *Init) Create(ctx context.Context, r *CreateConfig) error {
  3. var (
  4. err error
  5. socket *runc.Socket
  6. )
  7. if r.Terminal {
  8. if socket, err = runc.NewTempConsoleSocket(); err != nil {
  9. return errors.Wrap(err, "failed to create OCI runtime console socket")
  10. }
  11. defer socket.Close()
  12. } else if hasNoIO(r) {
  13. if p.io, err = runc.NewNullIO(); err != nil {
  14. return errors.Wrap(err, "creating new NULL IO")
  15. }
  16. } else {
  17. if p.io, err = runc.NewPipeIO(p.IoUID, p.IoGID, withConditionalIO(p.stdio)); err != nil {
  18. return errors.Wrap(err, "failed to create OCI runtime io pipes")
  19. }
  20. }
  21. pidFile := filepath.Join(p.Bundle, InitPidFile)
  22. if r.Checkpoint != "" {
  23. opts := &runc.RestoreOpts{
  24. CheckpointOpts: runc.CheckpointOpts{
  25. ImagePath: r.Checkpoint,
  26. WorkDir: p.CriuWorkPath,
  27. ParentPath: r.ParentCheckpoint,
  28. },
  29. PidFile: pidFile,
  30. IO: p.io,
  31. NoPivot: p.NoPivotRoot,
  32. Detach: true,
  33. NoSubreaper: true,
  34. }
  35. p.initState = &createdCheckpointState{
  36. p: p,
  37. opts: opts,
  38. }
  39. return nil
  40. }
  41. opts := &runc.CreateOpts{
  42. PidFile: pidFile,
  43. IO: p.io,
  44. NoPivot: p.NoPivotRoot,
  45. NoNewKeyring: p.NoNewKeyring,
  46. }
  47. if socket != nil {
  48. opts.ConsoleSocket = socket
  49. }
  50. // ********************************** NOTICE ********************************** //
  51. if err := p.runtime.Create(ctx, r.ID, r.Bundle, opts); err != nil {
  52. // ********************************** NOTICE ********************************** //
  53. return p.runtimeError(err, "OCI runtime create failed")
  54. }
  55. if r.Stdin != "" {
  56. sc, err := fifo.OpenFifo(context.Background(), r.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
  57. if err != nil {
  58. return errors.Wrapf(err, "failed to open stdin fifo %s", r.Stdin)
  59. }
  60. p.stdin = sc
  61. p.closers = append(p.closers, sc)
  62. }
  63. var copyWaitGroup sync.WaitGroup
  64. ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
  65. defer cancel()
  66. if socket != nil {
  67. console, err := socket.ReceiveMaster()
  68. if err != nil {
  69. return errors.Wrap(err, "failed to retrieve console master")
  70. }
  71. console, err = p.Platform.CopyConsole(ctx, console, r.Stdin, r.Stdout, r.Stderr, &p.wg, &copyWaitGroup)
  72. if err != nil {
  73. return errors.Wrap(err, "failed to start console copy")
  74. }
  75. p.console = console
  76. } else if !hasNoIO(r) {
  77. if err := copyPipes(ctx, p.io, r.Stdin, r.Stdout, r.Stderr, &p.wg, &copyWaitGroup); err != nil {
  78. return errors.Wrap(err, "failed to start io pipe copy")
  79. }
  80. }
  81. copyWaitGroup.Wait()
  82. pid, err := runc.ReadPidFile(pidFile)
  83. if err != nil {
  84. return errors.Wrap(err, "failed to retrieve OCI runtime container pid")
  85. }
  86. p.pid = pid
  87. return nil
  88. }
  89. // Create creates a new container and returns its pid if it was created successfully
  90. func (r *Runc) Create(context context.Context, id, bundle string, opts *CreateOpts) error {
  91. // ********************************** NOTICE ********************************** //
  92. args := []string{"create", "--bundle", bundle}
  93. // ********************************** NOTICE ********************************** //
  94. if opts != nil {
  95. oargs, err := opts.args()
  96. if err != nil {
  97. return err
  98. }
  99. args = append(args, oargs...)
  100. }
  101. cmd := r.command(context, append(args, id)...)
  102. if opts != nil && opts.IO != nil {
  103. opts.Set(cmd)
  104. }
  105. cmd.ExtraFiles = opts.ExtraFiles
  106. if cmd.Stdout == nil && cmd.Stderr == nil {
  107. data, err := cmdOutput(cmd, true)
  108. if err != nil {
  109. return fmt.Errorf("%s: %s", err, data)
  110. }
  111. return nil
  112. }
  113. ec, err := Monitor.Start(cmd)
  114. if err != nil {
  115. return err
  116. }
  117. if opts != nil && opts.IO != nil {
  118. if c, ok := opts.IO.(StartCloser); ok {
  119. if err := c.CloseAfterStart(); err != nil {
  120. return err
  121. }
  122. }
  123. }
  124. status, err := Monitor.Wait(cmd, ec)
  125. if err == nil && status != 0 {
  126. err = fmt.Errorf("%s did not terminate sucessfully", cmd.Args[0])
  127. }
  128. return err
  129. }

2) task.go#task.Start

  1. func (t *task) Start(ctx context.Context) error {
  2. r, err := t.client.TaskService().Start(ctx, &tasks.StartRequest{
  3. ContainerID: t.id,
  4. })
  5. if err != nil {
  6. if t.io != nil {
  7. t.io.Cancel()
  8. t.io.Close()
  9. }
  10. return errdefs.FromGRPC(err)
  11. }
  12. t.pid = r.Pid
  13. return nil
  14. }

2.1) api/services/tasks/v1/tasks.pb.go#tasksClient.Start

  1. func (c *tasksClient) Start(ctx context.Context, in *StartRequest, opts ...grpc.CallOption) (*StartResponse, error) {
  2. out := new(StartResponse)
  3. err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Start", in, out, c.cc, opts...)
  4. if err != nil {
  5. return nil, err
  6. }
  7. return out, nil
  8. }

2.1.1) services/tasks/local.go#local.Start

  1. func (l *local) Start(ctx context.Context, r *api.StartRequest, _ ...grpc.CallOption) (*api.StartResponse, error) {
  2. t, err := l.getTask(ctx, r.ContainerID)
  3. if err != nil {
  4. return nil, err
  5. }
  6. p := runtime.Process(t)
  7. // 这里为空
  8. if r.ExecID != "" {
  9. if p, err = t.Process(ctx, r.ExecID); err != nil {
  10. return nil, errdefs.ToGRPC(err)
  11. }
  12. }
  13. // ********************************** NOTICE ********************************** //
  14. if err := p.Start(ctx); err != nil {
  15. // ********************************** NOTICE ********************************** //
  16. return nil, errdefs.ToGRPC(err)
  17. }
  18. state, err := p.State(ctx)
  19. if err != nil {
  20. return nil, errdefs.ToGRPC(err)
  21. }
  22. return &api.StartResponse{
  23. Pid: state.Pid,
  24. }, nil
  25. }

2.1.1.1) runtime/v1/shim/local.go#local.Start

  1. func (c *local) Start(ctx context.Context, in *shimapi.StartRequest) (*shimapi.StartResponse, error) {
  2. return c.s.Start(ctx, in)
  3. }

—2.1.1.1.1) runtime/v1/shim/service.go#Service.Start

  1. // Start a process
  2. func (s *Service) Start(ctx context.Context, r *shimapi.StartRequest) (*shimapi.StartResponse, error) {
  3. p, err := s.getExecProcess(r.ID)
  4. if err != nil {
  5. return nil, err
  6. }
  7. // ********************************** NOTICE ********************************** //
  8. if err := p.Start(ctx); err != nil {
  9. // ********************************** NOTICE ********************************** //
  10. return nil, err
  11. }
  12. return &shimapi.StartResponse{
  13. ID: p.ID(),
  14. Pid: uint32(p.Pid()),
  15. }, nil
  16. }
  1. // Start the init process
  2. func (p *Init) Start(ctx context.Context) error {
  3. p.mu.Lock()
  4. defer p.mu.Unlock()
  5. // ********************************** NOTICE ********************************** //
  6. return p.initState.Start(ctx)
  7. // ********************************** NOTICE ********************************** //
  8. }
  1. func (s *createdState) Start(ctx context.Context) error {
  2. // ********************************** NOTICE ********************************** //
  3. if err := s.p.start(ctx); err != nil {
  4. // ********************************** NOTICE ********************************** //
  5. return err
  6. }
  7. return s.transition("running")
  8. }
  1. func (p *Init) start(ctx context.Context) error {
  2. err := p.runtime.Start(ctx, p.id)
  3. return p.runtimeError(err, "OCI runtime start failed")
  4. }
  5. // Start will start an already created container
  6. func (r *Runc) Start(context context.Context, id string) error {
  7. return r.runOrError(r.command(context, "start", id))
  8. }
  9. func (r *Runc) command(context context.Context, args ...string) *exec.Cmd {
  10. command := r.Command
  11. if command == "" {
  12. command = DefaultCommand
  13. }
  14. cmd := exec.CommandContext(context, command, append(r.args(), args...)...)
  15. cmd.SysProcAttr = &syscall.SysProcAttr{
  16. Setpgid: r.Setpgid,
  17. }
  18. cmd.Env = os.Environ()
  19. if r.PdeathSignal != 0 {
  20. cmd.SysProcAttr.Pdeathsig = r.PdeathSignal
  21. }
  22. return cmd
  23. }
  24. // runOrError will run the provided command. If an error is
  25. // encountered and neither Stdout or Stderr was set the error and the
  26. // stderr of the command will be returned in the format of <error>:
  27. // <stderr>
  28. func (r *Runc) runOrError(cmd *exec.Cmd) error {
  29. if cmd.Stdout != nil || cmd.Stderr != nil {
  30. ec, err := Monitor.Start(cmd)
  31. if err != nil {
  32. return err
  33. }
  34. status, err := Monitor.Wait(cmd, ec)
  35. if err == nil && status != 0 {
  36. err = fmt.Errorf("%s did not terminate sucessfully", cmd.Args[0])
  37. }
  38. return err
  39. }
  40. data, err := cmdOutput(cmd, true)
  41. if err != nil {
  42. return fmt.Errorf("%s: %s", err, data)
  43. }
  44. return nil
  45. }