container_linux.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package runtime
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "os"
  7. "path/filepath"
  8. "strings"
  9. "syscall"
  10. "github.com/docker/containerd/specs"
  11. "github.com/docker/containerd/subreaper/exec"
  12. "github.com/opencontainers/runc/libcontainer"
  13. ocs "github.com/opencontainers/runtime-spec/specs-go"
  14. )
  15. func (c *container) getLibctContainer() (libcontainer.Container, error) {
  16. runtimeRoot := "/run/runc"
  17. // Check that the root wasn't changed
  18. for _, opt := range c.runtimeArgs {
  19. if strings.HasPrefix(opt, "--root=") {
  20. runtimeRoot = strings.TrimPrefix(opt, "--root=")
  21. break
  22. }
  23. }
  24. f, err := libcontainer.New(runtimeRoot, libcontainer.Cgroupfs)
  25. if err != nil {
  26. return nil, err
  27. }
  28. return f.Load(c.id)
  29. }
  30. func (c *container) OOM() (OOM, error) {
  31. container, err := c.getLibctContainer()
  32. if err != nil {
  33. if lerr, ok := err.(libcontainer.Error); ok {
  34. // with oom registration sometimes the container can run, exit, and be destroyed
  35. // faster than we can get the state back so we can just ignore this
  36. if lerr.Code() == libcontainer.ContainerNotExists {
  37. return nil, ErrContainerExited
  38. }
  39. }
  40. return nil, err
  41. }
  42. state, err := container.State()
  43. if err != nil {
  44. return nil, err
  45. }
  46. memoryPath := state.CgroupPaths["memory"]
  47. return c.getMemeoryEventFD(memoryPath)
  48. }
  49. func u64Ptr(i uint64) *uint64 { return &i }
  50. func (c *container) UpdateResources(r *Resource) error {
  51. sr := ocs.Resources{
  52. Memory: &ocs.Memory{
  53. Limit: u64Ptr(uint64(r.Memory)),
  54. Reservation: u64Ptr(uint64(r.MemoryReservation)),
  55. Swap: u64Ptr(uint64(r.MemorySwap)),
  56. Kernel: u64Ptr(uint64(r.KernelMemory)),
  57. },
  58. CPU: &ocs.CPU{
  59. Shares: u64Ptr(uint64(r.CPUShares)),
  60. Quota: u64Ptr(uint64(r.CPUQuota)),
  61. Period: u64Ptr(uint64(r.CPUPeriod)),
  62. Cpus: &r.CpusetCpus,
  63. Mems: &r.CpusetMems,
  64. },
  65. BlockIO: &ocs.BlockIO{
  66. Weight: &r.BlkioWeight,
  67. },
  68. }
  69. srStr := bytes.NewBuffer(nil)
  70. if err := json.NewEncoder(srStr).Encode(&sr); err != nil {
  71. return err
  72. }
  73. args := c.runtimeArgs
  74. args = append(args, "update", "-r", "-", c.id)
  75. cmd := exec.Command(c.runtime, args...)
  76. cmd.Stdin = srStr
  77. b, err := cmd.CombinedOutput()
  78. if err != nil {
  79. return fmt.Errorf(string(b))
  80. }
  81. return nil
  82. }
  83. func getRootIDs(s *specs.Spec) (int, int, error) {
  84. if s == nil {
  85. return 0, 0, nil
  86. }
  87. var hasUserns bool
  88. for _, ns := range s.Linux.Namespaces {
  89. if ns.Type == ocs.UserNamespace {
  90. hasUserns = true
  91. break
  92. }
  93. }
  94. if !hasUserns {
  95. return 0, 0, nil
  96. }
  97. uid := hostIDFromMap(0, s.Linux.UIDMappings)
  98. gid := hostIDFromMap(0, s.Linux.GIDMappings)
  99. return uid, gid, nil
  100. }
  101. func (c *container) getMemeoryEventFD(root string) (*oom, error) {
  102. f, err := os.Open(filepath.Join(root, "memory.oom_control"))
  103. if err != nil {
  104. return nil, err
  105. }
  106. fd, _, serr := syscall.RawSyscall(syscall.SYS_EVENTFD2, 0, syscall.FD_CLOEXEC, 0)
  107. if serr != 0 {
  108. f.Close()
  109. return nil, serr
  110. }
  111. if err := c.writeEventFD(root, int(f.Fd()), int(fd)); err != nil {
  112. syscall.Close(int(fd))
  113. f.Close()
  114. return nil, err
  115. }
  116. return &oom{
  117. root: root,
  118. id: c.id,
  119. eventfd: int(fd),
  120. control: f,
  121. }, nil
  122. }