Docker Compose is a tool that allows you to define and manage multiple containers and Docker applications using a simple YAML configuration file. Instead of typing Docker CLI commands manually to set everything up, you can put all the configuration in a YAML file. Compose lets you configure and define everything in one place and start it up with a single command. This is especially useful if you have an application stack made of different pieces and want to start and automate them all together. Managing this with manual commands would be difficult and inefficient.
Make a directory for your project to keep clean
mkdir project
Go into your project directory
cd project
Make a YAML file named docker-compose.yml and put this docker-compose.yml into the project directory
nano docker-compose.yml
Copy and paste this in. After you paste it in hit ctrl + o then enter then ctrl + x to save it and exit nano.
services:
apache: # Name of the service (can be anything you like)
image: httpd:latest # Use the official Apache HTTP Server image (latest version)
ports:
- "8080:80" # Maps port 80 inside the container to port 8080 on your host
# So you'll access the site at http://localhost:8080

Now to run the compose file you would run this command with the -d which means detached mode. This would run the compose on the local machine only. By default, it looks for the name docker-compose.yml. If you named it something else you would need to specify the name with the -f (name) to specify your custom name which I will show you later.
docker compose up -d
Run this to see the compose running
docker compose ps
Containers should have opened and started to run as well. You can check this with docker ps
docker ps

We also have the site up and running. Just type in localhost:8080 in a browser and you should see your website pop up.

To shut the service down you would run this command
docker compose down

If you had a custom name for your docker-compose.yml like for example website.yml you would run the -f flag to specify the file name like this. Use the -d still because we want it to run in detached mode.
docker compose -f website.yml up -d
And to shut it down would be the same thing but with down
docker compose -f website.yml down
Let’s deploy this in a swarm. If you don’t have a swarm already you can read this page on how to make one: https://nodetechsystems.ca/docker-swarm-orchestration/
We need a new YAML file cause our original one does not have specified replicas and we need at least 3 replicas because I have 3 nodes in my swarm. I will make a new one. This one I will call custom-apache.yml.
nano custom-apache.yml
Below:
services:
apache: # Service name; you can choose any name here
image: httpd:latest # Use official Apache HTTP Server image from Docker Hub
ports:
- "8080:80" # Map port 8080 on the host to port 80 inside the container
# When deployed to Swarm, port 8080 will be published on all nodes,
# and traffic will be load balanced to replicas
deploy:
replicas: 3 # Run 3 instances of this service (Swarm will try to spread them across nodes)
restart_policy:
condition: on-failure # Restart containers only if they exit with failure (non-zero status)
# Helps keep the service healthy automatically

Deploy the stack on the swarm manager using this command. The -c flag specifies the compose file that will exist on your manager, this is the file you created on your manager that contains the configuration. I gave the stack name of nodestack. So, what this actually does is deploys a group of services (a stack) to the docker swarm cluster.
docker stack deploy -c custom-apache.yml nodestack

Docker swarm reads the compose file (custom-apache.yml) and creates all the services defined in it. It schedules those services across the nodes in our swarm cluster.
Check status of what’s going on behind the scenes
docker stack services nodestack
docker service ls
docker service ps nodestack_apache



We can scale this stack if we want to. We have 3 replicas (3 containers running across 3 nodes) so when we run this command go to each node and run docker ps, you should see 5 containers total running across your 3 nodes.
docker service scale nodestack_apache=5



To update the stack with a new configuration file (changes to the .YAML) run this
docker stack deploy -c custom-apache.yml nodestack
You can remove the stack with this command
docker stack rm nodestack

Keep in mind that docker compose commands are for local machine use only and docker stack deploy is for swarm only. If you are working with swarms you are using docker stack deploy commands and if you are just working with one machine you are using docker compose commands
We first deployed a Docker Compose YAML file on a single host, which created one running container (1 replica) for the service on that machine. Then, we deployed a different YAML stack file to the Docker Swarm cluster, which created 3 replicas (containers) of the service distributed automatically across the 3 nodes then we scaled the replicas to 5 (5 containers in the swarm now instead of 3). I did not cover volumes here, but we could have used one to mount a custom .html file but that would require placing the file on every node individually. If you want to go this route, you can configure it in the YAML file as well. Alternatively, you could use a shared volume backed by something like NFS or build a custom Apache image with the HTML file inside it. Docker compose is useful for automation because you can specify everything you need to specify in a single file and deploy that to either one local machine or multiple machines across the swarm. It is a powerful tool that simplifies deployment and makes life easier for anyone who needs to deploy complex applications consistently and efficiently without manually configuring each component on every machine.