skip to Main Content

For example, if I have a docker compose file and like the following:

version: '3.7'

services:
  my_app:
    image: my_app/image
    restart: always
    links:
      - mysql
  
  mysql:
    image: mysql
    restart: always

Is there a way to create and run more than 1 container of my_app without explicitly stating another one? The catch is, each app would use different env variables; each app instance would process for a different user accounts. This would be different from k8s as I’m not trying to scale horizontally. Or would I need to create a file like the following:

version: '3.7'

services:
  my_app1:
    image: my_app/image
    restart: always
    environment: 
      - ACCOUNT=1
      - ACCOUNT=2
      - ACCOUNT=3
    links:
      - mysql

  my_app2:
    image: my_app/image
    restart: always
    environment: 
      - ACCOUNT=4
      - ACCOUNT=5
      - ACCOUNT=6
    links:
      - mysql

  my_app3:
    image: my_app/image
    restart: always
    environment: 
      - ACCOUNT=7
      - ACCOUNT=8
      - ACCOUNT=9
    links:
      - mysql
  
  mysql:
    image: mysql

2

Answers


  1. Neither Compose nor any other orchestration system I’m aware of has a way to directly declare several containers that are similar except where they’re not. Some tools like the Kubernetes Helm tool can apply a templating engine that can generate YAML content, but this gets complicated quickly. For plain Compose, you need to list out all of the containers separately in the docker-compose.yml file.

    In the file you’ve shown, the links: option is obsolete and unnecessary, and you can safely just remove it. If you do that then the only thing you’re repeating between the different containers is the image: and restart: lines, which isn’t bad.

    One technique you’ll see in more complex Compose files is to use the YAML merge key extension in combination with a Compose extension field to declare common fields. In your file this could look like:

    version: '3.8'
    x-common: &common
      image: my_app/image
      restart: always
    services:
      my_app1:
        <<: *common
        environment:
          ACCOUNTS: '1,2,3'
      my_app2:
        <<: *common
        environment:
          ACCOUNTS: '4,5,6'
      mysql: {...}
    

    The one big limitation of this is that the merge is not recursive. If every container needs an environment variable MYSQL_HOST=mysql but also the different containers need different ACCOUNTS, you’ll have to repeat the entire environment: block for every service.

    Login or Signup to reply.
  2. AFAIK there is no "native" way. Since you would be changing only a few parts of the container definition the two possibilities I would consider is:

    1. As you said just create more container definitions. There you can use a for loop in a templating engine like Helm https://helm.sh/docs/chart_template_guide/control_structures/#looping-with-the-range-action

    2. For loop in your application. Unless it is too complicated, what is stopping you from passing in a list of the possible variables, and having a script that keeps starting the applications one by one?

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search