Multiple compose files management patterns

Multiple compose files management patterns

Table of contents

As a system grows you may need to handle multiple service changes over and over or handle multiple configurations which could bring complexity by themselves.

docker provides multiple compose file management options; hence you can divide your configurations into multiple compose files and integrate them together.

now let's take a look at them:

extends

you can share common configurations among different files.

usage:

# common configuration compose file
services:
    <common service name>:
        <snip>
services:
    <service name>:
        extends:
            file: <path to common configuration compose file>
            service: < common service name of which wanna use its configs>

you can define multiple services in common configuration compose file and use each service you want by their names.

merge

merge compose files together and create a composite compose configuration

compose reads "compose.yml" and "compose.override.yml" files by default which compose.yml is base configuration and compose.override.yml contains new values of base configuration which docker compose will overwrite it.

usage:

docker compose  -f compose.yml  -f override.compose.yml up
# base compose file
services:
    <service name>:
         image: ...
         ports: ...
# override compose file
services:
    <same service name>:
        environment:
           - ....
# new generated configuration
services:
   <service name>:
        image: ...
        ports: ...
        environment:
           - ....

When you use multiple Compose files, you must make sure all paths in the files are relative to the base Compose file.

merge rules:

  • for single-value options new values replace old values (i.e image, command)
  • for multiple value options both old and new values will be concatenated (i.e ports, dns)
  • for environment and labels; environment variables and labels with the same name will be replaced by new values.
    # base values
    services:
     <service name>:
          environment:
             - A=value1
             - B=value2
    
    # override values
    services:
     <same service name>:
          environment:
             - A=new value1
             - C=value3
    
    # result
    services:
     <service name>:
          environment:
             - A=new value1
             - B=value2
             - C=value3
    
  • for volumes and devices, mounts with the same mount point in the container will be replaced by new host mount point.
    # base values
    services:
     <service name>:
         volumes:
           - path1:/test
           - path2:/test2
    
    # override values
    services:
    <same service name>:
         volumes:
           - new path1:/test
           - path3:/test3
    
    # result
    services:
     <service name>:
         volumes:
           - new path1:/test
           - path2:/test2
           - path3:/test3
    

    Also you can use merge to overwrite your values based on your environments.

    docker compose -f compose.yml -f prod.compose.yml up
    

include

when have a complex application, you can break it into sub-modules. in compose files management you can break your compose file into sub-compose files and then use them in the main compose file using include.

Include is a top-level element. Each path within include loads an individual compose model and its own project directory, meaning all resources are copied into the current compose mode.

usage:

# main compose file
include:
    - <path to>/sub-compose1.yml
    - <path to>/sub-compose2.yml
services:
    some-service:
         <snip>

Also you can have a dedicated override compose file (which we talked about in merge section) for your sub-compose.

include:
    - path:
          - <path to>/sub-compose.yml
          - <path to>/override.compose.yml