Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: February 4, 2025
Maintaining multiple containers with complex configurations can become difficult if we’re relying on the docker run command. Conveniently, Docker Compose provides a solution by enabling us to define multi-container Docker applications using a YAML configuration file.
In this tutorial, we’ll demonstrate how to convert a docker run command into a docker-compose.yml file.
The docker run command is useful for creating and running containers:
$ docker run -d \
--name container_name \
-p host_port:container_port \
-e ENV_VAR=value \
-v /host/path:/container/path \
--network my-network \
image_name:tag
Let’s break down this command:
Now, let’s utilize the syntax to create and run the container my-container:
$ docker run -d \
--name my-container \
-p 8080:80 \
-e APP_ENV=production \
-v /var/www/html:/usr/share/nginx/html \
--network my-network \
nginx:latest
Implementing the docker run command is straightforward for simple cases but it can become repetitive and prone to errors for complex cases. Because of this, Docker Compose is often preferred.
To begin with, let’s see the general structure of the Compose file:
$ cat docker-compose.yml
version: '3.9'
services:
service_name:
image: image_name:tag
container_name: container_name
ports:
- "host_port:container_port"
environment:
- ENV_VAR=value
volumes:
- /host/path:/container/path
networks:
- network_name
networks:
network_name:
driver: bridge
Now, let’s use the above structure to translate the docker run command that we provided earlier:
$ cat docker-compose.yml
version: '3.9'
services:
my-container:
image: nginx:latest
container_name: my-container
ports:
- "8080:80"
environment:
- APP_ENV=production
- DB_HOST=db.example.com
volumes:
- /var/www/html:/usr/share/nginx/html
networks:
- my-network
networks:
my-network:
driver: bridge
So, let’s see what each directive does:
Usually, it’s more secure to define the environment variables in a .env file instead of hardcoding it in the Compose file.
Let’s discuss a few advantages Docker Compose provides over using the docker run command.
Docker Compose supports other essential configurations we can implement like service dependencies:
depends_on:
- database
This configuration ensures that containers start in the correct order.
Additionally, we can utilize the restart configuration:
restart: always
With this configuration, failed containers are automatically restarted.
Another option we can utilize is monitoring the health of a service:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
retries: 3
In this case, we instruct Docker to regularly check whether a service is reachable by sending a request to http://localhost. If the service is unresponsive, Docker tries to restart the container after a few failed attempts.
Docker Compose enables us to reduce complexity and errors since we can define all configurations in a single YAML file instead of using repetitive, complex, and multiple docker run commands. For example, teams can easily add new services, modify existing ones without manually modifying and restarting containers, and update configurations. It enables us to restart, stop, or inspect logs of multiple services enhancing debugging.
With Docker Compose, we can more easily scale services. Specifically, we can use the scale option to define the number of container instances for a specific service.
$ docker-compose up --scale my-container=3
In this example, Docker Compose starts 3 container instances for the service my-container.
The containers we define inside the same docker-compose.yml file can communicate with each other using their service names. Thus, Docker Compose removes the need to manually set up network connections making it more straightforward for containers to communicate. Typically, Docker Compose creates a default network in which all the services within the same Compose file can communicate without the need for additional configuration.
The docker-compose.yml file defines the services, configurations, and dependencies. It makes it easier for us to share and apply version control to the file, ensuring consistency, reproducibility, and easier collaboration across different environments.
To demonstrate, let’s use Docker Compose v2 which utilizes docker compose instead of docker-compose.
Now, we can start containers using a single command:
$ docker compose up -d
To stop and remove the containers specified in the docker-compose.yml file, we just use down:
$ docker compose down
After making any changes to the Compose file, we add –build:
$ docker compose up -d --build
Thus, we rebuild the container images before starting the containers.
Docker Compose integrates better with orchestration tools like Kubernetes. Hence, with a well-structured docker-compose.yml file, we can easily transition to more advanced container management solutions. For DevOps, we can leverage Docker Compose to include CI/CD pipelines and general deployment automation steps into workflows.
In this article, we saw how to convert a docker run command into a docker-compose file.
First, we discussed the basic structure of the docker run command along with that of a Compose file. After that, we looked at many advantages that Docker Compose offers over the docker run command. For instance, we get additional options helpful for configuration along with a better experience when working with multiple containers.