1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Add STOPSIGNAL instruction to dockerfiles.

This way, images creators can set the exit signal their programs use.

Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
David Calavera 2015-08-18 10:30:44 -07:00
parent 0e50d946a2
commit 3781cde61f
17 changed files with 98 additions and 19 deletions

View file

@ -17,6 +17,7 @@ const (
Expose = "expose" Expose = "expose"
Volume = "volume" Volume = "volume"
User = "user" User = "user"
StopSignal = "stopsignal"
) )
// Commands is list of all Dockerfile commands // Commands is list of all Dockerfile commands
@ -35,4 +36,5 @@ var Commands = map[string]struct{}{
Expose: {}, Expose: {},
Volume: {}, Volume: {},
User: {}, User: {},
StopSignal: {},
} }

View file

@ -20,6 +20,7 @@ import (
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/nat" "github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/stringutils" "github.com/docker/docker/pkg/stringutils"
"github.com/docker/docker/pkg/system" "github.com/docker/docker/pkg/system"
"github.com/docker/docker/runconfig" "github.com/docker/docker/runconfig"
@ -534,3 +535,21 @@ func volume(b *builder, args []string, attributes map[string]bool, original stri
} }
return nil return nil
} }
// STOPSIGNAL signal
//
// Set the signal that will be used to kill the container.
func stopSignal(b *builder, args []string, attributes map[string]bool, original string) error {
if len(args) != 1 {
return fmt.Errorf("STOPSIGNAL requires exactly one argument")
}
sig := args[0]
_, err := signal.ParseSignal(sig)
if err != nil {
return err
}
b.Config.StopSignal = sig
return b.commit("", b.Config.Cmd, fmt.Sprintf("STOPSIGNAL %v", args))
}

View file

@ -53,6 +53,7 @@ var replaceEnvAllowed = map[string]struct{}{
command.Expose: {}, command.Expose: {},
command.Volume: {}, command.Volume: {},
command.User: {}, command.User: {},
command.StopSignal: {},
} }
var evaluateTable map[string]func(*builder, []string, map[string]bool, string) error var evaluateTable map[string]func(*builder, []string, map[string]bool, string) error
@ -73,6 +74,7 @@ func init() {
command.Expose: expose, command.Expose: expose,
command.Volume: volume, command.Volume: volume,
command.User: user, command.User: user,
command.StopSignal: stopSignal,
} }
} }

View file

@ -61,6 +61,7 @@ func init() {
command.Entrypoint: parseMaybeJSON, command.Entrypoint: parseMaybeJSON,
command.Expose: parseStringsWhitespaceDelimited, command.Expose: parseStringsWhitespaceDelimited,
command.Volume: parseMaybeJSONToList, command.Volume: parseMaybeJSONToList,
command.StopSignal: parseString,
} }
} }

View file

@ -23,6 +23,7 @@
<item> WORKDIR </item> <item> WORKDIR </item>
<item> USER </item> <item> USER </item>
<item> LABEL </item> <item> LABEL </item>
<item> STOPSIGNAL </item>
</list> </list>
<contexts> <contexts>

View file

@ -25,7 +25,7 @@
</dict> </dict>
</dict> </dict>
<key>match</key> <key>match</key>
<string>^\s*(?:(ONBUILD)\s+)?(FROM|MAINTAINER|RUN|EXPOSE|ENV|ADD|VOLUME|USER|WORKDIR|COPY|LABEL)\s</string> <string>^\s*(?:(ONBUILD)\s+)?(FROM|MAINTAINER|RUN|EXPOSE|ENV|ADD|VOLUME|USER|WORKDIR|COPY|LABEL|STOPSIGNAL)\s</string>
</dict> </dict>
<dict> <dict>
<key>captures</key> <key>captures</key>

View file

