运行时文件/var/lib/docker

├── aufs/
│ ├── diff/
│ │ ├── 3e5dad646755b80ceeb2776db26d93cd8b2a45b66c670173eb0a5def51b27a26/
│ │ ├── 890f6393af02ab70fac8d9de2e9d37b92fc0a461d72bf3a17b73e1f809e1b01a/
│ │ ├── 9f2849b92cad358be0cfc0cbada718203184791d8b9dc4d02fb966ab7ef7f703/
│ │ ├── 9f2849b92cad358be0cfc0cbada718203184791d8b9dc4d02fb966ab7ef7f703-init/
│ │ ├── b2fe7fefbb164b8a8adb84273b94eeccc6794c231fc3958bc98a35cc72225cbb/
│ │ ├── d0ff844478a02c0f0544115e77626cf4f0c4a7996a6a6764eea2a2dd29201910/
│ │ └── d0ff844478a02c0f0544115e77626cf4f0c4a7996a6a6764eea2a2dd29201910-init/
│ ├── layers/
│ │ ├── 3e5dad646755b80ceeb2776db26d93cd8b2a45b66c670173eb0a5def51b27a26
│ │ ├── 890f6393af02ab70fac8d9de2e9d37b92fc0a461d72bf3a17b73e1f809e1b01a
│ │ ├── 9f2849b92cad358be0cfc0cbada718203184791d8b9dc4d02fb966ab7ef7f703
│ │ ├── 9f2849b92cad358be0cfc0cbada718203184791d8b9dc4d02fb966ab7ef7f703-init
│ │ ├── b2fe7fefbb164b8a8adb84273b94eeccc6794c231fc3958bc98a35cc72225cbb
│ │ ├── d0ff844478a02c0f0544115e77626cf4f0c4a7996a6a6764eea2a2dd29201910
│ │ └── d0ff844478a02c0f0544115e77626cf4f0c4a7996a6a6764eea2a2dd29201910-init
│ └── mnt/
│ ├── 3e5dad646755b80ceeb2776db26d93cd8b2a45b66c670173eb0a5def51b27a26/
│ ├── 890f6393af02ab70fac8d9de2e9d37b92fc0a461d72bf3a17b73e1f809e1b01a/
│ ├── 9f2849b92cad358be0cfc0cbada718203184791d8b9dc4d02fb966ab7ef7f703/
│ ├── 9f2849b92cad358be0cfc0cbada718203184791d8b9dc4d02fb966ab7ef7f703-init/
│ ├── b2fe7fefbb164b8a8adb84273b94eeccc6794c231fc3958bc98a35cc72225cbb/
│ ├── d0ff844478a02c0f0544115e77626cf4f0c4a7996a6a6764eea2a2dd29201910/
│ └── d0ff844478a02c0f0544115e77626cf4f0c4a7996a6a6764eea2a2dd29201910-init/
├── builder/
│ └── fscache.db
├── buildkit/
│ ├── content/
│ │ └── ingest/
│ ├── executor/
│ ├── cache.db
│ ├── metadata.db
│ └── snapshots.db
├── containerd/
│ └── daemon/
│ ├── io.containerd.content.v1.content/
│ ├── io.containerd.metadata.v1.bolt/
│ ├── io.containerd.runtime.v1.linux/
│ ├── io.containerd.runtime.v2.task/
│ ├── io.containerd.snapshotter.v1.btrfs/
│ ├── io.containerd.snapshotter.v1.native/
│ ├── io.containerd.snapshotter.v1.overlayfs/
│ └── tmpmounts/
├── containers/
│ ├── a8205034ae074d1fbc73327fa348ffaac3a1568d6a3de1953aeb49ea99dcfdb0/
│ │ ├── checkpoints/
│ │ ├── mounts/
│ │ ├── a8205034ae074d1fbc73327fa348ffaac3a1568d6a3de1953aeb49ea99dcfdb0-json.log
│ │ ├── config.v2.json
│ │ ├── hostconfig.json
│ │ ├── hostname
│ │ ├── hosts
│ │ ├── resolv.conf
│ │ └── resolv.conf.hash
│ └── bf1b6932346bfd4793f4ebea51ca7a0ce5d460620b07bea3b3a6e1beb9e502b8/
│ ├── checkpoints/
│ ├── mounts/
│ ├── bf1b6932346bfd4793f4ebea51ca7a0ce5d460620b07bea3b3a6e1beb9e502b8-json.log
│ ├── config.v2.json
│ ├── hostconfig.json
│ ├── hostname
│ ├── hosts
│ ├── resolv.conf
│ └── resolv.conf.hash
├── image/
│ ├── aufs/
│ │ ├── distribution/
│ │ ├── imagedb/
│ │ ├── layerdb/
│ │ └── repositories.json
│ └── overlay/
│ ├── distribution/
│ ├── imagedb/
│ ├── layerdb/
│ └── repositories.json
├── network/
│ └── files/
│ └── local-kv.db
├── overlay/
├── plugins/
│ ├── storage/
│ │ └── blobs/
│ └── tmp/
├── runtimes/
├── swarm/
├── tmp/
├── trust/
└── volumes/
└── metadata.db

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

  1. func (s *containerRouter) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  2. // If contentLength is -1, we can assumed chunked encoding
  3. // or more technically that the length is unknown
  4. // https://golang.org/src/pkg/net/http/request.go#L139
  5. // net/http otherwise seems to swallow any headers related to chunked encoding
  6. // including r.TransferEncoding
  7. // allow a nil body for backwards compatibility
  8. version := httputils.VersionFromContext(ctx)
  9. var hostConfig *container.HostConfig
  10. // A non-nil json object is at least 7 characters.
  11. if r.ContentLength > 7 || r.ContentLength == -1 {
  12. if versions.GreaterThanOrEqualTo(version, "1.24") {
  13. return bodyOnStartError{}
  14. }
  15. if err := httputils.CheckForJSON(r); err != nil {
  16. return err
  17. }
  18. c, err := s.decoder.DecodeHostConfig(r.Body)
  19. if err != nil {
  20. return err
  21. }
  22. hostConfig = c
  23. }
  24. if err := httputils.ParseForm(r); err != nil {
  25. return err
  26. }
  27. checkpoint := r.Form.Get("checkpoint")
  28. checkpointDir := r.Form.Get("checkpoint-dir")
  29. // ********************************** NOTICE ********************************** //
  30. if err := s.backend.ContainerStart(vars["name"], hostConfig, checkpoint, checkpointDir); err != nil {
  31. // ********************************** NOTICE ********************************** //
  32. return err
  33. }
  34. w.WriteHeader(http.StatusNoContent)
  35. return nil
  36. }

1) daemon/start.go#Daemon.ContainerStart

  1. // ContainerStart starts a container.
  2. func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.HostConfig, checkpoint string, checkpointDir string) error {
  3. if checkpoint != "" && !daemon.HasExperimental() {
  4. return errdefs.InvalidParameter(errors.New("checkpoint is only supported in experimental mode"))
  5. }
  6. // ********************************** NOTICE ********************************** //
  7. container, err := daemon.GetContainer(name)
  8. // ********************************** NOTICE ********************************** //
  9. if err != nil {
  10. return err
  11. }
  12. validateState := func() error {
  13. container.Lock()
  14. defer container.Unlock()
  15. if container.Paused {
  16. return errdefs.Conflict(errors.New("cannot start a paused container, try unpause instead"))
  17. }
  18. if container.Running {
  19. return containerNotModifiedError{running: true}
  20. }
  21. if container.RemovalInProgress || container.Dead {
  22. return errdefs.Conflict(errors.New("container is marked for removal and cannot be started"))
  23. }
  24. return nil
  25. }
  26. if err := validateState(); err != nil {
  27. return err
  28. }
  29. // Windows does not have the backwards compatibility issue here.
  30. if runtime.GOOS != "windows" {
  31. // This is kept for backward compatibility - hostconfig should be passed when
  32. // creating a container, not during start.
  33. if hostConfig != nil {
  34. logrus.Warn("DEPRECATED: Setting host configuration options when the container starts is deprecated and has been removed in Docker 1.12")
  35. oldNetworkMode := container.HostConfig.NetworkMode
  36. if err := daemon.setSecurityOptions(container, hostConfig); err != nil {
  37. return errdefs.InvalidParameter(err)
  38. }
  39. if err := daemon.mergeAndVerifyLogConfig(&hostConfig.LogConfig); err != nil {
  40. return errdefs.InvalidParameter(err)
  41. }
  42. if err := daemon.setHostConfig(container, hostConfig); err != nil {
  43. return errdefs.InvalidParameter(err)
  44. }
  45. newNetworkMode := container.HostConfig.NetworkMode
  46. if string(oldNetworkMode) != string(newNetworkMode) {
  47. // if user has change the network mode on starting, clean up the
  48. // old networks. It is a deprecated feature and has been removed in Docker 1.12
  49. container.NetworkSettings.Networks = nil
  50. if err := container.CheckpointTo(daemon.containersReplica); err != nil {
  51. return errdefs.System(err)
  52. }
  53. }
  54. container.InitDNSHostConfig()
  55. }
  56. } else {
  57. if hostConfig != nil {
  58. return errdefs.InvalidParameter(errors.New("Supplying a hostconfig on start is not supported. It should be supplied on create"))
  59. }
  60. }
  61. // check if hostConfig is in line with the current system settings.
  62. // It may happen cgroups are umounted or the like.
  63. if _, err = daemon.verifyContainerSettings(container.OS, container.HostConfig, nil, false); err != nil {
  64. return errdefs.InvalidParameter(err)
  65. }
  66. // Adapt for old containers in case we have updates in this function and
  67. // old containers never have chance to call the new function in create stage.
  68. if hostConfig != nil {
  69. if err := daemon.adaptContainerSettings(container.HostConfig, false); err != nil {
  70. return errdefs.InvalidParameter(err)
  71. }
  72. }
  73. // ********************************** NOTICE ********************************** //
  74. return daemon.containerStart(container, checkpoint, checkpointDir, true)
  75. // ********************************** NOTICE ********************************** //
  76. }

1.1) daemon/container.go#Daemon.GetContainer

  1. func (daemon *Daemon) GetContainer(prefixOrName string) (*container.Container, error) {
  2. if len(prefixOrName) == 0 {
  3. return nil, errors.WithStack(invalidIdentifier(prefixOrName))
  4. }
  5. if containerByID := daemon.containers.Get(prefixOrName); containerByID != nil {
  6. // prefix is an exact match to a full container ID
  7. return containerByID, nil
  8. }
  9. // GetByName will match only an exact name provided; we ignore errors
  10. if containerByName, _ := daemon.GetByName(prefixOrName); containerByName != nil {
  11. // prefix is an exact match to a full container Name
  12. return containerByName, nil
  13. }
  14. containerID, indexError := daemon.idIndex.Get(prefixOrName)
  15. if indexError != nil {
  16. // When truncindex defines an error type, use that instead
  17. if indexError == truncindex.ErrNotExist {
  18. return nil, containerNotFound(prefixOrName)
  19. }
  20. return nil, errdefs.System(indexError)
  21. }
  22. // ********************************** NOTICE ********************************** //
  23. return daemon.containers.Get(containerID), nil
  24. // ********************************** NOTICE ********************************** //
  25. }

1.2) daemon/start.go#Daemon.containerStart

  1. func (daemon *Daemon) containerStart(container *container.Container, checkpoint string, checkpointDir string, resetRestartManager bool) (err error) {
  2. start := time.Now()
  3. container.Lock()
  4. defer container.Unlock()
  5. if resetRestartManager && container.Running { // skip this check if already in restarting step and resetRestartManager==false
  6. return nil
  7. }
  8. if container.RemovalInProgress || container.Dead {
  9. return errdefs.Conflict(errors.New("container is marked for removal and cannot be started"))
  10. }
  11. if checkpointDir != "" {
  12. // TODO(mlaventure): how would we support that?
  13. return errdefs.Forbidden(errors.New("custom checkpointdir is not supported"))
  14. }
  15. // if we encounter an error during start we need to ensure that any other
  16. // setup has been cleaned up properly
  17. defer func() {
  18. if err != nil {
  19. container.SetError(err)
  20. // if no one else has set it, make sure we don't leave it at zero
  21. if container.ExitCode() == 0 {
  22. container.SetExitCode(128)
  23. }
  24. if err := container.CheckpointTo(daemon.containersReplica); err != nil {
  25. logrus.Errorf("%s: failed saving state on start failure: %v", container.ID, err)
  26. }
  27. container.Reset(false)
  28. daemon.Cleanup(container)
  29. // if containers AutoRemove flag is set, remove it after clean up
  30. if container.HostConfig.AutoRemove {
  31. container.Unlock()
  32. if err := daemon.ContainerRm(container.ID, &types.ContainerRmConfig{ForceRemove: true, RemoveVolume: true}); err != nil {
  33. logrus.Errorf("can't remove container %s: %v", container.ID, err)
  34. }
  35. container.Lock()
  36. }
  37. }
  38. }()
  39. if err := daemon.conditionalMountOnStart(container); err != nil {
  40. return err
  41. }
  42. // ********************************** NOTICE ********************************** //
  43. if err := daemon.initializeNetworking(container); err != nil {
  44. // ********************************** NOTICE ********************************** //
  45. return err
  46. }
  47. // ********************************** NOTICE ********************************** //
  48. spec, err := daemon.createSpec(container)
  49. // ********************************** NOTICE ********************************** //
  50. if err != nil {
  51. return errdefs.System(err)
  52. }
  53. if resetRestartManager {
  54. container.ResetRestartManager(true)
  55. container.HasBeenManuallyStopped = false
  56. }
  57. if daemon.saveApparmorConfig(container); err != nil {
  58. return err
  59. }
  60. if checkpoint != "" {
  61. checkpointDir, err = getCheckpointDir(checkpointDir, checkpoint, container.Name, container.ID, container.CheckpointDir(), false)
  62. if err != nil {
  63. return err
  64. }
  65. }
  66. createOptions, err := daemon.getLibcontainerdCreateOptions(container)
  67. if err != nil {
  68. return err
  69. }
  70. // ********************************** NOTICE ********************************** //
  71. err = daemon.containerd.Create(context.Background(), container.ID, spec, createOptions)
  72. // ********************************** NOTICE ********************************** //
  73. if err != nil {
  74. return translateContainerdStartErr(container.Path, container.SetExitCode, err)
  75. }
  76. // TODO(mlaventure): we need to specify checkpoint options here
  77. // ********************************** NOTICE ********************************** //
  78. pid, err := daemon.containerd.Start(context.Background(), container.ID, checkpointDir,
  79. container.StreamConfig.Stdin() != nil || container.Config.Tty,
  80. container.InitializeStdio)
  81. // ********************************** NOTICE ********************************** //
  82. if err != nil {
  83. if err := daemon.containerd.Delete(context.Background(), container.ID); err != nil {
  84. logrus.WithError(err).WithField("container", container.ID).
  85. Error("failed to delete failed start container")
  86. }
  87. return translateContainerdStartErr(container.Path, container.SetExitCode, err)
  88. }
  89. container.SetRunning(pid, true)
  90. container.HasBeenStartedBefore = true
  91. daemon.setStateCounter(container)
  92. daemon.initHealthMonitor(container)
  93. if err := container.CheckpointTo(daemon.containersReplica); err != nil {
  94. logrus.WithError(err).WithField("container", container.ID).
  95. Errorf("failed to store container")
  96. }
  97. daemon.LogContainerEvent(container, "start")
  98. containerActions.WithValues("start").UpdateSince(start)
  99. return nil
  100. }

