api/server/router/container/container_routes.go#containerRouter.postContainersCreate

  1. func (s *containerRouter) postContainersCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  2. if err := httputils.ParseForm(r); err != nil {
  3. return err
  4. }
  5. if err := httputils.CheckForJSON(r); err != nil {
  6. return err
  7. }
  8. name := r.Form.Get("name")
  9. config, hostConfig, networkingConfig, err := s.decoder.DecodeConfig(r.Body)
  10. if err != nil {
  11. return err
  12. }
  13. version := httputils.VersionFromContext(ctx)
  14. adjustCPUShares := versions.LessThan(version, "1.19")
  15. // When using API 1.24 and under, the client is responsible for removing the container
  16. if hostConfig != nil && versions.LessThan(version, "1.25") {
  17. hostConfig.AutoRemove = false
  18. }
  19. if hostConfig != nil && versions.LessThan(version, "1.40") {
  20. // Ignore BindOptions.NonRecursive because it was added in API 1.40.
  21. for _, m := range hostConfig.Mounts {
  22. if bo := m.BindOptions; bo != nil {
  23. bo.NonRecursive = false
  24. }
  25. }
  26. // Ignore KernelMemoryTCP because it was added in API 1.40.
  27. hostConfig.KernelMemoryTCP = 0
  28. }
  29. // Ignore Capabilities because it was added in API 1.40.
  30. if hostConfig != nil && versions.LessThan(version, "1.40") {
  31. hostConfig.Capabilities = nil
  32. }
  33. // ********************************** NOTICE ********************************** //
  34. ccr, err := s.backend.ContainerCreate(types.ContainerCreateConfig{
  35. Name: name,
  36. Config: config,
  37. HostConfig: hostConfig,
  38. NetworkingConfig: networkingConfig,
  39. AdjustCPUShares: adjustCPUShares,
  40. })
  41. // ********************************** NOTICE ********************************** //
  42. if err != nil {
  43. return err
  44. }
  45. return httputils.WriteJSON(w, http.StatusCreated, ccr)
  46. }

1) daemon/create.go#Daemon.ContainerCreate

  1. // ContainerCreate creates a regular container
  2. func (daemon *Daemon) ContainerCreate(params types.ContainerCreateConfig) (containertypes.ContainerCreateCreatedBody, error) {
  3. return daemon.containerCreate(params, false)
  4. }
  5. func (daemon *Daemon) containerCreate(params types.ContainerCreateConfig, managed bool) (containertypes.ContainerCreateCreatedBody, error) {
  6. start := time.Now()
  7. if params.Config == nil {
  8. return containertypes.ContainerCreateCreatedBody{}, errdefs.InvalidParameter(errors.New("Config cannot be empty in order to create a container"))
  9. }
  10. os := runtime.GOOS
  11. if params.Config.Image != "" {
  12. // ********************************** NOTICE ********************************** //
  13. img, err := daemon.imageService.GetImage(params.Config.Image)
  14. // ********************************** NOTICE ********************************** //
  15. if err == nil {
  16. os = img.OS
  17. }
  18. } else {
  19. // This mean scratch. On Windows, we can safely assume that this is a linux
  20. // container. On other platforms, it's the host OS (which it already is)
  21. if runtime.GOOS == "windows" && system.LCOWSupported() {
  22. os = "linux"
  23. }
  24. }
  25. warnings, err := daemon.verifyContainerSettings(os, params.HostConfig, params.Config, false)
  26. if err != nil {
  27. return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, errdefs.InvalidParameter(err)
  28. }
  29. err = verifyNetworkingConfig(params.NetworkingConfig)
  30. if err != nil {
  31. return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, errdefs.InvalidParameter(err)
  32. }
  33. if params.HostConfig == nil {
  34. params.HostConfig = &containertypes.HostConfig{}
  35. }
  36. err = daemon.adaptContainerSettings(params.HostConfig, params.AdjustCPUShares)
  37. if err != nil {
  38. return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, errdefs.InvalidParameter(err)
  39. }
  40. // ********************************** NOTICE ********************************** //
  41. container, err := daemon.create(params, managed)
  42. // ********************************** NOTICE ********************************** //
  43. if err != nil {
  44. return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, err
  45. }
  46. containerActions.WithValues("create").UpdateSince(start)
  47. return containertypes.ContainerCreateCreatedBody{ID: container.ID, Warnings: warnings}, nil
  48. }

1.1) daemon/images/image.go#ImageService.GetImage

  1. // GetImage returns an image corresponding to the image referred to by refOrID.
  2. func (i *ImageService) GetImage(refOrID string) (*image.Image, error) {
  3. ref, err := reference.ParseAnyReference(refOrID)
  4. if err != nil {
  5. return nil, errdefs.InvalidParameter(err)
  6. }
  7. namedRef, ok := ref.(reference.Named)
  8. if !ok {
  9. digested, ok := ref.(reference.Digested)
  10. if !ok {
  11. return nil, ErrImageDoesNotExist{ref}
  12. }
  13. id := image.IDFromDigest(digested.Digest())
  14. if img, err := i.imageStore.Get(id); err == nil {
  15. return img, nil
  16. }
  17. return nil, ErrImageDoesNotExist{ref}
  18. }
  19. if digest, err := i.referenceStore.Get(namedRef); err == nil {
  20. // Search the image stores to get the operating system, defaulting to host OS.
  21. id := image.IDFromDigest(digest)
  22. if img, err := i.imageStore.Get(id); err == nil {
  23. return img, nil
  24. }
  25. }
  26. // Search based on ID
  27. if id, err := i.imageStore.Search(refOrID); err == nil {
  28. img, err := i.imageStore.Get(id)
  29. if err != nil {
  30. return nil, ErrImageDoesNotExist{ref}
  31. }
  32. return img, nil
  33. }
  34. return nil, ErrImageDoesNotExist{ref}
  35. }

1.2) daemon/create.go#Daemon.create

  1. // Create creates a new container from the given configuration with a given name.
  2. func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (retC *container.Container, retErr error) {
  3. var (
  4. container *container.Container
  5. img *image.Image
  6. imgID image.ID
  7. err error
  8. )
  9. os := runtime.GOOS
  10. if params.Config.Image != "" {
  11. img, err = daemon.imageService.GetImage(params.Config.Image)
  12. if err != nil {
  13. return nil, err
  14. }
  15. if img.OS != "" {
  16. os = img.OS
  17. } else {
  18. // default to the host OS except on Windows with LCOW
  19. if runtime.GOOS == "windows" && system.LCOWSupported() {
  20. os = "linux"
  21. }
  22. }
  23. imgID = img.ID()
  24. if runtime.GOOS == "windows" && img.OS == "linux" && !system.LCOWSupported() {
  25. return nil, errors.New("operating system on which parent image was created is not Windows")
  26. }
  27. } else {
  28. if runtime.GOOS == "windows" {
  29. os = "linux" // 'scratch' case.
  30. }
  31. }
  32. if err := daemon.mergeAndVerifyConfig(params.Config, img); err != nil {
  33. return nil, errdefs.InvalidParameter(err)
  34. }
  35. if err := daemon.mergeAndVerifyLogConfig(&params.HostConfig.LogConfig); err != nil {
  36. return nil, errdefs.InvalidParameter(err)
  37. }
  38. // ********************************** NOTICE ********************************** //
  39. if container, err = daemon.newContainer(params.Name, os, params.Config, params.HostConfig, imgID, managed); err != nil {
  40. // ********************************** NOTICE ********************************** //
  41. return nil, err
  42. }
  43. defer func() {
  44. if retErr != nil {
  45. if err := daemon.cleanupContainer(container, true, true); err != nil {
  46. logrus.Errorf("failed to cleanup container on create error: %v", err)
  47. }
  48. }
  49. }()
  50. if err := daemon.setSecurityOptions(container, params.HostConfig); err != nil {
  51. return nil, err
  52. }
  53. container.HostConfig.StorageOpt = params.HostConfig.StorageOpt
  54. // Fixes: https://github.com/moby/moby/issues/34074 and
  55. // https://github.com/docker/for-win/issues/999.
  56. // Merge the daemon's storage options if they aren't already present. We only
  57. // do this on Windows as there's no effective sandbox size limit other than
  58. // physical on Linux.
  59. if runtime.GOOS == "windows" {
  60. if container.HostConfig.StorageOpt == nil {
  61. container.HostConfig.StorageOpt = make(map[string]string)
  62. }
  63. for _, v := range daemon.configStore.GraphOptions {
  64. opt := strings.SplitN(v, "=", 2)
  65. if _, ok := container.HostConfig.StorageOpt[opt[0]]; !ok {
  66. container.HostConfig.StorageOpt[opt[0]] = opt[1]
  67. }
  68. }
  69. }
  70. // Set RWLayer for container after mount labels have been set
  71. rwLayer, err := daemon.imageService.CreateLayer(container, setupInitLayer(daemon.idMapping))
  72. if err != nil {
  73. return nil, errdefs.System(err)
  74. }
  75. container.RWLayer = rwLayer
  76. rootIDs := daemon.idMapping.RootPair()
  77. if err := idtools.MkdirAndChown(container.Root, 0700, rootIDs); err != nil {
  78. return nil, err
  79. }
  80. if err := idtools.MkdirAndChown(container.CheckpointDir(), 0700, rootIDs); err != nil {
  81. return nil, err
  82. }
  83. if err := daemon.setHostConfig(container, params.HostConfig); err != nil {
  84. return nil, err
  85. }
  86. if err := daemon.createContainerOSSpecificSettings(container, params.Config, params.HostConfig); err != nil {
  87. return nil, err
  88. }
  89. var endpointsConfigs map[string]*networktypes.EndpointSettings
  90. if params.NetworkingConfig != nil {
  91. endpointsConfigs = params.NetworkingConfig.EndpointsConfig
  92. }
  93. // Make sure NetworkMode has an acceptable value. We do this to ensure
  94. // backwards API compatibility.
  95. runconfig.SetDefaultNetModeIfBlank(container.HostConfig)
  96. daemon.updateContainerNetworkSettings(container, endpointsConfigs)
  97. // ********************************** NOTICE ********************************** //
  98. if err := daemon.Register(container); err != nil {
  99. // ********************************** NOTICE ********************************** //
  100. return nil, err
  101. }
  102. stateCtr.set(container.ID, "stopped")
  103. daemon.LogContainerEvent(container, "create")
  104. return container, nil
  105. }