@ -11,7 +11,7 @@ let b:current_syntax = "dockerfile"
syntax case ignore syntax case ignore
syntax match dockerfileKeyword /\v^\s*(ONBUILD\s+)?(ADD|CMD|ENTRYPOINT|ENV|EXPOSE|FROM|MAINTAINER|RUN|USER|LABEL|VOLUME|WORKDIR|COPY)\s/ syntax match dockerfileKeyword /\v^\s*(ONBUILD\s+)?(ADD|CMD|ENTRYPOINT|ENV|EXPOSE|FROM|MAINTAINER|RUN|USER|LABEL|VOLUME|WORKDIR|COPY|STOPSIGNAL)\s/
highlight link dockerfileKeyword Keyword highlight link dockerfileKeyword Keyword
syntax region dockerfileString start=/\v"/ skip=/\v\\./ end=/\v"/ syntax region dockerfileString start=/\v"/ skip=/\v\\./ end=/\v"/

View file

@ -524,7 +524,7 @@ func (container *Container) Stop(seconds int) error {
} }
} }
container.LogEvent("stop") container.logEvent("stop")
return nil return nil
} }

View file

@ -1,6 +1,11 @@
package daemon package daemon
import "testing" import (
"testing"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/runconfig"
)
func TestGetFullName(t *testing.T) { func TestGetFullName(t *testing.T) {
name, err := GetFullContainerName("testing") name, err := GetFullContainerName("testing")

View file

@ -1076,6 +1076,13 @@ func (daemon *Daemon) verifyContainerSettings(hostConfig *runconfig.HostConfig,
return nil, fmt.Errorf("The working directory '%s' is invalid. It needs to be an absolute path.", config.WorkingDir) return nil, fmt.Errorf("The working directory '%s' is invalid. It needs to be an absolute path.", config.WorkingDir)
} }
} }
if len(config.StopSignal) > 0 {
_, err := signal.ParseSignal(config.StopSignal)
if err != nil {
return nil, err
}
}
} }
if hostConfig == nil { if hostConfig == nil {
@ -1095,11 +1102,6 @@ func (daemon *Daemon) verifyContainerSettings(hostConfig *runconfig.HostConfig,
} }
} }
_, err := signal.ParseSignal(config.StopSignal)
if err != nil {
return nil, err
}
// Now do platform-specific verification // Now do platform-specific verification
return verifyPlatformContainerSettings(daemon, hostConfig, config) return verifyPlatformContainerSettings(daemon, hostConfig, config)
} }

View file

@ -166,6 +166,7 @@ Create a container
"ExposedPorts": { "ExposedPorts": {
"22/tcp": {} "22/tcp": {}
}, },
"StopSignal": "SIGTERM",
"HostConfig": { "HostConfig": {
"Binds": ["/tmp:/tmp"], "Binds": ["/tmp:/tmp"],
"Links": ["redis3:redis"], "Links": ["redis3:redis"],
@ -250,6 +251,7 @@ Json Parameters:
container container
- **ExposedPorts** - An object mapping ports to an empty object in the form of: - **ExposedPorts** - An object mapping ports to an empty object in the form of:
`"ExposedPorts": { "<port>/<tcp|udp>: {}" }` `"ExposedPorts": { "<port>/<tcp|udp>: {}" }`
- **StopSignal** - Signal to stop a container as a string or unsigned integer. `SIGTERM` by default.
- **HostConfig** - **HostConfig**
- **Binds** A list of volume bindings for this container. Each volume binding is a string in one of these forms: - **Binds** A list of volume bindings for this container. Each volume binding is a string in one of these forms:
+ `container_path` to create a new volume for the container + `container_path` to create a new volume for the container
@ -367,7 +369,8 @@ Return low-level information on the container `id`
"Tty": false, "Tty": false,
"User": "", "User": "",
"Volumes": null, "Volumes": null,
"WorkingDir": "" "WorkingDir": "",
"StopSignal": "SIGTERM"
}, },
"Created": "2015-01-06T15:47:31.485331387Z", "Created": "2015-01-06T15:47:31.485331387Z",
"Driver": "devicemapper", "Driver": "devicemapper",

View file