1.2.1) daemon/container_operations.go#Daemon.initializingNetworking

  1. func (daemon *Daemon) initializeNetworking(container *container.Container) error {
  2. var err error
  3. // container模式
  4. if container.HostConfig.NetworkMode.IsContainer() {
  5. // we need to get the hosts files from the container to join
  6. nc, err := daemon.getNetworkedContainer(container.ID, container.HostConfig.NetworkMode.ConnectedContainer())
  7. if err != nil {
  8. return err
  9. }
  10. err = daemon.initializeNetworkingPaths(container, nc)
  11. if err != nil {
  12. return err
  13. }
  14. container.Config.Hostname = nc.Config.Hostname
  15. container.Config.Domainname = nc.Config.Domainname
  16. return nil
  17. }
  18. // host模式
  19. if container.HostConfig.NetworkMode.IsHost() {
  20. if container.Config.Hostname == "" {
  21. container.Config.Hostname, err = os.Hostname()
  22. if err != nil {
  23. return err
  24. }
  25. }
  26. }
  27. // 其他模式,包括bridge和none
  28. // ********************************** NOTICE ********************************** //
  29. if err := daemon.allocateNetwork(container); err != nil {
  30. // ********************************** NOTICE ********************************** //
  31. return err
  32. }
  33. // ********************************** NOTICE ********************************** //
  34. return container.BuildHostnameFile()
  35. // ********************************** NOTICE ********************************** //
  36. }

1.2.1.1) daemon/container_operations.go#Daemon.allocateNetwork

  1. func (daemon *Daemon) allocateNetwork(container *container.Container) error {
  2. start := time.Now()
  3. controller := daemon.netController
  4. if daemon.netController == nil {
  5. return nil
  6. }
  7. // Cleanup any stale sandbox left over due to ungraceful daemon shutdown
  8. if err := controller.SandboxDestroy(container.ID); err != nil {
  9. logrus.Errorf("failed to cleanup up stale network sandbox for container %s", container.ID)
  10. }
  11. if container.Config.NetworkDisabled || container.HostConfig.NetworkMode.IsContainer() {
  12. return nil
  13. }
  14. updateSettings := false
  15. if len(container.NetworkSettings.Networks) == 0 {
  16. // ********************************** NOTICE ********************************** //
  17. daemon.updateContainerNetworkSettings(container, nil)
  18. // ********************************** NOTICE ********************************** //
  19. updateSettings = true
  20. }
  21. // 如果有bridge网络,那么连接即可(默认是有的)
  22. // always connect default network first since only default
  23. // network mode support link and we need do some setting
  24. // on sandbox initialize for link, but the sandbox only be initialized
  25. // on first network connecting.
  26. defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
  27. if nConf, ok := container.NetworkSettings.Networks[defaultNetName]; ok {
  28. cleanOperationalData(nConf)
  29. // ********************************** NOTICE ********************************** //
  30. if err := daemon.connectToNetwork(container, defaultNetName, nConf.EndpointSettings, updateSettings); err != nil {
  31. // ********************************** NOTICE ********************************** //
  32. return err
  33. }
  34. }
  35. // 下面不用看了
  36. // the intermediate map is necessary because "connectToNetwork" modifies "container.NetworkSettings.Networks"
  37. networks := make(map[string]*network.EndpointSettings)
  38. for n, epConf := range container.NetworkSettings.Networks {
  39. if n == defaultNetName {
  40. continue
  41. }
  42. networks[n] = epConf
  43. }
  44. for netName, epConf := range networks {
  45. cleanOperationalData(epConf)
  46. if err := daemon.connectToNetwork(container, netName, epConf.EndpointSettings, updateSettings); err != nil {
  47. return err
  48. }
  49. }
  50. // If the container is not to be connected to any network,
  51. // create its network sandbox now if not present
  52. if len(networks) == 0 {
  53. if nil == daemon.getNetworkSandbox(container) {
  54. options, err := daemon.buildSandboxOptions(container)
  55. if err != nil {
  56. return err
  57. }
  58. sb, err := daemon.netController.NewSandbox(container.ID, options...)
  59. if err != nil {
  60. return err
  61. }
  62. updateSandboxNetworkSettings(container, sb)
  63. defer func() {
  64. if err != nil {
  65. sb.Delete()
  66. }
  67. }()
  68. }
  69. }
  70. // ********************************** NOTICE ********************************** //
  71. if _, err := container.WriteHostConfig(); err != nil {
  72. // ********************************** NOTICE ********************************** //
  73. return err
  74. }
  75. networkActions.WithValues("allocate").UpdateSince(start)
  76. return nil
  77. }

—1.2.1.1.1) daemon/container_operations.go#Daemon.updateContainerNetworkSettings

  1. // updateContainerNetworkSettings updates the network settings
  2. // 第二个参数为nil
  3. func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) {
  4. var n libnetwork.Network
  5. mode := container.HostConfig.NetworkMode
  6. if container.Config.NetworkDisabled || mode.IsContainer() {
  7. return
  8. }
  9. networkName := mode.NetworkName()
  10. if mode.IsDefault() {
  11. // ********************************** NOTICE ********************************** //
  12. networkName = daemon.netController.Config().Daemon.DefaultNetwork
  13. // ********************************** NOTICE ********************************** //
  14. }
  15. if mode.IsUserDefined() {
  16. var err error
  17. n, err = daemon.FindNetwork(networkName)
  18. if err == nil {
  19. networkName = n.Name()
  20. }
  21. }
  22. if container.NetworkSettings == nil {
  23. container.NetworkSettings = &network.Settings{}
  24. }
  25. if len(endpointsConfig) > 0 {
  26. if container.NetworkSettings.Networks == nil {
  27. container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
  28. }
  29. for name, epConfig := range endpointsConfig {
  30. container.NetworkSettings.Networks[name] = &network.EndpointSettings{
  31. EndpointSettings: epConfig,
  32. }
  33. }
  34. }
  35. if container.NetworkSettings.Networks == nil {
  36. // ********************************** NOTICE ********************************** //
  37. container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
  38. // ********************************** NOTICE ********************************** //
  39. container.NetworkSettings.Networks[networkName] = &network.EndpointSettings{
  40. EndpointSettings: &networktypes.EndpointSettings{},
  41. }
  42. }
  43. // Convert any settings added by client in default name to
  44. // engine's default network name key
  45. if mode.IsDefault() {
  46. if nConf, ok := container.NetworkSettings.Networks[mode.NetworkName()]; ok {
  47. container.NetworkSettings.Networks[networkName] = nConf
  48. delete(container.NetworkSettings.Networks, mode.NetworkName())
  49. }
  50. }
  51. if !mode.IsUserDefined() {
  52. return
  53. }
  54. // Make sure to internally store the per network endpoint config by network name
  55. if _, ok := container.NetworkSettings.Networks[networkName]; ok {
  56. return
  57. }
  58. if n != nil {
  59. if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok {
  60. container.NetworkSettings.Networks[networkName] = nwConfig
  61. delete(container.NetworkSettings.Networks, n.ID())
  62. return
  63. }
  64. }
  65. }

—1.2.1.1.2) daemon/container_operations.go#Daemon.connectToNetwork

  1. func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
  2. start := time.Now()
  3. if container.HostConfig.NetworkMode.IsContainer() {
  4. return runconfig.ErrConflictSharedNetwork
  5. }
  6. if containertypes.NetworkMode(idOrName).IsBridge() &&
  7. daemon.configStore.DisableBridge {
  8. container.Config.NetworkDisabled = true
  9. return nil
  10. }
  11. if endpointConfig == nil {
  12. endpointConfig = &networktypes.EndpointSettings{}
  13. }
  14. // ********************************** NOTICE ********************************** //
  15. n, config, err := daemon.findAndAttachNetwork(container, idOrName, endpointConfig)
  16. // ********************************** NOTICE ********************************** //
  17. if err != nil {
  18. return err
  19. }
  20. if n == nil {
  21. return nil
  22. }
  23. var operIPAM bool
  24. if config != nil {
  25. if epConfig, ok := config.EndpointsConfig[n.Name()]; ok {
  26. if endpointConfig.IPAMConfig == nil ||
  27. (endpointConfig.IPAMConfig.IPv4Address == "" &&
  28. endpointConfig.IPAMConfig.IPv6Address == "" &&
  29. len(endpointConfig.IPAMConfig.LinkLocalIPs) == 0) {
  30. operIPAM = true
  31. }
  32. // copy IPAMConfig and NetworkID from epConfig via AttachNetwork
  33. endpointConfig.IPAMConfig = epConfig.IPAMConfig
  34. endpointConfig.NetworkID = epConfig.NetworkID
  35. }
  36. }
  37. err = daemon.updateNetworkConfig(container, n, endpointConfig, updateSettings)
  38. if err != nil {
  39. return err
  40. }
  41. controller := daemon.netController
  42. // ********************************** NOTICE ********************************** //
  43. sb := daemon.getNetworkSandbox(container)
  44. // ********************************** NOTICE ********************************** //
  45. createOptions, err := buildCreateEndpointOptions(container, n, endpointConfig, sb, daemon.configStore.DNS)
  46. // ********************************** NOTICE ********************************** //
  47. if err != nil {
  48. return err
  49. }
  50. endpointName := strings.TrimPrefix(container.Name, "/")
  51. // ********************************** NOTICE ********************************** //
  52. ep, err := n.CreateEndpoint(endpointName, createOptions...)
  53. // ********************************** NOTICE ********************************** //
  54. if err != nil {
  55. return err
  56. }
  57. defer func() {
  58. if err != nil {
  59. if e := ep.Delete(false); e != nil {
  60. logrus.Warnf("Could not rollback container connection to network %s", idOrName)
  61. }
  62. }
  63. }()
  64. container.NetworkSettings.Networks[n.Name()] = &network.EndpointSettings{
  65. EndpointSettings: endpointConfig,
  66. IPAMOperational: operIPAM,
  67. }
  68. if _, ok := container.NetworkSettings.Networks[n.ID()]; ok {
  69. delete(container.NetworkSettings.Networks, n.ID())
  70. }
  71. // ********************************** NOTICE ********************************** //
  72. if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil {
  73. // ********************************** NOTICE ********************************** //
  74. return err
  75. }
  76. if sb == nil {
  77. // ********************************** NOTICE ********************************** //
  78. options, err := daemon.buildSandboxOptions(container)
  79. // ********************************** NOTICE ********************************** //
  80. if err != nil {
  81. return err
  82. }
  83. // ********************************** NOTICE ********************************** //
  84. sb, err = controller.NewSandbox(container.ID, options...)
  85. // ********************************** NOTICE ********************************** //
  86. if err != nil {
  87. return err
  88. }
  89. // ********************************** NOTICE ********************************** //
  90. updateSandboxNetworkSettings(container, sb)
  91. // ********************************** NOTICE ********************************** //
  92. }
  93. // ********************************** NOTICE ********************************** //
  94. joinOptions, err := buildJoinOptions(container.NetworkSettings, n)
  95. // ********************************** NOTICE ********************************** //
  96. if err != nil {
  97. return err
  98. }
  99. // ********************************** NOTICE ********************************** //
  100. if err := ep.Join(sb, joinOptions...); err != nil {
  101. // ********************************** NOTICE ********************************** //
  102. return err
  103. }
  104. if !container.Managed {
  105. // add container name/alias to DNS
  106. if err := daemon.ActivateContainerServiceBinding(container.Name); err != nil {
  107. return fmt.Errorf("Activate container service binding for %s failed: %v", container.Name, err)
  108. }
  109. }
  110. if err := updateJoinInfo(container.NetworkSettings, n, ep); err != nil {
  111. return fmt.Errorf("Updating join info failed: %v", err)
  112. }
  113. container.NetworkSettings.Ports = getPortMapInfo(sb)
  114. daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID})
  115. networkActions.WithValues("connect").UpdateSince(start)
  116. return nil
  117. }

——1.2.1.1.2.1) daemon/container_operations.go#findAndAttachNetwork

  1. func (daemon *Daemon) findAndAttachNetwork(container *container.Container, idOrName string, epConfig *networktypes.EndpointSettings) (libnetwork.Network, *networktypes.NetworkingConfig, error) {
  2. id := getNetworkID(idOrName, epConfig)
  3. n, err := daemon.FindNetwork(id)
  4. if err != nil {
  5. // We should always be able to find the network for a
  6. // managed container.
  7. if container.Managed {
  8. return nil, nil, err
  9. }
  10. }
  11. // If we found a network and if it is not dynamically created
  12. // we should never attempt to attach to that network here.
  13. if n != nil {
  14. if container.Managed || !n.Info().Dynamic() {
  15. return n, nil, nil
  16. }
  17. }
  18. var addresses []string
  19. if epConfig != nil && epConfig.IPAMConfig != nil {
  20. if epConfig.IPAMConfig.IPv4Address != "" {
  21. addresses = append(addresses, epConfig.IPAMConfig.IPv4Address)
  22. }
  23. if epConfig.IPAMConfig.IPv6Address != "" {
  24. addresses = append(addresses, epConfig.IPAMConfig.IPv6Address)
  25. }
  26. }
  27. var (
  28. config *networktypes.NetworkingConfig
  29. retryCount int
  30. )
  31. if n == nil && daemon.attachableNetworkLock != nil {
  32. daemon.attachableNetworkLock.Lock(id)
  33. defer daemon.attachableNetworkLock.Unlock(id)
  34. }
  35. for {
  36. // In all other cases, attempt to attach to the network to
  37. // trigger attachment in the swarm cluster manager.
  38. if daemon.clusterProvider != nil {
  39. var err error
  40. config, err = daemon.clusterProvider.AttachNetwork(id, container.ID, addresses)
  41. if err != nil {
  42. return nil, nil, err
  43. }
  44. }
  45. n, err = daemon.FindNetwork(id)
  46. if err != nil {
  47. if daemon.clusterProvider != nil {
  48. if err := daemon.clusterProvider.DetachNetwork(id, container.ID); err != nil {
  49. logrus.Warnf("Could not rollback attachment for container %s to network %s: %v", container.ID, idOrName, err)
  50. }
  51. }
  52. // Retry network attach again if we failed to
  53. // find the network after successful
  54. // attachment because the only reason that
  55. // would happen is if some other container
  56. // attached to the swarm scope network went down
  57. // and removed the network while we were in
  58. // the process of attaching.
  59. if config != nil {
  60. if _, ok := err.(libnetwork.ErrNoSuchNetwork); ok {
  61. if retryCount >= 5 {
  62. return nil, nil, fmt.Errorf("could not find network %s after successful attachment", idOrName)
  63. }
  64. retryCount++
  65. continue
  66. }
  67. }
  68. return nil, nil, err
  69. }
  70. break
  71. }
  72. // This container has attachment to a swarm scope
  73. // network. Update the container network settings accordingly.
  74. container.NetworkSettings.HasSwarmEndpoint = true
  75. return n, config, nil
  76. }

——1.2.1.1.2.2) daemon/container_operations.go#Daemon.getNetworkSandbox

  1. func (daemon *Daemon) getNetworkSandbox(container *container.Container) libnetwork.Sandbox {
  2. var sb libnetwork.Sandbox
  3. daemon.netController.WalkSandboxes(func(s libnetwork.Sandbox) bool {
  4. if s.ContainerID() == container.ID {
  5. sb = s
  6. return true
  7. }
  8. return false
  9. })
  10. return sb
  11. }

