mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
commit
59c6eb8c2f
22 changed files with 453 additions and 107 deletions
35
CHANGELOG.md
35
CHANGELOG.md
|
@ -5,6 +5,38 @@ information on the list of deprecated flags and APIs please have a look at
|
|||
https://docs.docker.com/engine/deprecated/ where target removal dates can also
|
||||
be found.
|
||||
|
||||
## 17.03.1-ce (2017-03-20)
|
||||
|
||||
### Remote API (v1.27) & Client
|
||||
|
||||
* Fix autoremove on older api [#31692](https://github.com/docker/docker/pull/31692)
|
||||
* Fix default network customization for a stack [#31258](https://github.com/docker/docker/pull/31258/)
|
||||
* Correct CPU usage calculation in presence of offline CPUs and newer Linux [#31802](https://github.com/docker/docker/pull/31802)
|
||||
* Fix issue where service healthcheck is `{}` in remote API [#30197](https://github.com/docker/docker/pull/30197)
|
||||
|
||||
### Runtime
|
||||
|
||||
* Update runc to 54296cf40ad8143b62dbcaa1d90e520a2136ddfe [#3166](https://github.com/docker/docker/pull/31666)
|
||||
* Ignore cgroup2 mountpoints [opencontainers/runc#1266](https://github.com/opencontainers/runc/pull/1266)
|
||||
* Update containerd to 595e75c212d19a81d2b808a518fe1afc1391dad5 [#31662](https://github.com/docker/docker/pull/31662)
|
||||
* Register healtcheck service before calling restore() [docker/containerd#609](https://github.com/docker/containerd/pull/609)
|
||||
* Fix `docker exec` not working after unattended upgrades that reload apparmor profiles [#31773](https://github.com/docker/docker/pull/31773)
|
||||
* Fix unmounting layer without merge dir with Overlay2 [#31069](https://github.com/docker/docker/pull/31069)
|
||||
* Do not ignore "volume in use" errors when force-delete [#31450](https://github.com/docker/docker/pull/31450)
|
||||
|
||||
### Swarm Mode
|
||||
|
||||
* Update swarmkit to 17756457ad6dc4d8a639a1f0b7a85d1b65a617bb [#31807](https://github.com/docker/docker/pull/31807)
|
||||
* 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)
|
||||
* Allow removal of a network when only dead tasks reference it [docker/swarmkit#2018](https://github.com/docker/swarmkit/pull/2018)
|
||||
* Retry failed network allocations less aggressively [docker/swarmkit#2021](https://github.com/docker/swarmkit/pull/2021)
|
||||
* Avoid network allocation for tasks that are no longer running [docker/swarmkit#2017](https://github.com/docker/swarmkit/pull/2017)
|
||||
* 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)
|
||||
|
||||
### Windows
|
||||
|
||||
* Cleanup HCS on restore [#31503](https://github.com/docker/docker/pull/31503)
|
||||
|
||||
## 17.03.0-ce (2017-03-01)
|
||||
|
||||
**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.
|
|||
### Swarm Mode
|
||||
|
||||
* Shutdown leaks an error when the container was never started [#31279](https://github.com/docker/docker/pull/31279)
|
||||
|
||||
### Swarm Mode
|
||||
|
||||
* Fix possibility of tasks getting stuck in the "NEW" state during a leader failover [docker/swarmkit#1938](https://github.com/docker/swarmkit/pull/1938)
|
||||
* 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)
|
||||
* 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)
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
17.03.0-ce
|
||||
17.03.1-ce-rc1
|
||||
|
|
|
@ -118,8 +118,6 @@ tags:
|
|||
Run new commands inside running containers. See the [command-line reference](https://docs.docker.com/engine/reference/commandline/exec/) for more information.
|
||||
|
||||
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`.
|
||||
- name: "Secret"
|
||||
x-displayName: "Secrets"
|
||||
# Swarm things
|
||||
- name: "Swarm"
|
||||
x-displayName: "Swarm"
|
||||
|
@ -137,6 +135,10 @@ tags:
|
|||
x-displayName: "Tasks"
|
||||
description: |
|
||||
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.
|
||||
- name: "Secret"
|
||||
x-displayName: "Secrets"
|
||||
description: |
|
||||
Secrets are sensitive data that can be used by services. Swarm mode must be enabled for these endpoints to work.
|
||||
# System things
|
||||
- name: "Plugin"
|
||||
x-displayName: "Plugins"
|
||||
|
|
|
@ -271,7 +271,7 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
|
|||
fmt.Fprintf(dockerCli.Out(), " %s\n", attribute)
|
||||
}
|
||||
// TODO: Engine labels with duplicate keys has been deprecated in 1.13 and will be error out
|
||||
// after 3 release cycles (1.16). For now, a WARNING will be generated. The following will
|
||||
// after 3 release cycles (17.12). For now, a WARNING will be generated. The following will
|
||||
// be removed eventually.
|
||||
labelMap := map[string]string{}
|
||||
for _, label := range info.Labels {
|
||||
|
|
|
@ -17,6 +17,8 @@ import (
|
|||
"github.com/docker/go-connections/nat"
|
||||
)
|
||||
|
||||
const defaultNetwork = "default"
|
||||
|
||||
// Services from compose-file types to engine API types
|
||||
// TODO: fix secrets API so that SecretAPIClient is not required here
|
||||
func Services(
|
||||
|
@ -157,18 +159,15 @@ func convertServiceNetworks(
|
|||
name string,
|
||||
) ([]swarm.NetworkAttachmentConfig, error) {
|
||||
if len(networks) == 0 {
|
||||
return []swarm.NetworkAttachmentConfig{
|
||||
{
|
||||
Target: namespace.Scope("default"),
|
||||
Aliases: []string{name},
|
||||
},
|
||||
}, nil
|
||||
networks = map[string]*composetypes.ServiceNetworkConfig{
|
||||
defaultNetwork: {},
|
||||
}
|
||||
}
|
||||
|
||||
nets := []swarm.NetworkAttachmentConfig{}
|
||||
for networkName, network := range networks {
|
||||
networkConfig, ok := networkConfigs[networkName]
|
||||
if !ok {
|
||||
if !ok && networkName != defaultNetwork {
|
||||
return []swarm.NetworkAttachmentConfig{}, fmt.Errorf(
|
||||
"service %q references network %q, which is not declared", name, networkName)
|
||||
}
|
||||
|
|
|
@ -145,10 +145,9 @@ func TestConvertHealthcheckDisableWithTest(t *testing.T) {
|
|||
|
||||
func TestConvertServiceNetworksOnlyDefault(t *testing.T) {
|
||||
networkConfigs := networkMap{}
|
||||
networks := map[string]*composetypes.ServiceNetworkConfig{}
|
||||
|
||||
configs, err := convertServiceNetworks(
|
||||
networks, networkConfigs, NewNamespace("foo"), "service")
|
||||
nil, networkConfigs, NewNamespace("foo"), "service")
|
||||
|
||||
expected := []swarm.NetworkAttachmentConfig{
|
||||
{
|
||||
|
@ -201,6 +200,31 @@ func TestConvertServiceNetworks(t *testing.T) {
|
|||
assert.DeepEqual(t, []swarm.NetworkAttachmentConfig(sortedConfigs), expected)
|
||||
}
|
||||
|
||||
func TestConvertServiceNetworksCustomDefault(t *testing.T) {
|
||||
networkConfigs := networkMap{
|
||||
"default": composetypes.NetworkConfig{
|
||||
External: composetypes.External{
|
||||
External: true,
|
||||
Name: "custom",
|
||||
},
|
||||
},
|
||||
}
|
||||
networks := map[string]*composetypes.ServiceNetworkConfig{}
|
||||
|
||||
configs, err := convertServiceNetworks(
|
||||
networks, networkConfigs, NewNamespace("foo"), "service")
|
||||
|
||||
expected := []swarm.NetworkAttachmentConfig{
|
||||
{
|
||||
Target: "custom",
|
||||
Aliases: []string{"service"},
|
||||
},
|
||||
}
|
||||
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, []swarm.NetworkAttachmentConfig(configs), expected)
|
||||
}
|
||||
|
||||
type byTargetSort []swarm.NetworkAttachmentConfig
|
||||
|
||||
func (s byTargetSort) Len() int {
|
||||
|
|
|
@ -433,7 +433,7 @@ func loadDaemonCliConfig(opts daemonOptions) (*daemon.Config, error) {
|
|||
// This is deprecated in 1.13, and, be removed after 3 release cycles.
|
||||
// The following will check the conflict of labels, and report a warning for deprecation.
|
||||
//
|
||||
// TODO: After 3 release cycles (1.16) an error will be returned, and labels will be
|
||||
// TODO: After 3 release cycles (17.12) an error will be returned, and labels will be
|
||||
// sanitized to consolidate duplicate key-value pairs (config.Labels = newLabels):
|
||||
//
|
||||
// newLabels, err := daemon.GetConflictFreeLabels(config.Labels)
|
||||
|
|
|
@ -570,7 +570,7 @@ __docker_subcommands() {
|
|||
$(__docker_to_extglob "$subcommands") )
|
||||
subcommand_pos=$counter
|
||||
local subcommand=${words[$counter]}
|
||||
local completions_func=_docker_${command}_${subcommand}
|
||||
local completions_func=_docker_${command}_${subcommand//-/_}
|
||||
declare -F $completions_func >/dev/null && $completions_func
|
||||
return 0
|
||||
;;
|
||||
|
@ -605,38 +605,25 @@ __docker_complete_local_interfaces() {
|
|||
COMPREPLY=( $( compgen -W "$(__docker_local_interfaces) $additional_interface" -- "$cur" ) )
|
||||
}
|
||||
|
||||
__docker_complete_capabilities() {
|
||||
# The list of capabilities is defined in types.go, ALL was added manually.
|
||||
# __docker_complete_capabilities_addable completes Linux capabilities which are
|
||||
# not granted by default and may be added.
|
||||
# see https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities
|
||||
__docker_complete_capabilities_addable() {
|
||||
COMPREPLY=( $( compgen -W "
|
||||
ALL
|
||||
AUDIT_CONTROL
|
||||
AUDIT_WRITE
|
||||
AUDIT_READ
|
||||
BLOCK_SUSPEND
|
||||
CHOWN
|
||||
DAC_OVERRIDE
|
||||
DAC_READ_SEARCH
|
||||
FOWNER
|
||||
FSETID
|
||||
IPC_LOCK
|
||||
IPC_OWNER
|
||||
KILL
|
||||
LEASE
|
||||
LINUX_IMMUTABLE
|
||||
MAC_ADMIN
|
||||
MAC_OVERRIDE
|
||||
MKNOD
|
||||
NET_ADMIN
|
||||
NET_BIND_SERVICE
|
||||
NET_BROADCAST
|
||||
NET_RAW
|
||||
SETFCAP
|
||||
SETGID
|
||||
SETPCAP
|
||||
SETUID
|
||||
SYS_ADMIN
|
||||
SYS_BOOT
|
||||
SYS_CHROOT
|
||||
SYSLOG
|
||||
SYS_MODULE
|
||||
SYS_NICE
|
||||
|
@ -650,7 +637,30 @@ __docker_complete_capabilities() {
|
|||
" -- "$cur" ) )
|
||||
}
|
||||
|
||||
__docker_complete_detach-keys() {
|
||||
# __docker_complete_capabilities_droppable completes Linux capability options which are
|
||||
# allowed by default and can be dropped.
|
||||
# see https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities
|
||||
__docker_complete_capabilities_droppable() {
|
||||
COMPREPLY=( $( compgen -W "
|
||||
ALL
|
||||
AUDIT_WRITE
|
||||
CHOWN
|
||||
DAC_OVERRIDE
|
||||
FOWNER
|
||||
FSETID
|
||||
KILL
|
||||
MKNOD
|
||||
NET_BIND_SERVICE
|
||||
NET_RAW
|
||||
SETFCAP
|
||||
SETGID
|
||||
SETPCAP
|
||||
SETUID
|
||||
SYS_CHROOT
|
||||
" -- "$cur" ) )
|
||||
}
|
||||
|
||||
__docker_complete_detach_keys() {
|
||||
case "$prev" in
|
||||
--detach-keys)
|
||||
case "$cur" in
|
||||
|
@ -1047,7 +1057,7 @@ _docker_container() {
|
|||
}
|
||||
|
||||
_docker_container_attach() {
|
||||
__docker_complete_detach-keys && return
|
||||
__docker_complete_detach_keys && return
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
|
@ -1154,7 +1164,7 @@ _docker_container_diff() {
|
|||
}
|
||||
|
||||
_docker_container_exec() {
|
||||
__docker_complete_detach-keys && return
|
||||
__docker_complete_detach_keys && return
|
||||
|
||||
case "$prev" in
|
||||
--env|-e)
|
||||
|
@ -1498,7 +1508,7 @@ _docker_container_run() {
|
|||
--rm
|
||||
--sig-proxy=false
|
||||
"
|
||||
__docker_complete_detach-keys && return
|
||||
__docker_complete_detach_keys && return
|
||||
fi
|
||||
|
||||
local all_options="$options_with_args $boolean_options"
|
||||
|
@ -1538,8 +1548,12 @@ _docker_container_run() {
|
|||
COMPREPLY=( $( compgen -W 'stdin stdout stderr' -- "$cur" ) )
|
||||
return
|
||||
;;
|
||||
--cap-add|--cap-drop)
|
||||
__docker_complete_capabilities
|
||||
--cap-add)
|
||||
__docker_complete_capabilities_addable
|
||||
return
|
||||
;;
|
||||
--cap-drop)
|
||||
__docker_complete_capabilities_droppable
|
||||
return
|
||||
;;
|
||||
--cidfile|--env-file|--init-path|--label-file)
|
||||
|
@ -1686,7 +1700,7 @@ _docker_container_run() {
|
|||
}
|
||||
|
||||
_docker_container_start() {
|
||||
__docker_complete_detach-keys && return
|
||||
__docker_complete_detach_keys && return
|
||||
|
||||
case "$prev" in
|
||||
--checkpoint)
|
||||
|
@ -3141,7 +3155,7 @@ _docker_swarm_join() {
|
|||
esac
|
||||
}
|
||||
|
||||
_docker_swarm_join-token() {
|
||||
_docker_swarm_join_token() {
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "--help --quiet -q --rotate" -- "$cur" ) )
|
||||
|
@ -3171,7 +3185,7 @@ _docker_swarm_unlock() {
|
|||
esac
|
||||
}
|
||||
|
||||
_docker_swarm_unlock-key() {
|
||||
_docker_swarm_unlock_key() {
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "--help --quiet -q --rotate" -- "$cur" ) )
|
||||
|
@ -4289,7 +4303,7 @@ _docker() {
|
|||
command_pos=0
|
||||
fi
|
||||
|
||||
local completions_func=_docker_${command}
|
||||
local completions_func=_docker_${command//-/_}
|
||||
declare -F $completions_func >/dev/null && $completions_func
|
||||
|
||||
eval "$previous_extglob_setting"
|
||||
|
|
|
@ -205,7 +205,7 @@ func (r *controller) Start(ctx context.Context) error {
|
|||
}
|
||||
|
||||
// no health check
|
||||
if ctnr.Config == nil || ctnr.Config.Healthcheck == nil {
|
||||
if ctnr.Config == nil || ctnr.Config.Healthcheck == nil || len(ctnr.Config.Healthcheck.Test) == 0 || ctnr.Config.Healthcheck.Test[0] == "NONE" {
|
||||
if err := r.adapter.activateServiceBinding(); err != nil {
|
||||
log.G(ctx).WithError(err).Errorf("failed to activate service binding for container %s which has no healthcheck config", r.adapter.container.name())
|
||||
return err
|
||||
|
@ -213,12 +213,6 @@ func (r *controller) Start(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
healthCmd := ctnr.Config.Healthcheck.Test
|
||||
|
||||
if len(healthCmd) == 0 || healthCmd[0] == "NONE" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// wait for container to be healthy
|
||||
eventq := r.adapter.events(ctx)
|
||||
|
||||
|
|
|
@ -279,7 +279,7 @@ func ReloadConfiguration(configFile string, flags *pflag.FlagSet, reload func(*C
|
|||
// This is deprecated in 1.13, and, be removed after 3 release cycles.
|
||||
// The following will check the conflict of labels, and report a warning for deprecation.
|
||||
//
|
||||
// TODO: After 3 release cycles (1.16) an error will be returned, and labels will be
|
||||
// TODO: After 3 release cycles (17.12) an error will be returned, and labels will be
|
||||
// sanitized to consolidate duplicate key-value pairs (config.Labels = newLabels):
|
||||
//
|
||||
// newLabels, err := GetConflictFreeLabels(newConfig.Labels)
|
||||
|
|
|
@ -8,11 +8,12 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/errors"
|
||||
apierrors "github.com/docker/docker/api/errors"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/layer"
|
||||
volumestore "github.com/docker/docker/volume/store"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ContainerRm removes the container id from the filesystem. An error
|
||||
|
@ -29,7 +30,7 @@ func (daemon *Daemon) ContainerRm(name string, config *types.ContainerRmConfig)
|
|||
// Container state RemovalInProgress should be used to avoid races.
|
||||
if inProgress := container.SetRemovalInProgress(); inProgress {
|
||||
err := fmt.Errorf("removal of container %s is already in progress", name)
|
||||
return errors.NewBadRequestError(err)
|
||||
return apierrors.NewBadRequestError(err)
|
||||
}
|
||||
defer container.ResetRemovalInProgress()
|
||||
|
||||
|
@ -80,7 +81,7 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo
|
|||
if container.IsRunning() {
|
||||
if !forceRemove {
|
||||
err := fmt.Errorf("You cannot remove a running container %s. Stop the container before attempting removal or use -f", container.ID)
|
||||
return errors.NewRequestConflictError(err)
|
||||
return apierrors.NewRequestConflictError(err)
|
||||
}
|
||||
if err := daemon.Kill(container); err != nil {
|
||||
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
|
|||
// This is called directly from the Engine API
|
||||
func (daemon *Daemon) VolumeRm(name string, force bool) error {
|
||||
err := daemon.volumeRm(name)
|
||||
if err != nil && volumestore.IsInUse(err) {
|
||||
return apierrors.NewRequestConflictError(err)
|
||||
}
|
||||
if err == nil || force {
|
||||
daemon.volumes.Purge(name)
|
||||
return nil
|
||||
|
@ -157,11 +161,7 @@ func (daemon *Daemon) volumeRm(name string) error {
|
|||
}
|
||||
|
||||
if err := daemon.volumes.Remove(v); err != nil {
|
||||
if volumestore.IsInUse(err) {
|
||||
err := fmt.Errorf("Unable to remove volume, volume still in use: %v", err)
|
||||
return errors.NewRequestConflictError(err)
|
||||
}
|
||||
return fmt.Errorf("Error while removing volume %s: %v", name, err)
|
||||
return errors.Wrap(err, "unable to remove volume")
|
||||
}
|
||||
daemon.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()})
|
||||
return nil
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"github.com/docker/docker/daemon/caps"
|
||||
"github.com/docker/docker/daemon/exec"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
"github.com/opencontainers/runc/libcontainer/apparmor"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
|
@ -23,5 +24,27 @@ func execSetPlatformOpt(c *container.Container, ec *exec.Config, p *libcontainer
|
|||
if ec.Privileged {
|
||||
p.Capabilities = caps.GetAllCapabilities()
|
||||
}
|
||||
if apparmor.IsEnabled() {
|
||||
var appArmorProfile string
|
||||
if c.AppArmorProfile != "" {
|
||||
appArmorProfile = c.AppArmorProfile
|
||||
} else if c.HostConfig.Privileged {
|
||||
appArmorProfile = "unconfined"
|
||||
} else {
|
||||
appArmorProfile = "docker-default"
|
||||
}
|
||||
|
||||
if appArmorProfile == "docker-default" {
|
||||
// Unattended upgrades and other fun services can unload AppArmor
|
||||
// profiles inadvertently. Since we cannot store our profile in
|
||||
// /etc/apparmor.d, nor can we practically add other ways of
|
||||
// telling the system to keep our profile loaded, in order to make
|
||||
// sure that we keep the default profile enabled we dynamically
|
||||
// reload it if necessary.
|
||||
if err := ensureDefaultAppArmorProfile(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
|
|||
return nil, err
|
||||
}
|
||||
if !supportsDType {
|
||||
// not a fatal error until v1.16 (#27443)
|
||||
// not a fatal error until v17.12 (#27443)
|
||||
logrus.Warn(overlayutils.ErrDTypeNotSupported("overlay", backingFs))
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ import (
|
|||
"github.com/docker/docker/pkg/mount"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"github.com/docker/go-units"
|
||||
units "github.com/docker/go-units"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/label"
|
||||
)
|
||||
|
@ -170,7 +170,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
|
|||
return nil, err
|
||||
}
|
||||
if !supportsDType {
|
||||
// not a fatal error until v1.16 (#27443)
|
||||
// not a fatal error until v17.12 (#27443)
|
||||
logrus.Warn(overlayutils.ErrDTypeNotSupported("overlay2", backingFs))
|
||||
}
|
||||
|
||||
|
@ -553,7 +553,17 @@ func (d *Driver) Get(id string, mountLabel string) (s string, err error) {
|
|||
|
||||
// Put unmounts the mount path created for the give id.
|
||||
func (d *Driver) Put(id string) error {
|
||||
mountpoint := path.Join(d.dir(id), "merged")
|
||||
dir := d.dir(id)
|
||||
_, err := ioutil.ReadFile(path.Join(dir, lowerFile))
|
||||
if err != nil {
|
||||
// If no lower, no mount happened and just return directly
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
mountpoint := path.Join(dir, "merged")
|
||||
if count := d.ctr.Decrement(mountpoint); count > 0 {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -13,6 +13,6 @@ func ErrDTypeNotSupported(driver, backingFs string) error {
|
|||
if backingFs == "xfs" {
|
||||
msg += " Reformat the filesystem with ftype=1 to enable d_type support."
|
||||
}
|
||||
msg += " Running without d_type support will no longer be supported in Docker 1.16."
|
||||
msg += " Running without d_type support will no longer be supported in Docker 17.12."
|
||||
return errors.New(msg)
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ The currently supported filters are:
|
|||
* id (network's id)
|
||||
* label (`label=<key>` or `label=<key>=<value>`)
|
||||
* name (network's name)
|
||||
* type (custom|builtin)
|
||||
* type (`custom|builtin`)
|
||||
|
||||
#### Driver
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ Options:
|
|||
- name=<string> a container's name
|
||||
- network=(<network-id>|<network-name>)
|
||||
- since=(<container-name>|<container-id>)
|
||||
- status=(created|restarting|removing|running|paused|exited)
|
||||
- status=(created|restarting|removing|running|paused|exited)
|
||||
- volume=(<volume name>|<mount point destination>)
|
||||
--format string Pretty-print containers using a Go template
|
||||
--help Print usage
|
||||
|
@ -84,11 +84,11 @@ The currently supported filters are:
|
|||
* label (`label=<key>` or `label=<key>=<value>`)
|
||||
* name (container's name)
|
||||
* exited (int - the code of exited containers. Only useful with `--all`)
|
||||
* status (created|restarting|running|removing|paused|exited|dead)
|
||||
* status (`created|restarting|running|removing|paused|exited|dead`)
|
||||
* ancestor (`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`) - filters containers that were created from the given image or a descendant.
|
||||
* before (container's id or name) - filters containers created before given id or name
|
||||
* since (container's id or name) - filters containers created since given id or name
|
||||
* isolation (default|process|hyperv) (Windows daemon only)
|
||||
* isolation (`default|process|hyperv`) (Windows daemon only)
|
||||
* volume (volume name or mount point) - filters containers that mount volumes.
|
||||
* network (network id or name) - filters containers connected to the provided network
|
||||
* health (starting|healthy|unhealthy|none) - filters containers based on healthcheck status
|
||||
|
|
|
@ -249,12 +249,69 @@ For more information about named volumes, see
|
|||
The following table describes options which apply to both bind-mounts and named
|
||||
volumes in a service:
|
||||
|
||||
| Option | Required | Description
|
||||
|:-----------------------------------------|:--------------------------|:-----------------------------------------------------------------------------------------
|
||||
| **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>
|
||||
| **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>
|
||||
| **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.
|
||||
| **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>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Option</th>
|
||||
<th>Required</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>types</b></td>
|
||||
<td></td>
|
||||
<td>
|
||||
<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.
|
||||
<ul>
|
||||
<li><tt>volume</tt>: mounts a [managed volume](volume_create.md) into the container.</li>
|
||||
<li><tt>bind</tt>: bind-mounts a directory or file from the host into the container.</li>
|
||||
<li><tt>tmpfs</tt>: mount a tmpfs in the container</li>
|
||||
</ul></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>src</b> or <b>source</b></td>
|
||||
<td>for <tt>type=bind</tt> only></td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>
|
||||
<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>).
|
||||
If the named volume does not exist, it is automatically created. If no <tt>src</tt> 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 <i>container</i>
|
||||
is destroyed (which is upon <tt>service update</tt>, or when scaling or re-balancing the service)
|
||||
</li>
|
||||
<li>
|
||||
<tt>type=bind</tt>: <tt>src</tt> is required, and specifies an absolute path to the file or directory to bind-mount
|
||||
(for example, <tt>src=/path/on/host/</tt>). An error is produced if the file or directory does not exist.
|
||||
</li>
|
||||
<li>
|
||||
<tt>type=tmpfs</tt>: <tt>src</tt> is not supported.
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p><b>dst</b> or <b>destination</b> or <b>target</b></p></td>
|
||||
<td>yes</td>
|
||||
<td>
|
||||
<p>Mount path inside the container, for example <tt>/some/path/in/container/</tt>.
|
||||
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.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p><b>readonly</b> or <b>ro</b></p></td>
|
||||
<td></td>
|
||||
<td>
|
||||
<p>The Engine mounts binds and volumes <tt>read-write</tt> unless <tt>readonly</tt> option
|
||||
is given when mounting the bind or volume.
|
||||
<ul>
|
||||
<li><tt>true</tt> or <tt>1</tt> or no value: Mounts the bind or volume read-only.</li>
|
||||
<li><tt>false</tt> or <tt>0</tt>: Mounts the bind or volume read-write.</li>
|
||||
</ul></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
#### Bind Propagation
|
||||
|
||||
|
@ -294,22 +351,84 @@ For more information about bind propagation, see the
|
|||
[Linux kernel documentation for shared subtree](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt).
|
||||
|
||||
#### Options for Named Volumes
|
||||
|
||||
The following options can only be used for named volumes (`type=volume`);
|
||||
|
||||
| Option | Description
|
||||
|:----------------------|:--------------------------------------------------------------------------------------------------------------------
|
||||
| **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.
|
||||
| **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/).
|
||||
| **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>
|
||||
| **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.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Option</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>volume-driver</b></td>
|
||||
<td>
|
||||
<p>Name of the volume-driver plugin to use for the volume. Defaults to
|
||||
<tt>"local"</tt>, to use the local volume driver to create the volume if the
|
||||
volume does not exist.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>volume-label</b></td>
|
||||
<td>
|
||||
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
|
||||
<a href="https://docs.docker.com/engine/userguide/labels-custom-metadata/">apply custom metadata</a>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>volume-nocopy</b></td>
|
||||
<td>
|
||||
By default, if you attach an empty volume to a container, and files or
|
||||
directories already existed at the mount-path in the container (<tt>dst</tt>),
|
||||
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.
|
||||
|
||||
A value is optional:
|
||||
|
||||
<ul>
|
||||
<li><tt>true</tt> or <tt>1</tt>: Default if you do not provide a value. Disables copying.</li>
|
||||
<li><tt>false</tt> or <tt>0</tt>: Enables copying.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>volume-opt</b></td>
|
||||
<td>
|
||||
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,
|
||||
<tt>volume-opt=some-option=some-value,some-other-option=some-other-value</tt>.
|
||||
For available options for a given driver, refer to that driver's
|
||||
documentation.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
#### Options for tmpfs
|
||||
|
||||
The following options can only be used for tmpfs mounts (`type=tmpfs`);
|
||||
|
||||
| Option | Description
|
||||
|:----------------------|:--------------------------------------------------------------------------------------------------------------------
|
||||
| **tmpfs-size** | Size of the tmpfs mount in bytes. Unlimited by default in Linux.
|
||||
| **tmpfs-mode** | File mode of the tmpfs in octal. (e.g. `"700"` or `"0700"`.) Defaults to ``"1777"`` in Linux.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Option</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>tmpfs-size</b></td>
|
||||
<td>Size of the tmpfs mount in bytes. Unlimited by default in Linux.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>tmpfs-mode</b></td>
|
||||
<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>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
#### Differences between "--mount" and "--volume"
|
||||
|
||||
|
@ -412,13 +531,40 @@ constraint expressions. Multiple constraints find nodes that satisfy every
|
|||
expression (AND match). Constraints can match node or Docker Engine labels as
|
||||
follows:
|
||||
|
||||
| node attribute | matches | example |
|
||||
|:----------------|:--------------------------|:------------------------------------------------|
|
||||
| node.id | node ID | `node.id == 2ivku8v2gvtg4` |
|
||||
| node.hostname | node hostname | `node.hostname != node-2` |
|
||||
| node.role | node role: manager | `node.role == manager` |
|
||||
| node.labels | user defined node labels | `node.labels.security == high` |
|
||||
| engine.labels | Docker Engine's labels | `engine.labels.operatingsystem == ubuntu 14.04` |
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>node attribute</th>
|
||||
<th>matches</th>
|
||||
<th>example</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>node.id</tt></td>
|
||||
<td>Node ID</td>
|
||||
<td><tt>node.id == 2ivku8v2gvtg4</tt></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>node.hostname</tt></td>
|
||||
<td>Node hostname</td>
|
||||
<td><tt>node.hostname != node-2</tt></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td<tt>node.role</tt></td>
|
||||
<td><tt>node role: manager</tt></td>
|
||||
<td><tt>node.role == manager</tt></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>node.labels</tt></td>
|
||||
<td>user defined node labels</td>
|
||||
<td><tt>node.labels.security == high</tt></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>engine.labels</tt></td>
|
||||
<td>Docker Engine's labels</td>
|
||||
<td><tt>engine.labels.operatingsystem == ubuntu 14.04</tt></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
`engine.labels` apply to Docker Engine labels like operating system,
|
||||
drivers, etc. Swarm administrators add `node.labels` for operational purposes by
|
||||
|
@ -530,15 +676,42 @@ The supported flags are the following :
|
|||
|
||||
Valid placeholders for the Go template are listed below:
|
||||
|
||||
Placeholder | Description
|
||||
----------------- | --------------------------------------------
|
||||
`.Service.ID` | Service ID
|
||||
`.Service.Name` | Service name
|
||||
`.Service.Labels` | Service labels
|
||||
`.Node.ID` | Node ID
|
||||
`.Task.ID` | Task ID
|
||||
`.Task.Name` | Task name
|
||||
`.Task.Slot` | Task slot
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Placeholder</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>.Service.ID</tt></td>
|
||||
<td>Service ID</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>.Service.Name</tt></td>
|
||||
<td>Service name</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>.Service.Labels</tt></td>
|
||||
<td>Service labels</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>.Node.ID</tt></td>
|
||||
<td>Node ID</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>.Task.ID</tt></td>
|
||||
<td>Task ID</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>.Task.Name</tt></td>
|
||||
<td>Task name</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>.Task.Slot</tt></td>
|
||||
<td>Task slot</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
#### Template example
|
||||
|
||||
|
|
|
@ -27,12 +27,12 @@ Options:
|
|||
-q, --quiet Only display IDs
|
||||
```
|
||||
|
||||
### Description
|
||||
## Description
|
||||
|
||||
Lists the services that are running as part of the specified stack. This
|
||||
command has to be run targeting a manager node.
|
||||
|
||||
### Examples
|
||||
## Examples
|
||||
|
||||
The following command shows all services in the `myapp` stack:
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
"github.com/go-check/check"
|
||||
|
@ -1365,3 +1366,26 @@ func (s *DockerSwarmSuite) TestAPIDuplicateNetworks(c *check.C) {
|
|||
|
||||
c.Assert(r2.Scope, checker.Equals, "swarm")
|
||||
}
|
||||
|
||||
// Test case for 30178
|
||||
func (s *DockerSwarmSuite) TestAPISwarmHealthcheckNone(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
out, err := d.Cmd("network", "create", "-d", "overlay", "lb")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
instances := 1
|
||||
d.createService(c, simpleTestService, setInstances(instances), func(s *swarm.Service) {
|
||||
s.Spec.TaskTemplate.ContainerSpec.Healthcheck = &container.HealthConfig{}
|
||||
s.Spec.TaskTemplate.Networks = []swarm.NetworkAttachmentConfig{
|
||||
{Target: "lb"},
|
||||
}
|
||||
})
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, instances)
|
||||
|
||||
containers := d.activeContainers()
|
||||
|
||||
out, err = d.Cmd("exec", containers[0], "ping", "-c1", "-W3", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
}
|
||||
|
|
|
@ -398,14 +398,54 @@ func (s *DockerSuite) TestVolumeCLIRmForce(c *check.C) {
|
|||
out, _, err := runCommandWithOutput(exec.Command("rm", "-rf", path))
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
dockerCmd(c, "volume", "rm", "-f", "test")
|
||||
dockerCmd(c, "volume", "rm", "-f", name)
|
||||
out, _ = dockerCmd(c, "volume", "ls")
|
||||
c.Assert(out, checker.Not(checker.Contains), name)
|
||||
dockerCmd(c, "volume", "create", "test")
|
||||
dockerCmd(c, "volume", "create", name)
|
||||
out, _ = dockerCmd(c, "volume", "ls")
|
||||
c.Assert(out, checker.Contains, name)
|
||||
}
|
||||
|
||||
// TestVolumeCLIRmForceInUse verifies that repeated `docker volume rm -f` calls does not remove a volume
|
||||
// if it is in use. Test case for https://github.com/docker/docker/issues/31446
|
||||
func (s *DockerSuite) TestVolumeCLIRmForceInUse(c *check.C) {
|
||||
name := "testvolume"
|
||||
out, _ := dockerCmd(c, "volume", "create", name)
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(id, checker.Equals, name)
|
||||
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
out, e := dockerCmd(c, "create", "-v", "testvolume:"+prefix+slash+"foo", "busybox")
|
||||
cid := strings.TrimSpace(out)
|
||||
|
||||
_, _, err := dockerCmdWithError("volume", "rm", "-f", name)
|
||||
c.Assert(err, check.NotNil)
|
||||
c.Assert(err.Error(), checker.Contains, "volume is in use")
|
||||
out, _ = dockerCmd(c, "volume", "ls")
|
||||
c.Assert(out, checker.Contains, name)
|
||||
|
||||
// The original issue did not _remove_ the volume from the list
|
||||
// the first time. But a second call to `volume rm` removed it.
|
||||
// Calling `volume rm` a second time to confirm it's not removed
|
||||
// when calling twice.
|
||||
_, _, err = dockerCmdWithError("volume", "rm", "-f", name)
|
||||
c.Assert(err, check.NotNil)
|
||||
c.Assert(err.Error(), checker.Contains, "volume is in use")
|
||||
out, _ = dockerCmd(c, "volume", "ls")
|
||||
c.Assert(out, checker.Contains, name)
|
||||
|
||||
// Verify removing the volume after the container is removed works
|
||||
_, e = dockerCmd(c, "rm", cid)
|
||||
c.Assert(e, check.Equals, 0)
|
||||
|
||||
_, e = dockerCmd(c, "volume", "rm", "-f", name)
|
||||
c.Assert(e, check.Equals, 0)
|
||||
|
||||
out, e = dockerCmd(c, "volume", "ls")
|
||||
c.Assert(e, check.Equals, 0)
|
||||
c.Assert(out, checker.Not(checker.Contains), name)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCliInspectWithVolumeOpts(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
|
|
|
@ -552,8 +552,22 @@ func (clnt *client) Stats(containerID string) (*Stats, error) {
|
|||
|
||||
// Restore is the handler for restoring a container
|
||||
func (clnt *client) Restore(containerID string, _ StdioCallback, unusedOnWindows ...CreateOption) error {
|
||||
// TODO Windows: Implement this. For now, just tell the backend the container exited.
|
||||
logrus.Debugf("libcontainerd: Restore(%s)", containerID)
|
||||
|
||||
// TODO Windows: On RS1, a re-attach isn't possible.
|
||||
// However, there is a scenario in which there is an issue.
|
||||
// Consider a background container. The daemon dies unexpectedly.
|
||||
// HCS will still have the compute service alive and running.
|
||||
// For consistence, we call in to shoot it regardless if HCS knows about it
|
||||
// We explicitly just log a warning if the terminate fails.
|
||||
// Then we tell the backend the container exited.
|
||||
if hc, err := hcsshim.OpenContainer(containerID); err == nil {
|
||||
if err := hc.Terminate(); err != nil {
|
||||
if !hcsshim.IsPending(err) {
|
||||
logrus.Warnf("libcontainerd: failed to terminate %s on restore - %q", containerID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return clnt.backend.StateChanged(containerID, StateInfo{
|
||||
CommonStateInfo: CommonStateInfo{
|
||||
State: StateExit,
|
||||
|
|
Loading…
Add table
Reference in a new issue