Docker Tip #82: Using YAML Anchors and X Properties in Docker Compose
YAML anchors let you reuse parts of your YAML file like functions. You can use them to share default settings between services.
This is quite handy when you want to DRY out some bits of your docker-compose.yml
file.
Example web + worker set up without using this strategy:
Keep in mind this isn’t a full docker-compose.yml
file. I’ve only extracted
out a couple of services and fields to show case this feature specifically.
version: "3.4"
services:
web:
build:
context: "."
args:
- "APP_ENV=${APP_ENV:-prod}"
depends_on:
- "postgres"
- "redis"
env_file:
- ".env"
image: "nickjj/myapp"
ports:
- "8000:8000"
restart: "unless-stopped"
stop_grace_period: "3s"
volumes:
- ".:/app"
worker:
build:
context: "."
args:
- "APP_ENV=${APP_ENV:-prod}"
depends_on:
- "postgres"
- "redis"
env_file:
- ".env"
image: "nickjj/myapp"
restart: "unless-stopped"
stop_grace_period: "3s"
volumes:
- ".:/app"
So much duplication! Everything is the same except the ports
property on the web
service.
The same example using YAML Anchors and the X prefix to set defaults:
version: "3.4"
x-app: &default-app
build:
context: "."
args:
- "APP_ENV=${APP_ENV:-prod}"
depends_on:
- "postgres"
- "redis"
env_file:
- ".env"
image: "nickjj/myapp"
restart: "unless-stopped"
stop_grace_period: "3s"
volumes:
- ".:/app"
services:
web:
<<: *default-app
ports:
- "8000:8000"
worker:
<<: *default-app
Now we only need to write the common bits once, and multiple services can benefit from it. It’s very handy for setting up common things like logging or various other Docker properties.
You can name the x-
properties anything you want as long as it’s valid YAML
syntax. These x-
properties are called “Extension fields” in Docker Compose’s
documentation.
The basic idea is the extension field just acts as a “place” to define the YAML anchor. The extension field’s name doesn’t need to match the anchor, but it’s a reasonable idea to keep them the same for consistency.
Overriding default anchor values on a per service basis:
For example, if you wanted to set a different stop_grace_period
for the
worker
service you would end up doing:
worker:
<<: *default-app
stop_grace_period: "10s"
This takes advantage of YAML’s “merge” feature.
Overall this is definitely a handy feature, but like all abstractions, sometimes it’s easy to get carried away. In other words, it’s probably not worth it to DRY out 2 properties like this.
Fun fact! I opened a pull request on Docker Compose’s documentation back in Feb. 2015 to talk about the value of YAML anchors but it never got merged. Thankfully Docker now recognizes the value of this feature.