——1.2.1.1.2.3) daemon/network.go#buildCreateEndpointOptions

  1. // buildCreateEndpointOptions builds endpoint options from a given network.
  2. func buildCreateEndpointOptions(c *container.Container, n libnetwork.Network, epConfig *network.EndpointSettings, sb libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) {
  3. var (
  4. bindings = make(nat.PortMap)
  5. pbList []networktypes.PortBinding
  6. exposeList []networktypes.TransportPort
  7. createOptions []libnetwork.EndpointOption
  8. )
  9. defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
  10. if (!c.EnableServiceDiscoveryOnDefaultNetwork() && n.Name() == defaultNetName) ||
  11. c.NetworkSettings.IsAnonymousEndpoint {
  12. createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
  13. }
  14. if epConfig != nil {
  15. ipam := epConfig.IPAMConfig
  16. if ipam != nil {
  17. var (
  18. ipList []net.IP
  19. ip, ip6, linkip net.IP
  20. )
  21. for _, ips := range ipam.LinkLocalIPs {
  22. if linkip = net.ParseIP(ips); linkip == nil && ips != "" {
  23. return nil, errors.Errorf("Invalid link-local IP address: %s", ipam.LinkLocalIPs)
  24. }
  25. ipList = append(ipList, linkip)
  26. }
  27. if ip = net.ParseIP(ipam.IPv4Address); ip == nil && ipam.IPv4Address != "" {
  28. return nil, errors.Errorf("Invalid IPv4 address: %s)", ipam.IPv4Address)
  29. }
  30. if ip6 = net.ParseIP(ipam.IPv6Address); ip6 == nil && ipam.IPv6Address != "" {
  31. return nil, errors.Errorf("Invalid IPv6 address: %s)", ipam.IPv6Address)
  32. }
  33. createOptions = append(createOptions,
  34. libnetwork.CreateOptionIpam(ip, ip6, ipList, nil))
  35. }
  36. for _, alias := range epConfig.Aliases {
  37. createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias))
  38. }
  39. for k, v := range epConfig.DriverOpts {
  40. createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
  41. }
  42. }
  43. if c.NetworkSettings.Service != nil {
  44. svcCfg := c.NetworkSettings.Service
  45. var vip string
  46. if svcCfg.VirtualAddresses[n.ID()] != nil {
  47. vip = svcCfg.VirtualAddresses[n.ID()].IPv4
  48. }
  49. var portConfigs []*libnetwork.PortConfig
  50. for _, portConfig := range svcCfg.ExposedPorts {
  51. portConfigs = append(portConfigs, &libnetwork.PortConfig{
  52. Name: portConfig.Name,
  53. Protocol: libnetwork.PortConfig_Protocol(portConfig.Protocol),
  54. TargetPort: portConfig.TargetPort,
  55. PublishedPort: portConfig.PublishedPort,
  56. })
  57. }
  58. createOptions = append(createOptions, libnetwork.CreateOptionService(svcCfg.Name, svcCfg.ID, net.ParseIP(vip), portConfigs, svcCfg.Aliases[n.ID()]))
  59. }
  60. if !containertypes.NetworkMode(n.Name()).IsUserDefined() {
  61. createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
  62. }
  63. // configs that are applicable only for the endpoint in the network
  64. // to which container was connected to on docker run.
  65. // Ideally all these network-specific endpoint configurations must be moved under
  66. // container.NetworkSettings.Networks[n.Name()]
  67. if n.Name() == c.HostConfig.NetworkMode.NetworkName() ||
  68. (n.Name() == defaultNetName && c.HostConfig.NetworkMode.IsDefault()) {
  69. if c.Config.MacAddress != "" {
  70. mac, err := net.ParseMAC(c.Config.MacAddress)
  71. if err != nil {
  72. return nil, err
  73. }
  74. genericOption := options.Generic{
  75. netlabel.MacAddress: mac,
  76. }
  77. createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
  78. }
  79. }
  80. // Port-mapping rules belong to the container & applicable only to non-internal networks
  81. portmaps := getSandboxPortMapInfo(sb)
  82. if n.Info().Internal() || len(portmaps) > 0 {
  83. return createOptions, nil
  84. }
  85. if c.HostConfig.PortBindings != nil {
  86. for p, b := range c.HostConfig.PortBindings {
  87. bindings[p] = []nat.PortBinding{}
  88. for _, bb := range b {
  89. bindings[p] = append(bindings[p], nat.PortBinding{
  90. HostIP: bb.HostIP,
  91. HostPort: bb.HostPort,
  92. })
  93. }
  94. }
  95. }
  96. portSpecs := c.Config.ExposedPorts
  97. ports := make([]nat.Port, len(portSpecs))
  98. var i int
  99. for p := range portSpecs {
  100. ports[i] = p
  101. i++
  102. }
  103. nat.SortPortMap(ports, bindings)
  104. for _, port := range ports {
  105. expose := networktypes.TransportPort{}
  106. expose.Proto = networktypes.ParseProtocol(port.Proto())
  107. expose.Port = uint16(port.Int())
  108. exposeList = append(exposeList, expose)
  109. pb := networktypes.PortBinding{Port: expose.Port, Proto: expose.Proto}
  110. binding := bindings[port]
  111. for i := 0; i < len(binding); i++ {
  112. pbCopy := pb.GetCopy()
  113. newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
  114. var portStart, portEnd int
  115. if err == nil {
  116. portStart, portEnd, err = newP.Range()
  117. }
  118. if err != nil {
  119. return nil, errors.Wrapf(err, "Error parsing HostPort value (%s)", binding[i].HostPort)
  120. }
  121. pbCopy.HostPort = uint16(portStart)
  122. pbCopy.HostPortEnd = uint16(portEnd)
  123. pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
  124. pbList = append(pbList, pbCopy)
  125. }
  126. if c.HostConfig.PublishAllPorts && len(binding) == 0 {
  127. pbList = append(pbList, pb)
  128. }
  129. }
  130. var dns []string
  131. if len(c.HostConfig.DNS) > 0 {
  132. dns = c.HostConfig.DNS
  133. } else if len(daemonDNS) > 0 {
  134. dns = daemonDNS
  135. }
  136. if len(dns) > 0 {
  137. createOptions = append(createOptions,
  138. libnetwork.CreateOptionDNS(dns))
  139. }
  140. createOptions = append(createOptions,
  141. libnetwork.CreateOptionPortMapping(pbList),
  142. libnetwork.CreateOptionExposedPorts(exposeList))
  143. return createOptions, nil
  144. }

——1.2.1.1.2.4) libnetwork/network.go#network.CreateEndpoint

  1. func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
  2. var err error
  3. if !config.IsValidName(name) {
  4. return nil, ErrInvalidName(name)
  5. }
  6. if n.ConfigOnly() {
  7. return nil, types.ForbiddenErrorf("cannot create endpoint on configuration-only network")
  8. }
  9. if _, err = n.EndpointByName(name); err == nil {
  10. return nil, types.ForbiddenErrorf("endpoint with name %s already exists in network %s", name, n.Name())
  11. }
  12. n.ctrlr.networkLocker.Lock(n.id)
  13. defer n.ctrlr.networkLocker.Unlock(n.id)
  14. // ********************************** NOTICE ********************************** //
  15. return n.createEndpoint(name, options...)
  16. // ********************************** NOTICE ********************************** //
  17. }
  18. func (n *network) createEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
  19. var err error
  20. ep := &endpoint{name: name, generic: make(map[string]interface{}), iface: &endpointInterface{}}
  21. ep.id = stringid.GenerateRandomID()
  22. // Initialize ep.network with a possibly stale copy of n. We need this to get network from
  23. // store. But once we get it from store we will have the most uptodate copy possibly.
  24. ep.network = n
  25. ep.locator = n.getController().clusterHostID()
  26. ep.network, err = ep.getNetworkFromStore()
  27. if err != nil {
  28. return nil, fmt.Errorf("failed to get network during CreateEndpoint: %v", err)
  29. }
  30. n = ep.network
  31. ep.processOptions(options...)
  32. for _, llIPNet := range ep.Iface().LinkLocalAddresses() {
  33. if !llIPNet.IP.IsLinkLocalUnicast() {
  34. return nil, types.BadRequestErrorf("invalid link local IP address: %v", llIPNet.IP)
  35. }
  36. }
  37. if opt, ok := ep.generic[netlabel.MacAddress]; ok {
  38. if mac, ok := opt.(net.HardwareAddr); ok {
  39. ep.iface.mac = mac
  40. }
  41. }
  42. ipam, cap, err := n.getController().getIPAMDriver(n.ipamType)
  43. if err != nil {
  44. return nil, err
  45. }
  46. if cap.RequiresMACAddress {
  47. if ep.iface.mac == nil {
  48. ep.iface.mac = netutils.GenerateRandomMAC()
  49. }
  50. if ep.ipamOptions == nil {
  51. ep.ipamOptions = make(map[string]string)
  52. }
  53. ep.ipamOptions[netlabel.MacAddress] = ep.iface.mac.String()
  54. }
  55. // ********************************** NOTICE ********************************** //
  56. if err = ep.assignAddress(ipam, true, n.enableIPv6 && !n.postIPv6); err != nil {
  57. // ********************************** NOTICE ********************************** //
  58. return nil, err
  59. }
  60. defer func() {
  61. if err != nil {
  62. ep.releaseAddress()
  63. }
  64. }()
  65. // ********************************** NOTICE ********************************** //
  66. if err = n.addEndpoint(ep); err != nil {
  67. // ********************************** NOTICE ********************************** //
  68. return nil, err
  69. }
  70. defer func() {
  71. if err != nil {
  72. if e := ep.deleteEndpoint(false); e != nil {
  73. logrus.Warnf("cleaning up endpoint failed %s : %v", name, e)
  74. }
  75. }
  76. }()
  77. // We should perform updateToStore call right after addEndpoint
  78. // in order to have iface properly configured
  79. if err = n.getController().updateToStore(ep); err != nil {
  80. return nil, err
  81. }
  82. defer func() {
  83. if err != nil {
  84. if e := n.getController().deleteFromStore(ep); e != nil {
  85. logrus.Warnf("error rolling back endpoint %s from store: %v", name, e)
  86. }
  87. }
  88. }()
  89. if err = ep.assignAddress(ipam, false, n.enableIPv6 && n.postIPv6); err != nil {
  90. return nil, err
  91. }
  92. // Watch for service records
  93. n.getController().watchSvcRecord(ep)
  94. defer func() {
  95. if err != nil {
  96. n.getController().unWatchSvcRecord(ep)
  97. }
  98. }()
  99. // Increment endpoint count to indicate completion of endpoint addition
  100. if err = n.getEpCnt().IncEndpointCnt(); err != nil {
  101. return nil, err
  102. }
  103. return ep, nil
  104. }
  105. func (n *network) addEndpoint(ep *endpoint) error {
  106. d, err := n.driver(true)
  107. if err != nil {
  108. return fmt.Errorf("failed to add endpoint: %v", err)
  109. }
  110. // ********************************** NOTICE ********************************** //
  111. err = d.CreateEndpoint(n.id, ep.id, ep.Interface(), ep.generic)
  112. // ********************************** NOTICE ********************************** //
  113. if err != nil {
  114. return types.InternalErrorf("failed to create endpoint %s on network %s: %v",
  115. ep.Name(), n.Name(), err)
  116. }
  117. return nil
  118. }

BridgeDriver

——— 1.2.1.1.2.4.1) libnetwork/drivers/bridge/bridge.go#driver.CreateEndpoint

  1. func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
  2. defer osl.InitOSContext()()
  3. if ifInfo == nil {
  4. return errors.New("invalid interface info passed")
  5. }
  6. // Get the network handler and make sure it exists
  7. d.Lock()
  8. n, ok := d.networks[nid]
  9. dconfig := d.config
  10. d.Unlock()
  11. if !ok {
  12. return types.NotFoundErrorf("network %s does not exist", nid)
  13. }
  14. if n == nil {
  15. return driverapi.ErrNoNetwork(nid)
  16. }
  17. // Sanity check
  18. n.Lock()
  19. if n.id != nid {
  20. n.Unlock()
  21. return InvalidNetworkIDError(nid)
  22. }
  23. n.Unlock()
  24. // Check if endpoint id is good and retrieve correspondent endpoint
  25. ep, err := n.getEndpoint(eid)
  26. if err != nil {
  27. return err
  28. }
  29. // Endpoint with that id exists either on desired or other sandbox
  30. if ep != nil {
  31. return driverapi.ErrEndpointExists(eid)
  32. }
  33. // Try to convert the options to endpoint configuration
  34. epConfig, err := parseEndpointOptions(epOptions)
  35. if err != nil {
  36. return err
  37. }
  38. // Create and add the endpoint
  39. n.Lock()
  40. endpoint := &bridgeEndpoint{id: eid, nid: nid, config: epConfig}
  41. n.endpoints[eid] = endpoint
  42. n.Unlock()
  43. // On failure make sure to remove the endpoint
  44. defer func() {
  45. if err != nil {
  46. n.Lock()
  47. delete(n.endpoints, eid)
  48. n.Unlock()
  49. }
  50. }()
  51. // Generate a name for what will be the host side pipe interface
  52. hostIfName, err := netutils.GenerateIfaceName(d.nlh, vethPrefix, vethLen)
  53. if err != nil {
  54. return err
  55. }
  56. // Generate a name for what will be the sandbox side pipe interface
  57. containerIfName, err := netutils.GenerateIfaceName(d.nlh, vethPrefix, vethLen)
  58. if err != nil {
  59. return err
  60. }
  61. // Generate and add the interface pipe host <-> sandbox
  62. // ********************************** NOTICE ********************************** //
  63. veth := &netlink.Veth{
  64. LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0},
  65. PeerName: containerIfName}
  66. if err = d.nlh.LinkAdd(veth); err != nil {
  67. // ********************************** NOTICE ********************************** //
  68. return types.InternalErrorf("failed to add the host (%s) <=> sandbox (%s) pair interfaces: %v", hostIfName, containerIfName, err)
  69. }
  70. // Get the host side pipe interface handler
  71. host, err := d.nlh.LinkByName(hostIfName)
  72. if err != nil {
  73. return types.InternalErrorf("failed to find host side interface %s: %v", hostIfName, err)
  74. }
  75. defer func() {
  76. if err != nil {
  77. if err := d.nlh.LinkDel(host); err != nil {
  78. logrus.WithError(err).Warnf("Failed to delete host side interface (%s)'s link", hostIfName)
  79. }
  80. }
  81. }()
  82. // Get the sandbox side pipe interface handler
  83. sbox, err := d.nlh.LinkByName(containerIfName)
  84. if err != nil {
  85. return types.InternalErrorf("failed to find sandbox side interface %s: %v", containerIfName, err)
  86. }
  87. defer func() {
  88. if err != nil {
  89. if err := d.nlh.LinkDel(sbox); err != nil {
  90. logrus.WithError(err).Warnf("Failed to delete sandbox side interface (%s)'s link", containerIfName)
  91. }
  92. }
  93. }()
  94. n.Lock()
  95. config := n.config
  96. n.Unlock()
  97. // Add bridge inherited attributes to pipe interfaces
  98. if config.Mtu != 0 {
  99. err = d.nlh.LinkSetMTU(host, config.Mtu)
  100. if err != nil {
  101. return types.InternalErrorf("failed to set MTU on host interface %s: %v", hostIfName, err)
  102. }
  103. err = d.nlh.LinkSetMTU(sbox, config.Mtu)
  104. if err != nil {
  105. return types.InternalErrorf("failed to set MTU on sandbox interface %s: %v", containerIfName, err)
  106. }
  107. }
  108. // Attach host side pipe interface into the bridge
  109. // ********************************** NOTICE ********************************** //
  110. if err = addToBridge(d.nlh, hostIfName, config.BridgeName); err != nil {
  111. // ********************************** NOTICE ********************************** //
  112. return fmt.Errorf("adding interface %s to bridge %s failed: %v", hostIfName, config.BridgeName, err)
  113. }
  114. if !dconfig.EnableUserlandProxy {
  115. err = setHairpinMode(d.nlh, host, true)
  116. if err != nil {
  117. return err
  118. }
  119. }
  120. // Store the sandbox side pipe interface parameters
  121. endpoint.srcName = containerIfName
  122. endpoint.macAddress = ifInfo.MacAddress()
  123. endpoint.addr = ifInfo.Address()
  124. endpoint.addrv6 = ifInfo.AddressIPv6()
  125. // Set the sbox's MAC if not provided. If specified, use the one configured by user, otherwise generate one based on IP.
  126. if endpoint.macAddress == nil {
  127. endpoint.macAddress = electMacAddress(epConfig, endpoint.addr.IP)
  128. if err = ifInfo.SetMacAddress(endpoint.macAddress); err != nil {
  129. return err
  130. }
  131. }
  132. // Up the host interface after finishing all netlink configuration
  133. if err = d.nlh.LinkSetUp(host); err != nil {
  134. return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err)
  135. }
  136. if endpoint.addrv6 == nil && config.EnableIPv6 {
  137. var ip6 net.IP
  138. network := n.bridge.bridgeIPv6
  139. if config.AddressIPv6 != nil {
  140. network = config.AddressIPv6
  141. }
  142. ones, _ := network.Mask.Size()
  143. if ones > 80 {
  144. err = types.ForbiddenErrorf("Cannot self generate an IPv6 address on network %v: At least 48 host bits are needed.", network)
  145. return err
  146. }
  147. ip6 = make(net.IP, len(network.IP))
  148. copy(ip6, network.IP)
  149. for i, h := range endpoint.macAddress {
  150. ip6[i+10] = h
  151. }
  152. endpoint.addrv6 = &net.IPNet{IP: ip6, Mask: network.Mask}
  153. if err = ifInfo.SetIPAddress(endpoint.addrv6); err != nil {
  154. return err
  155. }
  156. }
  157. if err = d.storeUpdate(endpoint); err != nil {
  158. return fmt.Errorf("failed to save bridge endpoint %.7s to store: %v", endpoint.id, err)
  159. }
  160. return nil
  161. }
  162. func addToBridge(nlh *netlink.Handle, ifaceName, bridgeName string) error {
  163. link, err := nlh.LinkByName(ifaceName)
  164. if err != nil {
  165. return fmt.Errorf("could not find interface %s: %v", ifaceName, err)
  166. }
  167. if err = nlh.LinkSetMaster(link,
  168. &netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: bridgeName}}); err != nil {
  169. logrus.Debugf("Failed to add %s to bridge via netlink.Trying ioctl: %v", ifaceName, err)
  170. iface, err := net.InterfaceByName(ifaceName)
  171. if err != nil {
  172. return fmt.Errorf("could not find network interface %s: %v", ifaceName, err)
  173. }
  174. master, err := net.InterfaceByName(bridgeName)
  175. if err != nil {
  176. return fmt.Errorf("could not find bridge %s: %v", bridgeName, err)
  177. }
  178. return ioctlAddToBridge(iface, master)
  179. }
  180. return nil
  181. }

