1. Introduction
Validating the Docker Compose YAML file ensures that configurations are correct, prevents runtime errors, and saves time during development and deployment.
In this tutorial, we’ll explore how to validate a Docker Compose file. First, we’ll review the YAML format. Then, we’ll understand how Docker Compose employs it. Finally, we’ll explore manual and automated validation techniques that help maintain error-free configurations.
2. Understanding a YAML File
YAML (YAML Ain’t Markup Language) is a human-readable data serialization standard often used for configuration files. Unlike other markup languages such as XML or JSON, YAML aims to be easy to read and write. Its syntax is sensitive to indentation and formatting.
YAML files use indentation to indicate structure, similar to Python. However, tab characters aren’t allowed; we should only use spaces to ensure portability across different systems. At its core, YAML uses key-value pairs to represent data. A colon followed by a space separates keys and values.
Also, YAML supports various data types, including strings, integers, floats, booleans, null, dates, and times. The # symbol denotes comments. The parser ignores anything following this symbol on a line.
Finally, scalars are the simplest form of data in YAML, representing individual values such as strings, numbers, or booleans. We can write them in plain style (without quotes), single quotes, or double quotes.
3. Docker Compose and YAML File
A Docker Compose YAML file is a configuration file used to define and manage multi-container Docker applications. A typical compose.yaml file includes several sections that outline various aspects of the application’s architecture.
The services section defines the containers that make up the application. Each service corresponds to a container, and we can configure it with parameters such as images, ports, volumes, and environment variables. Examples of services include apps, web servers, and databases.
For a better understanding, let’s study an example available on the Official Docker GitHub:
services:
redis:
image: redislabs/redismod
ports:
- '6379:6379'
web:
build: .
ports:
- "8000:8000"
volumes:
- .:/code
depends_on:
- redis
This file sets up a web service to run with a Redis database. The Redis service is constructed using a ready-made image from Docker Hub, whereas the web service is created from a Dockerfile in the current directory (.). Additionally, the web service requires an active Redis service to operate correctly.
4. Validation Techniques
Let’s explore some techniques to verify the correctness of our compose file.
4.1. Manual Techniques
Docker Compose provides a built-in command to check the syntax and validity of a YAML file. The docker-compose config command parses the file and prints the configuration, highlighting any errors or issues.
To illustrate, let’s test the same YAML file as above:
$ docker compose config
name: baeldung
services:
redis:
image: redislabs/redismod
networks:
default: null
ports:
- mode: ingress
target: 6379
published: "6379"
protocol: tcp
web:
build:
context: /home/user/baeldung
dockerfile: Dockerfile
depends_on:
redis:
condition: service_started
required: true
networks:
default: null
ports:
- mode: ingress
target: 8000
published: "8000"
protocol: tcp
volumes:
- type: bind
source: /home/user/baeldung
target: /code
bind:
create_host_path: true
networks:
default:
name: baeldung_default
This output shows the effective configuration after Docker Compose has processed the YAML file. We observed that the configuration now includes additional specifications, such as communication protocols and network settings. These settings are essential for the services to function correctly. However, since we didn’t specify them, Docker uses the default values.
This command also replaces environment variables and resolves any variables defined in the file, an example being directory paths displayed in full where previously they were just a dot.
In this example, the command looked for the compose.yaml file in the current directory. However, we can designate the file with the -f flag (as in the following example) or by setting the COMPOSE_FILE environment variable to reference the file.
Now, let’s introduce an error into the file to analyze the output of the config command. To do this, we’ll delete the line indicating the image that Redis will use (image: redislabs/redismod):
$ docker compose -f compose.yaml config
service "redis" has neither an image nor a build context specified: invalid compose project
Docker Compose requires each service to specify either an image to pull from a Docker registry or a build context to build the image from a Dockerfile. In this case, the error indicates that the Redis service is defined but doesn’t have an image or a build context specified precisely because we’ve removed this specification.
As the output of the command can be long, a brief message is more interesting to receive, such as OK or an error. In this case, we can use the –quiet flag together with printf:
$ docker compose config --quiet && printf "OK\n" || printf "ERROR\n"
OK
$ docker compose config --quiet && printf "OK\n" || printf "ERROR\n"
service "redis" has neither an image nor a build context specified: invalid compose project
ERROR
4.2. Automated Techniques
We can validate our file using automation techniques. The first of these is the use of linting tools in the development environment. Installing a YAML linting extension provides real-time validation and highlights errors as we edit the compose file.
Several Integrated Development Environments and text editors, such as Visual Studio Code (VS Code), support YAML linting through extensions. To install it in VS Code, we must search for Red Hat’s YAML extension from the VS Code marketplace (ID: redhat.vscode-yaml). Once installed, when we access any YAML file, the extension will automatically highlight syntax errors and provide suggested fixes.
The second automation technique involves integrating YAML validation into the Continuous Integration/Continuous Deployment (CI/CD) pipeline. This ensures that the system automatically checks for errors in any changes to the YAML file. Many CI/CD platforms, such as Jenkins, GitHub Actions, and GitLab CI, support executing Docker Compose commands.
For example, let’s produce a workflow to validate a Docker Compose YAML file. So, let’s create a .github/workflows/validate-docker-compose.yaml file with the following content:
name: Validate Docker Compose
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Set up Docker
uses: docker/setup-buildx-action@v1
- name: Validate docker-compose.yaml
run: docker-compose config
This workflow triggers whenever we send code or make a pull request. It also fetches the repository code to access the compose.yaml file. Docker is configured in the runner environment to enable the execution of Docker commands. Finally, it runs docker-compose config to validate the compose.yaml file.
5. Conclusion
In this tutorial, we learned how to validate a compose.yaml file. The simplest way is to use the docker compose config command, which renders the file and reports any errors. We can also integrate this command into CI/CD to automate the check. Finally, we can use lint tools within the IDE to highlight problems in real-time.