Update libcontainer to support rlimit per process

This updates runc and libcontainer to handle rlimits per process and set
them correctly for the container.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby 2016-03-10 14:35:16 -08:00
parent 47eaa08f5a
commit 20422c9bd9
8 changed files with 43 additions and 28 deletions

View File

@ -138,7 +138,7 @@ type Config struct {
// Rlimits specifies the resource limits, such as max open files, to set in the container
// If Rlimits are not set, the container will inherit rlimits from the parent process
Rlimits []Rlimit `json:"rlimits"`
Rlimits []Rlimit `json:"rlimits,omitempty"`
// OomScoreAdj specifies the adjustment to be made by the kernel when calculating oom scores
// for a process. Valid values are between the range [-1000, '1000'], where processes with

View File

@ -332,6 +332,7 @@ func (c *linuxContainer) newInitConfig(process *Process) *initConfig {
NoNewPrivileges: c.config.NoNewPrivileges,
AppArmorProfile: c.config.AppArmorProfile,
ProcessLabel: c.config.ProcessLabel,
Rlimits: c.config.Rlimits,
}
if process.NoNewPrivileges != nil {
cfg.NoNewPrivileges = *process.NoNewPrivileges
@ -342,6 +343,9 @@ func (c *linuxContainer) newInitConfig(process *Process) *initConfig {
if process.Label != "" {
cfg.ProcessLabel = process.Label
}
if len(process.Rlimits) > 0 {
cfg.Rlimits = process.Rlimits
}
return cfg
}

View File

@ -44,19 +44,20 @@ type network struct {
// initConfig is used for transferring parameters from Exec() to Init()
type initConfig struct {
Args []string `json:"args"`
Env []string `json:"env"`
Cwd string `json:"cwd"`
Capabilities []string `json:"capabilities"`
ProcessLabel string `json:"process_label"`
AppArmorProfile string `json:"apparmor_profile"`
NoNewPrivileges bool `json:"no_new_privileges"`
User string `json:"user"`
Config *configs.Config `json:"config"`
Console string `json:"console"`
Networks []*network `json:"network"`
PassedFilesCount int `json:"passed_files_count"`
ContainerId string `json:"containerid"`
Args []string `json:"args"`
Env []string `json:"env"`
Cwd string `json:"cwd"`
Capabilities []string `json:"capabilities"`
ProcessLabel string `json:"process_label"`
AppArmorProfile string `json:"apparmor_profile"`
NoNewPrivileges bool `json:"no_new_privileges"`
User string `json:"user"`
Config *configs.Config `json:"config"`
Console string `json:"console"`
Networks []*network `json:"network"`
PassedFilesCount int `json:"passed_files_count"`
ContainerId string `json:"containerid"`
Rlimits []configs.Rlimit `json:"rlimits"`
}
type initer interface {
@ -315,8 +316,8 @@ func setupRoute(config *configs.Config) error {
return nil
}
func setupRlimits(config *configs.Config) error {
for _, rlimit := range config.Rlimits {
func setupRlimits(limits []configs.Rlimit) error {
for _, rlimit := range limits {
l := &syscall.Rlimit{Max: rlimit.Hard, Cur: rlimit.Soft}
if err := syscall.Setrlimit(rlimit.Type, l); err != nil {
return fmt.Errorf("error setting rlimit type %v: %v", rlimit.Type, err)

View File

@ -5,6 +5,8 @@ import (
"io"
"math"
"os"
"github.com/opencontainers/runc/libcontainer/configs"
)
type processOperations interface {
@ -58,6 +60,10 @@ type Process struct {
// NoNewPrivileges controls whether processes can gain additional privileges.
NoNewPrivileges *bool
// Rlimits specifies the resource limits, such as max open files, to set in the container
// If Rlimits are not set, the container will inherit rlimits from the parent process
Rlimits []configs.Rlimit
ops processOperations
}

View File

@ -28,7 +28,7 @@ func (l *linuxSetnsInit) Init() error {
if _, err := keyctl.JoinSessionKeyring(l.getSessionRingName()); err != nil {
return err
}
if err := setupRlimits(l.config.Config); err != nil {
if err := setupRlimits(l.config.Rlimits); err != nil {
return err
}
if l.config.NoNewPrivileges {

View File

@ -73,7 +73,7 @@ func (l *linuxStandardInit) Init() error {
if err := setupRoute(l.config.Config); err != nil {
return err
}
if err := setupRlimits(l.config.Config); err != nil {
if err := setupRlimits(l.config.Rlimits); err != nil {
return err
}

View File

@ -278,13 +278,6 @@ func createLibcontainerConfig(cgroupName string, spec *specs.Spec) (*configs.Con
if err := setupUserNamespace(spec, config); err != nil {
return nil, err
}
for _, rlimit := range spec.Process.Rlimits {
rl, err := createLibContainerRlimit(rlimit)
if err != nil {
return nil, err
}
config.Rlimits = append(config.Rlimits, rl)
}
c, err := createCgroupConfig(cgroupName, spec)
if err != nil {
return nil, err

View File

@ -232,8 +232,8 @@ func getDefaultImagePath(context *cli.Context) string {
// newProcess returns a new libcontainer Process with the arguments from the
// spec and stdio from the current process.
func newProcess(p specs.Process) *libcontainer.Process {
return &libcontainer.Process{
func newProcess(p specs.Process) (*libcontainer.Process, error) {
lp := &libcontainer.Process{
Args: p.Args,
Env: p.Env,
// TODO: fix libcontainer's API to better support uid/gid in a typesafe way.
@ -244,6 +244,14 @@ func newProcess(p specs.Process) *libcontainer.Process {
NoNewPrivileges: &p.NoNewPrivileges,
AppArmorProfile: p.ApparmorProfile,
}
for _, rlimit := range p.Rlimits {
rl, err := createLibContainerRlimit(rlimit)
if err != nil {
return nil, err
}
lp.Rlimits = append(lp.Rlimits, rl)
}
return lp, nil
}
func dupStdio(process *libcontainer.Process, rootuid int) error {
@ -332,7 +340,10 @@ func createContainer(context *cli.Context, id string, spec *specs.Spec) (libcont
// runProcess will create a new process in the specified container
// by executing the process specified in the 'config'.
func runProcess(container libcontainer.Container, config *specs.Process, listenFDs []*os.File, console string, pidFile string, detach bool) (int, error) {
process := newProcess(*config)
process, err := newProcess(*config)
if err != nil {
return -1, err
}
// Add extra file descriptors if needed
if len(listenFDs) > 0 {