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
CodePudding user response:
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.
CodePudding user response:
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:
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
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?