<p>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.</p>

<p>You tagged this as <a href="/questions/tagged/shell-script" class="post-tag" title="show questions tagged &#39;shell-script&#39;" rel="tag">shell-script</a>, and <a href="https://docs.docker.com/compose/reference/#specifying-multiple-compose-files" rel="noreferrer">Compose can take the YAML configuration on stdin</a>, so in principle one option is to write a shell script, and then pipe that into <code>docker-compose</code>:</p>

<pre class="lang-sh prettyprint-override"><code>#!/bin/sh

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

buildComposeYaml | docker-compose -f- "$@"
</code></pre>

<p>(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.)</p>

CC BY-SA 4.0
2020-05-07T23:44:18.290Z
Nice. I also had an idea to use a templating engine, like `jinja2` in `Ansible`.
Alexander Shcheblikin
CC BY-SA 4.0
2020-05-07T23:50:44.243Z
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
CC BY-SA 4.0
2020-04-12T12:20:05.320Z
2020-04-12T12:20:05.320Z
David Maze
<p>Using <code>docker-compose</code> version 3.3 extensions and with the long variants for <code>ports</code> &amp; <code>volumes</code>:</p>

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

<p>Not really more compact, but native :-)</p>

<p>Version 3.4 introduced <a href="https://medium.com/@kinghuang/docker-compose-anchors-aliases-extensions-a1e4105d70bd" rel="nofollow noreferrer">further improvements into making docker-compose.yml more DRY</a>. </p>

<p>Perhaps someone more experienced will point to even greater developments yet!</p>

CC BY-SA 4.0
2020-05-07T23:43:03.767Z
2020-05-07T23:43:03.767Z
Alexander Shcheblikin
<p>Trying to optimize definition of multiple services with <code>docker-compose.yml</code></p>

<p>Here is the original, "dumb" variant of the <code>docker-compose.yml</code>:</p>

<pre><code>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
</code></pre>

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

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

<docker><docker-compose><yaml><shell-script><templating>
docker-compose multiple services in a loop
Alexander Shcheblikin
# docker-compose multiple services in a loop

(Asked by: username_0 on 2020-04-11)

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

**Tags:** docker, docker-compose, yaml, shell-script, templating


---

## 2 answers

### Answer by username_1 on 2020-04-12. Score: 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 shell-script, 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 <
(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.)

> **Comments:**
> **username_0**: Nice. I also had an idea to use a templating engine, like `jinja2` in `Ansible`.  
> **username_0**: 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.  

---

### Answer by username_0 on 2020-05-07. Score: 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!


---

