| ... | ... |
@@ -5,6 +5,38 @@ information on the list of deprecated flags and APIs please have a look at |
| 5 | 5 |
https://docs.docker.com/engine/deprecated/ where target removal dates can also |
| 6 | 6 |
be found. |
| 7 | 7 |
|
| 8 |
+## 17.03.1-ce (2017-03-20) |
|
| 9 |
+ |
|
| 10 |
+### Remote API (v1.27) & Client |
|
| 11 |
+ |
|
| 12 |
+* Fix autoremove on older api [#31692](https://github.com/docker/docker/pull/31692) |
|
| 13 |
+* Fix default network customization for a stack [#31258](https://github.com/docker/docker/pull/31258/) |
|
| 14 |
+* Correct CPU usage calculation in presence of offline CPUs and newer Linux [#31802](https://github.com/docker/docker/pull/31802) |
|
| 15 |
+* Fix issue where service healthcheck is `{}` in remote API [#30197](https://github.com/docker/docker/pull/30197)
|
|
| 16 |
+ |
|
| 17 |
+### Runtime |
|
| 18 |
+ |
|
| 19 |
+* Update runc to 54296cf40ad8143b62dbcaa1d90e520a2136ddfe [#3166](https://github.com/docker/docker/pull/31666) |
|
| 20 |
+ * Ignore cgroup2 mountpoints [opencontainers/runc#1266](https://github.com/opencontainers/runc/pull/1266) |
|
| 21 |
+* Update containerd to 595e75c212d19a81d2b808a518fe1afc1391dad5 [#31662](https://github.com/docker/docker/pull/31662) |
|
| 22 |
+ * Register healtcheck service before calling restore() [docker/containerd#609](https://github.com/docker/containerd/pull/609) |
|
| 23 |
+* Fix `docker exec` not working after unattended upgrades that reload apparmor profiles [#31773](https://github.com/docker/docker/pull/31773) |
|
| 24 |
+* Fix unmounting layer without merge dir with Overlay2 [#31069](https://github.com/docker/docker/pull/31069) |
|
| 25 |
+* Do not ignore "volume in use" errors when force-delete [#31450](https://github.com/docker/docker/pull/31450) |
|
| 26 |
+ |
|
| 27 |
+### Swarm Mode |
|
| 28 |
+ |
|
| 29 |
+* Update swarmkit to 17756457ad6dc4d8a639a1f0b7a85d1b65a617bb [#31807](https://github.com/docker/docker/pull/31807) |
|
| 30 |
+ * Scheduler now correctly considers tasks which have been assigned to a node but aren't yet running [docker/swarmkit#1980](https://github.com/docker/swarmkit/pull/1980) |
|
| 31 |
+ * Allow removal of a network when only dead tasks reference it [docker/swarmkit#2018](https://github.com/docker/swarmkit/pull/2018) |
|
| 32 |
+ * Retry failed network allocations less aggressively [docker/swarmkit#2021](https://github.com/docker/swarmkit/pull/2021) |
|
| 33 |
+ * Avoid network allocation for tasks that are no longer running [docker/swarmkit#2017](https://github.com/docker/swarmkit/pull/2017) |
|
| 34 |
+ * Bookkeeping fixes inside network allocator allocator [docker/swarmkit#2019](https://github.com/docker/swarmkit/pull/2019) [docker/swarmkit#2020](https://github.com/docker/swarmkit/pull/2020) |
|
| 35 |
+ |
|
| 36 |
+### Windows |
|
| 37 |
+ |
|
| 38 |
+* Cleanup HCS on restore [#31503](https://github.com/docker/docker/pull/31503) |
|
| 39 |
+ |
|
| 8 | 40 |
## 17.03.0-ce (2017-03-01) |
| 9 | 41 |
|
| 10 | 42 |
**IMPORTANT**: Starting with this release, Docker is on a monthly release cycle and uses a |
| ... | ... |
@@ -45,9 +77,6 @@ Upgrading from Docker 1.13.1 to 17.03.0 is expected to be simple and low-risk. |
| 45 | 45 |
### Swarm Mode |
| 46 | 46 |
|
| 47 | 47 |
* Shutdown leaks an error when the container was never started [#31279](https://github.com/docker/docker/pull/31279) |
| 48 |
- |
|
| 49 |
-### Swarm Mode |
|
| 50 |
- |
|
| 51 | 48 |
* Fix possibility of tasks getting stuck in the "NEW" state during a leader failover [docker/swarmkit#1938](https://github.com/docker/swarmkit/pull/1938) |
| 52 | 49 |
* Fix extraneous task creations for global services that led to confusing replica counts in `docker service ls` [docker/swarmkit#1957](https://github.com/docker/swarmkit/pull/1957) |
| 53 | 50 |
* Fix problem that made rolling updates slow when `task-history-limit` was set to 1 [docker/swarmkit#1948](https://github.com/docker/swarmkit/pull/1948) |
| ... | ... |
@@ -118,8 +118,6 @@ tags: |
| 118 | 118 |
Run new commands inside running containers. See the [command-line reference](https://docs.docker.com/engine/reference/commandline/exec/) for more information. |
| 119 | 119 |
|
| 120 | 120 |
To exec a command in a container, you first need to create an exec instance, then start it. These two API endpoints are wrapped up in a single command-line command, `docker exec`. |
| 121 |
- - name: "Secret" |
|
| 122 |
- x-displayName: "Secrets" |
|
| 123 | 121 |
# Swarm things |
| 124 | 122 |
- name: "Swarm" |
| 125 | 123 |
x-displayName: "Swarm" |
| ... | ... |
@@ -137,6 +135,10 @@ tags: |
| 137 | 137 |
x-displayName: "Tasks" |
| 138 | 138 |
description: | |
| 139 | 139 |
A task is a container running on a swarm. It is the atomic scheduling unit of swarm. Swarm mode must be enabled for these endpoints to work. |
| 140 |
+ - name: "Secret" |
|
| 141 |
+ x-displayName: "Secrets" |
|
| 142 |
+ description: | |
|
| 143 |
+ Secrets are sensitive data that can be used by services. Swarm mode must be enabled for these endpoints to work. |
|
| 140 | 144 |
# System things |
| 141 | 145 |
- name: "Plugin" |
| 142 | 146 |
x-displayName: "Plugins" |
| ... | ... |
@@ -271,7 +271,7 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
|
| 271 | 271 |
fmt.Fprintf(dockerCli.Out(), " %s\n", attribute) |
| 272 | 272 |
} |
| 273 | 273 |
// TODO: Engine labels with duplicate keys has been deprecated in 1.13 and will be error out |
| 274 |
- // after 3 release cycles (1.16). For now, a WARNING will be generated. The following will |
|
| 274 |
+ // after 3 release cycles (17.12). For now, a WARNING will be generated. The following will |
|
| 275 | 275 |
// be removed eventually. |
| 276 | 276 |
labelMap := map[string]string{}
|
| 277 | 277 |
for _, label := range info.Labels {
|
| ... | ... |
@@ -17,6 +17,8 @@ import ( |
| 17 | 17 |
"github.com/docker/go-connections/nat" |
| 18 | 18 |
) |
| 19 | 19 |
|
| 20 |
+const defaultNetwork = "default" |
|
| 21 |
+ |
|
| 20 | 22 |
// Services from compose-file types to engine API types |
| 21 | 23 |
// TODO: fix secrets API so that SecretAPIClient is not required here |
| 22 | 24 |
func Services( |
| ... | ... |
@@ -157,18 +159,15 @@ func convertServiceNetworks( |
| 157 | 157 |
name string, |
| 158 | 158 |
) ([]swarm.NetworkAttachmentConfig, error) {
|
| 159 | 159 |
if len(networks) == 0 {
|
| 160 |
- return []swarm.NetworkAttachmentConfig{
|
|
| 161 |
- {
|
|
| 162 |
- Target: namespace.Scope("default"),
|
|
| 163 |
- Aliases: []string{name},
|
|
| 164 |
- }, |
|
| 165 |
- }, nil |
|
| 160 |
+ networks = map[string]*composetypes.ServiceNetworkConfig{
|
|
| 161 |
+ defaultNetwork: {},
|
|
| 162 |
+ } |
|
| 166 | 163 |
} |
| 167 | 164 |
|
| 168 | 165 |
nets := []swarm.NetworkAttachmentConfig{}
|
| 169 | 166 |
for networkName, network := range networks {
|
| 170 | 167 |
networkConfig, ok := networkConfigs[networkName] |
| 171 |
- if !ok {
|
|
| 168 |
+ if !ok && networkName != defaultNetwork {
|
|
| 172 | 169 |
return []swarm.NetworkAttachmentConfig{}, fmt.Errorf(
|
| 173 | 170 |
"service %q references network %q, which is not declared", name, networkName) |
| 174 | 171 |
} |
| ... | ... |
@@ -145,10 +145,9 @@ func TestConvertHealthcheckDisableWithTest(t *testing.T) {
|
| 145 | 145 |
|
| 146 | 146 |
func TestConvertServiceNetworksOnlyDefault(t *testing.T) {
|
| 147 | 147 |
networkConfigs := networkMap{}
|
| 148 |
- networks := map[string]*composetypes.ServiceNetworkConfig{}
|
|
| 149 | 148 |
|
| 150 | 149 |
configs, err := convertServiceNetworks( |
| 151 |
- networks, networkConfigs, NewNamespace("foo"), "service")
|
|
| 150 |
+ nil, networkConfigs, NewNamespace("foo"), "service")
|
|
| 152 | 151 |
|
| 153 | 152 |
expected := []swarm.NetworkAttachmentConfig{
|
| 154 | 153 |
{
|
| ... | ... |
@@ -201,6 +200,31 @@ func TestConvertServiceNetworks(t *testing.T) {
|
| 201 | 201 |
assert.DeepEqual(t, []swarm.NetworkAttachmentConfig(sortedConfigs), expected) |
| 202 | 202 |
} |
| 203 | 203 |
|
| 204 |
+func TestConvertServiceNetworksCustomDefault(t *testing.T) {
|
|
| 205 |
+ networkConfigs := networkMap{
|
|
| 206 |
+ "default": composetypes.NetworkConfig{
|
|
| 207 |
+ External: composetypes.External{
|
|
| 208 |
+ External: true, |
|
| 209 |
+ Name: "custom", |
|
| 210 |
+ }, |
|
| 211 |
+ }, |
|
| 212 |
+ } |
|
| 213 |
+ networks := map[string]*composetypes.ServiceNetworkConfig{}
|
|
| 214 |
+ |
|
| 215 |
+ configs, err := convertServiceNetworks( |
|
| 216 |
+ networks, networkConfigs, NewNamespace("foo"), "service")
|
|
| 217 |
+ |
|
| 218 |
+ expected := []swarm.NetworkAttachmentConfig{
|
|
| 219 |
+ {
|
|
| 220 |
+ Target: "custom", |
|
| 221 |
+ Aliases: []string{"service"},
|
|
| 222 |
+ }, |
|
| 223 |
+ } |
|
| 224 |
+ |
|
| 225 |
+ assert.NilError(t, err) |
|
| 226 |
+ assert.DeepEqual(t, []swarm.NetworkAttachmentConfig(configs), expected) |
|
| 227 |
+} |
|
| 228 |
+ |
|
| 204 | 229 |
type byTargetSort []swarm.NetworkAttachmentConfig |
| 205 | 230 |
|
| 206 | 231 |
func (s byTargetSort) Len() int {
|
| ... | ... |
@@ -433,7 +433,7 @@ func loadDaemonCliConfig(opts daemonOptions) (*daemon.Config, error) {
|
| 433 | 433 |
// This is deprecated in 1.13, and, be removed after 3 release cycles. |
| 434 | 434 |
// The following will check the conflict of labels, and report a warning for deprecation. |
| 435 | 435 |
// |
| 436 |
- // TODO: After 3 release cycles (1.16) an error will be returned, and labels will be |
|
| 436 |
+ // TODO: After 3 release cycles (17.12) an error will be returned, and labels will be |
|
| 437 | 437 |
// sanitized to consolidate duplicate key-value pairs (config.Labels = newLabels): |
| 438 | 438 |
// |
| 439 | 439 |
// newLabels, err := daemon.GetConflictFreeLabels(config.Labels) |
| ... | ... |
@@ -570,7 +570,7 @@ __docker_subcommands() {
|
| 570 | 570 |
$(__docker_to_extglob "$subcommands") ) |
| 571 | 571 |
subcommand_pos=$counter |
| 572 | 572 |
local subcommand=${words[$counter]}
|
| 573 |
- local completions_func=_docker_${command}_${subcommand}
|
|
| 573 |
+ local completions_func=_docker_${command}_${subcommand//-/_}
|
|
| 574 | 574 |
declare -F $completions_func >/dev/null && $completions_func |
| 575 | 575 |
return 0 |
| 576 | 576 |
;; |
| ... | ... |
@@ -605,38 +605,25 @@ __docker_complete_local_interfaces() {
|
| 605 | 605 |
COMPREPLY=( $( compgen -W "$(__docker_local_interfaces) $additional_interface" -- "$cur" ) ) |
| 606 | 606 |
} |
| 607 | 607 |
|
| 608 |
-__docker_complete_capabilities() {
|
|
| 609 |
- # The list of capabilities is defined in types.go, ALL was added manually. |
|
| 608 |
+# __docker_complete_capabilities_addable completes Linux capabilities which are |
|
| 609 |
+# not granted by default and may be added. |
|
| 610 |
+# see https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities |
|
| 611 |
+__docker_complete_capabilities_addable() {
|
|
| 610 | 612 |
COMPREPLY=( $( compgen -W " |
| 611 | 613 |
ALL |
| 612 | 614 |
AUDIT_CONTROL |
| 613 |
- AUDIT_WRITE |
|
| 614 |
- AUDIT_READ |
|
| 615 | 615 |
BLOCK_SUSPEND |
| 616 |
- CHOWN |
|
| 617 |
- DAC_OVERRIDE |
|
| 618 | 616 |
DAC_READ_SEARCH |
| 619 |
- FOWNER |
|
| 620 |
- FSETID |
|
| 621 | 617 |
IPC_LOCK |
| 622 | 618 |
IPC_OWNER |
| 623 |
- KILL |
|
| 624 | 619 |
LEASE |
| 625 | 620 |
LINUX_IMMUTABLE |
| 626 | 621 |
MAC_ADMIN |
| 627 | 622 |
MAC_OVERRIDE |
| 628 |
- MKNOD |
|
| 629 | 623 |
NET_ADMIN |
| 630 |
- NET_BIND_SERVICE |
|
| 631 | 624 |
NET_BROADCAST |
| 632 |
- NET_RAW |
|
| 633 |
- SETFCAP |
|
| 634 |
- SETGID |
|
| 635 |
- SETPCAP |
|
| 636 |
- SETUID |
|
| 637 | 625 |
SYS_ADMIN |
| 638 | 626 |
SYS_BOOT |
| 639 |
- SYS_CHROOT |
|
| 640 | 627 |
SYSLOG |
| 641 | 628 |
SYS_MODULE |
| 642 | 629 |
SYS_NICE |
| ... | ... |
@@ -650,7 +637,30 @@ __docker_complete_capabilities() {
|
| 650 | 650 |
" -- "$cur" ) ) |
| 651 | 651 |
} |
| 652 | 652 |
|
| 653 |
-__docker_complete_detach-keys() {
|
|
| 653 |
+# __docker_complete_capabilities_droppable completes Linux capability options which are |
|
| 654 |
+# allowed by default and can be dropped. |
|
| 655 |
+# see https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities |
|
| 656 |
+__docker_complete_capabilities_droppable() {
|
|
| 657 |
+ COMPREPLY=( $( compgen -W " |
|
| 658 |
+ ALL |
|
| 659 |
+ AUDIT_WRITE |
|
| 660 |
+ CHOWN |
|
| 661 |
+ DAC_OVERRIDE |
|
| 662 |
+ FOWNER |
|
| 663 |
+ FSETID |
|
| 664 |
+ KILL |
|
| 665 |
+ MKNOD |
|
| 666 |
+ NET_BIND_SERVICE |
|
| 667 |
+ NET_RAW |
|
| 668 |
+ SETFCAP |
|
| 669 |
+ SETGID |
|
| 670 |
+ SETPCAP |
|
| 671 |
+ SETUID |
|
| 672 |
+ SYS_CHROOT |
|
| 673 |
+ " -- "$cur" ) ) |
|
| 674 |
+} |
|
| 675 |
+ |
|
| 676 |
+__docker_complete_detach_keys() {
|
|
| 654 | 677 |
case "$prev" in |
| 655 | 678 |
--detach-keys) |
| 656 | 679 |
case "$cur" in |
| ... | ... |
@@ -1047,7 +1057,7 @@ _docker_container() {
|
| 1047 | 1047 |
} |
| 1048 | 1048 |
|
| 1049 | 1049 |
_docker_container_attach() {
|
| 1050 |
- __docker_complete_detach-keys && return |
|
| 1050 |
+ __docker_complete_detach_keys && return |
|
| 1051 | 1051 |
|
| 1052 | 1052 |
case "$cur" in |
| 1053 | 1053 |
-*) |
| ... | ... |
@@ -1154,7 +1164,7 @@ _docker_container_diff() {
|
| 1154 | 1154 |
} |
| 1155 | 1155 |
|
| 1156 | 1156 |
_docker_container_exec() {
|
| 1157 |
- __docker_complete_detach-keys && return |
|
| 1157 |
+ __docker_complete_detach_keys && return |
|
| 1158 | 1158 |
|
| 1159 | 1159 |
case "$prev" in |
| 1160 | 1160 |
--env|-e) |
| ... | ... |
@@ -1498,7 +1508,7 @@ _docker_container_run() {
|
| 1498 | 1498 |
--rm |
| 1499 | 1499 |
--sig-proxy=false |
| 1500 | 1500 |
" |
| 1501 |
- __docker_complete_detach-keys && return |
|
| 1501 |
+ __docker_complete_detach_keys && return |
|
| 1502 | 1502 |
fi |
| 1503 | 1503 |
|
| 1504 | 1504 |
local all_options="$options_with_args $boolean_options" |
| ... | ... |
@@ -1538,8 +1548,12 @@ _docker_container_run() {
|
| 1538 | 1538 |
COMPREPLY=( $( compgen -W 'stdin stdout stderr' -- "$cur" ) ) |
| 1539 | 1539 |
return |
| 1540 | 1540 |
;; |
| 1541 |
- --cap-add|--cap-drop) |
|
| 1542 |
- __docker_complete_capabilities |
|
| 1541 |
+ --cap-add) |
|
| 1542 |
+ __docker_complete_capabilities_addable |
|
| 1543 |
+ return |
|
| 1544 |
+ ;; |
|
| 1545 |
+ --cap-drop) |
|
| 1546 |
+ __docker_complete_capabilities_droppable |
|
| 1543 | 1547 |
return |
| 1544 | 1548 |
;; |
| 1545 | 1549 |
--cidfile|--env-file|--init-path|--label-file) |
| ... | ... |
@@ -1686,7 +1700,7 @@ _docker_container_run() {
|
| 1686 | 1686 |
} |
| 1687 | 1687 |
|
| 1688 | 1688 |
_docker_container_start() {
|
| 1689 |
- __docker_complete_detach-keys && return |
|
| 1689 |
+ __docker_complete_detach_keys && return |
|
| 1690 | 1690 |
|
| 1691 | 1691 |
case "$prev" in |
| 1692 | 1692 |
--checkpoint) |
| ... | ... |
@@ -3141,7 +3155,7 @@ _docker_swarm_join() {
|
| 3141 | 3141 |
esac |
| 3142 | 3142 |
} |
| 3143 | 3143 |
|
| 3144 |
-_docker_swarm_join-token() {
|
|
| 3144 |
+_docker_swarm_join_token() {
|
|
| 3145 | 3145 |
case "$cur" in |
| 3146 | 3146 |
-*) |
| 3147 | 3147 |
COMPREPLY=( $( compgen -W "--help --quiet -q --rotate" -- "$cur" ) ) |
| ... | ... |
@@ -3171,7 +3185,7 @@ _docker_swarm_unlock() {
|
| 3171 | 3171 |
esac |
| 3172 | 3172 |
} |
| 3173 | 3173 |
|
| 3174 |
-_docker_swarm_unlock-key() {
|
|
| 3174 |
+_docker_swarm_unlock_key() {
|
|
| 3175 | 3175 |
case "$cur" in |
| 3176 | 3176 |
-*) |
| 3177 | 3177 |
COMPREPLY=( $( compgen -W "--help --quiet -q --rotate" -- "$cur" ) ) |
| ... | ... |
@@ -4289,7 +4303,7 @@ _docker() {
|
| 4289 | 4289 |
command_pos=0 |
| 4290 | 4290 |
fi |
| 4291 | 4291 |
|
| 4292 |
- local completions_func=_docker_${command}
|
|
| 4292 |
+ local completions_func=_docker_${command//-/_}
|
|
| 4293 | 4293 |
declare -F $completions_func >/dev/null && $completions_func |
| 4294 | 4294 |
|
| 4295 | 4295 |
eval "$previous_extglob_setting" |
| ... | ... |
@@ -205,7 +205,7 @@ func (r *controller) Start(ctx context.Context) error {
|
| 205 | 205 |
} |
| 206 | 206 |
|
| 207 | 207 |
// no health check |
| 208 |
- if ctnr.Config == nil || ctnr.Config.Healthcheck == nil {
|
|
| 208 |
+ if ctnr.Config == nil || ctnr.Config.Healthcheck == nil || len(ctnr.Config.Healthcheck.Test) == 0 || ctnr.Config.Healthcheck.Test[0] == "NONE" {
|
|
| 209 | 209 |
if err := r.adapter.activateServiceBinding(); err != nil {
|
| 210 | 210 |
log.G(ctx).WithError(err).Errorf("failed to activate service binding for container %s which has no healthcheck config", r.adapter.container.name())
|
| 211 | 211 |
return err |
| ... | ... |
@@ -213,12 +213,6 @@ func (r *controller) Start(ctx context.Context) error {
|
| 213 | 213 |
return nil |
| 214 | 214 |
} |
| 215 | 215 |
|
| 216 |
- healthCmd := ctnr.Config.Healthcheck.Test |
|
| 217 |
- |
|
| 218 |
- if len(healthCmd) == 0 || healthCmd[0] == "NONE" {
|
|
| 219 |
- return nil |
|
| 220 |
- } |
|
| 221 |
- |
|
| 222 | 216 |
// wait for container to be healthy |
| 223 | 217 |
eventq := r.adapter.events(ctx) |
| 224 | 218 |
|
| ... | ... |
@@ -279,7 +279,7 @@ func ReloadConfiguration(configFile string, flags *pflag.FlagSet, reload func(*C |
| 279 | 279 |
// This is deprecated in 1.13, and, be removed after 3 release cycles. |
| 280 | 280 |
// The following will check the conflict of labels, and report a warning for deprecation. |
| 281 | 281 |
// |
| 282 |
- // TODO: After 3 release cycles (1.16) an error will be returned, and labels will be |
|
| 282 |
+ // TODO: After 3 release cycles (17.12) an error will be returned, and labels will be |
|
| 283 | 283 |
// sanitized to consolidate duplicate key-value pairs (config.Labels = newLabels): |
| 284 | 284 |
// |
| 285 | 285 |
// newLabels, err := GetConflictFreeLabels(newConfig.Labels) |
| ... | ... |
@@ -8,11 +8,12 @@ import ( |
| 8 | 8 |
"time" |
| 9 | 9 |
|
| 10 | 10 |
"github.com/Sirupsen/logrus" |
| 11 |
- "github.com/docker/docker/api/errors" |
|
| 11 |
+ apierrors "github.com/docker/docker/api/errors" |
|
| 12 | 12 |
"github.com/docker/docker/api/types" |
| 13 | 13 |
"github.com/docker/docker/container" |
| 14 | 14 |
"github.com/docker/docker/layer" |
| 15 | 15 |
volumestore "github.com/docker/docker/volume/store" |
| 16 |
+ "github.com/pkg/errors" |
|
| 16 | 17 |
) |
| 17 | 18 |
|
| 18 | 19 |
// ContainerRm removes the container id from the filesystem. An error |
| ... | ... |
@@ -29,7 +30,7 @@ func (daemon *Daemon) ContainerRm(name string, config *types.ContainerRmConfig) |
| 29 | 29 |
// Container state RemovalInProgress should be used to avoid races. |
| 30 | 30 |
if inProgress := container.SetRemovalInProgress(); inProgress {
|
| 31 | 31 |
err := fmt.Errorf("removal of container %s is already in progress", name)
|
| 32 |
- return errors.NewBadRequestError(err) |
|
| 32 |
+ return apierrors.NewBadRequestError(err) |
|
| 33 | 33 |
} |
| 34 | 34 |
defer container.ResetRemovalInProgress() |
| 35 | 35 |
|
| ... | ... |
@@ -80,7 +81,7 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo |
| 80 | 80 |
if container.IsRunning() {
|
| 81 | 81 |
if !forceRemove {
|
| 82 | 82 |
err := fmt.Errorf("You cannot remove a running container %s. Stop the container before attempting removal or use -f", container.ID)
|
| 83 |
- return errors.NewRequestConflictError(err) |
|
| 83 |
+ return apierrors.NewRequestConflictError(err) |
|
| 84 | 84 |
} |
| 85 | 85 |
if err := daemon.Kill(container); err != nil {
|
| 86 | 86 |
return fmt.Errorf("Could not kill running container %s, cannot remove - %v", container.ID, err)
|
| ... | ... |
@@ -143,6 +144,9 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo |
| 143 | 143 |
// This is called directly from the Engine API |
| 144 | 144 |
func (daemon *Daemon) VolumeRm(name string, force bool) error {
|
| 145 | 145 |
err := daemon.volumeRm(name) |
| 146 |
+ if err != nil && volumestore.IsInUse(err) {
|
|
| 147 |
+ return apierrors.NewRequestConflictError(err) |
|
| 148 |
+ } |
|
| 146 | 149 |
if err == nil || force {
|
| 147 | 150 |
daemon.volumes.Purge(name) |
| 148 | 151 |
return nil |
| ... | ... |
@@ -157,11 +161,7 @@ func (daemon *Daemon) volumeRm(name string) error {
|
| 157 | 157 |
} |
| 158 | 158 |
|
| 159 | 159 |
if err := daemon.volumes.Remove(v); err != nil {
|
| 160 |
- if volumestore.IsInUse(err) {
|
|
| 161 |
- err := fmt.Errorf("Unable to remove volume, volume still in use: %v", err)
|
|
| 162 |
- return errors.NewRequestConflictError(err) |
|
| 163 |
- } |
|
| 164 |
- return fmt.Errorf("Error while removing volume %s: %v", name, err)
|
|
| 160 |
+ return errors.Wrap(err, "unable to remove volume") |
|
| 165 | 161 |
} |
| 166 | 162 |
daemon.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()})
|
| 167 | 163 |
return nil |
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"github.com/docker/docker/daemon/caps" |
| 6 | 6 |
"github.com/docker/docker/daemon/exec" |
| 7 | 7 |
"github.com/docker/docker/libcontainerd" |
| 8 |
+ "github.com/opencontainers/runc/libcontainer/apparmor" |
|
| 8 | 9 |
"github.com/opencontainers/runtime-spec/specs-go" |
| 9 | 10 |
) |
| 10 | 11 |
|
| ... | ... |
@@ -23,5 +24,27 @@ func execSetPlatformOpt(c *container.Container, ec *exec.Config, p *libcontainer |
| 23 | 23 |
if ec.Privileged {
|
| 24 | 24 |
p.Capabilities = caps.GetAllCapabilities() |
| 25 | 25 |
} |
| 26 |
+ if apparmor.IsEnabled() {
|
|
| 27 |
+ var appArmorProfile string |
|
| 28 |
+ if c.AppArmorProfile != "" {
|
|
| 29 |
+ appArmorProfile = c.AppArmorProfile |
|
| 30 |
+ } else if c.HostConfig.Privileged {
|
|
| 31 |
+ appArmorProfile = "unconfined" |
|
| 32 |
+ } else {
|
|
| 33 |
+ appArmorProfile = "docker-default" |
|
| 34 |
+ } |
|
| 35 |
+ |
|
| 36 |
+ if appArmorProfile == "docker-default" {
|
|
| 37 |
+ // Unattended upgrades and other fun services can unload AppArmor |
|
| 38 |
+ // profiles inadvertently. Since we cannot store our profile in |
|
| 39 |
+ // /etc/apparmor.d, nor can we practically add other ways of |
|
| 40 |
+ // telling the system to keep our profile loaded, in order to make |
|
| 41 |
+ // sure that we keep the default profile enabled we dynamically |
|
| 42 |
+ // reload it if necessary. |
|
| 43 |
+ if err := ensureDefaultAppArmorProfile(); err != nil {
|
|
| 44 |
+ return err |
|
| 45 |
+ } |
|
| 46 |
+ } |
|
| 47 |
+ } |
|
| 26 | 48 |
return nil |
| 27 | 49 |
} |
| ... | ... |
@@ -144,7 +144,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap |
| 144 | 144 |
return nil, err |
| 145 | 145 |
} |
| 146 | 146 |
if !supportsDType {
|
| 147 |
- // not a fatal error until v1.16 (#27443) |
|
| 147 |
+ // not a fatal error until v17.12 (#27443) |
|
| 148 | 148 |
logrus.Warn(overlayutils.ErrDTypeNotSupported("overlay", backingFs))
|
| 149 | 149 |
} |
| 150 | 150 |
|
| ... | ... |
@@ -30,7 +30,7 @@ import ( |
| 30 | 30 |
"github.com/docker/docker/pkg/mount" |
| 31 | 31 |
"github.com/docker/docker/pkg/parsers" |
| 32 | 32 |
"github.com/docker/docker/pkg/parsers/kernel" |
| 33 |
- "github.com/docker/go-units" |
|
| 33 |
+ units "github.com/docker/go-units" |
|
| 34 | 34 |
|
| 35 | 35 |
"github.com/opencontainers/runc/libcontainer/label" |
| 36 | 36 |
) |
| ... | ... |
@@ -170,7 +170,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap |
| 170 | 170 |
return nil, err |
| 171 | 171 |
} |
| 172 | 172 |
if !supportsDType {
|
| 173 |
- // not a fatal error until v1.16 (#27443) |
|
| 173 |
+ // not a fatal error until v17.12 (#27443) |
|
| 174 | 174 |
logrus.Warn(overlayutils.ErrDTypeNotSupported("overlay2", backingFs))
|
| 175 | 175 |
} |
| 176 | 176 |
|
| ... | ... |
@@ -553,7 +553,17 @@ func (d *Driver) Get(id string, mountLabel string) (s string, err error) {
|
| 553 | 553 |
|
| 554 | 554 |
// Put unmounts the mount path created for the give id. |
| 555 | 555 |
func (d *Driver) Put(id string) error {
|
| 556 |
- mountpoint := path.Join(d.dir(id), "merged") |
|
| 556 |
+ dir := d.dir(id) |
|
| 557 |
+ _, err := ioutil.ReadFile(path.Join(dir, lowerFile)) |
|
| 558 |
+ if err != nil {
|
|
| 559 |
+ // If no lower, no mount happened and just return directly |
|
| 560 |
+ if os.IsNotExist(err) {
|
|
| 561 |
+ return nil |
|
| 562 |
+ } |
|
| 563 |
+ return err |
|
| 564 |
+ } |
|
| 565 |
+ |
|
| 566 |
+ mountpoint := path.Join(dir, "merged") |
|
| 557 | 567 |
if count := d.ctr.Decrement(mountpoint); count > 0 {
|
| 558 | 568 |
return nil |
| 559 | 569 |
} |
| ... | ... |
@@ -13,6 +13,6 @@ func ErrDTypeNotSupported(driver, backingFs string) error {
|
| 13 | 13 |
if backingFs == "xfs" {
|
| 14 | 14 |
msg += " Reformat the filesystem with ftype=1 to enable d_type support." |
| 15 | 15 |
} |
| 16 |
- msg += " Running without d_type support will no longer be supported in Docker 1.16." |
|
| 16 |
+ msg += " Running without d_type support will no longer be supported in Docker 17.12." |
|
| 17 | 17 |
return errors.New(msg) |
| 18 | 18 |
} |
| ... | ... |
@@ -35,7 +35,7 @@ Options: |
| 35 | 35 |
- name=<string> a container's name |
| 36 | 36 |
- network=(<network-id>|<network-name>) |
| 37 | 37 |
- since=(<container-name>|<container-id>) |
| 38 |
- - status=(created|restarting|removing|running|paused|exited) |
|
| 38 |
+ - status=(created|restarting|removing|running|paused|exited) |
|
| 39 | 39 |
- volume=(<volume name>|<mount point destination>) |
| 40 | 40 |
--format string Pretty-print containers using a Go template |
| 41 | 41 |
--help Print usage |
| ... | ... |
@@ -84,11 +84,11 @@ The currently supported filters are: |
| 84 | 84 |
* label (`label=<key>` or `label=<key>=<value>`) |
| 85 | 85 |
* name (container's name) |
| 86 | 86 |
* exited (int - the code of exited containers. Only useful with `--all`) |
| 87 |
-* status (created|restarting|running|removing|paused|exited|dead) |
|
| 87 |
+* status (`created|restarting|running|removing|paused|exited|dead`) |
|
| 88 | 88 |
* ancestor (`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`) - filters containers that were created from the given image or a descendant. |
| 89 | 89 |
* before (container's id or name) - filters containers created before given id or name |
| 90 | 90 |
* since (container's id or name) - filters containers created since given id or name |
| 91 |
-* isolation (default|process|hyperv) (Windows daemon only) |
|
| 91 |
+* isolation (`default|process|hyperv`) (Windows daemon only) |
|
| 92 | 92 |
* volume (volume name or mount point) - filters containers that mount volumes. |
| 93 | 93 |
* network (network id or name) - filters containers connected to the provided network |
| 94 | 94 |
* health (starting|healthy|unhealthy|none) - filters containers based on healthcheck status |
| ... | ... |
@@ -249,12 +249,69 @@ For more information about named volumes, see |
| 249 | 249 |
The following table describes options which apply to both bind-mounts and named |
| 250 | 250 |
volumes in a service: |
| 251 | 251 |
|
| 252 |
-| Option | Required | Description |
|
| 253 |
-|:-----------------------------------------|:--------------------------|:----------------------------------------------------------------------------------------- |
|
| 254 |
-| **type** | | The type of mount, can be either `volume`, `bind`, or `tmpfs`. Defaults to `volume` if no type is specified.<ul><li>`volume`: mounts a [managed volume](volume_create.md) into the container.</li><li>`bind`: bind-mounts a directory or file from the host into the container.</li><li>`tmpfs`: mount a tmpfs in the container</li></ul> |
|
| 255 |
-| **src** or **source** | for `type=bind` only | <ul><li>`type=volume`: `src` is an optional way to specify the name of the volume (for example, `src=my-volume`). If the named volume does not exist, it is automatically created. If no `src` is specified, the volume is assigned a random name which is guaranteed to be unique on the host, but may not be unique cluster-wide. A randomly-named volume has the same lifecycle as its container and is destroyed when the *container* is destroyed (which is upon `service update`, or when scaling or re-balancing the service).</li><li>`type=bind`: `src` is required, and specifies an absolute path to the file or directory to bind-mount (for example, `src=/path/on/host/`). An error is produced if the file or directory does not exist.</li><li>`type=tmpfs`: `src` is not supported.</li></ul> |
|
| 256 |
-| **dst** or **destination** or **target** | yes | Mount path inside the container, for example `/some/path/in/container/`. If the path does not exist in the container's filesystem, the Engine creates a directory at the specified location before mounting the volume or bind-mount. |
|
| 257 |
-| **readonly** or **ro** | | The Engine mounts binds and volumes `read-write` unless `readonly` option is given when mounting the bind or volume.<br /><br /><ul><li>`true` or `1` or no value: Mounts the bind or volume read-only.</li><li>`false` or `0`: Mounts the bind or volume read-write.</li></ul> |
|
| 252 |
+<table> |
|
| 253 |
+ <tr> |
|
| 254 |
+ <th>Option</th> |
|
| 255 |
+ <th>Required</th> |
|
| 256 |
+ <th>Description</th> |
|
| 257 |
+ </tr> |
|
| 258 |
+ <tr> |
|
| 259 |
+ <td><b>types</b></td> |
|
| 260 |
+ <td></td> |
|
| 261 |
+ <td> |
|
| 262 |
+ <p>The type of mount, can be either <tt>volume</tt>, <tt>bind</tt>, or <tt>tmpfs</tt>. Defaults to <tt>volume</tt> if no type is specified. |
|
| 263 |
+ <ul> |
|
| 264 |
+ <li><tt>volume</tt>: mounts a [managed volume](volume_create.md) into the container.</li> |
|
| 265 |
+ <li><tt>bind</tt>: bind-mounts a directory or file from the host into the container.</li> |
|
| 266 |
+ <li><tt>tmpfs</tt>: mount a tmpfs in the container</li> |
|
| 267 |
+ </ul></p> |
|
| 268 |
+ </td> |
|
| 269 |
+ </tr> |
|
| 270 |
+ <tr> |
|
| 271 |
+ <td><b>src</b> or <b>source</b></td> |
|
| 272 |
+ <td>for <tt>type=bind</tt> only></td> |
|
| 273 |
+ <td> |
|
| 274 |
+ <ul> |
|
| 275 |
+ <li> |
|
| 276 |
+ <tt>type=volume</tt>: <tt>src</tt> is an optional way to specify the name of the volume (for example, <tt>src=my-volume</tt>). |
|
| 277 |
+ If the named volume does not exist, it is automatically created. If no <tt>src</tt> is specified, the volume is |
|
| 278 |
+ assigned a random name which is guaranteed to be unique on the host, but may not be unique cluster-wide. |
|
| 279 |
+ A randomly-named volume has the same lifecycle as its container and is destroyed when the <i>container</i> |
|
| 280 |
+ is destroyed (which is upon <tt>service update</tt>, or when scaling or re-balancing the service) |
|
| 281 |
+ </li> |
|
| 282 |
+ <li> |
|
| 283 |
+ <tt>type=bind</tt>: <tt>src</tt> is required, and specifies an absolute path to the file or directory to bind-mount |
|
| 284 |
+ (for example, <tt>src=/path/on/host/</tt>). An error is produced if the file or directory does not exist. |
|
| 285 |
+ </li> |
|
| 286 |
+ <li> |
|
| 287 |
+ <tt>type=tmpfs</tt>: <tt>src</tt> is not supported. |
|
| 288 |
+ </li> |
|
| 289 |
+ </ul> |
|
| 290 |
+ </td> |
|
| 291 |
+ </tr> |
|
| 292 |
+ <tr> |
|
| 293 |
+ <td><p><b>dst</b> or <b>destination</b> or <b>target</b></p></td> |
|
| 294 |
+ <td>yes</td> |
|
| 295 |
+ <td> |
|
| 296 |
+ <p>Mount path inside the container, for example <tt>/some/path/in/container/</tt>. |
|
| 297 |
+ If the path does not exist in the container's filesystem, the Engine creates |
|
| 298 |
+ a directory at the specified location before mounting the volume or bind-mount.</p> |
|
| 299 |
+ </td> |
|
| 300 |
+ </tr> |
|
| 301 |
+ <tr> |
|
| 302 |
+ <td><p><b>readonly</b> or <b>ro</b></p></td> |
|
| 303 |
+ <td></td> |
|
| 304 |
+ <td> |
|
| 305 |
+ <p>The Engine mounts binds and volumes <tt>read-write</tt> unless <tt>readonly</tt> option |
|
| 306 |
+ is given when mounting the bind or volume. |
|
| 307 |
+ <ul> |
|
| 308 |
+ <li><tt>true</tt> or <tt>1</tt> or no value: Mounts the bind or volume read-only.</li> |
|
| 309 |
+ <li><tt>false</tt> or <tt>0</tt>: Mounts the bind or volume read-write.</li> |
|
| 310 |
+ </ul></p> |
|
| 311 |
+ </td> |
|
| 312 |
+ </tr> |
|
| 313 |
+</table> |
|
| 314 |
+ |
|
| 258 | 315 |
|
| 259 | 316 |
#### Bind Propagation |
| 260 | 317 |
|
| ... | ... |
@@ -294,22 +351,84 @@ For more information about bind propagation, see the |
| 294 | 294 |
[Linux kernel documentation for shared subtree](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt). |
| 295 | 295 |
|
| 296 | 296 |
#### Options for Named Volumes |
| 297 |
+ |
|
| 297 | 298 |
The following options can only be used for named volumes (`type=volume`); |
| 298 | 299 |
|
| 299 |
-| Option | Description |
|
| 300 |
-|:----------------------|:-------------------------------------------------------------------------------------------------------------------- |
|
| 301 |
-| **volume-driver** | Name of the volume-driver plugin to use for the volume. Defaults to ``"local"``, to use the local volume driver to create the volume if the volume does not exist. |
|
| 302 |
-| **volume-label** | One or more custom metadata ("labels") to apply to the volume upon creation. For example, `volume-label=mylabel=hello-world,my-other-label=hello-mars`. For more information about labels, refer to [apply custom metadata](https://docs.docker.com/engine/userguide/labels-custom-metadata/).
|
|
| 303 |
-| **volume-nocopy** | By default, if you attach an empty volume to a container, and files or directories already existed at the mount-path in the container (`dst`), the Engine copies those files and directories into the volume, allowing the host to access them. Set `volume-nocopy` to disables copying files from the container's filesystem to the volume and mount the empty volume.<br /><br />A value is optional:<ul><li>`true` or `1`: Default if you do not provide a value. Disables copying.</li><li>`false` or `0`: Enables copying.</li></ul> |
|
| 304 |
-| **volume-opt** | Options specific to a given volume driver, which will be passed to the driver when creating the volume. Options are provided as a comma-separated list of key/value pairs, for example, `volume-opt=some-option=some-value,some-other-option=some-other-value`. For available options for a given driver, refer to that driver's documentation. |
|
| 300 |
+ |
|
| 301 |
+<table> |
|
| 302 |
+ <tr> |
|
| 303 |
+ <th>Option</th> |
|
| 304 |
+ <th>Description</th> |
|
| 305 |
+ </tr> |
|
| 306 |
+ <tr> |
|
| 307 |
+ <td><b>volume-driver</b></td> |
|
| 308 |
+ <td> |
|
| 309 |
+ <p>Name of the volume-driver plugin to use for the volume. Defaults to |
|
| 310 |
+ <tt>"local"</tt>, to use the local volume driver to create the volume if the |
|
| 311 |
+ volume does not exist.</p> |
|
| 312 |
+ </td> |
|
| 313 |
+ </tr> |
|
| 314 |
+ <tr> |
|
| 315 |
+ <td><b>volume-label</b></td> |
|
| 316 |
+ <td> |
|
| 317 |
+ One or more custom metadata ("labels") to apply to the volume upon
|
|
| 318 |
+ creation. For example, |
|
| 319 |
+ `volume-label=mylabel=hello-world,my-other-label=hello-mars`. For more |
|
| 320 |
+ information about labels, refer to |
|
| 321 |
+ <a href="https://docs.docker.com/engine/userguide/labels-custom-metadata/">apply custom metadata</a>. |
|
| 322 |
+ </td> |
|
| 323 |
+ </tr> |
|
| 324 |
+ <tr> |
|
| 325 |
+ <td><b>volume-nocopy</b></td> |
|
| 326 |
+ <td> |
|
| 327 |
+ By default, if you attach an empty volume to a container, and files or |
|
| 328 |
+ directories already existed at the mount-path in the container (<tt>dst</tt>), |
|
| 329 |
+ the Engine copies those files and directories into the volume, allowing |
|
| 330 |
+ the host to access them. Set `volume-nocopy` to disables copying files |
|
| 331 |
+ from the container's filesystem to the volume and mount the empty volume. |
|
| 332 |
+ |
|
| 333 |
+ A value is optional: |
|
| 334 |
+ |
|
| 335 |
+ <ul> |
|
| 336 |
+ <li><tt>true</tt> or <tt>1</tt>: Default if you do not provide a value. Disables copying.</li> |
|
| 337 |
+ <li><tt>false</tt> or <tt>0</tt>: Enables copying.</li> |
|
| 338 |
+ </ul> |
|
| 339 |
+ </td> |
|
| 340 |
+ </tr> |
|
| 341 |
+ <tr> |
|
| 342 |
+ <td><b>volume-opt</b></td> |
|
| 343 |
+ <td> |
|
| 344 |
+ Options specific to a given volume driver, which will be passed to the |
|
| 345 |
+ driver when creating the volume. Options are provided as a comma-separated |
|
| 346 |
+ list of key/value pairs, for example, |
|
| 347 |
+ <tt>volume-opt=some-option=some-value,some-other-option=some-other-value</tt>. |
|
| 348 |
+ For available options for a given driver, refer to that driver's |
|
| 349 |
+ documentation. |
|
| 350 |
+ </td> |
|
| 351 |
+ </tr> |
|
| 352 |
+</table> |
|
| 353 |
+ |
|
| 305 | 354 |
|
| 306 | 355 |
#### Options for tmpfs |
| 356 |
+ |
|
| 307 | 357 |
The following options can only be used for tmpfs mounts (`type=tmpfs`); |
| 308 | 358 |
|
| 309 |
-| Option | Description |
|
| 310 |
-|:----------------------|:-------------------------------------------------------------------------------------------------------------------- |
|
| 311 |
-| **tmpfs-size** | Size of the tmpfs mount in bytes. Unlimited by default in Linux. |
|
| 312 |
-| **tmpfs-mode** | File mode of the tmpfs in octal. (e.g. `"700"` or `"0700"`.) Defaults to ``"1777"`` in Linux. |
|
| 359 |
+ |
|
| 360 |
+<table> |
|
| 361 |
+ <tr> |
|
| 362 |
+ <th>Option</th> |
|
| 363 |
+ <th>Description</th> |
|
| 364 |
+ </tr> |
|
| 365 |
+ <tr> |
|
| 366 |
+ <td><b>tmpfs-size</b></td> |
|
| 367 |
+ <td>Size of the tmpfs mount in bytes. Unlimited by default in Linux.</td> |
|
| 368 |
+ </tr> |
|
| 369 |
+ <tr> |
|
| 370 |
+ <td><b>tmpfs-mode</b></td> |
|
| 371 |
+ <td>File mode of the tmpfs in octal. (e.g. <tt>"700"</tt> or <tt>"0700"</tt>.) Defaults to <tt>"1777"</tt> in Linux.</td> |
|
| 372 |
+ </tr> |
|
| 373 |
+</table> |
|
| 374 |
+ |
|
| 313 | 375 |
|
| 314 | 376 |
#### Differences between "--mount" and "--volume" |
| 315 | 377 |
|
| ... | ... |
@@ -412,13 +531,40 @@ constraint expressions. Multiple constraints find nodes that satisfy every |
| 412 | 412 |
expression (AND match). Constraints can match node or Docker Engine labels as |
| 413 | 413 |
follows: |
| 414 | 414 |
|
| 415 |
-| node attribute | matches | example | |
|
| 416 |
-|:----------------|:--------------------------|:------------------------------------------------| |
|
| 417 |
-| node.id | node ID | `node.id == 2ivku8v2gvtg4` | |
|
| 418 |
-| node.hostname | node hostname | `node.hostname != node-2` | |
|
| 419 |
-| node.role | node role: manager | `node.role == manager` | |
|
| 420 |
-| node.labels | user defined node labels | `node.labels.security == high` | |
|
| 421 |
-| engine.labels | Docker Engine's labels | `engine.labels.operatingsystem == ubuntu 14.04` | |
|
| 415 |
+ |
|
| 416 |
+<table> |
|
| 417 |
+ <tr> |
|
| 418 |
+ <th>node attribute</th> |
|
| 419 |
+ <th>matches</th> |
|
| 420 |
+ <th>example</th> |
|
| 421 |
+ </tr> |
|
| 422 |
+ <tr> |
|
| 423 |
+ <td><tt>node.id</tt></td> |
|
| 424 |
+ <td>Node ID</td> |
|
| 425 |
+ <td><tt>node.id == 2ivku8v2gvtg4</tt></td> |
|
| 426 |
+ </tr> |
|
| 427 |
+ <tr> |
|
| 428 |
+ <td><tt>node.hostname</tt></td> |
|
| 429 |
+ <td>Node hostname</td> |
|
| 430 |
+ <td><tt>node.hostname != node-2</tt></td> |
|
| 431 |
+ </tr> |
|
| 432 |
+ <tr> |
|
| 433 |
+ <td<tt>node.role</tt></td> |
|
| 434 |
+ <td><tt>node role: manager</tt></td> |
|
| 435 |
+ <td><tt>node.role == manager</tt></td> |
|
| 436 |
+ </tr> |
|
| 437 |
+ <tr> |
|
| 438 |
+ <td><tt>node.labels</tt></td> |
|
| 439 |
+ <td>user defined node labels</td> |
|
| 440 |
+ <td><tt>node.labels.security == high</tt></td> |
|
| 441 |
+ </tr> |
|
| 442 |
+ <tr> |
|
| 443 |
+ <td><tt>engine.labels</tt></td> |
|
| 444 |
+ <td>Docker Engine's labels</td> |
|
| 445 |
+ <td><tt>engine.labels.operatingsystem == ubuntu 14.04</tt></td> |
|
| 446 |
+ </tr> |
|
| 447 |
+</table> |
|
| 448 |
+ |
|
| 422 | 449 |
|
| 423 | 450 |
`engine.labels` apply to Docker Engine labels like operating system, |
| 424 | 451 |
drivers, etc. Swarm administrators add `node.labels` for operational purposes by |
| ... | ... |
@@ -530,15 +676,42 @@ The supported flags are the following : |
| 530 | 530 |
|
| 531 | 531 |
Valid placeholders for the Go template are listed below: |
| 532 | 532 |
|
| 533 |
-Placeholder | Description |
|
| 534 |
-`.Service.ID` | Service ID |
|
| 535 |
-`.Service.Name` | Service name |
|
| 536 |
-`.Service.Labels` | Service labels |
|
| 537 |
-`.Node.ID` | Node ID |
|
| 538 |
-`.Task.ID` | Task ID |
|
| 539 |
-`.Task.Name` | Task name |
|
| 540 |
-`.Task.Slot` | Task slot |
|
| 533 |
+ |
|
| 534 |
+<table> |
|
| 535 |
+ <tr> |
|
| 536 |
+ <th>Placeholder</th> |
|
| 537 |
+ <th>Description</th> |
|
| 538 |
+ </tr> |
|
| 539 |
+ <tr> |
|
| 540 |
+ <td><tt>.Service.ID</tt></td> |
|
| 541 |
+ <td>Service ID</td> |
|
| 542 |
+ </tr> |
|
| 543 |
+ <tr> |
|
| 544 |
+ <td><tt>.Service.Name</tt></td> |
|
| 545 |
+ <td>Service name</td> |
|
| 546 |
+ </tr> |
|
| 547 |
+ <tr> |
|
| 548 |
+ <td><tt>.Service.Labels</tt></td> |
|
| 549 |
+ <td>Service labels</td> |
|
| 550 |
+ </tr> |
|
| 551 |
+ <tr> |
|
| 552 |
+ <td><tt>.Node.ID</tt></td> |
|
| 553 |
+ <td>Node ID</td> |
|
| 554 |
+ </tr> |
|
| 555 |
+ <tr> |
|
| 556 |
+ <td><tt>.Task.ID</tt></td> |
|
| 557 |
+ <td>Task ID</td> |
|
| 558 |
+ </tr> |
|
| 559 |
+ <tr> |
|
| 560 |
+ <td><tt>.Task.Name</tt></td> |
|
| 561 |
+ <td>Task name</td> |
|
| 562 |
+ </tr> |
|
| 563 |
+ <tr> |
|
| 564 |
+ <td><tt>.Task.Slot</tt></td> |
|
| 565 |
+ <td>Task slot</td> |
|
| 566 |
+ </tr> |
|
| 567 |
+</table> |
|
| 568 |
+ |
|
| 541 | 569 |
|
| 542 | 570 |
#### Template example |
| 543 | 571 |
|
| ... | ... |
@@ -27,12 +27,12 @@ Options: |
| 27 | 27 |
-q, --quiet Only display IDs |
| 28 | 28 |
``` |
| 29 | 29 |
|
| 30 |
-### Description |
|
| 30 |
+## Description |
|
| 31 | 31 |
|
| 32 | 32 |
Lists the services that are running as part of the specified stack. This |
| 33 | 33 |
command has to be run targeting a manager node. |
| 34 | 34 |
|
| 35 |
-### Examples |
|
| 35 |
+## Examples |
|
| 36 | 36 |
|
| 37 | 37 |
The following command shows all services in the `myapp` stack: |
| 38 | 38 |
|
| ... | ... |
@@ -15,6 +15,7 @@ import ( |
| 15 | 15 |
"time" |
| 16 | 16 |
|
| 17 | 17 |
"github.com/docker/docker/api/types" |
| 18 |
+ "github.com/docker/docker/api/types/container" |
|
| 18 | 19 |
"github.com/docker/docker/api/types/swarm" |
| 19 | 20 |
"github.com/docker/docker/pkg/integration/checker" |
| 20 | 21 |
"github.com/go-check/check" |
| ... | ... |
@@ -1365,3 +1366,26 @@ func (s *DockerSwarmSuite) TestAPIDuplicateNetworks(c *check.C) {
|
| 1365 | 1365 |
|
| 1366 | 1366 |
c.Assert(r2.Scope, checker.Equals, "swarm") |
| 1367 | 1367 |
} |
| 1368 |
+ |
|
| 1369 |
+// Test case for 30178 |
|
| 1370 |
+func (s *DockerSwarmSuite) TestAPISwarmHealthcheckNone(c *check.C) {
|
|
| 1371 |
+ d := s.AddDaemon(c, true, true) |
|
| 1372 |
+ |
|
| 1373 |
+ out, err := d.Cmd("network", "create", "-d", "overlay", "lb")
|
|
| 1374 |
+ c.Assert(err, checker.IsNil, check.Commentf(out)) |
|
| 1375 |
+ |
|
| 1376 |
+ instances := 1 |
|
| 1377 |
+ d.createService(c, simpleTestService, setInstances(instances), func(s *swarm.Service) {
|
|
| 1378 |
+ s.Spec.TaskTemplate.ContainerSpec.Healthcheck = &container.HealthConfig{}
|
|
| 1379 |
+ s.Spec.TaskTemplate.Networks = []swarm.NetworkAttachmentConfig{
|
|
| 1380 |
+ {Target: "lb"},
|
|
| 1381 |
+ } |
|
| 1382 |
+ }) |
|
| 1383 |
+ |
|
| 1384 |
+ waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, instances) |
|
| 1385 |
+ |
|
| 1386 |
+ containers := d.activeContainers() |
|
| 1387 |
+ |
|
| 1388 |
+ out, err = d.Cmd("exec", containers[0], "ping", "-c1", "-W3", "top")
|
|
| 1389 |
+ c.Assert(err, checker.IsNil, check.Commentf(out)) |
|
| 1390 |
+} |
| ... | ... |
@@ -398,14 +398,54 @@ func (s *DockerSuite) TestVolumeCLIRmForce(c *check.C) {
|
| 398 | 398 |
out, _, err := runCommandWithOutput(exec.Command("rm", "-rf", path))
|
| 399 | 399 |
c.Assert(err, check.IsNil) |
| 400 | 400 |
|
| 401 |
- dockerCmd(c, "volume", "rm", "-f", "test") |
|
| 401 |
+ dockerCmd(c, "volume", "rm", "-f", name) |
|
| 402 | 402 |
out, _ = dockerCmd(c, "volume", "ls") |
| 403 | 403 |
c.Assert(out, checker.Not(checker.Contains), name) |
| 404 |
- dockerCmd(c, "volume", "create", "test") |
|
| 404 |
+ dockerCmd(c, "volume", "create", name) |
|
| 405 | 405 |
out, _ = dockerCmd(c, "volume", "ls") |
| 406 | 406 |
c.Assert(out, checker.Contains, name) |
| 407 | 407 |
} |
| 408 | 408 |
|
| 409 |
+// TestVolumeCLIRmForceInUse verifies that repeated `docker volume rm -f` calls does not remove a volume |
|
| 410 |
+// if it is in use. Test case for https://github.com/docker/docker/issues/31446 |
|
| 411 |
+func (s *DockerSuite) TestVolumeCLIRmForceInUse(c *check.C) {
|
|
| 412 |
+ name := "testvolume" |
|
| 413 |
+ out, _ := dockerCmd(c, "volume", "create", name) |
|
| 414 |
+ id := strings.TrimSpace(out) |
|
| 415 |
+ c.Assert(id, checker.Equals, name) |
|
| 416 |
+ |
|
| 417 |
+ prefix, slash := getPrefixAndSlashFromDaemonPlatform() |
|
| 418 |
+ out, e := dockerCmd(c, "create", "-v", "testvolume:"+prefix+slash+"foo", "busybox") |
|
| 419 |
+ cid := strings.TrimSpace(out) |
|
| 420 |
+ |
|
| 421 |
+ _, _, err := dockerCmdWithError("volume", "rm", "-f", name)
|
|
| 422 |
+ c.Assert(err, check.NotNil) |
|
| 423 |
+ c.Assert(err.Error(), checker.Contains, "volume is in use") |
|
| 424 |
+ out, _ = dockerCmd(c, "volume", "ls") |
|
| 425 |
+ c.Assert(out, checker.Contains, name) |
|
| 426 |
+ |
|
| 427 |
+ // The original issue did not _remove_ the volume from the list |
|
| 428 |
+ // the first time. But a second call to `volume rm` removed it. |
|
| 429 |
+ // Calling `volume rm` a second time to confirm it's not removed |
|
| 430 |
+ // when calling twice. |
|
| 431 |
+ _, _, err = dockerCmdWithError("volume", "rm", "-f", name)
|
|
| 432 |
+ c.Assert(err, check.NotNil) |
|
| 433 |
+ c.Assert(err.Error(), checker.Contains, "volume is in use") |
|
| 434 |
+ out, _ = dockerCmd(c, "volume", "ls") |
|
| 435 |
+ c.Assert(out, checker.Contains, name) |
|
| 436 |
+ |
|
| 437 |
+ // Verify removing the volume after the container is removed works |
|
| 438 |
+ _, e = dockerCmd(c, "rm", cid) |
|
| 439 |
+ c.Assert(e, check.Equals, 0) |
|
| 440 |
+ |
|
| 441 |
+ _, e = dockerCmd(c, "volume", "rm", "-f", name) |
|
| 442 |
+ c.Assert(e, check.Equals, 0) |
|
| 443 |
+ |
|
| 444 |
+ out, e = dockerCmd(c, "volume", "ls") |
|
| 445 |
+ c.Assert(e, check.Equals, 0) |
|
| 446 |
+ c.Assert(out, checker.Not(checker.Contains), name) |
|
| 447 |
+} |
|
| 448 |
+ |
|
| 409 | 449 |
func (s *DockerSuite) TestVolumeCliInspectWithVolumeOpts(c *check.C) {
|
| 410 | 450 |
testRequires(c, DaemonIsLinux) |
| 411 | 451 |
|
| ... | ... |
@@ -552,8 +552,22 @@ func (clnt *client) Stats(containerID string) (*Stats, error) {
|
| 552 | 552 |
|
| 553 | 553 |
// Restore is the handler for restoring a container |
| 554 | 554 |
func (clnt *client) Restore(containerID string, _ StdioCallback, unusedOnWindows ...CreateOption) error {
|
| 555 |
- // TODO Windows: Implement this. For now, just tell the backend the container exited. |
|
| 556 | 555 |
logrus.Debugf("libcontainerd: Restore(%s)", containerID)
|
| 556 |
+ |
|
| 557 |
+ // TODO Windows: On RS1, a re-attach isn't possible. |
|
| 558 |
+ // However, there is a scenario in which there is an issue. |
|
| 559 |
+ // Consider a background container. The daemon dies unexpectedly. |
|
| 560 |
+ // HCS will still have the compute service alive and running. |
|
| 561 |
+ // For consistence, we call in to shoot it regardless if HCS knows about it |
|
| 562 |
+ // We explicitly just log a warning if the terminate fails. |
|
| 563 |
+ // Then we tell the backend the container exited. |
|
| 564 |
+ if hc, err := hcsshim.OpenContainer(containerID); err == nil {
|
|
| 565 |
+ if err := hc.Terminate(); err != nil {
|
|
| 566 |
+ if !hcsshim.IsPending(err) {
|
|
| 567 |
+ logrus.Warnf("libcontainerd: failed to terminate %s on restore - %q", containerID, err)
|
|
| 568 |
+ } |
|
| 569 |
+ } |
|
| 570 |
+ } |
|
| 557 | 571 |
return clnt.backend.StateChanged(containerID, StateInfo{
|
| 558 | 572 |
CommonStateInfo: CommonStateInfo{
|
| 559 | 573 |
State: StateExit, |