——1.2.1.1.2.5) daemon/container_operations.go#Daemon.updateEndpointNetworkSettings

  1. func (daemon *Daemon) updateEndpointNetworkSettings(container *container.Container, n libnetwork.Network, ep libnetwork.Endpoint) error {
  2. if err := buildEndpointInfo(container.NetworkSettings, n, ep); err != nil {
  3. return err
  4. }
  5. if container.HostConfig.NetworkMode == runconfig.DefaultDaemonNetworkMode() {
  6. container.NetworkSettings.Bridge = daemon.configStore.BridgeConfig.Iface
  7. }
  8. return nil
  9. }

——1.2.1.1.2.6) daemon/container_operations.go#Daemon.buildSandboxOptions

  1. func (daemon *Daemon) buildSandboxOptions(container *container.Container) ([]libnetwork.SandboxOption, error) {
  2. var (
  3. sboxOptions []libnetwork.SandboxOption
  4. err error
  5. dns []string
  6. dnsOptions []string
  7. bindings = make(nat.PortMap)
  8. pbList []types.PortBinding
  9. exposeList []types.TransportPort
  10. )
  11. defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
  12. sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname),
  13. libnetwork.OptionDomainname(container.Config.Domainname))
  14. if container.HostConfig.NetworkMode.IsHost() {
  15. sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox())
  16. } else {
  17. // OptionUseExternalKey is mandatory for userns support.
  18. // But optional for non-userns support
  19. sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey())
  20. }
  21. if err = daemon.setupPathsAndSandboxOptions(container, &sboxOptions); err != nil {
  22. return nil, err
  23. }
  24. if len(container.HostConfig.DNS) > 0 {
  25. dns = container.HostConfig.DNS
  26. } else if len(daemon.configStore.DNS) > 0 {
  27. dns = daemon.configStore.DNS
  28. }
  29. for _, d := range dns {
  30. sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d))
  31. }
  32. dnsSearch := daemon.getDNSSearchSettings(container)
  33. for _, ds := range dnsSearch {
  34. sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds))
  35. }
  36. if len(container.HostConfig.DNSOptions) > 0 {
  37. dnsOptions = container.HostConfig.DNSOptions
  38. } else if len(daemon.configStore.DNSOptions) > 0 {
  39. dnsOptions = daemon.configStore.DNSOptions
  40. }
  41. for _, ds := range dnsOptions {
  42. sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds))
  43. }
  44. if container.NetworkSettings.SecondaryIPAddresses != nil {
  45. name := container.Config.Hostname
  46. if container.Config.Domainname != "" {
  47. name = name + "." + container.Config.Domainname
  48. }
  49. for _, a := range container.NetworkSettings.SecondaryIPAddresses {
  50. sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr))
  51. }
  52. }
  53. for _, extraHost := range container.HostConfig.ExtraHosts {
  54. // allow IPv6 addresses in extra hosts; only split on first ":"
  55. if _, err := opts.ValidateExtraHost(extraHost); err != nil {
  56. return nil, err
  57. }
  58. parts := strings.SplitN(extraHost, ":", 2)
  59. sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1]))
  60. }
  61. if container.HostConfig.PortBindings != nil {
  62. for p, b := range container.HostConfig.PortBindings {
  63. bindings[p] = []nat.PortBinding{}
  64. for _, bb := range b {
  65. bindings[p] = append(bindings[p], nat.PortBinding{
  66. HostIP: bb.HostIP,
  67. HostPort: bb.HostPort,
  68. })
  69. }
  70. }
  71. }
  72. portSpecs := container.Config.ExposedPorts
  73. ports := make([]nat.Port, len(portSpecs))
  74. var i int
  75. for p := range portSpecs {
  76. ports[i] = p
  77. i++
  78. }
  79. nat.SortPortMap(ports, bindings)
  80. for _, port := range ports {
  81. expose := types.TransportPort{}
  82. expose.Proto = types.ParseProtocol(port.Proto())
  83. expose.Port = uint16(port.Int())
  84. exposeList = append(exposeList, expose)
  85. pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
  86. binding := bindings[port]
  87. for i := 0; i < len(binding); i++ {
  88. pbCopy := pb.GetCopy()
  89. newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
  90. var portStart, portEnd int
  91. if err == nil {
  92. portStart, portEnd, err = newP.Range()
  93. }
  94. if err != nil {
  95. return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err)
  96. }
  97. pbCopy.HostPort = uint16(portStart)
  98. pbCopy.HostPortEnd = uint16(portEnd)
  99. pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
  100. pbList = append(pbList, pbCopy)
  101. }
  102. if container.HostConfig.PublishAllPorts && len(binding) == 0 {
  103. pbList = append(pbList, pb)
  104. }
  105. }
  106. sboxOptions = append(sboxOptions,
  107. libnetwork.OptionPortMapping(pbList),
  108. libnetwork.OptionExposedPorts(exposeList))
  109. // Legacy Link feature is supported only for the default bridge network.
  110. // return if this call to build join options is not for default bridge network
  111. // Legacy Link is only supported by docker run --link
  112. bridgeSettings, ok := container.NetworkSettings.Networks[defaultNetName]
  113. if !ok || bridgeSettings.EndpointSettings == nil {
  114. return sboxOptions, nil
  115. }
  116. if bridgeSettings.EndpointID == "" {
  117. return sboxOptions, nil
  118. }
  119. var (
  120. childEndpoints, parentEndpoints []string
  121. cEndpointID string
  122. )
  123. children := daemon.children(container)
  124. for linkAlias, child := range children {
  125. if !isLinkable(child) {
  126. return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name)
  127. }
  128. _, alias := path.Split(linkAlias)
  129. // allow access to the linked container via the alias, real name, and container hostname
  130. aliasList := alias + " " + child.Config.Hostname
  131. // only add the name if alias isn't equal to the name
  132. if alias != child.Name[1:] {
  133. aliasList = aliasList + " " + child.Name[1:]
  134. }
  135. sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks[defaultNetName].IPAddress))
  136. cEndpointID = child.NetworkSettings.Networks[defaultNetName].EndpointID
  137. if cEndpointID != "" {
  138. childEndpoints = append(childEndpoints, cEndpointID)
  139. }
  140. }
  141. for alias, parent := range daemon.parents(container) {
  142. if daemon.configStore.DisableBridge || !container.HostConfig.NetworkMode.IsPrivate() {
  143. continue
  144. }
  145. _, alias = path.Split(alias)
  146. logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", parent.ID, alias, bridgeSettings.IPAddress)
  147. sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(
  148. parent.ID,
  149. alias,
  150. bridgeSettings.IPAddress,
  151. ))
  152. if cEndpointID != "" {
  153. parentEndpoints = append(parentEndpoints, cEndpointID)
  154. }
  155. }
  156. linkOptions := options.Generic{
  157. netlabel.GenericData: options.Generic{
  158. "ParentEndpoints": parentEndpoints,
  159. "ChildEndpoints": childEndpoints,
  160. },
  161. }
  162. sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions))
  163. return sboxOptions, nil
  164. }

——1.2.1.1.2.7-创建NetNS) libnetwork/controller.go#controller.NewSandbox

  1. // NetworkController provides the interface for controller instance which manages
  2. // networks.
  3. type NetworkController interface {
  4. // ID provides a unique identity for the controller
  5. ID() string
  6. // BuiltinDrivers returns list of builtin drivers
  7. BuiltinDrivers() []string
  8. // BuiltinIPAMDrivers returns list of builtin ipam drivers
  9. BuiltinIPAMDrivers() []string
  10. // Config method returns the bootup configuration for the controller
  11. Config() config.Config
  12. // Create a new network. The options parameter carries network specific options.
  13. NewNetwork(networkType, name string, id string, options ...NetworkOption) (Network, error)
  14. // Networks returns the list of Network(s) managed by this controller.
  15. Networks() []Network
  16. // WalkNetworks uses the provided function to walk the Network(s) managed by this controller.
  17. WalkNetworks(walker NetworkWalker)
  18. // NetworkByName returns the Network which has the passed name. If not found, the error ErrNoSuchNetwork is returned.
  19. NetworkByName(name string) (Network, error)
  20. // NetworkByID returns the Network which has the passed id. If not found, the error ErrNoSuchNetwork is returned.
  21. NetworkByID(id string) (Network, error)
  22. // NewSandbox creates a new network sandbox for the passed container id
  23. NewSandbox(containerID string, options ...SandboxOption) (Sandbox, error)
  24. // Sandboxes returns the list of Sandbox(s) managed by this controller.
  25. Sandboxes() []Sandbox
  26. // WalkSandboxes uses the provided function to walk the Sandbox(s) managed by this controller.
  27. WalkSandboxes(walker SandboxWalker)
  28. // SandboxByID returns the Sandbox which has the passed id. If not found, a types.NotFoundError is returned.
  29. SandboxByID(id string) (Sandbox, error)
  30. // SandboxDestroy destroys a sandbox given a container ID
  31. SandboxDestroy(id string) error
  32. // Stop network controller
  33. Stop()
  34. // ReloadConfiguration updates the controller configuration
  35. ReloadConfiguration(cfgOptions ...config.Option) error
  36. // SetClusterProvider sets cluster provider
  37. SetClusterProvider(provider cluster.Provider)
  38. // Wait for agent initialization complete in libnetwork controller
  39. AgentInitWait()
  40. // Wait for agent to stop if running
  41. AgentStopWait()
  42. // SetKeys configures the encryption key for gossip and overlay data path
  43. SetKeys(keys []*types.EncryptionKey) error
  44. // StartDiagnostic start the network diagnostic mode
  45. StartDiagnostic(port int)
  46. // StopDiagnostic start the network diagnostic mode
  47. StopDiagnostic()
  48. // IsDiagnosticEnabled returns true if the diagnostic is enabled
  49. IsDiagnosticEnabled() bool
  50. }
  1. // NewSandbox creates a new sandbox for the passed container id
  2. func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (Sandbox, error) {
  3. if containerID == "" {
  4. return nil, types.BadRequestErrorf("invalid container ID")
  5. }
  6. var sb *sandbox
  7. c.Lock()
  8. for _, s := range c.sandboxes {
  9. if s.containerID == containerID {
  10. // If not a stub, then we already have a complete sandbox.
  11. if !s.isStub {
  12. sbID := s.ID()
  13. c.Unlock()
  14. return nil, types.ForbiddenErrorf("container %s is already present in sandbox %s", containerID, sbID)
  15. }
  16. // We already have a stub sandbox from the
  17. // store. Make use of it so that we don't lose
  18. // the endpoints from store but reset the
  19. // isStub flag.
  20. sb = s
  21. sb.isStub = false
  22. break
  23. }
  24. }
  25. c.Unlock()
  26. sandboxID := stringid.GenerateRandomID()
  27. if runtime.GOOS == "windows" {
  28. sandboxID = containerID
  29. }
  30. // Create sandbox and process options first. Key generation depends on an option
  31. if sb == nil {
  32. sb = &sandbox{
  33. id: sandboxID,
  34. containerID: containerID,
  35. endpoints: []*endpoint{},
  36. epPriority: map[string]int{},
  37. populatedEndpoints: map[string]struct{}{},
  38. config: containerConfig{},
  39. controller: c,
  40. extDNS: []extDNSEntry{},
  41. }
  42. }
  43. sb.processOptions(options...)
  44. c.Lock()
  45. if sb.ingress && c.ingressSandbox != nil {
  46. c.Unlock()
  47. return nil, types.ForbiddenErrorf("ingress sandbox already present")
  48. }
  49. if sb.ingress {
  50. c.ingressSandbox = sb
  51. sb.config.hostsPath = filepath.Join(c.cfg.Daemon.DataDir, "/network/files/hosts")
  52. sb.config.resolvConfPath = filepath.Join(c.cfg.Daemon.DataDir, "/network/files/resolv.conf")
  53. sb.id = "ingress_sbox"
  54. } else if sb.loadBalancerNID != "" {
  55. sb.id = "lb_" + sb.loadBalancerNID
  56. }
  57. c.Unlock()
  58. var err error
  59. defer func() {
  60. if err != nil {
  61. c.Lock()
  62. if sb.ingress {
  63. c.ingressSandbox = nil
  64. }
  65. c.Unlock()
  66. }
  67. }()
  68. // ********************************** NOTICE ********************************** //
  69. if err = sb.setupResolutionFiles(); err != nil {
  70. // ********************************** NOTICE ********************************** //
  71. return nil, err
  72. }
  73. if sb.config.useDefaultSandBox {
  74. c.sboxOnce.Do(func() {
  75. c.defOsSbox, err = osl.NewSandbox(sb.Key(), false, false)
  76. })
  77. if err != nil {
  78. c.sboxOnce = sync.Once{}
  79. return nil, fmt.Errorf("failed to create default sandbox: %v", err)
  80. }
  81. sb.osSbox = c.defOsSbox
  82. }
  83. if sb.osSbox == nil && !sb.config.useExternalKey {
  84. // ********************************** NOTICE ********************************** //
  85. if sb.osSbox, err = osl.NewSandbox(sb.Key(), !sb.config.useDefaultSandBox, false);
  86. err != nil {
  87. // ********************************** NOTICE ********************************** //
  88. return nil, fmt.Errorf("failed to create new osl sandbox: %v", err)
  89. }
  90. }
  91. if sb.osSbox != nil {
  92. // Apply operating specific knobs on the load balancer sandbox
  93. sb.osSbox.ApplyOSTweaks(sb.oslTypes)
  94. }
  95. c.Lock()
  96. c.sandboxes[sb.id] = sb
  97. c.Unlock()
  98. defer func() {
  99. if err != nil {
  100. c.Lock()
  101. delete(c.sandboxes, sb.id)
  102. c.Unlock()
  103. }
  104. }()
  105. err = sb.storeUpdate()
  106. if err != nil {
  107. return nil, fmt.Errorf("failed to update the store state of sandbox: %v", err)
  108. }
  109. return sb, nil
  110. }

