5

Trying to optimize definition of multiple services with docker-compose.yml

Here is the original, "dumb" variant of the docker-compose.yml:

version: '3'
services:
  s1:
    build: .
    ports:
    - "5001:9000"
    volumes:
    - ../www1:/var/www
  s2:
    build: .
    ports:
    - "5002:9000"
    volumes:
    - ../www2:/var/www
  s3:
    build: .
    ports:
    - "5003:9000"
    volumes:
    - ../www3:/var/www

Is there some sort of an iterator to compact this to just one block like the following?

version: '3'
services:
  for i in 1,2,3:
    s$i:
      build: .
      ports:
      - "500$i:9000"
      volumes:
      - ../www$i:/var/www

2 Answers2

5

Not in pure Docker Compose. If you have a plain-text templating engine you like (Mustache, Jinja, m4, ...) you can ask it to do this for you.

You tagged this as , and Compose can take the YAML configuration on stdin, so in principle one option is to write a shell script, and then pipe that into docker-compose:

#!/bin/sh

buildComposeYaml() {
  cat <<HEADER
version: '3'
services:
HEADER
  for i in $(seq 3); do
    cat <<BLOCK
  s$i:
    build: ../www$i
    ports:
      - "500$i:9000"
BLOCK
  done
}

buildComposeYaml | docker-compose -f- "$@"

(Note that YAML is indentation-sensitive, and the script is mixing indentation for the script itself, the YAML embedded in the script, and the end-of-heredoc markers; so this will work for a simple tool but it wouldn't be my long-term choice.)

David Maze
  • 511
  • 3
  • 5
  • Nice. I also had an idea to use a templating engine, like jinja2 in Ansible. – Alexander Shcheblikin May 07 '20 at 23:44
  • The issue with external processes generating configuration is difficulty incorporating the approach into CM. And also, docker-compose is likely to have harder time determining if configuration has undergone changes and containers need to be updated. – Alexander Shcheblikin May 07 '20 at 23:50
3

Using docker-compose version 3.3 extensions and with the long variants for ports & volumes:

version: '3.3'
services:
  s1: &s
    build: .
    ports:
    - published: 5001
      target: 9000
    volumes:
    - source: ../www1
      target: /var/www
  s2:
    <<: *s
    ports:
    - published: 5002
    volumes:
    - source: ../www2
  s3:
    <<: *s
    ports:
    - published: 5003
    volumes:
    - source: ../www3

Not really more compact, but native :-)

Version 3.4 introduced further improvements into making docker-compose.yml more DRY.

Perhaps someone more experienced will point to even greater developments yet!