Jonathan Tullett
Jonathan Tullett

Reputation: 393

Valid docker-compose file not deploying as stack when using yaml anchors

I have been refactoring some docker-compose files to try and take advantage of tip #82 and hit a problem I haven't been able to find a solution to; I'm hoping someone can assist.

Using the following stripped example test-compose.yml file:

version: '3'

x-test: &test
  deploy:
    mode: replicated

services:
  hello-world:
    <<: *test
    image: alpine
    command: ["ping", "www.google.com"]
    deploy:
      replicas: 2

Running under docker-compose works as expected:

root@docker01:~# docker-compose -f test-compose.yml up
Recreating root_hello-world_1 ... done
Recreating root_hello-world_2 ... done
Attaching to root_hello-world_2, root_hello-world_1
hello-world_1  | PING www.google.com (172.217.16.228): 56 data bytes
hello-world_1  | 64 bytes from 172.217.16.228: seq=0 ttl=114 time=6.704 ms
hello-world_2  | PING www.google.com (172.217.16.228): 56 data bytes
hello-world_2  | 64 bytes from 172.217.16.228: seq=0 ttl=114 time=6.595 ms

However launching the same as a stack, fails:

root@docker01:~# docker stack deploy --compose-file test-compose.yml hello-world
(root) Additional property x-test is not allowed

Is there a way to get the same extensions ("x-* properties) working for both docker-compose and stack?

Upvotes: 1

Views: 1440

Answers (1)

Chris Becke
Chris Becke

Reputation: 36016

So, two things are going to bite you here:

First, docker stack deploy is fussy about the version you specify, so you need to strictly specify a valid compose version equal to or higher than the feature you are trying to use. Not sure when anchor support was added, but it definitely works when the version is specified as "3.9".

Your next problem is that merging is shallow. In your example case this isn't a problem because x-test contains only one setting which is already on its default value, but more generally, to handle complex cases, something like this is needed:

version: "3.9"
x-defaults:
  service: &service-defaults
    deploy: &deploy-defaults
      placement:
        constraints:
        - node.role==worker

services:
  hello-world:
    <<: *service-defaults
    image: alpine
    deploy:
      <<: *deploy-defaults
      replicas: 2

As adding "deploy" to the hello-world map completely overrides any entry set by the default-service, it needs its own anchor reference to import sub-settings.

Upvotes: 1

Related Questions