daemon_unix.go 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160
  1. // +build linux freebsd
  2. package daemon
  3. import (
  4. "bytes"
  5. "fmt"
  6. "io/ioutil"
  7. "net"
  8. "os"
  9. "path/filepath"
  10. "runtime"
  11. "runtime/debug"
  12. "strconv"
  13. "strings"
  14. "syscall"
  15. "github.com/Sirupsen/logrus"
  16. "github.com/docker/docker/container"
  17. "github.com/docker/docker/image"
  18. "github.com/docker/docker/pkg/idtools"
  19. "github.com/docker/docker/pkg/parsers"
  20. "github.com/docker/docker/pkg/parsers/kernel"
  21. "github.com/docker/docker/pkg/sysinfo"
  22. "github.com/docker/docker/runconfig"
  23. runconfigopts "github.com/docker/docker/runconfig/opts"
  24. "github.com/docker/engine-api/types"
  25. "github.com/docker/engine-api/types/blkiodev"
  26. pblkiodev "github.com/docker/engine-api/types/blkiodev"
  27. containertypes "github.com/docker/engine-api/types/container"
  28. "github.com/docker/libnetwork"
  29. nwconfig "github.com/docker/libnetwork/config"
  30. "github.com/docker/libnetwork/drivers/bridge"
  31. "github.com/docker/libnetwork/netlabel"
  32. "github.com/docker/libnetwork/netutils"
  33. "github.com/docker/libnetwork/options"
  34. lntypes "github.com/docker/libnetwork/types"
  35. "github.com/golang/protobuf/ptypes"
  36. "github.com/opencontainers/runc/libcontainer/label"
  37. "github.com/opencontainers/runc/libcontainer/user"
  38. "github.com/opencontainers/specs/specs-go"
  39. )
  40. const (
  41. // See https://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/tree/kernel/sched/sched.h?id=8cd9234c64c584432f6992fe944ca9e46ca8ea76#n269
  42. linuxMinCPUShares = 2
  43. linuxMaxCPUShares = 262144
  44. platformSupported = true
  45. // It's not kernel limit, we want this 4M limit to supply a reasonable functional container
  46. linuxMinMemory = 4194304
  47. // constants for remapped root settings
  48. defaultIDSpecifier string = "default"
  49. defaultRemappedID string = "dockremap"
  50. // constant for cgroup drivers
  51. cgroupFsDriver = "cgroupfs"
  52. cgroupSystemdDriver = "systemd"
  53. )
  54. func getMemoryResources(config containertypes.Resources) *specs.Memory {
  55. memory := specs.Memory{}
  56. if config.Memory > 0 {
  57. limit := uint64(config.Memory)
  58. memory.Limit = &limit
  59. }
  60. if config.MemoryReservation > 0 {
  61. reservation := uint64(config.MemoryReservation)
  62. memory.Reservation = &reservation
  63. }
  64. if config.MemorySwap != 0 {
  65. swap := uint64(config.MemorySwap)
  66. memory.Swap = &swap
  67. }
  68. if config.MemorySwappiness != nil {
  69. swappiness := uint64(*config.MemorySwappiness)
  70. memory.Swappiness = &swappiness
  71. }
  72. if config.KernelMemory != 0 {
  73. kernelMemory := uint64(config.KernelMemory)
  74. memory.Kernel = &kernelMemory
  75. }
  76. return &memory
  77. }
  78. func getCPUResources(config containertypes.Resources) *specs.CPU {
  79. cpu := specs.CPU{}
  80. if config.CPUShares != 0 {
  81. shares := uint64(config.CPUShares)
  82. cpu.Shares = &shares
  83. }
  84. if config.CpusetCpus != "" {
  85. cpuset := config.CpusetCpus
  86. cpu.Cpus = &cpuset
  87. }
  88. if config.CpusetMems != "" {
  89. cpuset := config.CpusetMems
  90. cpu.Mems = &cpuset
  91. }
  92. if config.CPUPeriod != 0 {
  93. period := uint64(config.CPUPeriod)
  94. cpu.Period = &period
  95. }
  96. if config.CPUQuota != 0 {
  97. quota := uint64(config.CPUQuota)
  98. cpu.Quota = &quota
  99. }
  100. return &cpu
  101. }
  102. func getBlkioWeightDevices(config containertypes.Resources) ([]specs.WeightDevice, error) {
  103. var stat syscall.Stat_t
  104. var blkioWeightDevices []specs.WeightDevice
  105. for _, weightDevice := range config.BlkioWeightDevice {
  106. if err := syscall.Stat(weightDevice.Path, &stat); err != nil {
  107. return nil, err
  108. }
  109. weight := weightDevice.Weight
  110. d := specs.WeightDevice{Weight: &weight}
  111. d.Major = int64(stat.Rdev / 256)
  112. d.Minor = int64(stat.Rdev % 256)
  113. blkioWeightDevices = append(blkioWeightDevices, d)
  114. }
  115. return blkioWeightDevices, nil
  116. }
  117. func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
  118. var (
  119. labelOpts []string
  120. err error
  121. )
  122. for _, opt := range config.SecurityOpt {
  123. if opt == "no-new-privileges" {
  124. container.NoNewPrivileges = true
  125. } else {
  126. var con []string
  127. if strings.Contains(opt, "=") {
  128. con = strings.SplitN(opt, "=", 2)
  129. } else if strings.Contains(opt, ":") {
  130. con = strings.SplitN(opt, ":", 2)
  131. logrus.Warn("Security options with `:` as a separator are deprecated and will be completely unsupported in 1.13, use `=` instead.")
  132. }
  133. if len(con) != 2 {
  134. return fmt.Errorf("Invalid --security-opt 1: %q", opt)
  135. }
  136. switch con[0] {
  137. case "label":
  138. labelOpts = append(labelOpts, con[1])
  139. case "apparmor":
  140. container.AppArmorProfile = con[1]
  141. case "seccomp":
  142. container.SeccompProfile = con[1]
  143. default:
  144. return fmt.Errorf("Invalid --security-opt 2: %q", opt)
  145. }
  146. }
  147. }
  148. container.ProcessLabel, container.MountLabel, err = label.InitLabels(labelOpts)
  149. return err
  150. }
  151. func getBlkioThrottleDevices(devs []*blkiodev.ThrottleDevice) ([]specs.ThrottleDevice, error) {
  152. var throttleDevices []specs.ThrottleDevice
  153. var stat syscall.Stat_t
  154. for _, d := range devs {
  155. if err := syscall.Stat(d.Path, &stat); err != nil {
  156. return nil, err
  157. }
  158. rate := d.Rate
  159. d := specs.ThrottleDevice{Rate: &rate}
  160. d.Major = int64(stat.Rdev / 256)
  161. d.Minor = int64(stat.Rdev % 256)
  162. throttleDevices = append(throttleDevices, d)
  163. }
  164. return throttleDevices, nil
  165. }
  166. func checkKernelVersion(k, major, minor int) bool {
  167. if v, err := kernel.GetKernelVersion(); err != nil {
  168. logrus.Warnf("error getting kernel version: %s", err)
  169. } else {
  170. if kernel.CompareKernelVersion(*v, kernel.VersionInfo{Kernel: k, Major: major, Minor: minor}) < 0 {
  171. return false
  172. }
  173. }
  174. return true
  175. }
  176. func checkKernel() error {
  177. // Check for unsupported kernel versions
  178. // FIXME: it would be cleaner to not test for specific versions, but rather
  179. // test for specific functionalities.
  180. // Unfortunately we can't test for the feature "does not cause a kernel panic"
  181. // without actually causing a kernel panic, so we need this workaround until
  182. // the circumstances of pre-3.10 crashes are clearer.
  183. // For details see https://github.com/docker/docker/issues/407
  184. // Docker 1.11 and above doesn't actually run on kernels older than 3.4,
  185. // due to containerd-shim usage of PR_SET_CHILD_SUBREAPER (introduced in 3.4).
  186. if !checkKernelVersion(3, 10, 0) {
  187. v, _ := kernel.GetKernelVersion()
  188. if os.Getenv("DOCKER_NOWARN_KERNEL_VERSION") == "" {
  189. logrus.Fatalf("Your Linux kernel version %s is not supported for running docker. Please upgrade your kernel to 3.10.0 or newer.", v.String())
  190. }
  191. }
  192. return nil
  193. }
  194. // adaptContainerSettings is called during container creation to modify any
  195. // settings necessary in the HostConfig structure.
  196. func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error {
  197. if adjustCPUShares && hostConfig.CPUShares > 0 {
  198. // Handle unsupported CPUShares
  199. if hostConfig.CPUShares < linuxMinCPUShares {
  200. logrus.Warnf("Changing requested CPUShares of %d to minimum allowed of %d", hostConfig.CPUShares, linuxMinCPUShares)
  201. hostConfig.CPUShares = linuxMinCPUShares
  202. } else if hostConfig.CPUShares > linuxMaxCPUShares {
  203. logrus.Warnf("Changing requested CPUShares of %d to maximum allowed of %d", hostConfig.CPUShares, linuxMaxCPUShares)
  204. hostConfig.CPUShares = linuxMaxCPUShares
  205. }
  206. }
  207. if hostConfig.Memory > 0 && hostConfig.MemorySwap == 0 {
  208. // By default, MemorySwap is set to twice the size of Memory.
  209. hostConfig.MemorySwap = hostConfig.Memory * 2
  210. }
  211. if hostConfig.ShmSize == 0 {
  212. hostConfig.ShmSize = container.DefaultSHMSize
  213. }
  214. var err error
  215. if hostConfig.SecurityOpt == nil {
  216. hostConfig.SecurityOpt, err = daemon.generateSecurityOpt(hostConfig.IpcMode, hostConfig.PidMode, hostConfig.Privileged)
  217. if err != nil {
  218. return err
  219. }
  220. }
  221. if hostConfig.MemorySwappiness == nil {
  222. defaultSwappiness := int64(-1)
  223. hostConfig.MemorySwappiness = &defaultSwappiness
  224. }
  225. if hostConfig.OomKillDisable == nil {
  226. defaultOomKillDisable := false
  227. hostConfig.OomKillDisable = &defaultOomKillDisable
  228. }
  229. return nil
  230. }
  231. func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysinfo.SysInfo, update bool) ([]string, error) {
  232. warnings := []string{}
  233. // memory subsystem checks and adjustments
  234. if resources.Memory != 0 && resources.Memory < linuxMinMemory {
  235. return warnings, fmt.Errorf("Minimum memory limit allowed is 4MB")
  236. }
  237. if resources.Memory > 0 && !sysInfo.MemoryLimit {
  238. warnings = append(warnings, "Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
  239. logrus.Warn("Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
  240. resources.Memory = 0
  241. resources.MemorySwap = -1
  242. }
  243. if resources.Memory > 0 && resources.MemorySwap != -1 && !sysInfo.SwapLimit {
  244. warnings = append(warnings, "Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.")
  245. logrus.Warn("Your kernel does not support swap limit capabilities,or the cgroup is not mounted. Memory limited without swap.")
  246. resources.MemorySwap = -1
  247. }
  248. if resources.Memory > 0 && resources.MemorySwap > 0 && resources.MemorySwap < resources.Memory {
  249. return warnings, fmt.Errorf("Minimum memoryswap limit should be larger than memory limit, see usage")
  250. }
  251. if resources.Memory == 0 && resources.MemorySwap > 0 && !update {
  252. return warnings, fmt.Errorf("You should always set the Memory limit when using Memoryswap limit, see usage")
  253. }
  254. if resources.MemorySwappiness != nil && *resources.MemorySwappiness != -1 && !sysInfo.MemorySwappiness {
  255. warnings = append(warnings, "Your kernel does not support memory swappiness capabilities or the cgroup is not mounted. Memory swappiness discarded.")
  256. logrus.Warn("Your kernel does not support memory swappiness capabilities, or the cgroup is not mounted. Memory swappiness discarded.")
  257. resources.MemorySwappiness = nil
  258. }
  259. if resources.MemorySwappiness != nil {
  260. swappiness := *resources.MemorySwappiness
  261. if swappiness < -1 || swappiness > 100 {
  262. return warnings, fmt.Errorf("Invalid value: %v, valid memory swappiness range is 0-100", swappiness)
  263. }
  264. }
  265. if resources.MemoryReservation > 0 && !sysInfo.MemoryReservation {
  266. warnings = append(warnings, "Your kernel does not support memory soft limit capabilities or the cgroup is not mounted. Limitation discarded.")
  267. logrus.Warn("Your kernel does not support memory soft limit capabilities or the cgroup is not mounted. Limitation discarded.")
  268. resources.MemoryReservation = 0
  269. }
  270. if resources.MemoryReservation > 0 && resources.MemoryReservation < linuxMinMemory {
  271. return warnings, fmt.Errorf("Minimum memory reservation allowed is 4MB")
  272. }
  273. if resources.Memory > 0 && resources.MemoryReservation > 0 && resources.Memory < resources.MemoryReservation {
  274. return warnings, fmt.Errorf("Minimum memory limit can not be less than memory reservation limit, see usage")
  275. }
  276. if resources.KernelMemory > 0 && !sysInfo.KernelMemory {
  277. warnings = append(warnings, "Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
  278. logrus.Warn("Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
  279. resources.KernelMemory = 0
  280. }
  281. if resources.KernelMemory > 0 && resources.KernelMemory < linuxMinMemory {
  282. return warnings, fmt.Errorf("Minimum kernel memory limit allowed is 4MB")
  283. }
  284. if resources.KernelMemory > 0 && !checkKernelVersion(4, 0, 0) {
  285. warnings = append(warnings, "You specified a kernel memory limit on a kernel older than 4.0. Kernel memory limits are experimental on older kernels, it won't work as expected and can cause your system to be unstable.")
  286. logrus.Warn("You specified a kernel memory limit on a kernel older than 4.0. Kernel memory limits are experimental on older kernels, it won't work as expected and can cause your system to be unstable.")
  287. }
  288. if resources.OomKillDisable != nil && !sysInfo.OomKillDisable {
  289. // only produce warnings if the setting wasn't to *disable* the OOM Kill; no point
  290. // warning the caller if they already wanted the feature to be off
  291. if *resources.OomKillDisable {
  292. warnings = append(warnings, "Your kernel does not support OomKillDisable. OomKillDisable discarded.")
  293. logrus.Warn("Your kernel does not support OomKillDisable. OomKillDisable discarded.")
  294. }
  295. resources.OomKillDisable = nil
  296. }
  297. if resources.PidsLimit != 0 && !sysInfo.PidsLimit {
  298. warnings = append(warnings, "Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.")
  299. logrus.Warn("Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.")
  300. resources.PidsLimit = 0
  301. }
  302. // cpu subsystem checks and adjustments
  303. if resources.CPUShares > 0 && !sysInfo.CPUShares {
  304. warnings = append(warnings, "Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.")
  305. logrus.Warn("Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.")
  306. resources.CPUShares = 0
  307. }
  308. if resources.CPUPeriod > 0 && !sysInfo.CPUCfsPeriod {
  309. warnings = append(warnings, "Your kernel does not support CPU cfs period or the cgroup is not mounted. Period discarded.")
  310. logrus.Warn("Your kernel does not support CPU cfs period or the cgroup is not mounted. Period discarded.")
  311. resources.CPUPeriod = 0
  312. }
  313. if resources.CPUPeriod != 0 && (resources.CPUPeriod < 1000 || resources.CPUPeriod > 1000000) {
  314. return warnings, fmt.Errorf("CPU cfs period can not be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)")
  315. }
  316. if resources.CPUQuota > 0 && !sysInfo.CPUCfsQuota {
  317. warnings = append(warnings, "Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.")
  318. logrus.Warn("Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.")
  319. resources.CPUQuota = 0
  320. }
  321. if resources.CPUQuota > 0 && resources.CPUQuota < 1000 {
  322. return warnings, fmt.Errorf("CPU cfs quota can not be less than 1ms (i.e. 1000)")
  323. }
  324. if resources.CPUPercent > 0 {
  325. warnings = append(warnings, "%s does not support CPU percent. Percent discarded.", runtime.GOOS)
  326. logrus.Warnf("%s does not support CPU percent. Percent discarded.", runtime.GOOS)
  327. resources.CPUPercent = 0
  328. }
  329. // cpuset subsystem checks and adjustments
  330. if (resources.CpusetCpus != "" || resources.CpusetMems != "") && !sysInfo.Cpuset {
  331. warnings = append(warnings, "Your kernel does not support cpuset or the cgroup is not mounted. Cpuset discarded.")
  332. logrus.Warn("Your kernel does not support cpuset or the cgroup is not mounted. Cpuset discarded.")
  333. resources.CpusetCpus = ""
  334. resources.CpusetMems = ""
  335. }
  336. cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(resources.CpusetCpus)
  337. if err != nil {
  338. return warnings, fmt.Errorf("Invalid value %s for cpuset cpus", resources.CpusetCpus)
  339. }
  340. if !cpusAvailable {
  341. return warnings, fmt.Errorf("Requested CPUs are not available - requested %s, available: %s", resources.CpusetCpus, sysInfo.Cpus)
  342. }
  343. memsAvailable, err := sysInfo.IsCpusetMemsAvailable(resources.CpusetMems)
  344. if err != nil {
  345. return warnings, fmt.Errorf("Invalid value %s for cpuset mems", resources.CpusetMems)
  346. }
  347. if !memsAvailable {
  348. return warnings, fmt.Errorf("Requested memory nodes are not available - requested %s, available: %s", resources.CpusetMems, sysInfo.Mems)
  349. }
  350. // blkio subsystem checks and adjustments
  351. if resources.BlkioWeight > 0 && !sysInfo.BlkioWeight {
  352. warnings = append(warnings, "Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.")
  353. logrus.Warn("Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.")
  354. resources.BlkioWeight = 0
  355. }
  356. if resources.BlkioWeight > 0 && (resources.BlkioWeight < 10 || resources.BlkioWeight > 1000) {
  357. return warnings, fmt.Errorf("Range of blkio weight is from 10 to 1000")
  358. }
  359. if resources.IOMaximumBandwidth != 0 || resources.IOMaximumIOps != 0 {
  360. return warnings, fmt.Errorf("Invalid QoS settings: %s does not support Maximum IO Bandwidth or Maximum IO IOps", runtime.GOOS)
  361. }
  362. if len(resources.BlkioWeightDevice) > 0 && !sysInfo.BlkioWeightDevice {
  363. warnings = append(warnings, "Your kernel does not support Block I/O weight_device or the cgroup is not mounted. Weight-device discarded.")
  364. logrus.Warn("Your kernel does not support Block I/O weight_device or the cgroup is not mounted. Weight-device discarded.")
  365. resources.BlkioWeightDevice = []*pblkiodev.WeightDevice{}
  366. }
  367. if len(resources.BlkioDeviceReadBps) > 0 && !sysInfo.BlkioReadBpsDevice {
  368. warnings = append(warnings, "Your kernel does not support BPS Block I/O read limit or the cgroup is not mounted. Block I/O BPS read limit discarded.")
  369. logrus.Warn("Your kernel does not support BPS Block I/O read limit or the cgroup is not mounted. Block I/O BPS read limit discarded")
  370. resources.BlkioDeviceReadBps = []*pblkiodev.ThrottleDevice{}
  371. }
  372. if len(resources.BlkioDeviceWriteBps) > 0 && !sysInfo.BlkioWriteBpsDevice {
  373. warnings = append(warnings, "Your kernel does not support BPS Block I/O write limit or the cgroup is not mounted. Block I/O BPS write limit discarded.")
  374. logrus.Warn("Your kernel does not support BPS Block I/O write limit or the cgroup is not mounted. Block I/O BPS write limit discarded.")
  375. resources.BlkioDeviceWriteBps = []*pblkiodev.ThrottleDevice{}
  376. }
  377. if len(resources.BlkioDeviceReadIOps) > 0 && !sysInfo.BlkioReadIOpsDevice {
  378. warnings = append(warnings, "Your kernel does not support IOPS Block read limit or the cgroup is not mounted. Block I/O IOPS read limit discarded.")
  379. logrus.Warn("Your kernel does not support IOPS Block I/O read limit in IO or the cgroup is not mounted. Block I/O IOPS read limit discarded.")
  380. resources.BlkioDeviceReadIOps = []*pblkiodev.ThrottleDevice{}
  381. }
  382. if len(resources.BlkioDeviceWriteIOps) > 0 && !sysInfo.BlkioWriteIOpsDevice {
  383. warnings = append(warnings, "Your kernel does not support IOPS Block write limit or the cgroup is not mounted. Block I/O IOPS write limit discarded.")
  384. logrus.Warn("Your kernel does not support IOPS Block I/O write limit or the cgroup is not mounted. Block I/O IOPS write limit discarded.")
  385. resources.BlkioDeviceWriteIOps = []*pblkiodev.ThrottleDevice{}
  386. }
  387. return warnings, nil
  388. }
  389. func (daemon *Daemon) getCgroupDriver() string {
  390. cgroupDriver := cgroupFsDriver
  391. if UsingSystemd(daemon.configStore) {
  392. cgroupDriver = cgroupSystemdDriver
  393. }
  394. return cgroupDriver
  395. }
  396. // getCD gets the raw value of the native.cgroupdriver option, if set.
  397. func getCD(config *Config) string {
  398. for _, option := range config.ExecOptions {
  399. key, val, err := parsers.ParseKeyValueOpt(option)
  400. if err != nil || !strings.EqualFold(key, "native.cgroupdriver") {
  401. continue
  402. }
  403. return val
  404. }
  405. return ""
  406. }
  407. // VerifyCgroupDriver validates native.cgroupdriver
  408. func VerifyCgroupDriver(config *Config) error {
  409. cd := getCD(config)
  410. if cd == "" || cd == cgroupFsDriver || cd == cgroupSystemdDriver {
  411. return nil
  412. }
  413. return fmt.Errorf("native.cgroupdriver option %s not supported", cd)
  414. }
  415. // UsingSystemd returns true if cli option includes native.cgroupdriver=systemd
  416. func UsingSystemd(config *Config) bool {
  417. return getCD(config) == cgroupSystemdDriver
  418. }
  419. // verifyPlatformContainerSettings performs platform-specific validation of the
  420. // hostconfig and config structures.
  421. func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
  422. warnings := []string{}
  423. sysInfo := sysinfo.New(true)
  424. warnings, err := daemon.verifyExperimentalContainerSettings(hostConfig, config)
  425. if err != nil {
  426. return warnings, err
  427. }
  428. w, err := verifyContainerResources(&hostConfig.Resources, sysInfo, update)
  429. if err != nil {
  430. return warnings, err
  431. }
  432. warnings = append(warnings, w...)
  433. if hostConfig.ShmSize < 0 {
  434. return warnings, fmt.Errorf("SHM size can not be less than 0")
  435. }
  436. if hostConfig.OomScoreAdj < -1000 || hostConfig.OomScoreAdj > 1000 {
  437. return warnings, fmt.Errorf("Invalid value %d, range for oom score adj is [-1000, 1000]", hostConfig.OomScoreAdj)
  438. }
  439. // ip-forwarding does not affect container with '--net=host' (or '--net=none')
  440. if sysInfo.IPv4ForwardingDisabled && !(hostConfig.NetworkMode.IsHost() || hostConfig.NetworkMode.IsNone()) {
  441. warnings = append(warnings, "IPv4 forwarding is disabled. Networking will not work.")
  442. logrus.Warn("IPv4 forwarding is disabled. Networking will not work")
  443. }
  444. // check for various conflicting options with user namespaces
  445. if daemon.configStore.RemappedRoot != "" && hostConfig.UsernsMode.IsPrivate() {
  446. if hostConfig.Privileged {
  447. return warnings, fmt.Errorf("Privileged mode is incompatible with user namespaces")
  448. }
  449. if hostConfig.NetworkMode.IsHost() {
  450. return warnings, fmt.Errorf("Cannot share the host's network namespace when user namespaces are enabled")
  451. }
  452. if hostConfig.PidMode.IsHost() {
  453. return warnings, fmt.Errorf("Cannot share the host PID namespace when user namespaces are enabled")
  454. }
  455. if hostConfig.ReadonlyRootfs {
  456. return warnings, fmt.Errorf("Cannot use the --read-only option when user namespaces are enabled")
  457. }
  458. }
  459. if hostConfig.CgroupParent != "" && UsingSystemd(daemon.configStore) {
  460. // CgroupParent for systemd cgroup should be named as "xxx.slice"
  461. if len(hostConfig.CgroupParent) <= 6 || !strings.HasSuffix(hostConfig.CgroupParent, ".slice") {
  462. return warnings, fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"")
  463. }
  464. }
  465. if hostConfig.Runtime == "" {
  466. hostConfig.Runtime = daemon.configStore.GetDefaultRuntimeName()
  467. }
  468. if rt := daemon.configStore.GetRuntime(hostConfig.Runtime); rt == nil {
  469. return warnings, fmt.Errorf("Unknown runtime specified %s", hostConfig.Runtime)
  470. }
  471. return warnings, nil
  472. }
  473. // platformReload update configuration with platform specific options
  474. func (daemon *Daemon) platformReload(config *Config, attributes *map[string]string) {
  475. if config.IsValueSet("runtimes") {
  476. daemon.configStore.Runtimes = config.Runtimes
  477. // Always set the default one
  478. daemon.configStore.Runtimes[stockRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary}
  479. }
  480. if config.DefaultRuntime != "" {
  481. daemon.configStore.DefaultRuntime = config.DefaultRuntime
  482. }
  483. // Update attributes
  484. var runtimeList bytes.Buffer
  485. for name, rt := range daemon.configStore.Runtimes {
  486. if runtimeList.Len() > 0 {
  487. runtimeList.WriteRune(' ')
  488. }
  489. runtimeList.WriteString(fmt.Sprintf("%s:%s", name, rt))
  490. }
  491. (*attributes)["runtimes"] = runtimeList.String()
  492. (*attributes)["default-runtime"] = daemon.configStore.DefaultRuntime
  493. }
  494. // verifyDaemonSettings performs validation of daemon config struct
  495. func verifyDaemonSettings(config *Config) error {
  496. // Check for mutually incompatible config options
  497. if config.bridgeConfig.Iface != "" && config.bridgeConfig.IP != "" {
  498. return fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one")
  499. }
  500. if !config.bridgeConfig.EnableIPTables && !config.bridgeConfig.InterContainerCommunication {
  501. return fmt.Errorf("You specified --iptables=false with --icc=false. ICC=false uses iptables to function. Please set --icc or --iptables to true")
  502. }
  503. if !config.bridgeConfig.EnableIPTables && config.bridgeConfig.EnableIPMasq {
  504. config.bridgeConfig.EnableIPMasq = false
  505. }
  506. if err := VerifyCgroupDriver(config); err != nil {
  507. return err
  508. }
  509. if config.CgroupParent != "" && UsingSystemd(config) {
  510. if len(config.CgroupParent) <= 6 || !strings.HasSuffix(config.CgroupParent, ".slice") {
  511. return fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"")
  512. }
  513. }
  514. if config.DefaultRuntime == "" {
  515. config.DefaultRuntime = stockRuntimeName
  516. }
  517. if config.Runtimes == nil {
  518. config.Runtimes = make(map[string]types.Runtime)
  519. }
  520. stockRuntimeOpts := []string{}
  521. if UsingSystemd(config) {
  522. stockRuntimeOpts = append(stockRuntimeOpts, "--systemd-cgroup=true")
  523. }
  524. config.Runtimes[stockRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary, Args: stockRuntimeOpts}
  525. return nil
  526. }
  527. // checkSystem validates platform-specific requirements
  528. func checkSystem() error {
  529. if os.Geteuid() != 0 {
  530. return fmt.Errorf("The Docker daemon needs to be run as root")
  531. }
  532. return checkKernel()
  533. }
  534. // configureMaxThreads sets the Go runtime max threads threshold
  535. // which is 90% of the kernel setting from /proc/sys/kernel/threads-max
  536. func configureMaxThreads(config *Config) error {
  537. mt, err := ioutil.ReadFile("/proc/sys/kernel/threads-max")
  538. if err != nil {
  539. return err
  540. }
  541. mtint, err := strconv.Atoi(strings.TrimSpace(string(mt)))
  542. if err != nil {
  543. return err
  544. }
  545. maxThreads := (mtint / 100) * 90
  546. debug.SetMaxThreads(maxThreads)
  547. logrus.Debugf("Golang's threads limit set to %d", maxThreads)
  548. return nil
  549. }
  550. // configureKernelSecuritySupport configures and validates security support for the kernel
  551. func configureKernelSecuritySupport(config *Config, driverName string) error {
  552. if config.EnableSelinuxSupport {
  553. if selinuxEnabled() {
  554. // As Docker on overlayFS and SELinux are incompatible at present, error on overlayfs being enabled
  555. if driverName == "overlay" {
  556. return fmt.Errorf("SELinux is not supported with the %s graph driver", driverName)
  557. }
  558. logrus.Debug("SELinux enabled successfully")
  559. } else {
  560. logrus.Warn("Docker could not enable SELinux on the host system")
  561. }
  562. } else {
  563. selinuxSetDisabled()
  564. }
  565. return nil
  566. }
  567. func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) {
  568. netOptions, err := daemon.networkOptions(config, activeSandboxes)
  569. if err != nil {
  570. return nil, err
  571. }
  572. controller, err := libnetwork.New(netOptions...)
  573. if err != nil {
  574. return nil, fmt.Errorf("error obtaining controller instance: %v", err)
  575. }
  576. if len(activeSandboxes) > 0 {
  577. logrus.Infof("There are old running containers, the network config will not take affect")
  578. return controller, nil
  579. }
  580. // Initialize default network on "null"
  581. if n, _ := controller.NetworkByName("none"); n == nil {
  582. if _, err := controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(true)); err != nil {
  583. return nil, fmt.Errorf("Error creating default \"null\" network: %v", err)
  584. }
  585. }
  586. // Initialize default network on "host"
  587. if n, _ := controller.NetworkByName("host"); n == nil {
  588. if _, err := controller.NewNetwork("host", "host", "", libnetwork.NetworkOptionPersist(true)); err != nil {
  589. return nil, fmt.Errorf("Error creating default \"host\" network: %v", err)
  590. }
  591. }
  592. if !config.DisableBridge {
  593. // Initialize default driver "bridge"
  594. if err := initBridgeDriver(controller, config); err != nil {
  595. return nil, err
  596. }
  597. }
  598. return controller, nil
  599. }
  600. func driverOptions(config *Config) []nwconfig.Option {
  601. bridgeConfig := options.Generic{
  602. "EnableIPForwarding": config.bridgeConfig.EnableIPForward,
  603. "EnableIPTables": config.bridgeConfig.EnableIPTables,
  604. "EnableUserlandProxy": config.bridgeConfig.EnableUserlandProxy}
  605. bridgeOption := options.Generic{netlabel.GenericData: bridgeConfig}
  606. dOptions := []nwconfig.Option{}
  607. dOptions = append(dOptions, nwconfig.OptionDriverConfig("bridge", bridgeOption))
  608. return dOptions
  609. }
  610. func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error {
  611. if n, err := controller.NetworkByName("bridge"); err == nil {
  612. if err = n.Delete(); err != nil {
  613. return fmt.Errorf("could not delete the default bridge network: %v", err)
  614. }
  615. }
  616. bridgeName := bridge.DefaultBridgeName
  617. if config.bridgeConfig.Iface != "" {
  618. bridgeName = config.bridgeConfig.Iface
  619. }
  620. netOption := map[string]string{
  621. bridge.BridgeName: bridgeName,
  622. bridge.DefaultBridge: strconv.FormatBool(true),
  623. netlabel.DriverMTU: strconv.Itoa(config.Mtu),
  624. bridge.EnableIPMasquerade: strconv.FormatBool(config.bridgeConfig.EnableIPMasq),
  625. bridge.EnableICC: strconv.FormatBool(config.bridgeConfig.InterContainerCommunication),
  626. }
  627. // --ip processing
  628. if config.bridgeConfig.DefaultIP != nil {
  629. netOption[bridge.DefaultBindingIP] = config.bridgeConfig.DefaultIP.String()
  630. }
  631. var (
  632. ipamV4Conf *libnetwork.IpamConf
  633. ipamV6Conf *libnetwork.IpamConf
  634. )
  635. ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
  636. nw, nw6List, err := netutils.ElectInterfaceAddresses(bridgeName)
  637. if err == nil {
  638. ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String()
  639. hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask)
  640. if hip.IsGlobalUnicast() {
  641. ipamV4Conf.Gateway = nw.IP.String()
  642. }
  643. }
  644. if config.bridgeConfig.IP != "" {
  645. ipamV4Conf.PreferredPool = config.bridgeConfig.IP
  646. ip, _, err := net.ParseCIDR(config.bridgeConfig.IP)
  647. if err != nil {
  648. return err
  649. }
  650. ipamV4Conf.Gateway = ip.String()
  651. } else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" {
  652. logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool)
  653. }
  654. if config.bridgeConfig.FixedCIDR != "" {
  655. _, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR)
  656. if err != nil {
  657. return err
  658. }
  659. ipamV4Conf.SubPool = fCIDR.String()
  660. }
  661. if config.bridgeConfig.DefaultGatewayIPv4 != nil {
  662. ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.bridgeConfig.DefaultGatewayIPv4.String()
  663. }
  664. var deferIPv6Alloc bool
  665. if config.bridgeConfig.FixedCIDRv6 != "" {
  666. _, fCIDRv6, err := net.ParseCIDR(config.bridgeConfig.FixedCIDRv6)
  667. if err != nil {
  668. return err
  669. }
  670. // In case user has specified the daemon flag --fixed-cidr-v6 and the passed network has
  671. // at least 48 host bits, we need to guarantee the current behavior where the containers'
  672. // IPv6 addresses will be constructed based on the containers' interface MAC address.
  673. // We do so by telling libnetwork to defer the IPv6 address allocation for the endpoints
  674. // on this network until after the driver has created the endpoint and returned the
  675. // constructed address. Libnetwork will then reserve this address with the ipam driver.
  676. ones, _ := fCIDRv6.Mask.Size()
  677. deferIPv6Alloc = ones <= 80
  678. if ipamV6Conf == nil {
  679. ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
  680. }
  681. ipamV6Conf.PreferredPool = fCIDRv6.String()
  682. // In case the --fixed-cidr-v6 is specified and the current docker0 bridge IPv6
  683. // address belongs to the same network, we need to inform libnetwork about it, so
  684. // that it can be reserved with IPAM and it will not be given away to somebody else
  685. for _, nw6 := range nw6List {
  686. if fCIDRv6.Contains(nw6.IP) {
  687. ipamV6Conf.Gateway = nw6.IP.String()
  688. break
  689. }
  690. }
  691. }
  692. if config.bridgeConfig.DefaultGatewayIPv6 != nil {
  693. if ipamV6Conf == nil {
  694. ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
  695. }
  696. ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.bridgeConfig.DefaultGatewayIPv6.String()
  697. }
  698. v4Conf := []*libnetwork.IpamConf{ipamV4Conf}
  699. v6Conf := []*libnetwork.IpamConf{}
  700. if ipamV6Conf != nil {
  701. v6Conf = append(v6Conf, ipamV6Conf)
  702. }
  703. // Initialize default network on "bridge" with the same name
  704. _, err = controller.NewNetwork("bridge", "bridge", "",
  705. libnetwork.NetworkOptionEnableIPv6(config.bridgeConfig.EnableIPv6),
  706. libnetwork.NetworkOptionDriverOpts(netOption),
  707. libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
  708. libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc))
  709. if err != nil {
  710. return fmt.Errorf("Error creating default \"bridge\" network: %v", err)
  711. }
  712. return nil
  713. }
  714. // setupInitLayer populates a directory with mountpoints suitable
  715. // for bind-mounting things into the container.
  716. //
  717. // This extra layer is used by all containers as the top-most ro layer. It protects
  718. // the container from unwanted side-effects on the rw layer.
  719. func setupInitLayer(initLayer string, rootUID, rootGID int) error {
  720. for pth, typ := range map[string]string{
  721. "/dev/pts": "dir",
  722. "/dev/shm": "dir",
  723. "/proc": "dir",
  724. "/sys": "dir",
  725. "/.dockerenv": "file",
  726. "/etc/resolv.conf": "file",
  727. "/etc/hosts": "file",
  728. "/etc/hostname": "file",
  729. "/dev/console": "file",
  730. "/etc/mtab": "/proc/mounts",
  731. } {
  732. parts := strings.Split(pth, "/")
  733. prev := "/"
  734. for _, p := range parts[1:] {
  735. prev = filepath.Join(prev, p)
  736. syscall.Unlink(filepath.Join(initLayer, prev))
  737. }
  738. if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
  739. if os.IsNotExist(err) {
  740. if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootUID, rootGID); err != nil {
  741. return err
  742. }
  743. switch typ {
  744. case "dir":
  745. if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, pth), 0755, rootUID, rootGID); err != nil {
  746. return err
  747. }
  748. case "file":
  749. f, err := os.OpenFile(filepath.Join(initLayer, pth), os.O_CREATE, 0755)
  750. if err != nil {
  751. return err
  752. }
  753. f.Chown(rootUID, rootGID)
  754. f.Close()
  755. default:
  756. if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {
  757. return err
  758. }
  759. }
  760. } else {
  761. return err
  762. }
  763. }
  764. }
  765. // Layer is ready to use, if it wasn't before.
  766. return nil
  767. }
  768. // Parse the remapped root (user namespace) option, which can be one of:
  769. // username - valid username from /etc/passwd
  770. // username:groupname - valid username; valid groupname from /etc/group
  771. // uid - 32-bit unsigned int valid Linux UID value
  772. // uid:gid - uid value; 32-bit unsigned int Linux GID value
  773. //
  774. // If no groupname is specified, and a username is specified, an attempt
  775. // will be made to lookup a gid for that username as a groupname
  776. //
  777. // If names are used, they are verified to exist in passwd/group
  778. func parseRemappedRoot(usergrp string) (string, string, error) {
  779. var (
  780. userID, groupID int
  781. username, groupname string
  782. )
  783. idparts := strings.Split(usergrp, ":")
  784. if len(idparts) > 2 {
  785. return "", "", fmt.Errorf("Invalid user/group specification in --userns-remap: %q", usergrp)
  786. }
  787. if uid, err := strconv.ParseInt(idparts[0], 10, 32); err == nil {
  788. // must be a uid; take it as valid
  789. userID = int(uid)
  790. luser, err := user.LookupUid(userID)
  791. if err != nil {
  792. return "", "", fmt.Errorf("Uid %d has no entry in /etc/passwd: %v", userID, err)
  793. }
  794. username = luser.Name
  795. if len(idparts) == 1 {
  796. // if the uid was numeric and no gid was specified, take the uid as the gid
  797. groupID = userID
  798. lgrp, err := user.LookupGid(groupID)
  799. if err != nil {
  800. return "", "", fmt.Errorf("Gid %d has no entry in /etc/group: %v", groupID, err)
  801. }
  802. groupname = lgrp.Name
  803. }
  804. } else {
  805. lookupName := idparts[0]
  806. // special case: if the user specified "default", they want Docker to create or
  807. // use (after creation) the "dockremap" user/group for root remapping
  808. if lookupName == defaultIDSpecifier {
  809. lookupName = defaultRemappedID
  810. }
  811. luser, err := user.LookupUser(lookupName)
  812. if err != nil && idparts[0] != defaultIDSpecifier {
  813. // error if the name requested isn't the special "dockremap" ID
  814. return "", "", fmt.Errorf("Error during uid lookup for %q: %v", lookupName, err)
  815. } else if err != nil {
  816. // special case-- if the username == "default", then we have been asked
  817. // to create a new entry pair in /etc/{passwd,group} for which the /etc/sub{uid,gid}
  818. // ranges will be used for the user and group mappings in user namespaced containers
  819. _, _, err := idtools.AddNamespaceRangesUser(defaultRemappedID)
  820. if err == nil {
  821. return defaultRemappedID, defaultRemappedID, nil
  822. }
  823. return "", "", fmt.Errorf("Error during %q user creation: %v", defaultRemappedID, err)
  824. }
  825. username = luser.Name
  826. if len(idparts) == 1 {
  827. // we only have a string username, and no group specified; look up gid from username as group
  828. group, err := user.LookupGroup(lookupName)
  829. if err != nil {
  830. return "", "", fmt.Errorf("Error during gid lookup for %q: %v", lookupName, err)
  831. }
  832. groupID = group.Gid
  833. groupname = group.Name
  834. }
  835. }
  836. if len(idparts) == 2 {
  837. // groupname or gid is separately specified and must be resolved
  838. // to an unsigned 32-bit gid
  839. if gid, err := strconv.ParseInt(idparts[1], 10, 32); err == nil {
  840. // must be a gid, take it as valid
  841. groupID = int(gid)
  842. lgrp, err := user.LookupGid(groupID)
  843. if err != nil {
  844. return "", "", fmt.Errorf("Gid %d has no entry in /etc/passwd: %v", groupID, err)
  845. }
  846. groupname = lgrp.Name
  847. } else {
  848. // not a number; attempt a lookup
  849. if _, err := user.LookupGroup(idparts[1]); err != nil {
  850. return "", "", fmt.Errorf("Error during groupname lookup for %q: %v", idparts[1], err)
  851. }
  852. groupname = idparts[1]
  853. }
  854. }
  855. return username, groupname, nil
  856. }
  857. func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) {
  858. if runtime.GOOS != "linux" && config.RemappedRoot != "" {
  859. return nil, nil, fmt.Errorf("User namespaces are only supported on Linux")
  860. }
  861. // if the daemon was started with remapped root option, parse
  862. // the config option to the int uid,gid values
  863. var (
  864. uidMaps, gidMaps []idtools.IDMap
  865. )
  866. if config.RemappedRoot != "" {
  867. username, groupname, err := parseRemappedRoot(config.RemappedRoot)
  868. if err != nil {
  869. return nil, nil, err
  870. }
  871. if username == "root" {
  872. // Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op
  873. // effectively
  874. logrus.Warn("User namespaces: root cannot be remapped with itself; user namespaces are OFF")
  875. return uidMaps, gidMaps, nil
  876. }
  877. logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname)
  878. // update remapped root setting now that we have resolved them to actual names
  879. config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname)
  880. uidMaps, gidMaps, err = idtools.CreateIDMappings(username, groupname)
  881. if err != nil {
  882. return nil, nil, fmt.Errorf("Can't create ID mappings: %v", err)
  883. }
  884. }
  885. return uidMaps, gidMaps, nil
  886. }
  887. func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error {
  888. config.Root = rootDir
  889. // the docker root metadata directory needs to have execute permissions for all users (g+x,o+x)
  890. // so that syscalls executing as non-root, operating on subdirectories of the graph root
  891. // (e.g. mounted layers of a container) can traverse this path.
  892. // The user namespace support will create subdirectories for the remapped root host uid:gid
  893. // pair owned by that same uid:gid pair for proper write access to those needed metadata and
  894. // layer content subtrees.
  895. if _, err := os.Stat(rootDir); err == nil {
  896. // root current exists; verify the access bits are correct by setting them
  897. if err = os.Chmod(rootDir, 0711); err != nil {
  898. return err
  899. }
  900. } else if os.IsNotExist(err) {
  901. // no root exists yet, create it 0711 with root:root ownership
  902. if err := os.MkdirAll(rootDir, 0711); err != nil {
  903. return err
  904. }
  905. }
  906. // if user namespaces are enabled we will create a subtree underneath the specified root
  907. // with any/all specified remapped root uid/gid options on the daemon creating
  908. // a new subdirectory with ownership set to the remapped uid/gid (so as to allow
  909. // `chdir()` to work for containers namespaced to that uid/gid)
  910. if config.RemappedRoot != "" {
  911. config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootUID, rootGID))
  912. logrus.Debugf("Creating user namespaced daemon root: %s", config.Root)
  913. // Create the root directory if it doesn't exist
  914. if err := idtools.MkdirAllAs(config.Root, 0700, rootUID, rootGID); err != nil {
  915. return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err)
  916. }
  917. }
  918. return nil
  919. }
  920. // registerLinks writes the links to a file.
  921. func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error {
  922. if hostConfig == nil || hostConfig.NetworkMode.IsUserDefined() {
  923. return nil
  924. }
  925. for _, l := range hostConfig.Links {
  926. name, alias, err := runconfigopts.ParseLink(l)
  927. if err != nil {
  928. return err
  929. }
  930. child, err := daemon.GetContainer(name)
  931. if err != nil {
  932. return fmt.Errorf("Could not get container for %s", name)
  933. }
  934. for child.HostConfig.NetworkMode.IsContainer() {
  935. parts := strings.SplitN(string(child.HostConfig.NetworkMode), ":", 2)
  936. child, err = daemon.GetContainer(parts[1])
  937. if err != nil {
  938. return fmt.Errorf("Could not get container for %s", parts[1])
  939. }
  940. }
  941. if child.HostConfig.NetworkMode.IsHost() {
  942. return runconfig.ErrConflictHostNetworkAndLinks
  943. }
  944. if err := daemon.registerLink(container, child, alias); err != nil {
  945. return err
  946. }
  947. }
  948. // After we load all the links into the daemon
  949. // set them to nil on the hostconfig
  950. return container.WriteHostConfig()
  951. }
  952. // conditionalMountOnStart is a platform specific helper function during the
  953. // container start to call mount.
  954. func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
  955. return daemon.Mount(container)
  956. }
  957. // conditionalUnmountOnCleanup is a platform specific helper function called
  958. // during the cleanup of a container to unmount.
  959. func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error {
  960. return daemon.Unmount(container)
  961. }
  962. func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
  963. if !c.IsRunning() {
  964. return nil, errNotRunning{c.ID}
  965. }
  966. stats, err := daemon.containerd.Stats(c.ID)
  967. if err != nil {
  968. return nil, err
  969. }
  970. s := &types.StatsJSON{}
  971. cgs := stats.CgroupStats
  972. if cgs != nil {
  973. s.BlkioStats = types.BlkioStats{
  974. IoServiceBytesRecursive: copyBlkioEntry(cgs.BlkioStats.IoServiceBytesRecursive),
  975. IoServicedRecursive: copyBlkioEntry(cgs.BlkioStats.IoServicedRecursive),
  976. IoQueuedRecursive: copyBlkioEntry(cgs.BlkioStats.IoQueuedRecursive),
  977. IoServiceTimeRecursive: copyBlkioEntry(cgs.BlkioStats.IoServiceTimeRecursive),
  978. IoWaitTimeRecursive: copyBlkioEntry(cgs.BlkioStats.IoWaitTimeRecursive),
  979. IoMergedRecursive: copyBlkioEntry(cgs.BlkioStats.IoMergedRecursive),
  980. IoTimeRecursive: copyBlkioEntry(cgs.BlkioStats.IoTimeRecursive),
  981. SectorsRecursive: copyBlkioEntry(cgs.BlkioStats.SectorsRecursive),
  982. }
  983. cpu := cgs.CpuStats
  984. s.CPUStats = types.CPUStats{
  985. CPUUsage: types.CPUUsage{
  986. TotalUsage: cpu.CpuUsage.TotalUsage,
  987. PercpuUsage: cpu.CpuUsage.PercpuUsage,
  988. UsageInKernelmode: cpu.CpuUsage.UsageInKernelmode,
  989. UsageInUsermode: cpu.CpuUsage.UsageInUsermode,
  990. },
  991. ThrottlingData: types.ThrottlingData{
  992. Periods: cpu.ThrottlingData.Periods,
  993. ThrottledPeriods: cpu.ThrottlingData.ThrottledPeriods,
  994. ThrottledTime: cpu.ThrottlingData.ThrottledTime,
  995. },
  996. }
  997. mem := cgs.MemoryStats.Usage
  998. s.MemoryStats = types.MemoryStats{
  999. Usage: mem.Usage,
  1000. MaxUsage: mem.MaxUsage,
  1001. Stats: cgs.MemoryStats.Stats,
  1002. Failcnt: mem.Failcnt,
  1003. Limit: mem.Limit,
  1004. }
  1005. // if the container does not set memory limit, use the machineMemory
  1006. if mem.Limit > daemon.statsCollector.machineMemory && daemon.statsCollector.machineMemory > 0 {
  1007. s.MemoryStats.Limit = daemon.statsCollector.machineMemory
  1008. }
  1009. if cgs.PidsStats != nil {
  1010. s.PidsStats = types.PidsStats{
  1011. Current: cgs.PidsStats.Current,
  1012. }
  1013. }
  1014. }
  1015. s.Read, err = ptypes.Timestamp(stats.Timestamp)
  1016. if err != nil {
  1017. return nil, err
  1018. }
  1019. return s, nil
  1020. }
  1021. // setDefaultIsolation determines the default isolation mode for the
  1022. // daemon to run in. This is only applicable on Windows
  1023. func (daemon *Daemon) setDefaultIsolation() error {
  1024. return nil
  1025. }
  1026. func rootFSToAPIType(rootfs *image.RootFS) types.RootFS {
  1027. var layers []string
  1028. for _, l := range rootfs.DiffIDs {
  1029. layers = append(layers, l.String())
  1030. }
  1031. return types.RootFS{
  1032. Type: rootfs.Type,
  1033. Layers: layers,
  1034. }
  1035. }
  1036. // setupDaemonProcess sets various settings for the daemon's process
  1037. func setupDaemonProcess(config *Config) error {
  1038. // setup the daemons oom_score_adj
  1039. return setupOOMScoreAdj(config.OOMScoreAdjust)
  1040. }
  1041. func setupOOMScoreAdj(score int) error {
  1042. f, err := os.OpenFile("/proc/self/oom_score_adj", os.O_WRONLY, 0)
  1043. if err != nil {
  1044. return err
  1045. }
  1046. _, err = f.WriteString(strconv.Itoa(score))
  1047. f.Close()
  1048. return err
  1049. }