Merge pull request #235 from mlaventure/update-via-runc
Use the new runtime update command to process UpdateResources requests
This commit is contained in:
commit
9344ea9d7d
7 changed files with 91 additions and 33 deletions
|
@ -36,7 +36,7 @@ RUN set -x \
|
||||||
&& rm -rf "$SECCOMP_PATH"
|
&& rm -rf "$SECCOMP_PATH"
|
||||||
|
|
||||||
# Install runc
|
# Install runc
|
||||||
ENV RUNC_COMMIT 9c89737e6e117a8be5a4980bc9795fe1a2b1028e
|
ENV RUNC_COMMIT d49ece5a83da3dcb820121d6850e2b61bd0a5fbe
|
||||||
RUN set -x \
|
RUN set -x \
|
||||||
&& export GOPATH="$(mktemp -d)" \
|
&& export GOPATH="$(mktemp -d)" \
|
||||||
&& git clone git://github.com/opencontainers/runc.git "$GOPATH/src/github.com/opencontainers/runc" \
|
&& git clone git://github.com/opencontainers/runc.git "$GOPATH/src/github.com/opencontainers/runc" \
|
||||||
|
|
|
@ -14,7 +14,7 @@ clone git github.com/docker/go-units 5d2041e26a699eaca682e2ea41c8f891e1060444
|
||||||
clone git github.com/godbus/dbus e2cf28118e66a6a63db46cf6088a35d2054d3bb0
|
clone git github.com/godbus/dbus e2cf28118e66a6a63db46cf6088a35d2054d3bb0
|
||||||
clone git github.com/golang/glog 23def4e6c14b4da8ac2ed8007337bc5eb5007998
|
clone git github.com/golang/glog 23def4e6c14b4da8ac2ed8007337bc5eb5007998
|
||||||
clone git github.com/golang/protobuf 8d92cf5fc15a4382f8964b08e1f42a75c0591aa3
|
clone git github.com/golang/protobuf 8d92cf5fc15a4382f8964b08e1f42a75c0591aa3
|
||||||
clone git github.com/opencontainers/runc 89c3c97a8482f3a57cd4bb683df1a7b2c61405d8
|
clone git github.com/opencontainers/runc d49ece5a83da3dcb820121d6850e2b61bd0a5fbe
|
||||||
clone git github.com/opencontainers/runtime-spec f955d90e70a98ddfb886bd930ffd076da9b67998
|
clone git github.com/opencontainers/runtime-spec f955d90e70a98ddfb886bd930ffd076da9b67998
|
||||||
clone git github.com/rcrowley/go-metrics eeba7bd0dd01ace6e690fa833b3f22aaec29af43
|
clone git github.com/rcrowley/go-metrics eeba7bd0dd01ace6e690fa833b3f22aaec29af43
|
||||||
clone git github.com/satori/go.uuid f9ab0dce87d815821e221626b772e3475a0d2749
|
clone git github.com/satori/go.uuid f9ab0dce87d815821e221626b772e3475a0d2749
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -260,23 +261,42 @@ func (c *container) RemoveProcess(pid string) error {
|
||||||
return os.RemoveAll(filepath.Join(c.root, c.id, pid))
|
return os.RemoveAll(filepath.Join(c.root, c.id, pid))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func u64Ptr(i uint64) *uint64 { return &i }
|
||||||
|
|
||||||
func (c *container) UpdateResources(r *Resource) error {
|
func (c *container) UpdateResources(r *Resource) error {
|
||||||
container, err := c.getLibctContainer()
|
sr := ocs.Resources{
|
||||||
if err != nil {
|
Memory: &ocs.Memory{
|
||||||
|
Limit: u64Ptr(uint64(r.Memory)),
|
||||||
|
Reservation: u64Ptr(uint64(r.MemoryReservation)),
|
||||||
|
Swap: u64Ptr(uint64(r.MemorySwap)),
|
||||||
|
Kernel: u64Ptr(uint64(r.KernelMemory)),
|
||||||
|
},
|
||||||
|
CPU: &ocs.CPU{
|
||||||
|
Shares: u64Ptr(uint64(r.CPUShares)),
|
||||||
|
Quota: u64Ptr(uint64(r.CPUQuota)),
|
||||||
|
Period: u64Ptr(uint64(r.CPUPeriod)),
|
||||||
|
Cpus: &r.CpusetCpus,
|
||||||
|
Mems: &r.CpusetMems,
|
||||||
|
},
|
||||||
|
BlockIO: &ocs.BlockIO{
|
||||||
|
Weight: &r.BlkioWeight,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
srStr := bytes.NewBuffer(nil)
|
||||||
|
if err := json.NewEncoder(srStr).Encode(&sr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
config := container.Config()
|
|
||||||
config.Cgroups.Resources.CpuShares = r.CPUShares
|
args := c.runtimeArgs
|
||||||
config.Cgroups.Resources.BlkioWeight = r.BlkioWeight
|
args = append(args, "update", "-r", "-", c.id)
|
||||||
config.Cgroups.Resources.CpuPeriod = r.CPUPeriod
|
cmd := exec.Command(c.runtime, args...)
|
||||||
config.Cgroups.Resources.CpuQuota = r.CPUQuota
|
cmd.Stdin = srStr
|
||||||
config.Cgroups.Resources.CpusetCpus = r.CpusetCpus
|
b, err := cmd.CombinedOutput()
|
||||||
config.Cgroups.Resources.CpusetMems = r.CpusetMems
|
if err != nil {
|
||||||
config.Cgroups.Resources.KernelMemory = r.KernelMemory
|
return fmt.Errorf(string(b))
|
||||||
config.Cgroups.Resources.Memory = r.Memory
|
}
|
||||||
config.Cgroups.Resources.MemoryReservation = r.MemoryReservation
|
return nil
|
||||||
config.Cgroups.Resources.MemorySwap = r.MemorySwap
|
|
||||||
return container.Set(config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRootIDs(s *specs.Spec) (int, int, error) {
|
func getRootIDs(s *specs.Spec) (int, int, error) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ package apparmor
|
||||||
// #include <stdlib.h>
|
// #include <stdlib.h>
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
@ -32,7 +33,7 @@ func ApplyProfile(name string) error {
|
||||||
cName := C.CString(name)
|
cName := C.CString(name)
|
||||||
defer C.free(unsafe.Pointer(cName))
|
defer C.free(unsafe.Pointer(cName))
|
||||||
if _, err := C.aa_change_onexec(cName); err != nil {
|
if _, err := C.aa_change_onexec(cName); err != nil {
|
||||||
return err
|
return fmt.Errorf("apparmor failed to apply profile: %s", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ package fs
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -12,6 +13,7 @@ import (
|
||||||
|
|
||||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
|
"github.com/opencontainers/runc/libcontainer/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MemoryGroup struct {
|
type MemoryGroup struct {
|
||||||
|
@ -33,7 +35,7 @@ func (s *MemoryGroup) Apply(d *cgroupData) (err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We have to set kernel memory here, as we can't change it once
|
// We have to set kernel memory here, as we can't change it once
|
||||||
// processes have been attached.
|
// processes have been attached to the cgroup.
|
||||||
if err := s.SetKernelMemory(path, d.config); err != nil {
|
if err := s.SetKernelMemory(path, d.config); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -55,9 +57,44 @@ func (s *MemoryGroup) Apply(d *cgroupData) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MemoryGroup) SetKernelMemory(path string, cgroup *configs.Cgroup) error {
|
func (s *MemoryGroup) SetKernelMemory(path string, cgroup *configs.Cgroup) error {
|
||||||
// This has to be done separately because it has special constraints (it
|
// This has to be done separately because it has special
|
||||||
// can't be done after there are processes attached to the cgroup).
|
// constraints (it can only be initialized before setting up a
|
||||||
if cgroup.Resources.KernelMemory > 0 {
|
// hierarchy or adding a task to the cgroups. However, if
|
||||||
|
// sucessfully initialized, it can be updated anytime afterwards)
|
||||||
|
if cgroup.Resources.KernelMemory != 0 {
|
||||||
|
kmemInitialized := false
|
||||||
|
// Is kmem.limit_in_bytes already set?
|
||||||
|
kmemValue, err := getCgroupParamUint(path, "memory.kmem.limit_in_bytes")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch system.GetLongBit() {
|
||||||
|
case 32:
|
||||||
|
kmemInitialized = uint32(kmemValue) != uint32(math.MaxUint32)
|
||||||
|
case 64:
|
||||||
|
kmemInitialized = kmemValue != uint64(math.MaxUint64)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !kmemInitialized {
|
||||||
|
// If hierarchy is set, we can't change the limit
|
||||||
|
usesHierarchy, err := getCgroupParamUint(path, "memory.use_hierarchy")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if usesHierarchy != 0 {
|
||||||
|
return fmt.Errorf("cannot initialize kmem.limit_in_bytes if use_hierarchy is already set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's already tasks in the cgroup, we can't change the limit either
|
||||||
|
tasks, err := getCgroupParamString(path, "tasks")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if tasks != "" {
|
||||||
|
return fmt.Errorf("cannot initialize kmem.limit_in_bytes after task have joined this cgroup")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := writeFile(path, "memory.kmem.limit_in_bytes", strconv.FormatInt(cgroup.Resources.KernelMemory, 10)); err != nil {
|
if err := writeFile(path, "memory.kmem.limit_in_bytes", strconv.FormatInt(cgroup.Resources.KernelMemory, 10)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -113,6 +150,10 @@ func (s *MemoryGroup) Set(path string, cgroup *configs.Cgroup) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := s.SetKernelMemory(path, cgroup); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if cgroup.Resources.MemoryReservation != 0 {
|
if cgroup.Resources.MemoryReservation != 0 {
|
||||||
if err := writeFile(path, "memory.soft_limit_in_bytes", strconv.FormatInt(cgroup.Resources.MemoryReservation, 10)); err != nil {
|
if err := writeFile(path, "memory.soft_limit_in_bytes", strconv.FormatInt(cgroup.Resources.MemoryReservation, 10)); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -214,11 +214,9 @@ func (m *Manager) Apply(pid int) error {
|
||||||
newProp("BlockIOWeight", uint64(c.Resources.BlkioWeight)))
|
newProp("BlockIOWeight", uint64(c.Resources.BlkioWeight)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to set kernel memory before processes join cgroup because
|
// We have to set kernel memory here, as we can't change it once
|
||||||
// kmem.limit_in_bytes can only be set when the cgroup is empty.
|
// processes have been attached to the cgroup.
|
||||||
// And swap memory limit needs to be set after memory limit, only
|
if c.Resources.KernelMemory != 0 {
|
||||||
// memory limit is handled by systemd, so it's kind of ugly here.
|
|
||||||
if c.Resources.KernelMemory > 0 {
|
|
||||||
if err := setKernelMemory(c); err != nil {
|
if err := setKernelMemory(c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -469,11 +467,5 @@ func setKernelMemory(c *configs.Cgroup) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(path, 0755); err != nil {
|
return os.MkdirAll(path, 0755)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// This doesn't get called by manager.Set, so we need to do it here.
|
|
||||||
s := &fs.MemoryGroup{}
|
|
||||||
return s.SetKernelMemory(path, c)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,3 +10,7 @@ import "C"
|
||||||
func GetClockTicks() int {
|
func GetClockTicks() int {
|
||||||
return int(C.sysconf(C._SC_CLK_TCK))
|
return int(C.sysconf(C._SC_CLK_TCK))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetLongBit() int {
|
||||||
|
return int(C.sysconf(C._SC_LONG_BIT))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue