docker / docker/cli

Prevent from changing volume options (local driver) of a service when deploying a stack

Open
#1,279 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

area/swarm
Dominant language
Go
Stars
6.1k
Forks
2.2k
Avg merge
1d 15h
Merged PRs (30d)
43

Description

Expected behavior

When deploying a stack to a Swarm, we should be informed that we are not allowed to change volume options (with local driver) of a service. This behavior is needed especially when you attach NFS volumes to your services, and you want to change one of these options: server address, remote path, mounting options... Which is a really common use case!

Maybe you could copy docker-compose's error message, which alreay handles this case:

ERROR: Configuration for volume foo specifies "o" driver_opt addr=192.168.77.254,ro,proto=tcp, but a volume with the same name uses a different "o" driver_opt (addr=192.168.77.254,rw). If you wish to use the new configuration, please remove the existing volume "foo" first:

Of course, it would be better to support volume options update. But since it would perform a umount/mount in case of NFS, I don't think it is possible. But maybe do you know some betters ways to share a NFS volume between service tasks? I know some plugins exist, but I wish Docker could handle this natively. Do you know if it is planned? What about being able to create "Swarm volumes", like overlay networks :D?

Today, to be able to update a volume options, you have to:

This is very uncomfortable!

Actual behavior

When re-deploying a stack after changing volume options:

  • we are not warned about it and the deploy command successes
  • Case 1: the task remains on the same node: volume is not updated
  • Case 2: the task is created on a another node, where the volume did not exist: the volume is created with the new options!
    • --> the behavior is thus unpredictable!

Steps to reproduce the behavior

Create this docker-compose.yml file:

---
version: "3.6"
services:
  test:
    image: alpine
    command: top
    volumes:
      - foo:/mnt/foo

volumes:
  foo:
    name: foo
    driver_opts:
      type: nfs
      o: addr=192.168.77.254,rw,proto=udp
      device: ":/var/exports/fornfsdev"

Deploy the stack:

➜  ~ docker stack deploy -c docker-nfs-issue/docker-compose.yml nfs-issue
Creating network nfs-issue_default
Creating service nfs-issue_test

Check that the volume has been created on the task node:

➜  ~ docker volume inspect foo
[
    {
        "CreatedAt": "2018-08-07T13:09:24+02:00",
        "Driver": "local",
        "Labels": {
            "com.docker.stack.namespace": "nfs-issue"
        },
        "Mountpoint": "/var/lib/docker/volumes/foo/_data",
        "Name": "foo",
        "Options": {
            "device": ":/var/exports/fornfsdev",
            "o": "addr=192.168.77.254,rw,proto=udp",
            "type": "nfs"
        },
        "Scope": "local"
    }
]

Then, replace o: addr=192.168.77.254,rw,proto=udp by o: addr=192.168.77.42,ro,proto=tcp in the docker-compose.yml and re-deploy the stack:

➜  ~ docker stack deploy -c docker-nfs-issue/docker-compose.yml nfs-issue
Updating service nfs-issue_test (id: 8pjcg8xggq6rfypc2xjsxw1h1)

The service has been updated, and the volume remains the same. And we have not been warned about this:

➜  ~ docker volume inspect foo                                           
[
    {
        "CreatedAt": "2018-08-07T13:09:24+02:00",
        "Driver": "local",
        "Labels": {
            "com.docker.stack.namespace": "nfs-issue"
        },
        "Mountpoint": "/var/lib/docker/volumes/foo/_data",
        "Name": "foo",
        "Options": {
            "device": ":/var/exports/fornfsdev",
            "o": "addr=192.168.77.254,rw,proto=udp",
            "type": "nfs"
        },
        "Scope": "local"
    }
]

Even worse, if the new task has been re-created on another node (where the volume did not exist), the volume has been created on this other node with the new options! So the behavior is totally unpredictable.

Output of docker version:

➜  ~ docker version
Client:
 Version:           18.06.0-ce
 API version:       1.38
 Go version:        go1.10.3
 Git commit:        0ffa825
 Built:             Wed Jul 18 19:09:54 2018
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.06.0-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.3
  Git commit:       0ffa825
  Built:            Wed Jul 18 19:07:56 2018
  OS/Arch:          linux/amd64
  Experimental:     false

Output of docker info:

➜  ~ docker info
Containers: 3
 Running: 2
 Paused: 0
 Stopped: 1
Images: 73
Server Version: 18.06.0-ce
Storage Driver: overlay2
 Backing Filesystem: extfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: bridge host macvlan null overlay
 Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog
Swarm: active
 NodeID: crers6copztuj09mxvcdosbvp
 Is Manager: true
 ClusterID: 8rn62v8lkdulsgrkn09ft3k64
 Managers: 1
 Nodes: 1
 Orchestration:
  Task History Retention Limit: 5
 Raft:
  Snapshot Interval: 10000
  Number of Old Snapshots to Retain: 0
  Heartbeat Tick: 1
  Election Tick: 10
 Dispatcher:
  Heartbeat Period: 5 seconds
 CA Configuration:
  Expiry Duration: 3 months
  Force Rotate: 0
 Autolock Managers: false
 Root Rotation In Progress: false
 Node Address: 127.0.0.1
 Manager Addresses:
  127.0.0.1:2377
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: d64c661f1d51c48782c9cec8fda7604785f93587
runc version: 69663f0bd4b60df09991c08812a60108003fa340
init version: fec3683
Security Options:
 apparmor
 seccomp
  Profile: default
Kernel Version: 4.15.0-30-generic
Operating System: Ubuntu 18.04.1 LTS
OSType: linux
Architecture: x86_64
CPUs: 8
Total Memory: 15.39GiB
Name: frioul
ID: NLDT:JDY2:RL36:DZZZ:LZIE:3WUW:6VEQ:OBNC:ZUA6:3BTV:AW7F:65UX
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
 127.0.0.0/8
Registry Mirrors:
 http://127.0.0.1:5000/
Live Restore Enabled: false

WARNING: No swap limit support

Possible solution

I absolutely don't know how Docker works internally, but since docker service inspect returns the Mounts section (with volume options) in Spec and PreviousSpec, I suppose it would be possible to detect a volume options change, and stop the deploy.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the docker stack deploy flow and compare the service inspect Mounts data in Spec and PreviousSpec, as suggested in the issue. Reproduce the NFS volume option change with the provided docker-compose.yml, then verify that redeployment detects the changed local-driver options and reports the condition instead of silently succeeding.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, go
Domain
cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.