container_unix.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. // +build linux freebsd
  2. package container
  3. import (
  4. "fmt"
  5. "io/ioutil"
  6. "net"
  7. "os"
  8. "path/filepath"
  9. "strconv"
  10. "strings"
  11. "syscall"
  12. "github.com/Sirupsen/logrus"
  13. "github.com/docker/docker/daemon/execdriver"
  14. "github.com/docker/docker/daemon/network"
  15. derr "github.com/docker/docker/errors"
  16. "github.com/docker/docker/pkg/chrootarchive"
  17. "github.com/docker/docker/pkg/nat"
  18. "github.com/docker/docker/pkg/symlink"
  19. "github.com/docker/docker/pkg/system"
  20. "github.com/docker/docker/utils"
  21. "github.com/docker/docker/volume"
  22. "github.com/docker/libnetwork"
  23. "github.com/docker/libnetwork/netlabel"
  24. "github.com/docker/libnetwork/options"
  25. "github.com/docker/libnetwork/types"
  26. "github.com/opencontainers/runc/libcontainer/label"
  27. )
  28. const (
  29. // DefaultPathEnv is unix style list of directories to search for
  30. // executables. Each directory is separated from the next by a colon
  31. // ':' character .
  32. DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
  33. // DefaultSHMSize is the default size (64MB) of the SHM which will be mounted in the container
  34. DefaultSHMSize int64 = 67108864
  35. )
  36. // Container holds the fields specific to unixen implementations. See
  37. // CommonContainer for standard fields common to all containers.
  38. type Container struct {
  39. CommonContainer
  40. // Fields below here are platform specific.
  41. AppArmorProfile string
  42. HostnamePath string
  43. HostsPath string
  44. ShmPath string
  45. MqueuePath string
  46. ResolvConfPath string
  47. }
  48. // CreateDaemonEnvironment returns the list of all environment variables given the list of
  49. // environment variables related to links.
  50. // Sets PATH, HOSTNAME and if container.Config.Tty is set: TERM.
  51. // The defaults set here do not override the values in container.Config.Env
  52. func (container *Container) CreateDaemonEnvironment(linkedEnv []string) []string {
  53. // if a domain name was specified, append it to the hostname (see #7851)
  54. fullHostname := container.Config.Hostname
  55. if container.Config.Domainname != "" {
  56. fullHostname = fmt.Sprintf("%s.%s", fullHostname, container.Config.Domainname)
  57. }
  58. // Setup environment
  59. env := []string{
  60. "PATH=" + DefaultPathEnv,
  61. "HOSTNAME=" + fullHostname,
  62. // Note: we don't set HOME here because it'll get autoset intelligently
  63. // based on the value of USER inside dockerinit, but only if it isn't
  64. // set already (ie, that can be overridden by setting HOME via -e or ENV
  65. // in a Dockerfile).
  66. }
  67. if container.Config.Tty {
  68. env = append(env, "TERM=xterm")
  69. }
  70. env = append(env, linkedEnv...)
  71. // because the env on the container can override certain default values
  72. // we need to replace the 'env' keys where they match and append anything
  73. // else.
  74. env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env)
  75. return env
  76. }
  77. // TrySetNetworkMount attempts to set the network mounts given a provided destination and
  78. // the path to use for it; return true if the given destination was a network mount file
  79. func (container *Container) TrySetNetworkMount(destination string, path string) bool {
  80. if destination == "/etc/resolv.conf" {
  81. container.ResolvConfPath = path
  82. return true
  83. }
  84. if destination == "/etc/hostname" {
  85. container.HostnamePath = path
  86. return true
  87. }
  88. if destination == "/etc/hosts" {
  89. container.HostsPath = path
  90. return true
  91. }
  92. return false
  93. }
  94. // BuildHostnameFile writes the container's hostname file.
  95. func (container *Container) BuildHostnameFile() error {
  96. hostnamePath, err := container.GetRootResourcePath("hostname")
  97. if err != nil {
  98. return err
  99. }
  100. container.HostnamePath = hostnamePath
  101. if container.Config.Domainname != "" {
  102. return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644)
  103. }
  104. return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
  105. }
  106. // GetEndpointInNetwork returns the container's endpoint to the provided network.
  107. func (container *Container) GetEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) {
  108. endpointName := strings.TrimPrefix(container.Name, "/")
  109. return n.EndpointByName(endpointName)
  110. }
  111. func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error {
  112. if ep == nil {
  113. return derr.ErrorCodeEmptyEndpoint
  114. }
  115. networkSettings := container.NetworkSettings
  116. if networkSettings == nil {
  117. return derr.ErrorCodeEmptyNetwork
  118. }
  119. driverInfo, err := ep.DriverInfo()
  120. if err != nil {
  121. return err
  122. }
  123. if driverInfo == nil {
  124. // It is not an error for epInfo to be nil
  125. return nil
  126. }
  127. if networkSettings.Ports == nil {
  128. networkSettings.Ports = nat.PortMap{}
  129. }
  130. if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
  131. if exposedPorts, ok := expData.([]types.TransportPort); ok {
  132. for _, tp := range exposedPorts {
  133. natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
  134. if err != nil {
  135. return derr.ErrorCodeParsingPort.WithArgs(tp.Port, err)
  136. }
  137. networkSettings.Ports[natPort] = nil
  138. }
  139. }
  140. }
  141. mapData, ok := driverInfo[netlabel.PortMap]
  142. if !ok {
  143. return nil
  144. }
  145. if portMapping, ok := mapData.([]types.PortBinding); ok {
  146. for _, pp := range portMapping {
  147. natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
  148. if err != nil {
  149. return err
  150. }
  151. natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
  152. networkSettings.Ports[natPort] = append(networkSettings.Ports[natPort], natBndg)
  153. }
  154. }
  155. return nil
  156. }
  157. // BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
  158. func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
  159. if ep == nil {
  160. return derr.ErrorCodeEmptyEndpoint
  161. }
  162. networkSettings := container.NetworkSettings
  163. if networkSettings == nil {
  164. return derr.ErrorCodeEmptyNetwork
  165. }
  166. epInfo := ep.Info()
  167. if epInfo == nil {
  168. // It is not an error to get an empty endpoint info
  169. return nil
  170. }
  171. if _, ok := networkSettings.Networks[n.Name()]; !ok {
  172. networkSettings.Networks[n.Name()] = new(network.EndpointSettings)
  173. }
  174. networkSettings.Networks[n.Name()].EndpointID = ep.ID()
  175. iface := epInfo.Iface()
  176. if iface == nil {
  177. return nil
  178. }
  179. if iface.MacAddress() != nil {
  180. networkSettings.Networks[n.Name()].MacAddress = iface.MacAddress().String()
  181. }
  182. if iface.Address() != nil {
  183. ones, _ := iface.Address().Mask.Size()
  184. networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String()
  185. networkSettings.Networks[n.Name()].IPPrefixLen = ones
  186. }
  187. if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
  188. onesv6, _ := iface.AddressIPv6().Mask.Size()
  189. networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String()
  190. networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6
  191. }
  192. return nil
  193. }
  194. // UpdateJoinInfo updates network settings when container joins network n with endpoint ep.
  195. func (container *Container) UpdateJoinInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
  196. if err := container.buildPortMapInfo(ep); err != nil {
  197. return err
  198. }
  199. epInfo := ep.Info()
  200. if epInfo == nil {
  201. // It is not an error to get an empty endpoint info
  202. return nil
  203. }
  204. if epInfo.Gateway() != nil {
  205. container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
  206. }
  207. if epInfo.GatewayIPv6().To16() != nil {
  208. container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
  209. }
  210. return nil
  211. }
  212. // UpdateSandboxNetworkSettings updates the sandbox ID and Key.
  213. func (container *Container) UpdateSandboxNetworkSettings(sb libnetwork.Sandbox) error {
  214. container.NetworkSettings.SandboxID = sb.ID()
  215. container.NetworkSettings.SandboxKey = sb.Key()
  216. return nil
  217. }
  218. // BuildCreateEndpointOptions builds endpoint options from a given network.
  219. func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) {
  220. var (
  221. portSpecs = make(nat.PortSet)
  222. bindings = make(nat.PortMap)
  223. pbList []types.PortBinding
  224. exposeList []types.TransportPort
  225. createOptions []libnetwork.EndpointOption
  226. )
  227. if n.Name() == "bridge" || container.NetworkSettings.IsAnonymousEndpoint {
  228. createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
  229. }
  230. // Other configs are applicable only for the endpoint in the network
  231. // to which container was connected to on docker run.
  232. if n.Name() != container.HostConfig.NetworkMode.NetworkName() &&
  233. !(n.Name() == "bridge" && container.HostConfig.NetworkMode.IsDefault()) {
  234. return createOptions, nil
  235. }
  236. if container.Config.ExposedPorts != nil {
  237. portSpecs = container.Config.ExposedPorts
  238. }
  239. if container.HostConfig.PortBindings != nil {
  240. for p, b := range container.HostConfig.PortBindings {
  241. bindings[p] = []nat.PortBinding{}
  242. for _, bb := range b {
  243. bindings[p] = append(bindings[p], nat.PortBinding{
  244. HostIP: bb.HostIP,
  245. HostPort: bb.HostPort,
  246. })
  247. }
  248. }
  249. }
  250. ports := make([]nat.Port, len(portSpecs))
  251. var i int
  252. for p := range portSpecs {
  253. ports[i] = p
  254. i++
  255. }
  256. nat.SortPortMap(ports, bindings)
  257. for _, port := range ports {
  258. expose := types.TransportPort{}
  259. expose.Proto = types.ParseProtocol(port.Proto())
  260. expose.Port = uint16(port.Int())
  261. exposeList = append(exposeList, expose)
  262. pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
  263. binding := bindings[port]
  264. for i := 0; i < len(binding); i++ {
  265. pbCopy := pb.GetCopy()
  266. newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
  267. var portStart, portEnd int
  268. if err == nil {
  269. portStart, portEnd, err = newP.Range()
  270. }
  271. if err != nil {
  272. return nil, derr.ErrorCodeHostPort.WithArgs(binding[i].HostPort, err)
  273. }
  274. pbCopy.HostPort = uint16(portStart)
  275. pbCopy.HostPortEnd = uint16(portEnd)
  276. pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
  277. pbList = append(pbList, pbCopy)
  278. }
  279. if container.HostConfig.PublishAllPorts && len(binding) == 0 {
  280. pbList = append(pbList, pb)
  281. }
  282. }
  283. createOptions = append(createOptions,
  284. libnetwork.CreateOptionPortMapping(pbList),
  285. libnetwork.CreateOptionExposedPorts(exposeList))
  286. if container.Config.MacAddress != "" {
  287. mac, err := net.ParseMAC(container.Config.MacAddress)
  288. if err != nil {
  289. return nil, err
  290. }
  291. genericOption := options.Generic{
  292. netlabel.MacAddress: mac,
  293. }
  294. createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
  295. }
  296. return createOptions, nil
  297. }
  298. // SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir
  299. func (container *Container) SetupWorkingDirectory() error {
  300. if container.Config.WorkingDir == "" {
  301. return nil
  302. }
  303. container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir)
  304. pth, err := container.GetResourcePath(container.Config.WorkingDir)
  305. if err != nil {
  306. return err
  307. }
  308. pthInfo, err := os.Stat(pth)
  309. if err != nil {
  310. if !os.IsNotExist(err) {
  311. return err
  312. }
  313. if err := system.MkdirAll(pth, 0755); err != nil {
  314. return err
  315. }
  316. }
  317. if pthInfo != nil && !pthInfo.IsDir() {
  318. return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir)
  319. }
  320. return nil
  321. }
  322. // appendNetworkMounts appends any network mounts to the array of mount points passed in
  323. func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) {
  324. for _, mnt := range container.NetworkMounts() {
  325. dest, err := container.GetResourcePath(mnt.Destination)
  326. if err != nil {
  327. return nil, err
  328. }
  329. volumeMounts = append(volumeMounts, volume.MountPoint{Destination: dest})
  330. }
  331. return volumeMounts, nil
  332. }
  333. // NetworkMounts returns the list of network mounts.
  334. func (container *Container) NetworkMounts() []execdriver.Mount {
  335. var mounts []execdriver.Mount
  336. shared := container.HostConfig.NetworkMode.IsContainer()
  337. if container.ResolvConfPath != "" {
  338. if _, err := os.Stat(container.ResolvConfPath); err != nil {
  339. logrus.Warnf("ResolvConfPath set to %q, but can't stat this filename (err = %v); skipping", container.ResolvConfPath, err)
  340. } else {
  341. label.Relabel(container.ResolvConfPath, container.MountLabel, shared)
  342. writable := !container.HostConfig.ReadonlyRootfs
  343. if m, exists := container.MountPoints["/etc/resolv.conf"]; exists {
  344. writable = m.RW
  345. }
  346. mounts = append(mounts, execdriver.Mount{
  347. Source: container.ResolvConfPath,
  348. Destination: "/etc/resolv.conf",
  349. Writable: writable,
  350. Private: true,
  351. })
  352. }
  353. }
  354. if container.HostnamePath != "" {
  355. if _, err := os.Stat(container.HostnamePath); err != nil {
  356. logrus.Warnf("HostnamePath set to %q, but can't stat this filename (err = %v); skipping", container.HostnamePath, err)
  357. } else {
  358. label.Relabel(container.HostnamePath, container.MountLabel, shared)
  359. writable := !container.HostConfig.ReadonlyRootfs
  360. if m, exists := container.MountPoints["/etc/hostname"]; exists {
  361. writable = m.RW
  362. }
  363. mounts = append(mounts, execdriver.Mount{
  364. Source: container.HostnamePath,
  365. Destination: "/etc/hostname",
  366. Writable: writable,
  367. Private: true,
  368. })
  369. }
  370. }
  371. if container.HostsPath != "" {
  372. if _, err := os.Stat(container.HostsPath); err != nil {
  373. logrus.Warnf("HostsPath set to %q, but can't stat this filename (err = %v); skipping", container.HostsPath, err)
  374. } else {
  375. label.Relabel(container.HostsPath, container.MountLabel, shared)
  376. writable := !container.HostConfig.ReadonlyRootfs
  377. if m, exists := container.MountPoints["/etc/hosts"]; exists {
  378. writable = m.RW
  379. }
  380. mounts = append(mounts, execdriver.Mount{
  381. Source: container.HostsPath,
  382. Destination: "/etc/hosts",
  383. Writable: writable,
  384. Private: true,
  385. })
  386. }
  387. }
  388. return mounts
  389. }
  390. // CopyImagePathContent copies files in destination to the volume.
  391. func (container *Container) CopyImagePathContent(v volume.Volume, destination string) error {
  392. rootfs, err := symlink.FollowSymlinkInScope(filepath.Join(container.BaseFS, destination), container.BaseFS)
  393. if err != nil {
  394. return err
  395. }
  396. if _, err = ioutil.ReadDir(rootfs); err != nil {
  397. if os.IsNotExist(err) {
  398. return nil
  399. }
  400. return err
  401. }
  402. path, err := v.Mount()
  403. if err != nil {
  404. return err
  405. }
  406. if err := copyExistingContents(rootfs, path); err != nil {
  407. return err
  408. }
  409. return v.Unmount()
  410. }
  411. // ShmResourcePath returns path to shm
  412. func (container *Container) ShmResourcePath() (string, error) {
  413. return container.GetRootResourcePath("shm")
  414. }
  415. // MqueueResourcePath returns path to mqueue
  416. func (container *Container) MqueueResourcePath() (string, error) {
  417. return container.GetRootResourcePath("mqueue")
  418. }
  419. // HasMountFor checks if path is a mountpoint
  420. func (container *Container) HasMountFor(path string) bool {
  421. _, exists := container.MountPoints[path]
  422. return exists
  423. }
  424. // UnmountIpcMounts uses the provided unmount function to unmount shm and mqueue if they were mounted
  425. func (container *Container) UnmountIpcMounts(unmount func(pth string) error) {
  426. if container.HostConfig.IpcMode.IsContainer() || container.HostConfig.IpcMode.IsHost() {
  427. return
  428. }
  429. var warnings []string
  430. if !container.HasMountFor("/dev/shm") {
  431. shmPath, err := container.ShmResourcePath()
  432. if err != nil {
  433. logrus.Error(err)
  434. warnings = append(warnings, err.Error())
  435. } else if shmPath != "" {
  436. if err := unmount(shmPath); err != nil {
  437. warnings = append(warnings, fmt.Sprintf("failed to umount %s: %v", shmPath, err))
  438. }
  439. }
  440. }
  441. if !container.HasMountFor("/dev/mqueue") {
  442. mqueuePath, err := container.MqueueResourcePath()
  443. if err != nil {
  444. logrus.Error(err)
  445. warnings = append(warnings, err.Error())
  446. } else if mqueuePath != "" {
  447. if err := unmount(mqueuePath); err != nil {
  448. warnings = append(warnings, fmt.Sprintf("failed to umount %s: %v", mqueuePath, err))
  449. }
  450. }
  451. }
  452. if len(warnings) > 0 {
  453. logrus.Warnf("failed to cleanup ipc mounts:\n%v", strings.Join(warnings, "\n"))
  454. }
  455. }
  456. // IpcMounts returns the list of IPC mounts
  457. func (container *Container) IpcMounts() []execdriver.Mount {
  458. var mounts []execdriver.Mount
  459. if !container.HasMountFor("/dev/shm") {
  460. label.SetFileLabel(container.ShmPath, container.MountLabel)
  461. mounts = append(mounts, execdriver.Mount{
  462. Source: container.ShmPath,
  463. Destination: "/dev/shm",
  464. Writable: true,
  465. Private: true,
  466. })
  467. }
  468. if !container.HasMountFor("/dev/mqueue") {
  469. label.SetFileLabel(container.MqueuePath, container.MountLabel)
  470. mounts = append(mounts, execdriver.Mount{
  471. Source: container.MqueuePath,
  472. Destination: "/dev/mqueue",
  473. Writable: true,
  474. Private: true,
  475. })
  476. }
  477. return mounts
  478. }
  479. func detachMounted(path string) error {
  480. return syscall.Unmount(path, syscall.MNT_DETACH)
  481. }
  482. // UnmountVolumes unmounts all volumes
  483. func (container *Container) UnmountVolumes(forceSyscall bool) error {
  484. var (
  485. volumeMounts []volume.MountPoint
  486. err error
  487. )
  488. for _, mntPoint := range container.MountPoints {
  489. dest, err := container.GetResourcePath(mntPoint.Destination)
  490. if err != nil {
  491. return err
  492. }
  493. volumeMounts = append(volumeMounts, volume.MountPoint{Destination: dest, Volume: mntPoint.Volume})
  494. }
  495. // Append any network mounts to the list (this is a no-op on Windows)
  496. if volumeMounts, err = appendNetworkMounts(container, volumeMounts); err != nil {
  497. return err
  498. }
  499. for _, volumeMount := range volumeMounts {
  500. if forceSyscall {
  501. if err := detachMounted(volumeMount.Destination); err != nil {
  502. logrus.Warnf("%s unmountVolumes: Failed to do lazy umount %v", container.ID, err)
  503. }
  504. }
  505. if volumeMount.Volume != nil {
  506. if err := volumeMount.Volume.Unmount(); err != nil {
  507. return err
  508. }
  509. }
  510. }
  511. return nil
  512. }
  513. // copyExistingContents copies from the source to the destination and
  514. // ensures the ownership is appropriately set.
  515. func copyExistingContents(source, destination string) error {
  516. volList, err := ioutil.ReadDir(source)
  517. if err != nil {
  518. return err
  519. }
  520. if len(volList) > 0 {
  521. srcList, err := ioutil.ReadDir(destination)
  522. if err != nil {
  523. return err
  524. }
  525. if len(srcList) == 0 {
  526. // If the source volume is empty copy files from the root into the volume
  527. if err := chrootarchive.CopyWithTar(source, destination); err != nil {
  528. return err
  529. }
  530. }
  531. }
  532. return copyOwnership(source, destination)
  533. }
  534. // copyOwnership copies the permissions and uid:gid of the source file
  535. // to the destination file
  536. func copyOwnership(source, destination string) error {
  537. stat, err := system.Stat(source)
  538. if err != nil {
  539. return err
  540. }
  541. if err := os.Chown(destination, int(stat.UID()), int(stat.GID())); err != nil {
  542. return err
  543. }
  544. return os.Chmod(destination, os.FileMode(stat.Mode()))
  545. }
  546. // TmpfsMounts returns the list of tmpfs mounts
  547. func (container *Container) TmpfsMounts() []execdriver.Mount {
  548. var mounts []execdriver.Mount
  549. for dest, data := range container.HostConfig.Tmpfs {
  550. mounts = append(mounts, execdriver.Mount{
  551. Source: "tmpfs",
  552. Destination: dest,
  553. Data: data,
  554. })
  555. }
  556. return mounts
  557. }