mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #15348 from tonistiigi/11008-always-unless-stopped-restart-policy
Add always-unless-stopped restart policy
This commit is contained in:
commit
fd8b25c802
12 changed files with 99 additions and 10 deletions
|
@ -79,6 +79,7 @@ type CommonContainer struct {
|
|||
MountLabel, ProcessLabel string
|
||||
RestartCount int
|
||||
HasBeenStartedBefore bool
|
||||
HasBeenManuallyStopped bool // used for unless-stopped restart policy
|
||||
hostConfig *runconfig.HostConfig
|
||||
command *execdriver.Command
|
||||
monitor *containerMonitor
|
||||
|
@ -1066,6 +1067,7 @@ func copyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error)
|
|||
|
||||
func (container *Container) shouldRestart() bool {
|
||||
return container.hostConfig.RestartPolicy.Name == "always" ||
|
||||
(container.hostConfig.RestartPolicy.Name == "unless-stopped" && !container.HasBeenManuallyStopped) ||
|
||||
(container.hostConfig.RestartPolicy.Name == "on-failure" && container.ExitCode != 0)
|
||||
}
|
||||
|
||||
|
|
|
@ -103,6 +103,7 @@ type Daemon struct {
|
|||
EventsService *events.Events
|
||||
netController libnetwork.NetworkController
|
||||
root string
|
||||
shutdown bool
|
||||
}
|
||||
|
||||
// Get looks for a container using the provided information, which could be
|
||||
|
@ -749,6 +750,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
|
|||
}
|
||||
|
||||
func (daemon *Daemon) Shutdown() error {
|
||||
daemon.shutdown = true
|
||||
if daemon.containers != nil {
|
||||
group := sync.WaitGroup{}
|
||||
logrus.Debug("starting clean shutdown of all containers...")
|
||||
|
|
|
@ -119,6 +119,10 @@ func (m *containerMonitor) Start() error {
|
|||
}
|
||||
m.Close()
|
||||
}()
|
||||
// reset stopped flag
|
||||
if m.container.HasBeenManuallyStopped {
|
||||
m.container.HasBeenManuallyStopped = false
|
||||
}
|
||||
|
||||
// reset the restart count
|
||||
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
|
||||
if m.shouldStop {
|
||||
m.container.HasBeenManuallyStopped = !m.container.daemon.shutdown
|
||||
return false
|
||||
}
|
||||
|
||||
switch {
|
||||
case m.restartPolicy.IsAlways():
|
||||
case m.restartPolicy.IsAlways(), m.restartPolicy.IsUnlessStopped():
|
||||
return true
|
||||
case m.restartPolicy.IsOnFailure():
|
||||
// the default value of 0 for MaximumRetryCount means that we will not enforce a maximum count
|
||||
|
|
|
@ -278,7 +278,8 @@ Json Parameters:
|
|||
- **Capdrop** - A list of kernel capabilities to drop from the container.
|
||||
- **RestartPolicy** – The behavior to apply when the container exits. The
|
||||
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`
|
||||
controls the number of times to retry before giving up.
|
||||
The default is not to restart. (optional)
|
||||
|
|
|
@ -59,7 +59,7 @@ Creates a new container.
|
|||
--pid="" PID namespace to use
|
||||
--privileged=false Give extended privileges to this container
|
||||
--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
|
||||
-t, --tty=false Allocate a pseudo-TTY
|
||||
--disable-content-trust=true Skip image verification
|
||||
|
|
|
@ -59,7 +59,7 @@ weight=1
|
|||
--pid="" PID namespace to use
|
||||
--privileged=false Give extended privileges to this container
|
||||
--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
|
||||
--security-opt=[] Security Options
|
||||
--sig-proxy=true Proxy received signals to the process
|
||||
|
@ -441,7 +441,16 @@ Docker supports the following restart policies:
|
|||
<td>
|
||||
Always restart the container regardless of the exit status.
|
||||
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>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -402,7 +402,16 @@ Docker supports the following restart policies:
|
|||
<td>
|
||||
Always restart the container regardless of the exit status.
|
||||
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>
|
||||
</tr>
|
||||
</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) {
|
||||
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)
|
||||
|
|
|
@ -234,7 +234,7 @@ This value should always larger than **-m**, so you should always use this with
|
|||
Mount the container's root filesystem as read only.
|
||||
|
||||
**--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 Options
|
||||
|
|
|
@ -370,7 +370,7 @@ to write files anywhere. By specifying the `--read-only` flag the container wil
|
|||
its root filesystem mounted as read only prohibiting any writes.
|
||||
|
||||
**--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*
|
||||
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"
|
||||
}
|
||||
|
||||
// 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.
|
||||
type LogConfig struct {
|
||||
Type string
|
||||
|
|
|
@ -426,9 +426,9 @@ func ParseRestartPolicy(policy string) (RestartPolicy, error) {
|
|||
|
||||
p.Name = name
|
||||
switch name {
|
||||
case "always":
|
||||
case "always", "unless-stopped":
|
||||
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":
|
||||
// do nothing
|
||||
|
|
Loading…
Reference in a new issue