———1.2.1.1.2.7.1) libnetwork/sandbox_dns_unix.go#sandbox.setupResolutionFiles

  1. func (sb *sandbox) setupResolutionFiles() error {
  2. // ********************************** NOTICE ********************************** //
  3. if err := sb.buildHostsFile(); err != nil {
  4. // ********************************** NOTICE ********************************** //
  5. return err
  6. }
  7. if err := sb.updateParentHosts(); err != nil {
  8. return err
  9. }
  10. // ********************************** NOTICE ********************************** //
  11. return sb.setupDNS()
  12. // ********************************** NOTICE ********************************** //
  13. }

————1.2.1.1.2.7.1.1) libnetwork/sandbox_dns_unix.go#sandbox.buildHostsFile

  1. func (sb *sandbox) buildHostsFile() error {
  2. if sb.config.hostsPath == "" {
  3. sb.config.hostsPath = defaultPrefix + "/" + sb.id + "/hosts"
  4. }
  5. dir, _ := filepath.Split(sb.config.hostsPath)
  6. if err := createBasePath(dir); err != nil {
  7. return err
  8. }
  9. // This is for the host mode networking
  10. if sb.config.useDefaultSandBox && len(sb.config.extraHosts) == 0 {
  11. // We are working under the assumption that the origin file option had been properly expressed by the upper layer
  12. // if not here we are going to error out
  13. if err := copyFile(sb.config.originHostsPath, sb.config.hostsPath); err != nil && !os.IsNotExist(err) {
  14. return types.InternalErrorf("could not copy source hosts file %s to %s: %v", sb.config.originHostsPath, sb.config.hostsPath, err)
  15. }
  16. return nil
  17. }
  18. extraContent := make([]etchosts.Record, 0, len(sb.config.extraHosts))
  19. for _, extraHost := range sb.config.extraHosts {
  20. extraContent = append(extraContent, etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
  21. }
  22. return etchosts.Build(sb.config.hostsPath, "", sb.config.hostName, sb.config.domainName, extraContent)
  23. }

————1.2.1.1.2.7.1.2) libnetwork/sandbox_dns_unix.go#sandbox.setupDNS

  1. func (sb *sandbox) setupDNS() error {
  2. var newRC *resolvconf.File
  3. if sb.config.resolvConfPath == "" {
  4. sb.config.resolvConfPath = defaultPrefix + "/" + sb.id + "/resolv.conf"
  5. }
  6. sb.config.resolvConfHashFile = sb.config.resolvConfPath + ".hash"
  7. dir, _ := filepath.Split(sb.config.resolvConfPath)
  8. if err := createBasePath(dir); err != nil {
  9. return err
  10. }
  11. // When the user specify a conainter in the host namespace and do no have any dns option specified
  12. // we just copy the host resolv.conf from the host itself
  13. if sb.config.useDefaultSandBox &&
  14. len(sb.config.dnsList) == 0 && len(sb.config.dnsSearchList) == 0 && len(sb.config.dnsOptionsList) == 0 {
  15. // We are working under the assumption that the origin file option had been properly expressed by the upper layer
  16. // if not here we are going to error out
  17. if err := copyFile(sb.config.originResolvConfPath, sb.config.resolvConfPath); err != nil {
  18. if !os.IsNotExist(err) {
  19. return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", sb.config.originResolvConfPath, sb.config.resolvConfPath, err)
  20. }
  21. logrus.Infof("%s does not exist, we create an empty resolv.conf for container", sb.config.originResolvConfPath)
  22. if err := createFile(sb.config.resolvConfPath); err != nil {
  23. return err
  24. }
  25. }
  26. return nil
  27. }
  28. originResolvConfPath := sb.config.originResolvConfPath
  29. if originResolvConfPath == "" {
  30. // if not specified fallback to default /etc/resolv.conf
  31. originResolvConfPath = resolvconf.DefaultResolvConf
  32. }
  33. currRC, err := resolvconf.GetSpecific(originResolvConfPath)
  34. if err != nil {
  35. if !os.IsNotExist(err) {
  36. return err
  37. }
  38. // it's ok to continue if /etc/resolv.conf doesn't exist, default resolvers (Google's Public DNS)
  39. // will be used
  40. currRC = &resolvconf.File{}
  41. logrus.Infof("/etc/resolv.conf does not exist")
  42. }
  43. if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
  44. var (
  45. err error
  46. dnsList = resolvconf.GetNameservers(currRC.Content, types.IP)
  47. dnsSearchList = resolvconf.GetSearchDomains(currRC.Content)
  48. dnsOptionsList = resolvconf.GetOptions(currRC.Content)
  49. )
  50. if len(sb.config.dnsList) > 0 {
  51. dnsList = sb.config.dnsList
  52. }
  53. if len(sb.config.dnsSearchList) > 0 {
  54. dnsSearchList = sb.config.dnsSearchList
  55. }
  56. if len(sb.config.dnsOptionsList) > 0 {
  57. dnsOptionsList = sb.config.dnsOptionsList
  58. }
  59. newRC, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
  60. if err != nil {
  61. return err
  62. }
  63. // After building the resolv.conf from the user config save the
  64. // external resolvers in the sandbox. Note that --dns 127.0.0.x
  65. // config refers to the loopback in the container namespace
  66. sb.setExternalResolvers(newRC.Content, types.IPv4, false)
  67. } else {
  68. // If the host resolv.conf file has 127.0.0.x container should
  69. // use the host resolver for queries. This is supported by the
  70. // docker embedded DNS server. Hence save the external resolvers
  71. // before filtering it out.
  72. sb.setExternalResolvers(currRC.Content, types.IPv4, true)
  73. // Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true)
  74. if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil {
  75. return err
  76. }
  77. // No contention on container resolv.conf file at sandbox creation
  78. if err := ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, filePerm); err != nil {
  79. return types.InternalErrorf("failed to write unhaltered resolv.conf file content when setting up dns for sandbox %s: %v", sb.ID(), err)
  80. }
  81. }
  82. // Write hash
  83. if err := ioutil.WriteFile(sb.config.resolvConfHashFile, []byte(newRC.Hash), filePerm); err != nil {
  84. return types.InternalErrorf("failed to write resolv.conf hash file when setting up dns for sandbox %s: %v", sb.ID(), err)
  85. }
  86. return nil
  87. }

———1.2.1.1.2.7.2) libnetwork/osl/namespace_linux.go#NewSandbox

  1. // NewSandbox provides a new sandbox instance created in an os specific way
  2. // provided a key which uniquely identifies the sandbox
  3. func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) {
  4. if !isRestore {
  5. // ********************************** NOTICE ********************************** //
  6. err := createNetworkNamespace(key, osCreate)
  7. // ********************************** NOTICE ********************************** //
  8. if err != nil {
  9. return nil, err
  10. }
  11. } else {
  12. once.Do(createBasePath)
  13. }
  14. n := &networkNamespace{path: key, isDefault: !osCreate, nextIfIndex: make(map[string]int)}
  15. // ********************************** NOTICE ********************************** //
  16. sboxNs, err := netns.GetFromPath(n.path)
  17. // ********************************** NOTICE ********************************** //
  18. if err != nil {
  19. return nil, fmt.Errorf("failed get network namespace %q: %v", n.path, err)
  20. }
  21. defer sboxNs.Close()
  22. n.nlHandle, err = netlink.NewHandleAt(sboxNs, syscall.NETLINK_ROUTE)
  23. if err != nil {
  24. return nil, fmt.Errorf("failed to create a netlink handle: %v", err)
  25. }
  26. err = n.nlHandle.SetSocketTimeout(ns.NetlinkSocketsTimeout)
  27. if err != nil {
  28. logrus.Warnf("Failed to set the timeout on the sandbox netlink handle sockets: %v", err)
  29. }
  30. // In live-restore mode, IPV6 entries are getting cleaned up due to below code
  31. // We should retain IPV6 configurations in live-restore mode when Docker Daemon
  32. // comes back. It should work as it is on other cases
  33. // As starting point, disable IPv6 on all interfaces
  34. if !isRestore && !n.isDefault {
  35. err = setIPv6(n.path, "all", false)
  36. if err != nil {
  37. logrus.Warnf("Failed to disable IPv6 on all interfaces on network namespace %q: %v", n.path, err)
  38. }
  39. }
  40. if err = n.loopbackUp(); err != nil {
  41. n.nlHandle.Delete()
  42. return nil, err
  43. }
  44. return n, nil
  45. }

————1.2.1.1.2.7.2.1) libnetwork/osl/namespace_linux.go#createNetworkNamespace

  1. func createNetworkNamespace(path string, osCreate bool) error {
  2. // ********************************** NOTICE ********************************** //
  3. if err := createNamespaceFile(path); err != nil {
  4. // ********************************** NOTICE ********************************** //
  5. return err
  6. }
  7. cmd := &exec.Cmd{
  8. Path: reexec.Self(),
  9. Args: append([]string{"netns-create"}, path),
  10. Stdout: os.Stdout,
  11. Stderr: os.Stderr,
  12. }
  13. if osCreate {
  14. cmd.SysProcAttr = &syscall.SysProcAttr{}
  15. cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWNET
  16. }
  17. if err := cmd.Run(); err != nil {
  18. return fmt.Errorf("namespace creation reexec command failed: %v", err)
  19. }
  20. return nil
  21. }
  22. func createNamespaceFile(path string) (err error) {
  23. var f *os.File
  24. once.Do(createBasePath)
  25. // Remove it from garbage collection list if present
  26. removeFromGarbagePaths(path)
  27. // If the path is there unmount it first
  28. unmountNamespaceFile(path)
  29. // wait for garbage collection to complete if it is in progress
  30. // before trying to create the file.
  31. gpmWg.Wait()
  32. if f, err = os.Create(path); err == nil {
  33. f.Close()
  34. }
  35. return err
  36. }
  37. func createBasePath() {
  38. err := os.MkdirAll(basePath(), 0755)
  39. if err != nil {
  40. panic("Could not create net namespace path directory")
  41. }
  42. // Start the garbage collection go routine
  43. go removeUnusedPaths()
  44. }
  45. // prefix是/var/run/docker
  46. func basePath() string {
  47. return filepath.Join(prefix, "netns")
  48. }
  49. func init() {
  50. reexec.Register("netns-create", reexecCreateNamespace)
  51. }
  52. func reexecCreateNamespace() {
  53. if len(os.Args) < 2 {
  54. logrus.Fatal("no namespace path provided")
  55. }
  56. if err := mountNetworkNamespace("/proc/self/ns/net", os.Args[1]); err != nil {
  57. logrus.Fatal(err)
  58. }
  59. }
  60. func mountNetworkNamespace(basePath string, lnPath string) error {
  61. return syscall.Mount(basePath, lnPath, "bind", syscall.MS_BIND, "")
  62. }

——1.2.1.1.2.8) daemon/container_operations.go#updateSandboxNetworkSettings

  1. // updateSandboxNetworkSettings updates the sandbox ID and Key.
  2. func updateSandboxNetworkSettings(c *container.Container, sb libnetwork.Sandbox) error {
  3. c.NetworkSettings.SandboxID = sb.ID()
  4. c.NetworkSettings.SandboxKey = sb.Key()
  5. return nil
  6. }

——1.2.1.1.2.9) daemon/network.go#buildJoinOptions

  1. // buildJoinOptions builds endpoint Join options from a given network.
  2. func buildJoinOptions(networkSettings *internalnetwork.Settings, n interface {
  3. Name() string
  4. }) ([]libnetwork.EndpointOption, error) {
  5. var joinOptions []libnetwork.EndpointOption
  6. if epConfig, ok := networkSettings.Networks[n.Name()]; ok {
  7. for _, str := range epConfig.Links {
  8. name, alias, err := opts.ParseLink(str)
  9. if err != nil {
  10. return nil, err
  11. }
  12. joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias))
  13. }
  14. for k, v := range epConfig.DriverOpts {
  15. joinOptions = append(joinOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
  16. }
  17. }
  18. return joinOptions, nil
  19. }

——1.2.1.1.2.10) libnetwork/endpoint.go#endpoint.Join

  1. func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {
  2. if sbox == nil {
  3. return types.BadRequestErrorf("endpoint cannot be joined by nil container")
  4. }
  5. sb, ok := sbox.(*sandbox)
  6. if !ok {
  7. return types.BadRequestErrorf("not a valid Sandbox interface")
  8. }
  9. sb.joinLeaveStart()
  10. defer sb.joinLeaveEnd()
  11. // ********************************** NOTICE ********************************** //
  12. return ep.sbJoin(sb, options...)
  13. // ********************************** NOTICE ********************************** //
  14. }
  1. func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) (err error) {
  2. n, err := ep.getNetworkFromStore()
  3. if err != nil {
  4. return fmt.Errorf("failed to get network from store during join: %v", err)
  5. }
  6. ep, err = n.getEndpointFromStore(ep.ID())
  7. if err != nil {
  8. return fmt.Errorf("failed to get endpoint from store during join: %v", err)
  9. }
  10. ep.Lock()
  11. if ep.sandboxID != "" {
  12. ep.Unlock()
  13. return types.ForbiddenErrorf("another container is attached to the same network endpoint")
  14. }
  15. ep.network = n
  16. ep.sandboxID = sb.ID()
  17. ep.joinInfo = &endpointJoinInfo{}
  18. epid := ep.id
  19. ep.Unlock()
  20. defer func() {
  21. if err != nil {
  22. ep.Lock()
  23. ep.sandboxID = ""
  24. ep.Unlock()
  25. }
  26. }()
  27. nid := n.ID()
  28. ep.processOptions(options...)
  29. d, err := n.driver(true)
  30. if err != nil {
  31. return fmt.Errorf("failed to get driver during join: %v", err)
  32. }
  33. // ********************************** NOTICE ********************************** //
  34. err = d.Join(nid, epid, sb.Key(), ep, sb.Labels())
  35. // ********************************** NOTICE ********************************** //
  36. if err != nil {
  37. return err
  38. }
  39. defer func() {
  40. if err != nil {
  41. if e := d.Leave(nid, epid); e != nil {
  42. logrus.Warnf("driver leave failed while rolling back join: %v", e)
  43. }
  44. }
  45. }()
  46. // Watch for service records
  47. if !n.getController().isAgent() {
  48. n.getController().watchSvcRecord(ep)
  49. }
  50. if doUpdateHostsFile(n, sb) {
  51. address := ""
  52. if ip := ep.getFirstInterfaceAddress(); ip != nil {
  53. address = ip.String()
  54. }
  55. if err = sb.updateHostsFile(address); err != nil {
  56. return err
  57. }
  58. }
  59. if err = sb.updateDNS(n.enableIPv6); err != nil {
  60. return err
  61. }
  62. // Current endpoint providing external connectivity for the sandbox
  63. extEp := sb.getGatewayEndpoint()
  64. // ********************************** NOTICE ********************************** //
  65. sb.addEndpoint(ep)
  66. // ********************************** NOTICE ********************************** //
  67. defer func() {
  68. if err != nil {
  69. sb.removeEndpoint(ep)
  70. }
  71. }()
  72. // ********************************** NOTICE ********************************** //
  73. if err = sb.populateNetworkResources(ep); err != nil {
  74. // ********************************** NOTICE ********************************** //
  75. return err
  76. }
  77. if err = n.getController().updateToStore(ep); err != nil {
  78. return err
  79. }
  80. if err = ep.addDriverInfoToCluster(); err != nil {
  81. return err
  82. }
  83. defer func() {
  84. if err != nil {
  85. if e := ep.deleteDriverInfoFromCluster(); e != nil {
  86. logrus.Errorf("Could not delete endpoint state for endpoint %s from cluster on join failure: %v", ep.Name(), e)
  87. }
  88. }
  89. }()
  90. // Load balancing endpoints should never have a default gateway nor
  91. // should they alter the status of a network's default gateway
  92. if ep.loadBalancer && !sb.ingress {
  93. return nil
  94. }
  95. if sb.needDefaultGW() && sb.getEndpointInGWNetwork() == nil {
  96. return sb.setupDefaultGW()
  97. }
  98. moveExtConn := sb.getGatewayEndpoint() != extEp
  99. if moveExtConn {
  100. if extEp != nil {
  101. logrus.Debugf("Revoking external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID())
  102. extN, err := extEp.getNetworkFromStore()
  103. if err != nil {
  104. return fmt.Errorf("failed to get network from store for revoking external connectivity during join: %v", err)
  105. }
  106. extD, err := extN.driver(true)
  107. if err != nil {
  108. return fmt.Errorf("failed to get driver for revoking external connectivity during join: %v", err)
  109. }
  110. if err = extD.RevokeExternalConnectivity(extEp.network.ID(), extEp.ID()); err != nil {
  111. return types.InternalErrorf(
  112. "driver failed revoking external connectivity on endpoint %s (%s): %v",
  113. extEp.Name(), extEp.ID(), err)
  114. }
  115. defer func() {
  116. if err != nil {
  117. if e := extD.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); e != nil {
  118. logrus.Warnf("Failed to roll-back external connectivity on endpoint %s (%s): %v",
  119. extEp.Name(), extEp.ID(), e)
  120. }
  121. }
  122. }()
  123. }
  124. if !n.internal {
  125. logrus.Debugf("Programming external connectivity on endpoint %s (%s)", ep.Name(), ep.ID())
  126. if err = d.ProgramExternalConnectivity(n.ID(), ep.ID(), sb.Labels()); err != nil {
  127. return types.InternalErrorf(
  128. "driver failed programming external connectivity on endpoint %s (%s): %v",
  129. ep.Name(), ep.ID(), err)
  130. }
  131. }
  132. }
  133. if !sb.needDefaultGW() {
  134. if e := sb.clearDefaultGW(); e != nil {
  135. logrus.Warnf("Failure while disconnecting sandbox %s (%s) from gateway network: %v",
  136. sb.ID(), sb.ContainerID(), e)
  137. }
  138. }
  139. return nil
  140. }

———1.2.1.1.2.10.1) libnetwork/drivers/bridge/bridge.go#driver#Join

  1. // Join method is invoked when a Sandbox is attached to an endpoint.
  2. func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
  3. defer osl.InitOSContext()()
  4. network, err := d.getNetwork(nid)
  5. if err != nil {
  6. return err
  7. }
  8. endpoint, err := network.getEndpoint(eid)
  9. if err != nil {
  10. return err
  11. }
  12. if endpoint == nil {
  13. return EndpointNotFoundError(eid)
  14. }
  15. endpoint.containerConfig, err = parseContainerOptions(options)
  16. if err != nil {
  17. return err
  18. }
  19. iNames := jinfo.InterfaceName()
  20. containerVethPrefix := defaultContainerVethPrefix
  21. if network.config.ContainerIfacePrefix != "" {
  22. containerVethPrefix = network.config.ContainerIfacePrefix
  23. }
  24. err = iNames.SetNames(endpoint.srcName, containerVethPrefix)
  25. if err != nil {
  26. return err
  27. }
  28. err = jinfo.SetGateway(network.bridge.gatewayIPv4)
  29. if err != nil {
  30. return err
  31. }
  32. err = jinfo.SetGatewayIPv6(network.bridge.gatewayIPv6)
  33. if err != nil {
  34. return err
  35. }
  36. return nil
  37. }

———1.2.1.1.2.10.2) libnetwork/sandbox.go#sandbox.populateNetworkResources

  1. func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
  2. sb.Lock()
  3. if sb.osSbox == nil {
  4. sb.Unlock()
  5. return nil
  6. }
  7. inDelete := sb.inDelete
  8. sb.Unlock()
  9. ep.Lock()
  10. joinInfo := ep.joinInfo
  11. i := ep.iface
  12. lbModeIsDSR := ep.network.loadBalancerMode == loadBalancerModeDSR
  13. ep.Unlock()
  14. if ep.needResolver() {
  15. sb.startResolver(false)
  16. }
  17. if i != nil && i.srcName != "" {
  18. var ifaceOptions []osl.IfaceOption
  19. ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().Address(i.addr), sb.osSbox.InterfaceOptions().Routes(i.routes))
  20. if i.addrv6 != nil && i.addrv6.IP.To16() != nil {
  21. ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(i.addrv6))
  22. }
  23. if len(i.llAddrs) != 0 {
  24. ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().LinkLocalAddresses(i.llAddrs))
  25. }
  26. if i.mac != nil {
  27. ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().MacAddress(i.mac))
  28. }
  29. // ********************************** NOTICE ********************************** //
  30. if err := sb.osSbox.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil {
  31. // ********************************** NOTICE ********************************** //
  32. return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err)
  33. }
  34. if len(ep.virtualIP) > 0 && lbModeIsDSR {
  35. if sb.loadBalancerNID == "" {
  36. if err := sb.osSbox.DisableARPForVIP(i.srcName); err != nil {
  37. return fmt.Errorf("failed disable ARP for VIP: %v", err)
  38. }
  39. }
  40. ipNet := &net.IPNet{IP: ep.virtualIP, Mask: net.CIDRMask(32, 32)}
  41. if err := sb.osSbox.AddAliasIP(sb.osSbox.GetLoopbackIfaceName(), ipNet); err != nil {
  42. return fmt.Errorf("failed to add virtual ip %v to loopback: %v", ipNet, err)
  43. }
  44. }
  45. }
  46. if joinInfo != nil {
  47. // Set up non-interface routes.
  48. for _, r := range joinInfo.StaticRoutes {
  49. if err := sb.osSbox.AddStaticRoute(r); err != nil {
  50. return fmt.Errorf("failed to add static route %s: %v", r.Destination.String(), err)
  51. }
  52. }
  53. }
  54. if ep == sb.getGatewayEndpoint() {
  55. if err := sb.updateGateway(ep); err != nil {
  56. return err
  57. }
  58. }
  59. // Make sure to add the endpoint to the populated endpoint set
  60. // before populating loadbalancers.
  61. sb.Lock()
  62. sb.populatedEndpoints[ep.ID()] = struct{}{}
  63. sb.Unlock()
  64. // Populate load balancer only after updating all the other
  65. // information including gateway and other routes so that
  66. // loadbalancers are populated all the network state is in
  67. // place in the sandbox.
  68. sb.populateLoadBalancers(ep)
  69. // Only update the store if we did not come here as part of
  70. // sandbox delete. If we came here as part of delete then do
  71. // not bother updating the store. The sandbox object will be
  72. // deleted anyway
  73. if !inDelete {
  74. return sb.storeUpdate()
  75. }
  76. return nil
  77. }

————1.2.1.1.2.10.2.1) libnetwork/osl/interface_linux.go#networkNamespace#AddInterface

  1. func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...IfaceOption) error {
  2. i := &nwIface{srcName: srcName, dstName: dstPrefix, ns: n}
  3. i.processInterfaceOptions(options...)
  4. if i.master != "" {
  5. i.dstMaster = n.findDst(i.master, true)
  6. if i.dstMaster == "" {
  7. return fmt.Errorf("could not find an appropriate master %q for %q",
  8. i.master, i.srcName)
  9. }
  10. }
  11. n.Lock()
  12. if n.isDefault {
  13. i.dstName = i.srcName
  14. } else {
  15. i.dstName = fmt.Sprintf("%s%d", dstPrefix, n.nextIfIndex[dstPrefix])
  16. n.nextIfIndex[dstPrefix]++
  17. }
  18. path := n.path
  19. isDefault := n.isDefault
  20. nlh := n.nlHandle
  21. nlhHost := ns.NlHandle()
  22. n.Unlock()
  23. // If it is a bridge interface we have to create the bridge inside
  24. // the namespace so don't try to lookup the interface using srcName
  25. if i.bridge {
  26. link := &netlink.Bridge{
  27. LinkAttrs: netlink.LinkAttrs{
  28. Name: i.srcName,
  29. },
  30. }
  31. if err := nlh.LinkAdd(link); err != nil {
  32. return fmt.Errorf("failed to create bridge %q: %v", i.srcName, err)
  33. }
  34. } else {
  35. // Find the network interface identified by the SrcName attribute.
  36. iface, err := nlhHost.LinkByName(i.srcName)
  37. if err != nil {
  38. return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
  39. }
  40. // Move the network interface to the destination
  41. // namespace only if the namespace is not a default
  42. // type
  43. if !isDefault {
  44. newNs, err := netns.GetFromPath(path)
  45. if err != nil {
  46. return fmt.Errorf("failed get network namespace %q: %v", path, err)
  47. }
  48. defer newNs.Close()
  49. if err := nlhHost.LinkSetNsFd(iface, int(newNs)); err != nil {
  50. return fmt.Errorf("failed to set namespace on link %q: %v", i.srcName, err)
  51. }
  52. }
  53. }
  54. // Find the network interface identified by the SrcName attribute.
  55. iface, err := nlh.LinkByName(i.srcName)
  56. if err != nil {
  57. return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
  58. }
  59. // Down the interface before configuring
  60. if err := nlh.LinkSetDown(iface); err != nil {
  61. return fmt.Errorf("failed to set link down: %v", err)
  62. }
  63. // Configure the interface now this is moved in the proper namespace.
  64. if err := configureInterface(nlh, iface, i); err != nil {
  65. // If configuring the device fails move it back to the host namespace
  66. // and change the name back to the source name. This allows the caller
  67. // to properly cleanup the interface. Its important especially for
  68. // interfaces with global attributes, ex: vni id for vxlan interfaces.
  69. if nerr := nlh.LinkSetName(iface, i.SrcName()); nerr != nil {
  70. logrus.Errorf("renaming interface (%s->%s) failed, %v after config error %v", i.DstName(), i.SrcName(), nerr, err)
  71. }
  72. if nerr := nlh.LinkSetNsFd(iface, ns.ParseHandlerInt()); nerr != nil {
  73. logrus.Errorf("moving interface %s to host ns failed, %v, after config error %v", i.SrcName(), nerr, err)
  74. }
  75. return err
  76. }
  77. // Up the interface.
  78. cnt := 0
  79. for err = nlh.LinkSetUp(iface); err != nil && cnt < 3; cnt++ {
  80. logrus.Debugf("retrying link setup because of: %v", err)
  81. time.Sleep(10 * time.Millisecond)
  82. err = nlh.LinkSetUp(iface)
  83. }
  84. if err != nil {
  85. return fmt.Errorf("failed to set link up: %v", err)
  86. }
  87. // Set the routes on the interface. This can only be done when the interface is up.
  88. if err := setInterfaceRoutes(nlh, iface, i); err != nil {
  89. return fmt.Errorf("error setting interface %q routes to %q: %v", iface.Attrs().Name, i.Routes(), err)
  90. }
  91. n.Lock()
  92. n.iFaces = append(n.iFaces, i)
  93. n.Unlock()
  94. n.checkLoV6()
  95. return nil
  96. }

—1.2.1.1.3) container/container.go#Container.WriteHostConfig

  1. // WriteHostConfig saves the host configuration on disk for the container,
  2. // and returns a deep copy of the saved object. Callers must hold a Container lock.
  3. func (container *Container) WriteHostConfig() (*containertypes.HostConfig, error) {
  4. var (
  5. buf bytes.Buffer
  6. deepCopy containertypes.HostConfig
  7. )
  8. pth, err := container.HostConfigPath()
  9. if err != nil {
  10. return nil, err
  11. }
  12. f, err := ioutils.NewAtomicFileWriter(pth, 0644)
  13. if err != nil {
  14. return nil, err
  15. }
  16. defer f.Close()
  17. w := io.MultiWriter(&buf, f)
  18. if err := json.NewEncoder(w).Encode(&container.HostConfig); err != nil {
  19. return nil, err
  20. }
  21. if err := json.NewDecoder(&buf).Decode(&deepCopy); err != nil {
  22. return nil, err
  23. }
  24. return &deepCopy, nil
  25. }

1.2.1.2) container/container_unix.go#Container.BuildHostnameFile

  1. // BuildHostnameFile writes the container's hostname file.
  2. func (container *Container) BuildHostnameFile() error {
  3. hostnamePath, err := container.GetRootResourcePath("hostname")
  4. if err != nil {
  5. return err
  6. }
  7. container.HostnamePath = hostnamePath
  8. return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
  9. }

1.2.2) daemon/oci_linux.go#Daemon.createSpec

  1. func (daemon *Daemon) createSpec(c *container.Container) (retSpec *specs.Spec, err error) {
  2. // ********************************** NOTICE ********************************** //
  3. s := oci.DefaultSpec()
  4. // ********************************** NOTICE ********************************** //
  5. if err := daemon.populateCommonSpec(&s, c); err != nil {
  6. // ********************************** NOTICE ********************************** //
  7. return nil, err
  8. }
  9. var cgroupsPath string
  10. scopePrefix := "docker"
  11. parent := "/docker"
  12. useSystemd := UsingSystemd(daemon.configStore)
  13. if useSystemd {
  14. parent = "system.slice"
  15. }
  16. if c.HostConfig.CgroupParent != "" {
  17. parent = c.HostConfig.CgroupParent
  18. } else if daemon.configStore.CgroupParent != "" {
  19. parent = daemon.configStore.CgroupParent
  20. }
  21. if useSystemd {
  22. cgroupsPath = parent + ":" + scopePrefix + ":" + c.ID
  23. logrus.Debugf("createSpec: cgroupsPath: %s", cgroupsPath)
  24. } else {
  25. cgroupsPath = filepath.Join(parent, c.ID)
  26. }
  27. s.Linux.CgroupsPath = cgroupsPath
  28. if err := setResources(&s, c.HostConfig.Resources); err != nil {
  29. return nil, fmt.Errorf("linux runtime spec resources: %v", err)
  30. }
  31. // We merge the sysctls injected above with the HostConfig (latter takes
  32. // precedence for backwards-compatibility reasons).
  33. for k, v := range c.HostConfig.Sysctls {
  34. s.Linux.Sysctl[k] = v
  35. }
  36. p := s.Linux.CgroupsPath
  37. if useSystemd {
  38. initPath, err := cgroups.GetInitCgroup("cpu")
  39. if err != nil {
  40. return nil, err
  41. }
  42. _, err = cgroups.GetOwnCgroup("cpu")
  43. if err != nil {
  44. return nil, err
  45. }
  46. p = filepath.Join(initPath, s.Linux.CgroupsPath)
  47. }
  48. // Clean path to guard against things like ../../../BAD
  49. parentPath := filepath.Dir(p)
  50. if !filepath.IsAbs(parentPath) {
  51. parentPath = filepath.Clean("/" + parentPath)
  52. }
  53. if err := daemon.initCgroupsPath(parentPath); err != nil {
  54. return nil, fmt.Errorf("linux init cgroups path: %v", err)
  55. }
  56. if err := setDevices(&s, c); err != nil {
  57. return nil, fmt.Errorf("linux runtime spec devices: %v", err)
  58. }
  59. if err := daemon.setRlimits(&s, c); err != nil {
  60. return nil, fmt.Errorf("linux runtime spec rlimits: %v", err)
  61. }
  62. if err := setUser(&s, c); err != nil {
  63. return nil, fmt.Errorf("linux spec user: %v", err)
  64. }
  65. // ********************************** NOTICE ********************************** //
  66. if err := setNamespaces(daemon, &s, c); err != nil {
  67. // ********************************** NOTICE ********************************** //
  68. return nil, fmt.Errorf("linux spec namespaces: %v", err)
  69. }
  70. capabilities, err := caps.TweakCapabilities(oci.DefaultCapabilities(), c.HostConfig.CapAdd, c.HostConfig.CapDrop, c.HostConfig.Capabilities, c.HostConfig.Privileged)
  71. if err != nil {
  72. return nil, fmt.Errorf("linux spec capabilities: %v", err)
  73. }
  74. if err := oci.SetCapabilities(&s, capabilities); err != nil {
  75. return nil, fmt.Errorf("linux spec capabilities: %v", err)
  76. }
  77. if err := setSeccomp(daemon, &s, c); err != nil {
  78. return nil, fmt.Errorf("linux seccomp: %v", err)
  79. }
  80. // ********************************** NOTICE ********************************** //
  81. if err := daemon.setupContainerMountsRoot(c); err != nil {
  82. // ********************************** NOTICE ********************************** //
  83. return nil, err
  84. }
  85. if err := daemon.setupIpcDirs(c); err != nil {
  86. return nil, err
  87. }
  88. defer func() {
  89. if err != nil {
  90. daemon.cleanupSecretDir(c)
  91. }
  92. }()
  93. if err := daemon.setupSecretDir(c); err != nil {
  94. return nil, err
  95. }
  96. // ********************************** NOTICE ********************************** //
  97. ms, err := daemon.setupMounts(c)
  98. // ********************************** NOTICE ********************************** //
  99. if err != nil {
  100. return nil, err
  101. }
  102. if !c.HostConfig.IpcMode.IsPrivate() && !c.HostConfig.IpcMode.IsEmpty() {
  103. ms = append(ms, c.IpcMounts()...)
  104. }
  105. tmpfsMounts, err := c.TmpfsMounts()
  106. if err != nil {
  107. return nil, err
  108. }
  109. ms = append(ms, tmpfsMounts...)
  110. secretMounts, err := c.SecretMounts()
  111. if err != nil {
  112. return nil, err
  113. }
  114. ms = append(ms, secretMounts...)
  115. sort.Sort(mounts(ms))
  116. if err := setMounts(daemon, &s, c, ms); err != nil {
  117. return nil, fmt.Errorf("linux mounts: %v", err)
  118. }
  119. for _, ns := range s.Linux.Namespaces {
  120. if ns.Type == "network" && ns.Path == "" && !c.Config.NetworkDisabled {
  121. target := filepath.Join("/proc", strconv.Itoa(os.Getpid()), "exe")
  122. s.Hooks = &specs.Hooks{
  123. Prestart: []specs.Hook{{
  124. Path: target,
  125. Args: []string{"libnetwork-setkey", "-exec-root=" + daemon.configStore.GetExecRoot(), c.ID, daemon.netController.ID()},
  126. }},
  127. }
  128. }
  129. }
  130. if apparmor.IsEnabled() {
  131. var appArmorProfile string
  132. if c.AppArmorProfile != "" {
  133. appArmorProfile = c.AppArmorProfile
  134. } else if c.HostConfig.Privileged {
  135. appArmorProfile = "unconfined"
  136. } else {
  137. appArmorProfile = "docker-default"
  138. }
  139. if appArmorProfile == "docker-default" {
  140. // Unattended upgrades and other fun services can unload AppArmor
  141. // profiles inadvertently. Since we cannot store our profile in
  142. // /etc/apparmor.d, nor can we practically add other ways of
  143. // telling the system to keep our profile loaded, in order to make
  144. // sure that we keep the default profile enabled we dynamically
  145. // reload it if necessary.
  146. if err := ensureDefaultAppArmorProfile(); err != nil {
  147. return nil, err
  148. }
  149. }
  150. s.Process.ApparmorProfile = appArmorProfile
  151. }
  152. s.Process.SelinuxLabel = c.GetProcessLabel()
  153. s.Process.NoNewPrivileges = c.NoNewPrivileges
  154. s.Process.OOMScoreAdj = &c.HostConfig.OomScoreAdj
  155. s.Linux.MountLabel = c.MountLabel
  156. // Set the masked and readonly paths with regard to the host config options if they are set.
  157. if c.HostConfig.MaskedPaths != nil {
  158. s.Linux.MaskedPaths = c.HostConfig.MaskedPaths
  159. }
  160. if c.HostConfig.ReadonlyPaths != nil {
  161. s.Linux.ReadonlyPaths = c.HostConfig.ReadonlyPaths
  162. }
  163. if daemon.configStore.Rootless {
  164. if err := specconv.ToRootless(&s); err != nil {
  165. return nil, err
  166. }
  167. }
  168. return &s, nil
  169. }

1.2.2.1) oci/defaults.go#DefaultSpec

  1. // DefaultSpec returns the default spec used by docker for the current Platform
  2. func DefaultSpec() specs.Spec {
  3. return DefaultOSSpec(runtime.GOOS)
  4. }
  5. // DefaultLinuxSpec create a default spec for running Linux containers
  6. func DefaultLinuxSpec() specs.Spec {
  7. s := specs.Spec{
  8. Version: specs.Version,
  9. Process: &specs.Process{
  10. Capabilities: &specs.LinuxCapabilities{
  11. Bounding: DefaultCapabilities(),
  12. Permitted: DefaultCapabilities(),
  13. Inheritable: DefaultCapabilities(),
  14. Effective: DefaultCapabilities(),
  15. },
  16. },
  17. Root: &specs.Root{},
  18. }
  19. s.Mounts = []specs.Mount{
  20. {
  21. Destination: "/proc",
  22. Type: "proc",
  23. Source: "proc",
  24. Options: []string{"nosuid", "noexec", "nodev"},
  25. },
  26. {
  27. Destination: "/dev",
  28. Type: "tmpfs",
  29. Source: "tmpfs",
  30. Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
  31. },
  32. {
  33. Destination: "/dev/pts",
  34. Type: "devpts",
  35. Source: "devpts",
  36. Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
  37. },
  38. {
  39. Destination: "/sys",
  40. Type: "sysfs",
  41. Source: "sysfs",
  42. Options: []string{"nosuid", "noexec", "nodev", "ro"},
  43. },
  44. {
  45. Destination: "/sys/fs/cgroup",
  46. Type: "cgroup",
  47. Source: "cgroup",
  48. Options: []string{"ro", "nosuid", "noexec", "nodev"},
  49. },
  50. {
  51. Destination: "/dev/mqueue",
  52. Type: "mqueue",
  53. Source: "mqueue",
  54. Options: []string{"nosuid", "noexec", "nodev"},
  55. },
  56. {
  57. Destination: "/dev/shm",
  58. Type: "tmpfs",
  59. Source: "shm",
  60. Options: []string{"nosuid", "noexec", "nodev", "mode=1777"},
  61. },
  62. }
  63. s.Linux = &specs.Linux{
  64. MaskedPaths: []string{
  65. "/proc/asound",
  66. "/proc/acpi",
  67. "/proc/kcore",
  68. "/proc/keys",
  69. "/proc/latency_stats",
  70. "/proc/timer_list",
  71. "/proc/timer_stats",
  72. "/proc/sched_debug",
  73. "/proc/scsi",
  74. "/sys/firmware",
  75. },
  76. ReadonlyPaths: []string{
  77. "/proc/bus",
  78. "/proc/fs",
  79. "/proc/irq",
  80. "/proc/sys",
  81. "/proc/sysrq-trigger",
  82. },
  83. Namespaces: []specs.LinuxNamespace{
  84. {Type: "mount"},
  85. {Type: "network"},
  86. {Type: "uts"},
  87. {Type: "pid"},
  88. {Type: "ipc"},
  89. },
  90. // Devices implicitly contains the following devices:
  91. // null, zero, full, random, urandom, tty, console, and ptmx.
  92. // ptmx is a bind mount or symlink of the container's ptmx.
  93. // See also: https://github.com/opencontainers/runtime-spec/blob/master/config-linux.md#default-devices
  94. Devices: []specs.LinuxDevice{},
  95. Resources: &specs.LinuxResources{
  96. Devices: []specs.LinuxDeviceCgroup{
  97. {
  98. Allow: false,
  99. Access: "rwm",
  100. },
  101. {
  102. Allow: true,
  103. Type: "c",
  104. Major: iPtr(1),
  105. Minor: iPtr(5),
  106. Access: "rwm",
  107. },
  108. {
  109. Allow: true,
  110. Type: "c",
  111. Major: iPtr(1),
  112. Minor: iPtr(3),
  113. Access: "rwm",
  114. },
  115. {
  116. Allow: true,
  117. Type: "c",
  118. Major: iPtr(1),
  119. Minor: iPtr(9),
  120. Access: "rwm",
  121. },
  122. {
  123. Allow: true,
  124. Type: "c",
  125. Major: iPtr(1),
  126. Minor: iPtr(8),
  127. Access: "rwm",
  128. },
  129. {
  130. Allow: true,
  131. Type: "c",
  132. Major: iPtr(5),
  133. Minor: iPtr(0),
  134. Access: "rwm",
  135. },
  136. {
  137. Allow: true,
  138. Type: "c",
  139. Major: iPtr(5),
  140. Minor: iPtr(1),
  141. Access: "rwm",
  142. },
  143. {
  144. Allow: false,
  145. Type: "c",
  146. Major: iPtr(10),
  147. Minor: iPtr(229),
  148. Access: "rwm",
  149. },
  150. },
  151. },
  152. }
  153. // For LCOW support, populate a blank Windows spec
  154. if runtime.GOOS == "windows" {
  155. s.Windows = &specs.Windows{}
  156. }
  157. return s
  158. }

1.2.2.2-Link实现) daemon/oci_linux.go#Daemon.populateCommonSpec

  1. func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container) error {
  2. if c.BaseFS == nil {
  3. return errors.New("populateCommonSpec: BaseFS of container " + c.ID + " is unexpectedly nil")
  4. }
  5. // ********************************** NOTICE ********************************** //
  6. linkedEnv, err := daemon.setupLinkedContainers(c)
  7. // ********************************** NOTICE ********************************** //
  8. if err != nil {
  9. return err
  10. }
  11. s.Root = &specs.Root{
  12. Path: c.BaseFS.Path(),
  13. Readonly: c.HostConfig.ReadonlyRootfs,
  14. }
  15. if err := c.SetupWorkingDirectory(daemon.idMapping.RootPair()); err != nil {
  16. return err
  17. }
  18. cwd := c.Config.WorkingDir
  19. if len(cwd) == 0 {
  20. cwd = "/"
  21. }
  22. s.Process.Args = append([]string{c.Path}, c.Args...)
  23. // only add the custom init if it is specified and the container is running in its
  24. // own private pid namespace. It does not make sense to add if it is running in the
  25. // host namespace or another container's pid namespace where we already have an init
  26. if c.HostConfig.PidMode.IsPrivate() {
  27. if (c.HostConfig.Init != nil && *c.HostConfig.Init) ||
  28. (c.HostConfig.Init == nil && daemon.configStore.Init) {
  29. s.Process.Args = append([]string{inContainerInitPath, "--", c.Path}, c.Args...)
  30. path := daemon.configStore.InitPath
  31. if path == "" {
  32. path, err = exec.LookPath(daemonconfig.DefaultInitBinary)
  33. if err != nil {
  34. return err
  35. }
  36. }
  37. s.Mounts = append(s.Mounts, specs.Mount{
  38. Destination: inContainerInitPath,
  39. Type: "bind",
  40. Source: path,
  41. Options: []string{"bind", "ro"},
  42. })
  43. }
  44. }
  45. s.Process.Cwd = cwd
  46. // ********************************** NOTICE ********************************** //
  47. s.Process.Env = c.CreateDaemonEnvironment(c.Config.Tty, linkedEnv)
  48. // ********************************** NOTICE ********************************** //
  49. s.Process.Terminal = c.Config.Tty
  50. s.Hostname = c.Config.Hostname
  51. // There isn't a field in the OCI for the NIS domainname, but luckily there
  52. // is a sysctl which has an identical effect to setdomainname(2) so there's
  53. // no explicit need for runtime support.
  54. s.Linux.Sysctl = make(map[string]string)
  55. if c.Config.Domainname != "" {
  56. s.Linux.Sysctl["kernel.domainname"] = c.Config.Domainname
  57. }
  58. return nil
  59. }

1.2.2.3) daemon/oci_linux.go#setNamespaces

  1. func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error {
  2. userNS := false
  3. // user
  4. if c.HostConfig.UsernsMode.IsPrivate() {
  5. uidMap := daemon.idMapping.UIDs()
  6. if uidMap != nil {
  7. userNS = true
  8. ns := specs.LinuxNamespace{Type: "user"}
  9. setNamespace(s, ns)
  10. s.Linux.UIDMappings = specMapping(uidMap)
  11. s.Linux.GIDMappings = specMapping(daemon.idMapping.GIDs())
  12. }
  13. }
  14. // network
  15. if !c.Config.NetworkDisabled {
  16. ns := specs.LinuxNamespace{Type: "network"}
  17. parts := strings.SplitN(string(c.HostConfig.NetworkMode), ":", 2)
  18. if parts[0] == "container" {
  19. nc, err := daemon.getNetworkedContainer(c.ID, c.HostConfig.NetworkMode.ConnectedContainer())
  20. if err != nil {
  21. return err
  22. }
  23. ns.Path = fmt.Sprintf("/proc/%d/ns/net", nc.State.GetPID())
  24. if userNS {
  25. // to share a net namespace, they must also share a user namespace
  26. nsUser := specs.LinuxNamespace{Type: "user"}
  27. nsUser.Path = fmt.Sprintf("/proc/%d/ns/user", nc.State.GetPID())
  28. setNamespace(s, nsUser)
  29. }
  30. } else if c.HostConfig.NetworkMode.IsHost() {
  31. ns.Path = c.NetworkSettings.SandboxKey
  32. }
  33. // ********************************** NOTICE ********************************** //
  34. setNamespace(s, ns)
  35. // ********************************** NOTICE ********************************** //
  36. }
  37. // ipc
  38. ipcMode := c.HostConfig.IpcMode
  39. switch {
  40. case ipcMode.IsContainer():
  41. ns := specs.LinuxNamespace{Type: "ipc"}
  42. ic, err := daemon.getIpcContainer(ipcMode.Container())
  43. if err != nil {
  44. return err
  45. }
  46. ns.Path = fmt.Sprintf("/proc/%d/ns/ipc", ic.State.GetPID())
  47. setNamespace(s, ns)
  48. if userNS {
  49. // to share an IPC namespace, they must also share a user namespace
  50. nsUser := specs.LinuxNamespace{Type: "user"}
  51. nsUser.Path = fmt.Sprintf("/proc/%d/ns/user", ic.State.GetPID())
  52. setNamespace(s, nsUser)
  53. }
  54. case ipcMode.IsHost():
  55. oci.RemoveNamespace(s, specs.LinuxNamespaceType("ipc"))
  56. case ipcMode.IsEmpty():
  57. // A container was created by an older version of the daemon.
  58. // The default behavior used to be what is now called "shareable".
  59. fallthrough
  60. case ipcMode.IsPrivate(), ipcMode.IsShareable(), ipcMode.IsNone():
  61. ns := specs.LinuxNamespace{Type: "ipc"}
  62. setNamespace(s, ns)
  63. default:
  64. return fmt.Errorf("Invalid IPC mode: %v", ipcMode)
  65. }
  66. // pid
  67. if c.HostConfig.PidMode.IsContainer() {
  68. ns := specs.LinuxNamespace{Type: "pid"}
  69. pc, err := daemon.getPidContainer(c)
  70. if err != nil {
  71. return err
  72. }
  73. ns.Path = fmt.Sprintf("/proc/%d/ns/pid", pc.State.GetPID())
  74. setNamespace(s, ns)
  75. if userNS {
  76. // to share a PID namespace, they must also share a user namespace
  77. nsUser := specs.LinuxNamespace{Type: "user"}
  78. nsUser.Path = fmt.Sprintf("/proc/%d/ns/user", pc.State.GetPID())
  79. setNamespace(s, nsUser)
  80. }
  81. } else if c.HostConfig.PidMode.IsHost() {
  82. oci.RemoveNamespace(s, specs.LinuxNamespaceType("pid"))
  83. } else {
  84. ns := specs.LinuxNamespace{Type: "pid"}
  85. setNamespace(s, ns)
  86. }
  87. // uts
  88. if c.HostConfig.UTSMode.IsHost() {
  89. oci.RemoveNamespace(s, specs.LinuxNamespaceType("uts"))
  90. s.Hostname = ""
  91. }
  92. return nil
  93. }

