I have a docker-compose.override.yml
file that launches 10 different services that only differ in the name of the container and the command they run. They also need various envrionments variables, several volumes etc.
The file looks like this, but it has 10 section and each section actually has more configuration.
I don't like all that repetition.
Is there a way to move all the common configuration part to some other place and let all the services use this information?
Maybe some other solution to this?
version: "3"
services:
service-1:
image: my-image
tty: true
environment:
- APP_ENVIRONMENT=dev
working_dir: /source
volumes:
- .:/source:ro
command: run_services_1
service-2:
image: my-image
tty: true
environment:
- APP_ENVIRONMENT=dev
working_dir: /source
volumes:
- .:/source:ro
command: run_services_2
CodePudding user response:
Reusing blocks of code from a docker-compose file can be easily achieved by using the YAML anchors and aliases feature.
For example:
services:
service1: &default
image: alpine
environment:
APP_ENVIRONMENT: dev
command: env
service2:
<<: *default
command: echo some other command
service3:
<<: *default
environment:
APP_ENVIRONMENT: prod
For more advanced cases, you can also employ these two tricks:
- Mark only a part of the configuration block as belongs to
&default
or other marker. - Define multiple markers, and create a sort of inheritance between sections.
Here is a simple example of both features:
services:
bash:
build: .
# Only the below will be used for anyone inheriting from &default
<<: &default
image: me/my-image
environment:
APPENV: dev
web: &web
# Inherit from default
<<: *default
command: env
prod:
# Inherit from web
<<: *web
environment:
APPENV: production
You can try this alongside a simple Dockerfile just containing FROM alpine
or similar.
Finally, it is worth mentioning that docker-compose supports hidden configuration blocks, which they call Extension Fields. Anything that starts with x-
is ignored, so this can be used to define templates, for example:
x-service: &service
depends_on: [nginx]
restart: always
services:
service1:
<<: *service
command: ...
service2:
<<: *service
command: ...
image: ...
And as a side-tip: Remove version: 3
from your files, unless you have a specific reason. New docker compose no longer needs it.
CodePudding user response:
There is a way called yml templating, which looks like this:
version: "3"
services:
service-1: &service_template
image: my-image
tty: true
environment:
- APP_ENVIRONMENT=dev
working_dir: /source
volumes:
- .:/source:ro
command: run_services_1
service-2:
<<: *service_template
command: run_services_2
Everything you want to override just write it in the service where you are using the defined template, like the 'command' parameter in the example.
For more examples visit https://medium.com/@kinghuang/docker-compose-anchors-aliases-extensions-a1e4105d70bd
CodePudding user response:
Many of the details you show in the Compose file don't actually need to be runtime configuration; you can set them in the Dockerfile.
WORKDIR /source # replaces Compose working_dir:
COPY . ./ # application built into the image, so no Compose volumes:
# ENV APP_ENVIRONMENT=dev # if this is a build-time parameter
CMD run_default_command # good practice
You don't usually need to specify tty: true
(one prominent create-react-app bug requires stdin_open: true
). Your Compose file doesn't specify these, but you also don't usually need to provide network:
or container_name:
options, since Compose provides a reasonable network setup by default.
So, if you can specify the environment variables in the image, the best case looks like:
version: '3.8'
services:
service-1:
image: my-image
command: run_service_1
service-2:
image: my-image
command: run_service_2
# ports: [...]
In practice you probably do need some runtime configuration and it may need to be repeated across services. A common trick is to use YAML alias nodes in combination with Compose extension fields to have a block of environment variable definitions and include them in other services:
version: '3.8'
x-environment: &environment
- APP_ENVIRONMENT=dev
services:
service-1:
image: my-image
environment: *environment
command: run_service_1
Compose also supports YAML's merge type, if environment:
is a mapping, so it's possible to extend this list:
x-environment: &environment
APP_ENVIRONMENT: dev
services:
service-1:
image: my-image
command: run_service_1
environment:
<< : *environment
EXTERNAL_SERVICE_URL: http://external.example.com
You can use this same technique to provide arbitrary additional Compose settings, but relying on Compose's defaults and settings built into images is frequently easier to write and read.