1.2.1) daemon/container.go#Daemon.newContainer

  1. func (daemon *Daemon) newContainer(name string, operatingSystem string, config *containertypes.Config, hostConfig *containertypes.HostConfig, imgID image.ID, managed bool) (*container.Container, error) {
  2. var (
  3. id string
  4. err error
  5. noExplicitName = name == ""
  6. )
  7. id, name, err = daemon.generateIDAndName(name)
  8. if err != nil {
  9. return nil, err
  10. }
  11. if hostConfig.NetworkMode.IsHost() {
  12. if config.Hostname == "" {
  13. config.Hostname, err = os.Hostname()
  14. if err != nil {
  15. return nil, errdefs.System(err)
  16. }
  17. }
  18. } else {
  19. daemon.generateHostname(id, config)
  20. }
  21. entrypoint, args := daemon.getEntrypointAndArgs(config.Entrypoint, config.Cmd)
  22. // ********************************** NOTICE ********************************** //
  23. base := daemon.newBaseContainer(id)
  24. // ********************************** NOTICE ********************************** //
  25. base.Created = time.Now().UTC()
  26. base.Managed = managed
  27. base.Path = entrypoint
  28. base.Args = args //FIXME: de-duplicate from config
  29. base.Config = config
  30. base.HostConfig = &containertypes.HostConfig{}
  31. base.ImageID = imgID
  32. base.NetworkSettings = &network.Settings{IsAnonymousEndpoint: noExplicitName}
  33. base.Name = name
  34. base.Driver = daemon.imageService.GraphDriverForOS(operatingSystem)
  35. base.OS = operatingSystem
  36. return base, err
  37. }
  38. // newBaseContainer creates a new container with its initial
  39. // configuration based on the root storage from the daemon.
  40. func (daemon *Daemon) newBaseContainer(id string) *container.Container {
  41. // ********************************** NOTICE ********************************** //
  42. return container.NewBaseContainer(id, daemon.containerRoot(id))
  43. // ********************************** NOTICE ********************************** //
  44. }
  45. // NewBaseContainer creates a new container with its
  46. // basic configuration.
  47. func NewBaseContainer(id, root string) *Container {
  48. return &Container{
  49. ID: id,
  50. State: NewState(),
  51. ExecCommands: exec.NewStore(),
  52. Root: root,
  53. MountPoints: make(map[string]*volumemounts.MountPoint),
  54. StreamConfig: stream.NewConfig(),
  55. attachContext: &attachContext{},
  56. }
  57. }

1.2.2) daemon/container.go#Daemon.Register

  1. // Register makes a container object usable by the daemon as <container.ID>
  2. func (daemon *Daemon) Register(c *container.Container) error {
  3. // Attach to stdout and stderr
  4. if c.Config.OpenStdin {
  5. c.StreamConfig.NewInputPipes()
  6. } else {
  7. c.StreamConfig.NewNopInputPipe()
  8. }
  9. // once in the memory store it is visible to other goroutines
  10. // grab a Lock until it has been checkpointed to avoid races
  11. c.Lock()
  12. defer c.Unlock()
  13. // ********************************** NOTICE ********************************** //
  14. daemon.containers.Add(c.ID, c)
  15. daemon.idIndex.Add(c.ID)
  16. // ********************************** NOTICE ********************************** //
  17. return c.CheckpointTo(daemon.containersReplica)
  18. }

1.2.2.1) container/memory_store.go#memoryStore.Add

  1. // Store defines an interface that
  2. // any container store must implement.
  3. type Store interface {
  4. // Add appends a new container to the store.
  5. Add(string, *Container)
  6. // Get returns a container from the store by the identifier it was stored with.
  7. Get(string) *Container
  8. // Delete removes a container from the store by the identifier it was stored with.
  9. Delete(string)
  10. // List returns a list of containers from the store.
  11. List() []*Container
  12. // Size returns the number of containers in the store.
  13. Size() int
  14. // First returns the first container found in the store by a given filter.
  15. First(StoreFilter) *Container
  16. // ApplyAll calls the reducer function with every container in the store.
  17. ApplyAll(StoreReducer)
  18. }
  1. // memoryStore implements a Store in memory.
  2. type memoryStore struct {
  3. s map[string]*Container
  4. sync.RWMutex
  5. }
  6. // Add appends a new container to the memory store.
  7. // It overrides the id if it existed before.
  8. func (c *memoryStore) Add(id string, cont *Container) {
  9. c.Lock()
  10. c.s[id] = cont
  11. c.Unlock()
  12. }