mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
837eec064d
Cgroup resources are host dependent, they should be in hostConfig. For backward compatibility, we just copy it to hostConfig, and leave it in Config for now, so there is no regressions, but the right way to use this throught json is to put it in HostConfig, like: { "Hostname": "", ... "HostConfig": { "CpuShares": 512, "Memory": 314572800, ... } } As we will add CpusetMems, CpusetCpus is definitely a better name, but some users are already using Cpuset in their http APIs, we also make it compatible. The main idea is keep using Cpuset in Config Struct, and make it has the same value as CpusetCpus, but not always, some scenarios: - Users use --cpuset in docker command, it can setup cpuset.cpus and can get Cpuset field from docker inspect or other http API which will get config info. - Users use --cpuset-cpus in docker command, ditto. - Users use Cpuset field in their http APIs, ditto. - Users use CpusetCpus field in their http APIs, they won't get Cpuset field in Config info, because by then, they should already know what happens to Cpuset. Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
253 lines
6.9 KiB
Go
253 lines
6.9 KiB
Go
package lxc
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"text/template"
|
|
|
|
log "github.com/Sirupsen/logrus"
|
|
"github.com/docker/docker/daemon/execdriver"
|
|
nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template"
|
|
"github.com/docker/docker/utils"
|
|
"github.com/docker/libcontainer/label"
|
|
)
|
|
|
|
const LxcTemplate = `
|
|
{{if .Network.Interface}}
|
|
# network configuration
|
|
lxc.network.type = veth
|
|
lxc.network.link = {{.Network.Interface.Bridge}}
|
|
lxc.network.name = eth0
|
|
lxc.network.mtu = {{.Network.Mtu}}
|
|
lxc.network.flags = up
|
|
{{else if .Network.HostNetworking}}
|
|
lxc.network.type = none
|
|
{{else}}
|
|
# network is disabled (-n=false)
|
|
lxc.network.type = empty
|
|
lxc.network.flags = up
|
|
lxc.network.mtu = {{.Network.Mtu}}
|
|
{{end}}
|
|
|
|
# root filesystem
|
|
{{$ROOTFS := .Rootfs}}
|
|
lxc.rootfs = {{$ROOTFS}}
|
|
|
|
# use a dedicated pts for the container (and limit the number of pseudo terminal
|
|
# available)
|
|
lxc.pts = 1024
|
|
|
|
# disable the main console
|
|
lxc.console = none
|
|
|
|
# no controlling tty at all
|
|
lxc.tty = 1
|
|
|
|
{{if .ProcessConfig.Privileged}}
|
|
lxc.cgroup.devices.allow = a
|
|
{{else}}
|
|
# no implicit access to devices
|
|
lxc.cgroup.devices.deny = a
|
|
#Allow the devices passed to us in the AllowedDevices list.
|
|
{{range $allowedDevice := .AllowedDevices}}
|
|
lxc.cgroup.devices.allow = {{$allowedDevice.CgroupString}}
|
|
{{end}}
|
|
{{end}}
|
|
|
|
# standard mount point
|
|
# Use mnt.putold as per https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/986385
|
|
lxc.pivotdir = lxc_putold
|
|
|
|
# NOTICE: These mounts must be applied within the namespace
|
|
{{if .ProcessConfig.Privileged}}
|
|
# WARNING: mounting procfs and/or sysfs read-write is a known attack vector.
|
|
# See e.g. http://blog.zx2c4.com/749 and http://bit.ly/T9CkqJ
|
|
# We mount them read-write here, but later, dockerinit will call the Restrict() function to remount them read-only.
|
|
# We cannot mount them directly read-only, because that would prevent loading AppArmor profiles.
|
|
lxc.mount.entry = proc {{escapeFstabSpaces $ROOTFS}}/proc proc nosuid,nodev,noexec 0 0
|
|
lxc.mount.entry = sysfs {{escapeFstabSpaces $ROOTFS}}/sys sysfs nosuid,nodev,noexec 0 0
|
|
{{if .AppArmor}}
|
|
lxc.aa_profile = unconfined
|
|
{{end}}
|
|
{{else}}
|
|
# In non-privileged mode, lxc will automatically mount /proc and /sys in readonly mode
|
|
# for security. See: http://man7.org/linux/man-pages/man5/lxc.container.conf.5.html
|
|
lxc.mount.auto = proc sys
|
|
{{if .AppArmorProfile}}
|
|
lxc.aa_profile = {{.AppArmorProfile}}
|
|
{{end}}
|
|
{{end}}
|
|
|
|
{{if .ProcessConfig.Tty}}
|
|
lxc.mount.entry = {{.ProcessConfig.Console}} {{escapeFstabSpaces $ROOTFS}}/dev/console none bind,rw 0 0
|
|
{{end}}
|
|
|
|
lxc.mount.entry = devpts {{escapeFstabSpaces $ROOTFS}}/dev/pts devpts {{formatMountLabel "newinstance,ptmxmode=0666,nosuid,noexec" ""}} 0 0
|
|
lxc.mount.entry = shm {{escapeFstabSpaces $ROOTFS}}/dev/shm tmpfs {{formatMountLabel "size=65536k,nosuid,nodev,noexec" ""}} 0 0
|
|
|
|
{{range $value := .Mounts}}
|
|
{{$createVal := isDirectory $value.Source}}
|
|
{{if $value.Writable}}
|
|
lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabSpaces $value.Destination}} none rbind,rw,create={{$createVal}} 0 0
|
|
{{else}}
|
|
lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabSpaces $value.Destination}} none rbind,ro,create={{$createVal}} 0 0
|
|
{{end}}
|
|
{{end}}
|
|
|
|
# limits
|
|
{{if .Resources}}
|
|
{{if .Resources.Memory}}
|
|
lxc.cgroup.memory.limit_in_bytes = {{.Resources.Memory}}
|
|
lxc.cgroup.memory.soft_limit_in_bytes = {{.Resources.Memory}}
|
|
{{with $memSwap := getMemorySwap .Resources}}
|
|
lxc.cgroup.memory.memsw.limit_in_bytes = {{$memSwap}}
|
|
{{end}}
|
|
{{end}}
|
|
{{if .Resources.CpuShares}}
|
|
lxc.cgroup.cpu.shares = {{.Resources.CpuShares}}
|
|
{{end}}
|
|
{{if .Resources.CpusetCpus}}
|
|
lxc.cgroup.cpuset.cpus = {{.Resources.CpusetCpus}}
|
|
{{end}}
|
|
{{end}}
|
|
|
|
{{if .LxcConfig}}
|
|
{{range $value := .LxcConfig}}
|
|
lxc.{{$value}}
|
|
{{end}}
|
|
{{end}}
|
|
|
|
{{if .Network.Interface}}
|
|
{{if .Network.Interface.IPAddress}}
|
|
lxc.network.ipv4 = {{.Network.Interface.IPAddress}}/{{.Network.Interface.IPPrefixLen}}
|
|
{{end}}
|
|
{{if .Network.Interface.Gateway}}
|
|
lxc.network.ipv4.gateway = {{.Network.Interface.Gateway}}
|
|
{{end}}
|
|
{{if .Network.Interface.MacAddress}}
|
|
lxc.network.hwaddr = {{.Network.Interface.MacAddress}}
|
|
{{end}}
|
|
{{if .ProcessConfig.Env}}
|
|
lxc.utsname = {{getHostname .ProcessConfig.Env}}
|
|
{{end}}
|
|
|
|
{{if .ProcessConfig.Privileged}}
|
|
# No cap values are needed, as lxc is starting in privileged mode
|
|
{{else}}
|
|
{{ with keepCapabilities .CapAdd .CapDrop }}
|
|
{{range .}}
|
|
lxc.cap.keep = {{.}}
|
|
{{end}}
|
|
{{else}}
|
|
{{ with dropList .CapDrop }}
|
|
{{range .}}
|
|
lxc.cap.drop = {{.}}
|
|
{{end}}
|
|
{{end}}
|
|
{{end}}
|
|
{{end}}
|
|
{{end}}
|
|
`
|
|
|
|
var LxcTemplateCompiled *template.Template
|
|
|
|
// Escape spaces in strings according to the fstab documentation, which is the
|
|
// format for "lxc.mount.entry" lines in lxc.conf. See also "man 5 fstab".
|
|
func escapeFstabSpaces(field string) string {
|
|
return strings.Replace(field, " ", "\\040", -1)
|
|
}
|
|
|
|
func keepCapabilities(adds []string, drops []string) ([]string, error) {
|
|
container := nativeTemplate.New()
|
|
log.Debugf("adds %s drops %s\n", adds, drops)
|
|
caps, err := execdriver.TweakCapabilities(container.Capabilities, adds, drops)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var newCaps []string
|
|
for _, cap := range caps {
|
|
log.Debugf("cap %s\n", cap)
|
|
realCap := execdriver.GetCapability(cap)
|
|
numCap := fmt.Sprintf("%d", realCap.Value)
|
|
newCaps = append(newCaps, numCap)
|
|
}
|
|
|
|
return newCaps, nil
|
|
}
|
|
|
|
func dropList(drops []string) ([]string, error) {
|
|
if utils.StringsContainsNoCase(drops, "all") {
|
|
var newCaps []string
|
|
for _, capName := range execdriver.GetAllCapabilities() {
|
|
cap := execdriver.GetCapability(capName)
|
|
log.Debugf("drop cap %s\n", cap.Key)
|
|
numCap := fmt.Sprintf("%d", cap.Value)
|
|
newCaps = append(newCaps, numCap)
|
|
}
|
|
return newCaps, nil
|
|
}
|
|
return []string{}, nil
|
|
}
|
|
|
|
func isDirectory(source string) string {
|
|
f, err := os.Stat(source)
|
|
log.Debugf("dir: %s\n", source)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return "dir"
|
|
}
|
|
return ""
|
|
}
|
|
if f.IsDir() {
|
|
return "dir"
|
|
}
|
|
return "file"
|
|
}
|
|
|
|
func getMemorySwap(v *execdriver.Resources) int64 {
|
|
// By default, MemorySwap is set to twice the size of RAM.
|
|
// If you want to omit MemorySwap, set it to `-1'.
|
|
if v.MemorySwap < 0 {
|
|
return 0
|
|
}
|
|
return v.Memory * 2
|
|
}
|
|
|
|
func getLabel(c map[string][]string, name string) string {
|
|
label := c["label"]
|
|
for _, l := range label {
|
|
parts := strings.SplitN(l, "=", 2)
|
|
if strings.TrimSpace(parts[0]) == name {
|
|
return strings.TrimSpace(parts[1])
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func getHostname(env []string) string {
|
|
for _, kv := range env {
|
|
parts := strings.SplitN(kv, "=", 2)
|
|
if parts[0] == "HOSTNAME" && len(parts) == 2 {
|
|
return parts[1]
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func init() {
|
|
var err error
|
|
funcMap := template.FuncMap{
|
|
"getMemorySwap": getMemorySwap,
|
|
"escapeFstabSpaces": escapeFstabSpaces,
|
|
"formatMountLabel": label.FormatMountLabel,
|
|
"isDirectory": isDirectory,
|
|
"keepCapabilities": keepCapabilities,
|
|
"dropList": dropList,
|
|
"getHostname": getHostname,
|
|
}
|
|
LxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|