mirror of https://github.com/docker/docs.git
Add unless-stopped restart policy
Fixes #11008 Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
parent
6206cbe193
commit
10305dc5e8
|
@ -79,6 +79,7 @@ type CommonContainer struct {
|
||||||
MountLabel, ProcessLabel string
|
MountLabel, ProcessLabel string
|
||||||
RestartCount int
|
RestartCount int
|
||||||
HasBeenStartedBefore bool
|
HasBeenStartedBefore bool
|
||||||
|
HasBeenManuallyStopped bool // used for unless-stopped restart policy
|
||||||
hostConfig *runconfig.HostConfig
|
hostConfig *runconfig.HostConfig
|
||||||
command *execdriver.Command
|
command *execdriver.Command
|
||||||
monitor *containerMonitor
|
monitor *containerMonitor
|
||||||
|
@ -1063,6 +1064,7 @@ func copyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error)
|
||||||
|
|
||||||
func (container *Container) shouldRestart() bool {
|
func (container *Container) shouldRestart() bool {
|
||||||
return container.hostConfig.RestartPolicy.Name == "always" ||
|
return container.hostConfig.RestartPolicy.Name == "always" ||
|
||||||
|
(container.hostConfig.RestartPolicy.Name == "unless-stopped" && !container.HasBeenManuallyStopped) ||
|
||||||
(container.hostConfig.RestartPolicy.Name == "on-failure" && container.ExitCode != 0)
|
(container.hostConfig.RestartPolicy.Name == "on-failure" && container.ExitCode != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,7 @@ type Daemon struct {
|
||||||
EventsService *events.Events
|
EventsService *events.Events
|
||||||
netController libnetwork.NetworkController
|
netController libnetwork.NetworkController
|
||||||
root string
|
root string
|
||||||
|
shutdown bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get looks for a container using the provided information, which could be
|
// Get looks for a container using the provided information, which could be
|
||||||
|
@ -744,6 +745,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) Shutdown() error {
|
func (daemon *Daemon) Shutdown() error {
|
||||||
|
daemon.shutdown = true
|
||||||
if daemon.containers != nil {
|
if daemon.containers != nil {
|
||||||
group := sync.WaitGroup{}
|
group := sync.WaitGroup{}
|
||||||
logrus.Debug("starting clean shutdown of all containers...")
|
logrus.Debug("starting clean shutdown of all containers...")
|
||||||
|
|
|
@ -119,6 +119,10 @@ func (m *containerMonitor) Start() error {
|
||||||
}
|
}
|
||||||
m.Close()
|
m.Close()
|
||||||
}()
|
}()
|
||||||
|
// reset stopped flag
|
||||||
|
if m.container.HasBeenManuallyStopped {
|
||||||
|
m.container.HasBeenManuallyStopped = false
|
||||||
|
}
|
||||||
|
|
||||||
// reset the restart count
|
// reset the restart count
|
||||||
m.container.RestartCount = -1
|
m.container.RestartCount = -1
|
||||||
|
@ -223,11 +227,12 @@ func (m *containerMonitor) shouldRestart(exitCode int) bool {
|
||||||
|
|
||||||
// do not restart if the user or docker has requested that this container be stopped
|
// do not restart if the user or docker has requested that this container be stopped
|
||||||
if m.shouldStop {
|
if m.shouldStop {
|
||||||
|
m.container.HasBeenManuallyStopped = !m.container.daemon.shutdown
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case m.restartPolicy.IsAlways():
|
case m.restartPolicy.IsAlways(), m.restartPolicy.IsUnlessStopped():
|
||||||
return true
|
return true
|
||||||
case m.restartPolicy.IsOnFailure():
|
case m.restartPolicy.IsOnFailure():
|
||||||
// the default value of 0 for MaximumRetryCount means that we will not enforce a maximum count
|
// the default value of 0 for MaximumRetryCount means that we will not enforce a maximum count
|
||||||
|
|
|
@ -276,7 +276,8 @@ Json Parameters:
|
||||||
- **Capdrop** - A list of kernel capabilities to drop from the container.
|
- **Capdrop** - A list of kernel capabilities to drop from the container.
|
||||||
- **RestartPolicy** – The behavior to apply when the container exits. The
|
- **RestartPolicy** – The behavior to apply when the container exits. The
|
||||||
value is an object with a `Name` property of either `"always"` to
|
value is an object with a `Name` property of either `"always"` to
|
||||||
always restart or `"on-failure"` to restart only when the container
|
always restart, `"unless-stopped"` to restart always except when
|
||||||
|
user has manually stopped the container or `"on-failure"` to restart only when the container
|
||||||
exit code is non-zero. If `on-failure` is used, `MaximumRetryCount`
|
exit code is non-zero. If `on-failure` is used, `MaximumRetryCount`
|
||||||
controls the number of times to retry before giving up.
|
controls the number of times to retry before giving up.
|
||||||
The default is not to restart. (optional)
|
The default is not to restart. (optional)
|
||||||
|
|
|
@ -58,7 +58,7 @@ Creates a new container.
|
||||||
--pid="" PID namespace to use
|
--pid="" PID namespace to use
|
||||||
--privileged=false Give extended privileges to this container
|
--privileged=false Give extended privileges to this container
|
||||||
--read-only=false Mount the container's root filesystem as read only
|
--read-only=false Mount the container's root filesystem as read only
|
||||||
--restart="no" Restart policy (no, on-failure[:max-retry], always)
|
--restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped)
|
||||||
--security-opt=[] Security options
|
--security-opt=[] Security options
|
||||||
-t, --tty=false Allocate a pseudo-TTY
|
-t, --tty=false Allocate a pseudo-TTY
|
||||||
--disable-content-trust=true Skip image verification
|
--disable-content-trust=true Skip image verification
|
||||||
|
|
|
@ -58,7 +58,7 @@ weight=1
|
||||||
--pid="" PID namespace to use
|
--pid="" PID namespace to use
|
||||||
--privileged=false Give extended privileges to this container
|
--privileged=false Give extended privileges to this container
|
||||||
--read-only=false Mount the container's root filesystem as read only
|
--read-only=false Mount the container's root filesystem as read only
|
||||||
--restart="no" Restart policy (no, on-failure[:max-retry], always)
|
--restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped)
|
||||||
--rm=false Automatically remove the container when it exits
|
--rm=false Automatically remove the container when it exits
|
||||||
--security-opt=[] Security Options
|
--security-opt=[] Security Options
|
||||||
--sig-proxy=true Proxy received signals to the process
|
--sig-proxy=true Proxy received signals to the process
|
||||||
|
@ -440,7 +440,16 @@ Docker supports the following restart policies:
|
||||||
<td>
|
<td>
|
||||||
Always restart the container regardless of the exit status.
|
Always restart the container regardless of the exit status.
|
||||||
When you specify always, the Docker daemon will try to restart
|
When you specify always, the Docker daemon will try to restart
|
||||||
the container indefinitely.
|
the container indefinitely. The container will also always start
|
||||||
|
on daemon startup, regardless of the current state of the container.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>unless-stopped</strong></td>
|
||||||
|
<td>
|
||||||
|
Always restart the container regardless of the exit status, but
|
||||||
|
do not start it on daemon startup if the container has been put
|
||||||
|
to a stopped state before.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -398,7 +398,16 @@ Docker supports the following restart policies:
|
||||||
<td>
|
<td>
|
||||||
Always restart the container regardless of the exit status.
|
Always restart the container regardless of the exit status.
|
||||||
When you specify always, the Docker daemon will try to restart
|
When you specify always, the Docker daemon will try to restart
|
||||||
the container indefinitely.
|
the container indefinitely. The container will also always start
|
||||||
|
on daemon startup, regardless of the current state of the container.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>unless-stopped</strong></td>
|
||||||
|
<td>
|
||||||
|
Always restart the container regardless of the exit status, but
|
||||||
|
do not start it on daemon startup if the container has been put
|
||||||
|
to a stopped state before.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -87,6 +87,60 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithVolumesRefs(c *check.C) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #11008
|
||||||
|
func (s *DockerDaemonSuite) TestDaemonRestartUnlessStopped(c *check.C) {
|
||||||
|
err := s.d.StartWithBusybox()
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
|
out, err := s.d.Cmd("run", "-d", "--name", "top1", "--restart", "always", "busybox:latest", "top")
|
||||||
|
c.Assert(err, check.IsNil, check.Commentf("run top1: %v", out))
|
||||||
|
|
||||||
|
out, err = s.d.Cmd("run", "-d", "--name", "top2", "--restart", "unless-stopped", "busybox:latest", "top")
|
||||||
|
c.Assert(err, check.IsNil, check.Commentf("run top2: %v", out))
|
||||||
|
|
||||||
|
testRun := func(m map[string]bool, prefix string) {
|
||||||
|
var format string
|
||||||
|
for name, shouldRun := range m {
|
||||||
|
out, err := s.d.Cmd("ps")
|
||||||
|
c.Assert(err, check.IsNil, check.Commentf("run ps: %v", out))
|
||||||
|
if shouldRun {
|
||||||
|
format = "%scontainer %q is not running"
|
||||||
|
} else {
|
||||||
|
format = "%scontainer %q is running"
|
||||||
|
}
|
||||||
|
c.Assert(strings.Contains(out, name), check.Equals, shouldRun, check.Commentf(format, prefix, name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// both running
|
||||||
|
testRun(map[string]bool{"top1": true, "top2": true}, "")
|
||||||
|
|
||||||
|
out, err = s.d.Cmd("stop", "top1")
|
||||||
|
c.Assert(err, check.IsNil, check.Commentf(out))
|
||||||
|
|
||||||
|
out, err = s.d.Cmd("stop", "top2")
|
||||||
|
c.Assert(err, check.IsNil, check.Commentf(out))
|
||||||
|
|
||||||
|
// both stopped
|
||||||
|
testRun(map[string]bool{"top1": false, "top2": false}, "")
|
||||||
|
|
||||||
|
err = s.d.Restart()
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
|
// restart=always running
|
||||||
|
testRun(map[string]bool{"top1": true, "top2": false}, "After daemon restart: ")
|
||||||
|
|
||||||
|
out, err = s.d.Cmd("start", "top2")
|
||||||
|
c.Assert(err, check.IsNil, check.Commentf("start top2: %v", out))
|
||||||
|
|
||||||
|
err = s.d.Restart()
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
|
// both running
|
||||||
|
testRun(map[string]bool{"top1": true, "top2": true}, "After second daemon restart: ")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DockerDaemonSuite) TestDaemonStartIptablesFalse(c *check.C) {
|
func (s *DockerDaemonSuite) TestDaemonStartIptablesFalse(c *check.C) {
|
||||||
if err := s.d.Start("--iptables=false"); err != nil {
|
if err := s.d.Start("--iptables=false"); err != nil {
|
||||||
c.Fatalf("we should have been able to start the daemon with passing iptables=false: %v", err)
|
c.Fatalf("we should have been able to start the daemon with passing iptables=false: %v", err)
|
||||||
|
|
|
@ -226,7 +226,7 @@ This value should always larger than **-m**, so you should always use this with
|
||||||
Mount the container's root filesystem as read only.
|
Mount the container's root filesystem as read only.
|
||||||
|
|
||||||
**--restart**="no"
|
**--restart**="no"
|
||||||
Restart policy to apply when a container exits (no, on-failure[:max-retry], always)
|
Restart policy to apply when a container exits (no, on-failure[:max-retry], always, unless-stopped).
|
||||||
|
|
||||||
**--security-opt**=[]
|
**--security-opt**=[]
|
||||||
Security Options
|
Security Options
|
||||||
|
|
|
@ -360,7 +360,7 @@ to write files anywhere. By specifying the `--read-only` flag the container wil
|
||||||
its root filesystem mounted as read only prohibiting any writes.
|
its root filesystem mounted as read only prohibiting any writes.
|
||||||
|
|
||||||
**--restart**="no"
|
**--restart**="no"
|
||||||
Restart policy to apply when a container exits (no, on-failure[:max-retry], always)
|
Restart policy to apply when a container exits (no, on-failure[:max-retry], always, unless-stopped).
|
||||||
|
|
||||||
**--rm**=*true*|*false*
|
**--rm**=*true*|*false*
|
||||||
Automatically remove the container when it exits (incompatible with -d). The default is *false*.
|
Automatically remove the container when it exits (incompatible with -d). The default is *false*.
|
||||||
|
|
|
@ -140,6 +140,13 @@ func (rp *RestartPolicy) IsOnFailure() bool {
|
||||||
return rp.Name == "on-failure"
|
return rp.Name == "on-failure"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsUnlessStopped indicates whether the container has the
|
||||||
|
// "unless-stopped" restart policy. This means the container will
|
||||||
|
// automatically restart unless user has put it to stopped state.
|
||||||
|
func (rp *RestartPolicy) IsUnlessStopped() bool {
|
||||||
|
return rp.Name == "unless-stopped"
|
||||||
|
}
|
||||||
|
|
||||||
// LogConfig represents the logging configuration of the container.
|
// LogConfig represents the logging configuration of the container.
|
||||||
type LogConfig struct {
|
type LogConfig struct {
|
||||||
Type string
|
Type string
|
||||||
|
|
|
@ -450,9 +450,9 @@ func ParseRestartPolicy(policy string) (RestartPolicy, error) {
|
||||||
|
|
||||||
p.Name = name
|
p.Name = name
|
||||||
switch name {
|
switch name {
|
||||||
case "always":
|
case "always", "unless-stopped":
|
||||||
if len(parts) > 1 {
|
if len(parts) > 1 {
|
||||||
return p, fmt.Errorf("maximum restart count not valid with restart policy of \"always\"")
|
return p, fmt.Errorf("maximum restart count not valid with restart policy of \"%s\"", name)
|
||||||
}
|
}
|
||||||
case "no":
|
case "no":
|
||||||
// do nothing
|
// do nothing
|
||||||
|
|
Loading…
Reference in New Issue