mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Refactory cgroups into general pkg
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
This commit is contained in:
parent
f00f374138
commit
c442586305
4 changed files with 124 additions and 104 deletions
|
@ -5,10 +5,23 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dotcloud/docker/pkg/mount"
|
"github.com/dotcloud/docker/pkg/mount"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Cgroup struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Parent string `json:"parent,omitempty"`
|
||||||
|
|
||||||
|
DeviceAccess bool `json:"device_access,omitempty"` // name of parent cgroup or slice
|
||||||
|
Memory int64 `json:"memory,omitempty"` // Memory limit (in bytes)
|
||||||
|
MemorySwap int64 `json:"memory_swap,omitempty"` // Total memory usage (memory + swap); set `-1' to disable swap
|
||||||
|
CpuShares int64 `json:"cpu_shares,omitempty"` // CPU shares (relative weight vs. other containers)
|
||||||
|
}
|
||||||
|
|
||||||
// https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt
|
// https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt
|
||||||
func FindCgroupMountpoint(subsystem string) (string, error) {
|
func FindCgroupMountpoint(subsystem string) (string, error) {
|
||||||
mounts, err := mount.GetMounts()
|
mounts, err := mount.GetMounts()
|
||||||
|
@ -25,7 +38,6 @@ func FindCgroupMountpoint(subsystem string) (string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", fmt.Errorf("cgroup mountpoint not found for %s", subsystem)
|
return "", fmt.Errorf("cgroup mountpoint not found for %s", subsystem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,9 +62,50 @@ func GetInitCgroupDir(subsystem string) (string, error) {
|
||||||
return parseCgroupFile(subsystem, f)
|
return parseCgroupFile(subsystem, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Cgroup) Path(root, subsystem string) (string, error) {
|
||||||
|
cgroup := c.Name
|
||||||
|
if c.Parent != "" {
|
||||||
|
cgroup = filepath.Join(c.Parent, cgroup)
|
||||||
|
}
|
||||||
|
initPath, err := GetInitCgroupDir(subsystem)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return filepath.Join(root, subsystem, initPath, cgroup), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cgroup) Join(root, subsystem string, pid int) (string, error) {
|
||||||
|
path, err := c.Path(root, subsystem)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := writeFile(path, "tasks", strconv.Itoa(pid)); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cgroup) Cleanup(root string) error {
|
||||||
|
get := func(subsystem string) string {
|
||||||
|
path, _ := c.Path(root, subsystem)
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range []string{
|
||||||
|
get("memory"),
|
||||||
|
get("devices"),
|
||||||
|
get("cpu"),
|
||||||
|
} {
|
||||||
|
os.RemoveAll(path)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseCgroupFile(subsystem string, r io.Reader) (string, error) {
|
func parseCgroupFile(subsystem string, r io.Reader) (string, error) {
|
||||||
s := bufio.NewScanner(r)
|
s := bufio.NewScanner(r)
|
||||||
|
|
||||||
for s.Scan() {
|
for s.Scan() {
|
||||||
if err := s.Err(); err != nil {
|
if err := s.Err(); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -67,3 +120,7 @@ func parseCgroupFile(subsystem string, r io.Reader) (string, error) {
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("cgroup '%s' not found in /proc/self/cgroup", subsystem)
|
return "", fmt.Errorf("cgroup '%s' not found in /proc/self/cgroup", subsystem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func writeFile(dir, file, data string) error {
|
||||||
|
return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700)
|
||||||
|
}
|
||||||
|
|
|
@ -10,71 +10,46 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// We have two implementation of cgroups support, one is based on
|
func ApplyCgroup(container *libcontainer.Container, pid int) (err error) {
|
||||||
// systemd and the dbus api, and one is based on raw cgroup fs operations
|
if container.Cgroups == nil {
|
||||||
// following the pre-single-writer model docs at:
|
return nil
|
||||||
// http://www.freedesktop.org/wiki/Software/systemd/PaxControlGroups/
|
|
||||||
const (
|
|
||||||
cgroupRoot = "/sys/fs/cgroup"
|
|
||||||
)
|
|
||||||
|
|
||||||
func useSystemd() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func applyCgroupSystemd(container *libcontainer.Container, pid int) error {
|
|
||||||
return fmt.Errorf("not supported yet")
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeFile(dir, file, data string) error {
|
|
||||||
return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCgroup(subsystem string, container *libcontainer.Container) (string, error) {
|
|
||||||
cgroup := container.CgroupName
|
|
||||||
if container.CgroupParent != "" {
|
|
||||||
cgroup = filepath.Join(container.CgroupParent, cgroup)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initPath, err := cgroups.GetInitCgroupDir(subsystem)
|
// We have two implementation of cgroups support, one is based on
|
||||||
|
// systemd and the dbus api, and one is based on raw cgroup fs operations
|
||||||
|
// following the pre-single-writer model docs at:
|
||||||
|
// http://www.freedesktop.org/wiki/Software/systemd/PaxControlGroups/
|
||||||
|
//
|
||||||
|
// we can pick any subsystem to find the root
|
||||||
|
cgroupRoot, err := cgroups.FindCgroupMountpoint("memory")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return err
|
||||||
}
|
}
|
||||||
|
cgroupRoot = filepath.Dir(cgroupRoot)
|
||||||
path := filepath.Join(cgroupRoot, subsystem, initPath, cgroup)
|
|
||||||
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func joinCgroup(subsystem string, container *libcontainer.Container, pid int) (string, error) {
|
|
||||||
path, err := getCgroup(subsystem, container)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := writeFile(path, "tasks", strconv.Itoa(pid)); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func applyCgroupRaw(container *libcontainer.Container, pid int) (retErr error) {
|
|
||||||
if _, err := os.Stat(cgroupRoot); err != nil {
|
if _, err := os.Stat(cgroupRoot); err != nil {
|
||||||
return fmt.Errorf("cgroups fs not found")
|
return fmt.Errorf("cgroups fs not found")
|
||||||
}
|
}
|
||||||
|
if err := setupDevices(container, cgroupRoot, pid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := setupMemory(container, cgroupRoot, pid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := setupCpu(container, cgroupRoot, pid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if !container.DeviceAccess {
|
func setupDevices(container *libcontainer.Container, cgroupRoot string, pid int) (err error) {
|
||||||
dir, err := joinCgroup("devices", container, pid)
|
if !container.Cgroups.DeviceAccess {
|
||||||
|
dir, err := container.Cgroups.Join(cgroupRoot, "devices", pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if retErr != nil {
|
if err != nil {
|
||||||
os.RemoveAll(dir)
|
os.RemoveAll(dir)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -113,65 +88,53 @@ func applyCgroupRaw(container *libcontainer.Container, pid int) (retErr error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if container.Memory != 0 || container.MemorySwap != 0 {
|
func setupMemory(container *libcontainer.Container, cgroupRoot string, pid int) (err error) {
|
||||||
dir, err := joinCgroup("memory", container, pid)
|
if container.Cgroups.Memory != 0 || container.Cgroups.MemorySwap != 0 {
|
||||||
|
dir, err := container.Cgroups.Join(cgroupRoot, "memory", pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if retErr != nil {
|
if err != nil {
|
||||||
os.RemoveAll(dir)
|
os.RemoveAll(dir)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if container.Memory != 0 {
|
if container.Cgroups.Memory != 0 {
|
||||||
if err := writeFile(dir, "memory.limit_in_bytes", strconv.FormatInt(container.Memory, 10)); err != nil {
|
if err := writeFile(dir, "memory.limit_in_bytes", strconv.FormatInt(container.Cgroups.Memory, 10)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := writeFile(dir, "memory.soft_limit_in_bytes", strconv.FormatInt(container.Memory, 10)); err != nil {
|
if err := writeFile(dir, "memory.soft_limit_in_bytes", strconv.FormatInt(container.Cgroups.Memory, 10)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if container.MemorySwap != 0 {
|
if container.Cgroups.MemorySwap != 0 {
|
||||||
if err := writeFile(dir, "memory.memsw.limit_in_bytes", strconv.FormatInt(container.MemorySwap, 10)); err != nil {
|
if err := writeFile(dir, "memory.memsw.limit_in_bytes", strconv.FormatInt(container.Cgroups.MemorySwap, 10)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupCpu(container *libcontainer.Container, cgroupRoot string, pid int) (err error) {
|
||||||
// We always want to join the cpu group, to allow fair cpu scheduling
|
// We always want to join the cpu group, to allow fair cpu scheduling
|
||||||
// on a container basis
|
// on a container basis
|
||||||
dir, err := joinCgroup("cpu", container, pid)
|
dir, err := container.Cgroups.Join(cgroupRoot, "cpu", pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if container.CpuShares != 0 {
|
if container.Cgroups.CpuShares != 0 {
|
||||||
if err := writeFile(dir, "cpu.shares", strconv.FormatInt(container.CpuShares, 10)); err != nil {
|
if err := writeFile(dir, "cpu.shares", strconv.FormatInt(container.Cgroups.CpuShares, 10)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CleanupCgroup(container *libcontainer.Container) error {
|
func writeFile(dir, file, data string) error {
|
||||||
path, _ := getCgroup("memory", container)
|
return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700)
|
||||||
os.RemoveAll(path)
|
|
||||||
path, _ = getCgroup("devices", container)
|
|
||||||
os.RemoveAll(path)
|
|
||||||
path, _ = getCgroup("cpu", container)
|
|
||||||
os.RemoveAll(path)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ApplyCgroup(container *libcontainer.Container, pid int) error {
|
|
||||||
if container.CgroupName == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if useSystemd() {
|
|
||||||
return applyCgroupSystemd(container, pid)
|
|
||||||
} else {
|
|
||||||
return applyCgroupRaw(container, pid)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,21 @@
|
||||||
package libcontainer
|
package libcontainer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/dotcloud/docker/pkg/cgroups"
|
||||||
|
)
|
||||||
|
|
||||||
// Container defines configuration options for how a
|
// Container defines configuration options for how a
|
||||||
// container is setup inside a directory and how a process should be executed
|
// container is setup inside a directory and how a process should be executed
|
||||||
type Container struct {
|
type Container struct {
|
||||||
Hostname string `json:"hostname,omitempty"` // hostname
|
Hostname string `json:"hostname,omitempty"` // hostname
|
||||||
ReadonlyFs bool `json:"readonly_fs,omitempty"` // set the containers rootfs as readonly
|
ReadonlyFs bool `json:"readonly_fs,omitempty"` // set the containers rootfs as readonly
|
||||||
User string `json:"user,omitempty"` // user to execute the process as
|
User string `json:"user,omitempty"` // user to execute the process as
|
||||||
WorkingDir string `json:"working_dir,omitempty"` // current working directory
|
WorkingDir string `json:"working_dir,omitempty"` // current working directory
|
||||||
Env []string `json:"environment,omitempty"` // environment to set
|
Env []string `json:"environment,omitempty"` // environment to set
|
||||||
Namespaces Namespaces `json:"namespaces,omitempty"` // namespaces to apply
|
Namespaces Namespaces `json:"namespaces,omitempty"` // namespaces to apply
|
||||||
Capabilities Capabilities `json:"capabilities,omitempty"` // capabilities to drop
|
Capabilities Capabilities `json:"capabilities,omitempty"` // capabilities to drop
|
||||||
Network *Network `json:"network,omitempty"` // nil for host's network stack
|
Network *Network `json:"network,omitempty"` // nil for host's network stack
|
||||||
|
Cgroups *cgroups.Cgroup `json:"cgroups,omitempty"`
|
||||||
CgroupName string `json:"cgroup_name,omitempty"` // name of cgroup
|
|
||||||
CgroupParent string `json:"cgroup_parent,omitempty"` // name of parent cgroup or slice
|
|
||||||
DeviceAccess bool `json:"device_access,omitempty"` // name of parent cgroup or slice
|
|
||||||
Memory int64 `json:"memory,omitempty"` // Memory limit (in bytes)
|
|
||||||
MemorySwap int64 `json:"memory_swap,omitempty"` // Total memory usage (memory + swap); set `-1' to disable swap
|
|
||||||
CpuShares int64 `json:"cpu_shares,omitempty"` // CPU shares (relative weight vs. other containers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Network defines configuration for a container's networking stack
|
// Network defines configuration for a container's networking stack
|
||||||
|
|
|
@ -35,7 +35,9 @@
|
||||||
"bridge": "docker0",
|
"bridge": "docker0",
|
||||||
"mtu": 1500
|
"mtu": 1500
|
||||||
},
|
},
|
||||||
"cgroup_name": "docker-koye",
|
"cgroups": {
|
||||||
"cgroup_parent": "docker",
|
"name": "docker-koye",
|
||||||
"memory": 524800
|
"parent": "docker",
|
||||||
|
"memory": 524800
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue