oci_windows.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package daemon
  2. import (
  3. "syscall"
  4. containertypes "github.com/docker/docker/api/types/container"
  5. "github.com/docker/docker/container"
  6. "github.com/docker/docker/oci"
  7. "github.com/docker/docker/pkg/sysinfo"
  8. "github.com/opencontainers/runtime-spec/specs-go"
  9. )
  10. func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
  11. s := oci.DefaultSpec()
  12. linkedEnv, err := daemon.setupLinkedContainers(c)
  13. if err != nil {
  14. return nil, err
  15. }
  16. // Note, unlike Unix, we do NOT call into SetupWorkingDirectory as
  17. // this is done in VMCompute. Further, we couldn't do it for Hyper-V
  18. // containers anyway.
  19. // In base spec
  20. s.Hostname = c.FullHostname()
  21. if err := daemon.setupSecretDir(c); err != nil {
  22. return nil, err
  23. }
  24. if err := daemon.setupConfigDir(c); err != nil {
  25. return nil, err
  26. }
  27. // In s.Mounts
  28. mounts, err := daemon.setupMounts(c)
  29. if err != nil {
  30. return nil, err
  31. }
  32. var isHyperV bool
  33. if c.HostConfig.Isolation.IsDefault() {
  34. // Container using default isolation, so take the default from the daemon configuration
  35. isHyperV = daemon.defaultIsolation.IsHyperV()
  36. } else {
  37. // Container may be requesting an explicit isolation mode.
  38. isHyperV = c.HostConfig.Isolation.IsHyperV()
  39. }
  40. // If the container has not been started, and has configs or secrets
  41. // secrets, create symlinks to each confing and secret. If it has been
  42. // started before, the symlinks should have already been created. Also, it
  43. // is important to not mount a Hyper-V container that has been started
  44. // before, to protect the host from the container; for example, from
  45. // malicious mutation of NTFS data structures.
  46. if !c.HasBeenStartedBefore && (len(c.SecretReferences) > 0 || len(c.ConfigReferences) > 0) {
  47. // The container file system is mounted before this function is called,
  48. // except for Hyper-V containers, so mount it here in that case.
  49. if isHyperV {
  50. if err := daemon.Mount(c); err != nil {
  51. return nil, err
  52. }
  53. defer daemon.Unmount(c)
  54. }
  55. if err := c.CreateSecretSymlinks(); err != nil {
  56. return nil, err
  57. }
  58. if err := c.CreateConfigSymlinks(); err != nil {
  59. return nil, err
  60. }
  61. }
  62. if m := c.SecretMounts(); m != nil {
  63. mounts = append(mounts, m...)
  64. }
  65. if m := c.ConfigMounts(); m != nil {
  66. mounts = append(mounts, m...)
  67. }
  68. for _, mount := range mounts {
  69. m := specs.Mount{
  70. Source: mount.Source,
  71. Destination: mount.Destination,
  72. }
  73. if !mount.Writable {
  74. m.Options = append(m.Options, "ro")
  75. }
  76. s.Mounts = append(s.Mounts, m)
  77. }
  78. // In s.Process
  79. s.Process.Args = append([]string{c.Path}, c.Args...)
  80. if !c.Config.ArgsEscaped {
  81. s.Process.Args = escapeArgs(s.Process.Args)
  82. }
  83. s.Process.Cwd = c.Config.WorkingDir
  84. if len(s.Process.Cwd) == 0 {
  85. // We default to C:\ to workaround the oddity of the case that the
  86. // default directory for cmd running as LocalSystem (or
  87. // ContainerAdministrator) is c:\windows\system32. Hence docker run
  88. // <image> cmd will by default end in c:\windows\system32, rather
  89. // than 'root' (/) on Linux. The oddity is that if you have a dockerfile
  90. // which has no WORKDIR and has a COPY file ., . will be interpreted
  91. // as c:\. Hence, setting it to default of c:\ makes for consistency.
  92. s.Process.Cwd = `C:\`
  93. }
  94. s.Process.Env = c.CreateDaemonEnvironment(c.Config.Tty, linkedEnv)
  95. s.Process.ConsoleSize.Height = c.HostConfig.ConsoleSize[0]
  96. s.Process.ConsoleSize.Width = c.HostConfig.ConsoleSize[1]
  97. s.Process.Terminal = c.Config.Tty
  98. s.Process.User.Username = c.Config.User
  99. // In spec.Root. This is not set for Hyper-V containers
  100. if !isHyperV {
  101. s.Root.Path = c.BaseFS
  102. }
  103. s.Root.Readonly = false // Windows does not support a read-only root filesystem
  104. // In s.Windows.Resources
  105. cpuShares := uint16(c.HostConfig.CPUShares)
  106. cpuMaximum := uint16(c.HostConfig.CPUPercent) * 100
  107. cpuCount := uint64(c.HostConfig.CPUCount)
  108. if c.HostConfig.NanoCPUs > 0 {
  109. if isHyperV {
  110. cpuCount = uint64(c.HostConfig.NanoCPUs / 1e9)
  111. leftoverNanoCPUs := c.HostConfig.NanoCPUs % 1e9
  112. if leftoverNanoCPUs != 0 {
  113. cpuCount++
  114. cpuMaximum = uint16(c.HostConfig.NanoCPUs / int64(cpuCount) / (1e9 / 10000))
  115. if cpuMaximum < 1 {
  116. // The requested NanoCPUs is so small that we rounded to 0, use 1 instead
  117. cpuMaximum = 1
  118. }
  119. }
  120. } else {
  121. cpuMaximum = uint16(c.HostConfig.NanoCPUs / int64(sysinfo.NumCPU()) / (1e9 / 10000))
  122. if cpuMaximum < 1 {
  123. // The requested NanoCPUs is so small that we rounded to 0, use 1 instead
  124. cpuMaximum = 1
  125. }
  126. }
  127. }
  128. memoryLimit := uint64(c.HostConfig.Memory)
  129. s.Windows.Resources = &specs.WindowsResources{
  130. CPU: &specs.WindowsCPUResources{
  131. Maximum: &cpuMaximum,
  132. Shares: &cpuShares,
  133. Count: &cpuCount,
  134. },
  135. Memory: &specs.WindowsMemoryResources{
  136. Limit: &memoryLimit,
  137. },
  138. Storage: &specs.WindowsStorageResources{
  139. Bps: &c.HostConfig.IOMaximumBandwidth,
  140. Iops: &c.HostConfig.IOMaximumIOps,
  141. },
  142. }
  143. return (*specs.Spec)(&s), nil
  144. }
  145. func escapeArgs(args []string) []string {
  146. escapedArgs := make([]string, len(args))
  147. for i, a := range args {
  148. escapedArgs[i] = syscall.EscapeArg(a)
  149. }
  150. return escapedArgs
  151. }
  152. // mergeUlimits merge the Ulimits from HostConfig with daemon defaults, and update HostConfig
  153. // It will do nothing on non-Linux platform
  154. func (daemon *Daemon) mergeUlimits(c *containertypes.HostConfig) {
  155. return
  156. }