@ -158,6 +158,7 @@ the `Dockerfile`:
* `USER` * `USER`
* `WORKDIR` * `WORKDIR`
* `VOLUME` * `VOLUME`
* `STOPSIGNAL`
as well as: as well as:
@ -1012,6 +1013,14 @@ For example you might add something like this:
> **Warning**: The `ONBUILD` instruction may not trigger `FROM` or `MAINTAINER` instructions. > **Warning**: The `ONBUILD` instruction may not trigger `FROM` or `MAINTAINER` instructions.
## STOPSIGNAL
STOPSIGNAL signal
The `STOPSIGNAL` instruction sets the system call signal that will be sent to the container to exit.
This signal can be a valid unsigned number that matches a position in the kernel's syscall table, for instance 9,
or a signal name in the format SIGNAME, for instance SIGKILL.
## Dockerfile examples ## Dockerfile examples
# Nginx # Nginx

View file

@ -61,6 +61,7 @@ Creates a new 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, unless-stopped) --restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped)
--security-opt=[] Security options --security-opt=[] Security options
--stop-signal="SIGTERM" Signal to stop a container
-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
-u, --user="" Username or UID -u, --user="" Username or UID

View file

@ -62,6 +62,7 @@ weight=1
--restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped) --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
--stop-signal="SIGTERM" Signal to stop a container
--sig-proxy=true Proxy received signals to the process --sig-proxy=true Proxy received signals to the process
-t, --tty=false Allocate a pseudo-TTY -t, --tty=false Allocate a pseudo-TTY
-u, --user="" Username or UID (format: <name|uid>[:<group|gid>]) -u, --user="" Username or UID (format: <name|uid>[:<group|gid>])
@ -531,3 +532,9 @@ containers with `daemon` user:
The 4th container fails and reports "[8] System error: resource temporarily unavailable" error. The 4th container fails and reports "[8] System error: resource temporarily unavailable" error.
This fails because the caller set `nproc=3` resulting in the first three containers using up This fails because the caller set `nproc=3` resulting in the first three containers using up
the three processes quota set for the `daemon` user. the three processes quota set for the `daemon` user.
### Stopping a container with a specific signal
The `--stop-signal` flag sets the system call signal that will be sent to the container to exit.
This signal can be a valid unsigned number that matches a position in the kernel's syscall table, for instance 9,
or a signal name in the format SIGNAME, for instance SIGKILL.

View file

@ -5660,3 +5660,18 @@ func (s *DockerSuite) TestBuildNullStringInAddCopyVolume(c *check.C) {
_, err = buildImageFromContext(name, ctx, true) _, err = buildImageFromContext(name, ctx, true)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
} }
func (s *DockerSuite) TestBuildStopSignal(c *check.C) {
name := "test_build_stop_signal"
_, err := buildImage(name,
`FROM busybox
STOPSIGNAL SIGKILL`,
true)
c.Assert(err, check.IsNil)
res, err := inspectFieldJSON(name, "Config.StopSignal")
c.Assert(err, check.IsNil)
if res != `"SIGKILL"` {
c.Fatalf("Signal %s, expected SIGKILL", res)
}
}

View file

@ -458,3 +458,15 @@ func (s *DockerTrustSuite) TestTrustedCreateFromBadTrustServer(c *check.C) {
c.Fatalf("Missing expected output on trusted push:\n%s", out) c.Fatalf("Missing expected output on trusted push:\n%s", out)
} }
} }
func (s *DockerSuite) TestCreateStopSignal(c *check.C) {
name := "test_create_stop_signal"
dockerCmd(c, "create", "--name", name, "--stop-signal", "9", "busybox")
res, err := inspectFieldJSON(name, "Config.StopSignal")
c.Assert(err, check.IsNil)
if res != `"9"` {
c.Fatalf("Expected 9, got %s", res)
}
}

View file

@ -181,7 +181,7 @@ To get information on a container use its ID or instance name:
"MemorySwap": 0, "MemorySwap": 0,
"CpuShares": 0, "CpuShares": 0,
"Cpuset": "", "Cpuset": "",
"StopSignal": 15, "StopSignal": "SIGTERM"
} }
} }
] ]