1.2.2.3.1) daemon/oci_linux.go#setNamespace
  1. func setNamespace(s *specs.Spec, ns specs.LinuxNamespace) {
  2. for i, n := range s.Linux.Namespaces {
  3. if n.Type == ns.Type {
  4. s.Linux.Namespaces[i] = ns
  5. return
  6. }
  7. }
  8. s.Linux.Namespaces = append(s.Linux.Namespaces, ns)
  9. }

1.2.2.4) daemon/container_operations_unix.go#setupContainerMountsRoot

  1. func (daemon *Daemon) setupContainerMountsRoot(c *container.Container) error {
  2. // get the root mount path so we can make it unbindable
  3. p, err := c.MountsResourcePath("")
  4. if err != nil {
  5. return err
  6. }
  7. return idtools.MkdirAllAndChown(p, 0700, daemon.idMapping.RootPair())
  8. }

1.2.2.5) daemon/volumes_unix.go#setupMounts

  1. // setupMounts iterates through each of the mount points for a container and
  2. // calls Setup() on each. It also looks to see if is a network mount such as
  3. // /etc/resolv.conf, and if it is not, appends it to the array of mounts.
  4. func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, error) {
  5. var mounts []container.Mount
  6. // TODO: tmpfs mounts should be part of Mountpoints
  7. tmpfsMounts := make(map[string]bool)
  8. tmpfsMountInfo, err := c.TmpfsMounts()
  9. if err != nil {
  10. return nil, err
  11. }
  12. for _, m := range tmpfsMountInfo {
  13. tmpfsMounts[m.Destination] = true
  14. }
  15. for _, m := range c.MountPoints {
  16. if tmpfsMounts[m.Destination] {
  17. continue
  18. }
  19. // ********************************** NOTICE ********************************** //
  20. if err := daemon.lazyInitializeVolume(c.ID, m); err != nil {
  21. // ********************************** NOTICE ********************************** //
  22. return nil, err
  23. }
  24. // If the daemon is being shutdown, we should not let a container start if it is trying to
  25. // mount the socket the daemon is listening on. During daemon shutdown, the socket
  26. // (/var/run/docker.sock by default) doesn't exist anymore causing the call to m.Setup to
  27. // create at directory instead. This in turn will prevent the daemon to restart.
  28. checkfunc := func(m *volumemounts.MountPoint) error {
  29. if _, exist := daemon.hosts[m.Source]; exist && daemon.IsShuttingDown() {
  30. return fmt.Errorf("Could not mount %q to container while the daemon is shutting down", m.Source)
  31. }
  32. return nil
  33. }
  34. path, err := m.Setup(c.MountLabel, daemon.idMapping.RootPair(), checkfunc)
  35. if err != nil {
  36. return nil, err
  37. }
  38. if !c.TrySetNetworkMount(m.Destination, path) {
  39. mnt := container.Mount{
  40. Source: path,
  41. Destination: m.Destination,
  42. Writable: m.RW,
  43. Propagation: string(m.Propagation),
  44. }
  45. if m.Spec.Type == mounttypes.TypeBind && m.Spec.BindOptions != nil {
  46. mnt.NonRecursive = m.Spec.BindOptions.NonRecursive
  47. }
  48. if m.Volume != nil {
  49. attributes := map[string]string{
  50. "driver": m.Volume.DriverName(),
  51. "container": c.ID,
  52. "destination": m.Destination,
  53. "read/write": strconv.FormatBool(m.RW),
  54. "propagation": string(m.Propagation),
  55. }
  56. daemon.LogVolumeEvent(m.Volume.Name(), "mount", attributes)
  57. }
  58. mounts = append(mounts, mnt)
  59. }
  60. }
  61. mounts = sortMounts(mounts)
  62. // ********************************** NOTICE ********************************** //
  63. netMounts := c.NetworkMounts()
  64. // ********************************** NOTICE ********************************** //
  65. // if we are going to mount any of the network files from container
  66. // metadata, the ownership must be set properly for potential container
  67. // remapped root (user namespaces)
  68. rootIDs := daemon.idMapping.RootPair()
  69. for _, mount := range netMounts {
  70. // we should only modify ownership of network files within our own container
  71. // metadata repository. If the user specifies a mount path external, it is
  72. // up to the user to make sure the file has proper ownership for userns
  73. if strings.Index(mount.Source, daemon.repository) == 0 {
  74. if err := os.Chown(mount.Source, rootIDs.UID, rootIDs.GID); err != nil {
  75. return nil, err
  76. }
  77. }
  78. }
  79. return append(mounts, netMounts...), nil
  80. }

—1.2.2.5.1) container/container_unix.go#Container.NetworkMounts

  1. // NetworkMounts returns the list of network mounts.
  2. func (container *Container) NetworkMounts() []Mount {
  3. var mounts []Mount
  4. shared := container.HostConfig.NetworkMode.IsContainer()
  5. parser := volumemounts.NewParser(container.OS)
  6. if container.ResolvConfPath != "" {
  7. if _, err := os.Stat(container.ResolvConfPath); err != nil {
  8. logrus.Warnf("ResolvConfPath set to %q, but can't stat this filename (err = %v); skipping", container.ResolvConfPath, err)
  9. } else {
  10. writable := !container.HostConfig.ReadonlyRootfs
  11. if m, exists := container.MountPoints["/etc/resolv.conf"]; exists {
  12. writable = m.RW
  13. } else {
  14. label.Relabel(container.ResolvConfPath, container.MountLabel, shared)
  15. }
  16. mounts = append(mounts, Mount{
  17. Source: container.ResolvConfPath,
  18. Destination: "/etc/resolv.conf",
  19. Writable: writable,
  20. Propagation: string(parser.DefaultPropagationMode()),
  21. })
  22. }
  23. }
  24. if container.HostnamePath != "" {
  25. if _, err := os.Stat(container.HostnamePath); err != nil {
  26. logrus.Warnf("HostnamePath set to %q, but can't stat this filename (err = %v); skipping", container.HostnamePath, err)
  27. } else {
  28. writable := !container.HostConfig.ReadonlyRootfs
  29. if m, exists := container.MountPoints["/etc/hostname"]; exists {
  30. writable = m.RW
  31. } else {
  32. label.Relabel(container.HostnamePath, container.MountLabel, shared)
  33. }
  34. mounts = append(mounts, Mount{
  35. Source: container.HostnamePath,
  36. Destination: "/etc/hostname",
  37. Writable: writable,
  38. Propagation: string(parser.DefaultPropagationMode()),
  39. })
  40. }
  41. }
  42. if container.HostsPath != "" {
  43. if _, err := os.Stat(container.HostsPath); err != nil {
  44. logrus.Warnf("HostsPath set to %q, but can't stat this filename (err = %v); skipping", container.HostsPath, err)
  45. } else {
  46. writable := !container.HostConfig.ReadonlyRootfs
  47. if m, exists := container.MountPoints["/etc/hosts"]; exists {
  48. writable = m.RW
  49. } else {
  50. label.Relabel(container.HostsPath, container.MountLabel, shared)
  51. }
  52. mounts = append(mounts, Mount{
  53. Source: container.HostsPath,
  54. Destination: "/etc/hosts",
  55. Writable: writable,
  56. Propagation: string(parser.DefaultPropagationMode()),
  57. })
  58. }
  59. }
  60. return mounts
  61. }

1.2.3) libcontainerd/client_daemon.go#client.Create

  1. // Client provides access to containerd features.
  2. type Client interface {
  3. Version(ctx context.Context) (containerd.Version, error)
  4. Restore(ctx context.Context, containerID string, attachStdio StdioCallback) (alive bool, pid int, err error)
  5. Create(ctx context.Context, containerID string, spec *specs.Spec, runtimeOptions interface{}) error
  6. Start(ctx context.Context, containerID, checkpointDir string, withStdin bool, attachStdio StdioCallback) (pid int, err error)
  7. SignalProcess(ctx context.Context, containerID, processID string, signal int) error
  8. Exec(ctx context.Context, containerID, processID string, spec *specs.Process, withStdin bool, attachStdio StdioCallback) (int, error)
  9. ResizeTerminal(ctx context.Context, containerID, processID string, width, height int) error
  10. CloseStdin(ctx context.Context, containerID, processID string) error
  11. Pause(ctx context.Context, containerID string) error
  12. Resume(ctx context.Context, containerID string) error
  13. Stats(ctx context.Context, containerID string) (*Stats, error)
  14. ListPids(ctx context.Context, containerID string) ([]uint32, error)
  15. Summary(ctx context.Context, containerID string) ([]Summary, error)
  16. DeleteTask(ctx context.Context, containerID string) (uint32, time.Time, error)
  17. Delete(ctx context.Context, containerID string) error
  18. Status(ctx context.Context, containerID string) (Status, error)
  19. UpdateResources(ctx context.Context, containerID string, resources *Resources) error
  20. CreateCheckpoint(ctx context.Context, containerID, checkpointDir string, exit bool) error
  21. }
  22. type client struct {
  23. sync.RWMutex // protects containers map
  24. client *containerd.Client
  25. stateDir string
  26. logger *logrus.Entry
  27. ns string
  28. backend Backend
  29. eventQ queue
  30. // 容器缓存,放在内存里的
  31. containers map[string]*container
  32. }
  33. type container struct {
  34. mu sync.Mutex
  35. bundleDir string
  36. ctr containerd.Container
  37. task containerd.Task
  38. execs map[string]containerd.Process
  39. oomKilled bool
  40. }
  1. func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, runtimeOptions interface{}) error {
  2. if ctr := c.getContainer(id); ctr != nil {
  3. return errors.WithStack(newConflictError("id already in use"))
  4. }
  5. // ********************************** NOTICE ********************************** //
  6. bdir, err := prepareBundleDir(filepath.Join(c.stateDir, id), ociSpec)
  7. // ********************************** NOTICE ********************************** //
  8. if err != nil {
  9. return errdefs.System(errors.Wrap(err, "prepare bundle dir failed"))
  10. }
  11. c.logger.WithField("bundle", bdir).WithField("root", ociSpec.Root.Path).Debug("bundle dir created")
  12. // ********************************** NOTICE ********************************** //
  13. cdCtr, err := c.client.NewContainer(ctx, id,
  14. containerd.WithSpec(ociSpec),
  15. // TODO(mlaventure): when containerd support lcow, revisit runtime value
  16. containerd.WithRuntime(fmt.Sprintf("io.containerd.runtime.v1.%s", runtime.GOOS), runtimeOptions))
  17. // ********************************** NOTICE ********************************** //
  18. if err != nil {
  19. return wrapError(err)
  20. }
  21. c.Lock()
  22. c.containers[id] = &container{
  23. bundleDir: b
  24. dir,
  25. ctr: cdCtr,
  26. }
  27. c.Unlock()
  28. return nil
  29. }

1.2.4) libcontainerd/client_daemon.go#client.Start

  1. // Start create and start a task for the specified containerd id
  2. func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin bool, attachStdio StdioCallback) (int, error) {
  3. ctr := c.getContainer(id)
  4. if ctr == nil {
  5. return -1, errors.WithStack(newNotFoundError("no such container"))
  6. }
  7. // ********************************** NOTICE ********************************** //
  8. if t := ctr.getTask(); t != nil {
  9. // ********************************** NOTICE ********************************** //
  10. return -1, errors.WithStack(newConflictError("container already started"))
  11. }
  12. var (
  13. cp *types.Descriptor
  14. t containerd.Task
  15. rio cio.IO
  16. err error
  17. stdinCloseSync = make(chan struct{})
  18. )
  19. if checkpointDir != "" {
  20. // write checkpoint to the content store
  21. tar := archive.Diff(ctx, "", checkpointDir)
  22. cp, err = c.writeContent(ctx, images.MediaTypeContainerd1Checkpoint, checkpointDir, tar)
  23. // remove the checkpoint when we're done
  24. defer func() {
  25. if cp != nil {
  26. err := c.client.ContentStore().Delete(context.Background(), cp.Digest)
  27. if err != nil {
  28. c.logger.WithError(err).WithFields(logrus.Fields{
  29. "ref": checkpointDir,
  30. "digest": cp.Digest,
  31. }).Warnf("failed to delete temporary checkpoint entry")
  32. }
  33. }
  34. }()
  35. if err := tar.Close(); err != nil {
  36. return -1, errors.Wrap(err, "failed to close checkpoint tar stream")
  37. }
  38. if err != nil {
  39. return -1, errors.Wrapf(err, "failed to upload checkpoint to containerd")
  40. }
  41. }
  42. spec, err := ctr.ctr.Spec(ctx)
  43. if err != nil {
  44. return -1, errors.Wrap(err, "failed to retrieve spec")
  45. }
  46. uid, gid := getSpecUser(spec)
  47. // ********************************** NOTICE ********************************** //
  48. t, err = ctr.ctr.NewTask(ctx,
  49. func(id string) (cio.IO, error) {
  50. fifos := newFIFOSet(ctr.bundleDir, InitProcessName, withStdin, spec.Process.Terminal)
  51. rio, err = c.createIO(fifos, id, InitProcessName, stdinCloseSync, attachStdio)
  52. return rio, err
  53. },
  54. func(_ context.Context, _ *containerd.Client, info *containerd.TaskInfo) error {
  55. info.Checkpoint = cp
  56. info.Options = &runctypes.CreateOptions{
  57. IoUid: uint32(uid),
  58. IoGid: uint32(gid),
  59. NoPivotRoot: os.Getenv("DOCKER_RAMDISK") != "",
  60. }
  61. return nil
  62. })
  63. // ********************************** NOTICE ********************************** //
  64. if err != nil {
  65. close(stdinCloseSync)
  66. if rio != nil {
  67. rio.Cancel()
  68. rio.Close()
  69. }
  70. return -1, wrapError(err)
  71. }
  72. ctr.setTask(t)
  73. // Signal c.createIO that it can call CloseIO
  74. close(stdinCloseSync)
  75. // ********************************** NOTICE ********************************** //
  76. if err := t.Start(ctx); err != nil {
  77. // ********************************** NOTICE ********************************** //
  78. if _, err := t.Delete(ctx); err != nil {
  79. c.logger.WithError(err).WithField("container", id).
  80. Error("failed to delete task after fail start")
  81. }
  82. ctr.setTask(nil)
  83. return -1, wrapError(err)
  84. }
  85. return int(t.Pid()), nil
  86. }