mirror of https://github.com/containers/podman.git
libpod: support for cgroup namespace
allow a container to run in a new cgroup namespace. When running in a new cgroup namespace, the current cgroup appears to be the root, so that there is no way for the container to access cgroups outside of its own subtree. By default it uses --cgroup=host to keep the previous behavior. To create a new namespace, --cgroup=private must be provided. Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
parent
7488ed6d9a
commit
0b57e77d7c
|
@ -129,6 +129,10 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
|
|||
"cap-drop", []string{},
|
||||
"Drop capabilities from the container",
|
||||
)
|
||||
createFlags.String(
|
||||
"cgroupns", "host",
|
||||
"cgroup namespace to use",
|
||||
)
|
||||
createFlags.String(
|
||||
"cgroup-parent", "",
|
||||
"Optional parent cgroup for the container",
|
||||
|
|
|
@ -400,11 +400,12 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
|
|||
namespaceNet = c.String("net")
|
||||
}
|
||||
namespaces = map[string]string{
|
||||
"pid": c.String("pid"),
|
||||
"net": namespaceNet,
|
||||
"ipc": c.String("ipc"),
|
||||
"user": c.String("userns"),
|
||||
"uts": c.String("uts"),
|
||||
"cgroup": c.String("cgroupns"),
|
||||
"pid": c.String("pid"),
|
||||
"net": namespaceNet,
|
||||
"ipc": c.String("ipc"),
|
||||
"user": c.String("userns"),
|
||||
"uts": c.String("uts"),
|
||||
}
|
||||
|
||||
originalPodName := c.String("pod")
|
||||
|
@ -462,6 +463,11 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
|
|||
return nil, errors.Errorf("--uts %q is not valid", namespaces["uts"])
|
||||
}
|
||||
|
||||
cgroupMode := ns.CgroupMode(namespaces["cgroup"])
|
||||
if !cgroupMode.Valid() {
|
||||
return nil, errors.Errorf("--cgroup %q is not valid", namespaces["cgroup"])
|
||||
}
|
||||
|
||||
ipcMode := ns.IpcMode(namespaces["ipc"])
|
||||
if !cc.Valid(string(ipcMode), ipcMode) {
|
||||
return nil, errors.Errorf("--ipc %q is not valid", ipcMode)
|
||||
|
@ -652,6 +658,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
|
|||
CapAdd: c.StringSlice("cap-add"),
|
||||
CapDrop: c.StringSlice("cap-drop"),
|
||||
CidFile: c.String("cidfile"),
|
||||
Cgroupns: c.String("cgroupns"),
|
||||
CgroupParent: c.String("cgroup-parent"),
|
||||
Command: command,
|
||||
Detach: c.Bool("detach"),
|
||||
|
@ -687,6 +694,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
|
|||
NetMode: netMode,
|
||||
UtsMode: utsMode,
|
||||
PidMode: pidMode,
|
||||
CgroupMode: cgroupMode,
|
||||
Pod: podName,
|
||||
Privileged: c.Bool("privileged"),
|
||||
Publish: c.StringSlice("publish"),
|
||||
|
|
|
@ -370,6 +370,7 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIRes
|
|||
m["blkio-weight-device"] = newCRStringSlice(c, "blkio-weight-device")
|
||||
m["cap-add"] = newCRStringSlice(c, "cap-add")
|
||||
m["cap-drop"] = newCRStringSlice(c, "cap-drop")
|
||||
m["cgroupns"] = newCRString(c, "cgroupns")
|
||||
m["cgroup-parent"] = newCRString(c, "cgroup-parent")
|
||||
m["cidfile"] = newCRString(c, "cidfile")
|
||||
m["conmon-pidfile"] = newCRString(c, "conmon-pidfile")
|
||||
|
|
|
@ -63,6 +63,14 @@ Add Linux capabilities
|
|||
|
||||
Drop Linux capabilities
|
||||
|
||||
**--cgroupns**=*mode*
|
||||
|
||||
Set the cgroup namespace mode for the container, by default **host** is used.
|
||||
**host**: use the host's cgroup namespace inside the container.
|
||||
**container:<NAME|ID>**: join the namespace of the specified container.
|
||||
**private**: create a new cgroup namespace.
|
||||
**ns:<PATH>**: join the namespace at the specified path.
|
||||
|
||||
**--cgroup-parent**=*path*
|
||||
|
||||
Path to cgroups under which the cgroup for the container will be created. If the path is not absolute, the path is considered to be relative to the cgroups path of the init process. Cgroups will be created if they do not already exist.
|
||||
|
|
|
@ -77,6 +77,14 @@ Add Linux capabilities
|
|||
|
||||
Drop Linux capabilities
|
||||
|
||||
**--cgroupns**=*mode*
|
||||
|
||||
Set the cgroup namespace mode for the container, by default **host** is used.
|
||||
**host**: use the host's cgroup namespace inside the container.
|
||||
**container:<NAME|ID>**: join the namespace of the specified container.
|
||||
**private**: create a new cgroup namespace.
|
||||
**ns:<PATH>**: join the namespace at the specified path.
|
||||
|
||||
**--cgroup-parent**=*cgroup*
|
||||
|
||||
Path to cgroups under which the cgroup for the container will be created. If the path is not absolute, the path is considered to be relative to the cgroups path of the init process. Cgroups will be created if they do not already exist.
|
||||
|
|
|
@ -4,6 +4,63 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// CgroupMode represents cgroup mode in the container.
|
||||
type CgroupMode string
|
||||
|
||||
// IsHost indicates whether the container uses the host's cgroup.
|
||||
func (n CgroupMode) IsHost() bool {
|
||||
return n == "host"
|
||||
}
|
||||
|
||||
// IsNS indicates a cgroup namespace passed in by path (ns:<path>)
|
||||
func (n CgroupMode) IsNS() bool {
|
||||
return strings.HasPrefix(string(n), "ns:")
|
||||
}
|
||||
|
||||
// NS gets the path associated with a ns:<path> cgroup ns
|
||||
func (n CgroupMode) NS() string {
|
||||
parts := strings.SplitN(string(n), ":", 2)
|
||||
if len(parts) > 1 {
|
||||
return parts[1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// IsContainer indicates whether the container uses a new cgroup namespace.
|
||||
func (n CgroupMode) IsContainer() bool {
|
||||
parts := strings.SplitN(string(n), ":", 2)
|
||||
return len(parts) > 1 && parts[0] == "container"
|
||||
}
|
||||
|
||||
// Container returns the name of the container whose cgroup namespace is going to be used.
|
||||
func (n CgroupMode) Container() string {
|
||||
parts := strings.SplitN(string(n), ":", 2)
|
||||
if len(parts) > 1 {
|
||||
return parts[1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// IsPrivate indicates whether the container uses the a private cgroup.
|
||||
func (n CgroupMode) IsPrivate() bool {
|
||||
return n == "private"
|
||||
}
|
||||
|
||||
// Valid indicates whether the Cgroup namespace is valid.
|
||||
func (n CgroupMode) Valid() bool {
|
||||
parts := strings.Split(string(n), ":")
|
||||
switch mode := parts[0]; mode {
|
||||
case "", "host", "private", "ns":
|
||||
case "container":
|
||||
if len(parts) != 2 || parts[1] == "" {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// UsernsMode represents userns mode in the container.
|
||||
type UsernsMode string
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ type CreateConfig struct {
|
|||
CapDrop []string // cap-drop
|
||||
CidFile string
|
||||
ConmonPidFile string
|
||||
Cgroupns string
|
||||
CgroupParent string // cgroup-parent
|
||||
Command []string
|
||||
Detach bool // detach
|
||||
|
@ -101,6 +102,7 @@ type CreateConfig struct {
|
|||
NetworkAlias []string //network-alias
|
||||
PidMode namespaces.PidMode //pid
|
||||
Pod string //pod
|
||||
CgroupMode namespaces.CgroupMode //cgroup
|
||||
PortBindings nat.PortMap
|
||||
Privileged bool //privileged
|
||||
Publish []string //publish
|
||||
|
@ -268,6 +270,23 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l
|
|||
options = append(options, libpod.WithNetNS(portBindings, postConfigureNetNS, string(c.NetMode), networks))
|
||||
}
|
||||
|
||||
if c.CgroupMode.IsNS() {
|
||||
ns := c.CgroupMode.NS()
|
||||
if ns == "" {
|
||||
return nil, errors.Errorf("invalid empty user-defined network namespace")
|
||||
}
|
||||
_, err := os.Stat(ns)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if c.CgroupMode.IsContainer() {
|
||||
connectedCtr, err := runtime.LookupContainer(c.CgroupMode.Container())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "container %q not found", c.CgroupMode.Container())
|
||||
}
|
||||
options = append(options, libpod.WithCgroupNSFrom(connectedCtr))
|
||||
}
|
||||
|
||||
if c.PidMode.IsContainer() {
|
||||
connectedCtr, err := runtime.LookupContainer(c.PidMode.Container())
|
||||
if err != nil {
|
||||
|
|
|
@ -325,6 +325,10 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
|
|||
if err := addIpcNS(config, &g); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := addCgroupNS(config, &g); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configSpec := g.Config
|
||||
|
||||
// HANDLE CAPABILITIES
|
||||
|
@ -622,6 +626,23 @@ func addIpcNS(config *CreateConfig, g *generate.Generator) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func addCgroupNS(config *CreateConfig, g *generate.Generator) error {
|
||||
cgroupMode := config.CgroupMode
|
||||
if cgroupMode.IsNS() {
|
||||
return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), NS(string(cgroupMode)))
|
||||
}
|
||||
if cgroupMode.IsHost() {
|
||||
return g.RemoveLinuxNamespace(spec.CgroupNamespace)
|
||||
}
|
||||
if cgroupMode.IsPrivate() {
|
||||
return g.AddOrReplaceLinuxNamespace(spec.CgroupNamespace, "")
|
||||
}
|
||||
if cgroupMode.IsContainer() {
|
||||
logrus.Debug("Using container cgroup mode")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addRlimits(config *CreateConfig, g *generate.Generator) error {
|
||||
var (
|
||||
kernelMax uint64 = 1048576
|
||||
|
|
|
@ -51,6 +51,15 @@ var _ = Describe("Podman run ns", func() {
|
|||
Expect(session.ExitCode()).To(Not(Equal(0)))
|
||||
})
|
||||
|
||||
It("podman run --cgroup private test", func() {
|
||||
session := podmanTest.Podman([]string{"run", "--cgroupns=private", fedoraMinimal, "cat", "/proc/self/cgroup"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
output := session.OutputToString()
|
||||
Expect(output).ToNot(ContainSubstring("slice"))
|
||||
})
|
||||
|
||||
It("podman run ipcns test", func() {
|
||||
setup := SystemExec("ls", []string{"--inode", "-d", "/dev/shm"})
|
||||
Expect(setup.ExitCode()).To(Equal(0))
|
||||
|
|
Loading…
Reference in New Issue