зеркало из https://github.com/microsoft/docker.git
Merge pull request #14476 from crosbymichael/execid-growth-fix
Prevent uncontrolled exec config growth
This commit is contained in:
Коммит
382799a642
|
@ -835,13 +835,11 @@ func (container *Container) monitorExec(execConfig *execConfig, callback execdri
|
||||||
err error
|
err error
|
||||||
exitCode int
|
exitCode int
|
||||||
)
|
)
|
||||||
|
|
||||||
pipes := execdriver.NewPipes(execConfig.StreamConfig.stdin, execConfig.StreamConfig.stdout, execConfig.StreamConfig.stderr, execConfig.OpenStdin)
|
pipes := execdriver.NewPipes(execConfig.StreamConfig.stdin, execConfig.StreamConfig.stdout, execConfig.StreamConfig.stderr, execConfig.OpenStdin)
|
||||||
exitCode, err = container.daemon.Exec(container, execConfig, pipes, callback)
|
exitCode, err = container.daemon.Exec(container, execConfig, pipes, callback)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Error running command in existing container %s: %s", container.ID, err)
|
logrus.Errorf("Error running command in existing container %s: %s", container.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf("Exec task in container %s exited with code %d", container.ID, exitCode)
|
logrus.Debugf("Exec task in container %s exited with code %d", container.ID, exitCode)
|
||||||
if execConfig.OpenStdin {
|
if execConfig.OpenStdin {
|
||||||
if err := execConfig.StreamConfig.stdin.Close(); err != nil {
|
if err := execConfig.StreamConfig.stdin.Close(); err != nil {
|
||||||
|
@ -859,7 +857,9 @@ func (container *Container) monitorExec(execConfig *execConfig, callback execdri
|
||||||
logrus.Errorf("Error closing terminal while running in container %s: %s", container.ID, err)
|
logrus.Errorf("Error closing terminal while running in container %s: %s", container.ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// remove the exec command from the container's store only and not the
|
||||||
|
// daemon's store so that the exec command can be inspected.
|
||||||
|
container.execCommands.Delete(execConfig.ID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -735,6 +735,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
|
||||||
d.RegistryService = registryService
|
d.RegistryService = registryService
|
||||||
d.EventsService = eventsService
|
d.EventsService = eventsService
|
||||||
d.root = config.Root
|
d.root = config.Root
|
||||||
|
go d.execCommandGC()
|
||||||
|
|
||||||
if err := d.restore(); err != nil {
|
if err := d.restore(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/daemon/execdriver"
|
"github.com/docker/docker/daemon/execdriver"
|
||||||
|
@ -21,12 +22,13 @@ type execConfig struct {
|
||||||
ID string
|
ID string
|
||||||
Running bool
|
Running bool
|
||||||
ExitCode int
|
ExitCode int
|
||||||
ProcessConfig execdriver.ProcessConfig
|
ProcessConfig *execdriver.ProcessConfig
|
||||||
StreamConfig
|
StreamConfig
|
||||||
OpenStdin bool
|
OpenStdin bool
|
||||||
OpenStderr bool
|
OpenStderr bool
|
||||||
OpenStdout bool
|
OpenStdout bool
|
||||||
Container *Container
|
Container *Container
|
||||||
|
canRemove bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type execStore struct {
|
type execStore struct {
|
||||||
|
@ -128,7 +130,7 @@ func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, erro
|
||||||
user = container.Config.User
|
user = container.Config.User
|
||||||
}
|
}
|
||||||
|
|
||||||
processConfig := execdriver.ProcessConfig{
|
processConfig := &execdriver.ProcessConfig{
|
||||||
Tty: config.Tty,
|
Tty: config.Tty,
|
||||||
Entrypoint: entrypoint,
|
Entrypoint: entrypoint,
|
||||||
Arguments: args,
|
Arguments: args,
|
||||||
|
@ -221,7 +223,6 @@ func (d *Daemon) ContainerExecStart(execName string, stdin io.ReadCloser, stdout
|
||||||
execErr <- fmt.Errorf("Cannot run exec command %s in container %s: %s", execName, container.ID, err)
|
execErr <- fmt.Errorf("Cannot run exec command %s in container %s: %s", execName, container.ID, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case err := <-attachErr:
|
case err := <-attachErr:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -236,7 +237,7 @@ func (d *Daemon) ContainerExecStart(execName string, stdin io.ReadCloser, stdout
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Daemon) Exec(c *Container, execConfig *execConfig, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
|
func (d *Daemon) Exec(c *Container, execConfig *execConfig, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
|
||||||
exitStatus, err := d.execDriver.Exec(c.command, &execConfig.ProcessConfig, pipes, startCallback)
|
exitStatus, err := d.execDriver.Exec(c.command, execConfig.ProcessConfig, pipes, startCallback)
|
||||||
|
|
||||||
// On err, make sure we don't leave ExitCode at zero
|
// On err, make sure we don't leave ExitCode at zero
|
||||||
if err != nil && exitStatus == 0 {
|
if err != nil && exitStatus == 0 {
|
||||||
|
@ -248,3 +249,37 @@ func (d *Daemon) Exec(c *Container, execConfig *execConfig, pipes *execdriver.Pi
|
||||||
|
|
||||||
return exitStatus, err
|
return exitStatus, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// execCommandGC runs a ticker to clean up the daemon references
|
||||||
|
// of exec configs that are no longer part of the container.
|
||||||
|
func (d *Daemon) execCommandGC() {
|
||||||
|
for range time.Tick(5 * time.Minute) {
|
||||||
|
var (
|
||||||
|
cleaned int
|
||||||
|
liveExecCommands = d.containerExecIds()
|
||||||
|
)
|
||||||
|
for id, config := range d.execCommands.s {
|
||||||
|
if config.canRemove {
|
||||||
|
cleaned++
|
||||||
|
d.execCommands.Delete(id)
|
||||||
|
} else {
|
||||||
|
if _, exists := liveExecCommands[id]; !exists {
|
||||||
|
config.canRemove = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logrus.Debugf("clean %d unused exec commands", cleaned)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// containerExecIds returns a list of all the current exec ids that are in use
|
||||||
|
// and running inside a container.
|
||||||
|
func (d *Daemon) containerExecIds() map[string]struct{} {
|
||||||
|
ids := map[string]struct{}{}
|
||||||
|
for _, c := range d.containers.List() {
|
||||||
|
for _, id := range c.execCommands.List() {
|
||||||
|
ids[id] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
|
@ -124,6 +124,5 @@ func (daemon *Daemon) ContainerExecInspect(id string) (*execConfig, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return eConfig, nil
|
return eConfig, nil
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче