Docker is an outstanding tool that all fortune 500 companies use. This tutorial will walk through the difference between Docker vs. docker-compose. If you are new to Docker, you can check this link to get a basic understanding of Docker. I will also compare docker-compose with Kubernetes, docker swarm, and dockerfile, so let’s get started.
What is Docker?
Docker is one of the most popular containerized-based applications in the market. Docker is an open-source platform for building, deploying, and managing containerized applications. With Docker, we can easily package our applications into containers.
Docker containers will run the same way irrespective of the underlying OS you are running. Docker has gained momentum because it has the following advantages:
- Containers are very lightweight as they do not contain the entire OS payload.
- With Docker, you can run the same instance of an application multiple times as applications run in their separate environment.
- Docker containers can be easily sharable with other people, and they will function in the same manner in the environment.
Now we have a basic idea about what is Docker containers, let’s proceed further and understand what a dockerfile is.
What is Dockerfile?
A Dockerfile is a text document that Docker uses to build images. Docker can build images by reading the instruction from the Dockerfile. Dockerfile can create an image by simply typing the Docker build command.
The simple Dockerfile looks like below:
FROM scratch ADD busybox.tar.xz / CMD ["sh"]
This is the dockerfile for the busybox application. To get more information about this dockerfile, please visit this link.
Dockerfile consists of many keywords, and each keyword in Docker represents a layer. Some of the most widely used keywords in the dockerfile are:
ADD copies the files from a source on the host into the container’s own filesystem at the set destination. CMD can be used for executing a specific command within the container. ENTRYPOINT sets a default application to be used every time a container is created with the image. ENV sets environment variables. EXPOSE associates a specific port to enable networking between the container and the outside world. FROM defines the base image used to start the build process. MAINTAINER defines a full name and email address of the image creator. RUN is the central executing directive for Dockerfiles. USER sets the UID (or username) which is to run the container. VOLUME is used to enable access from the container to a directory on the host machine. WORKDIR sets the path where the command, defined with CMD, is to be executed. LABEL allows you to add a label to your docker image.
All keywords are not required for a Dockerfile to function. Using only a few keywords as well we can create a dockerfile
Now proceed further and understand what docker-compose is.
What is docker-compose?
Docker Compose is used to run multiple containers as a single service. For example, suppose you had a voting app that follows the below architecture:
- A front-end web app in Python that lets you vote between two options
- A Redis queue that collects new votes
- A worker who consumes votes and stores them in
- A Postgres database backed by a Docker volume
- An app that shows the results of the voting in real-time
More details about the voting app can be found here. With docker-compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from the YAML file.
Advantages of docker-compose
Docker-compose provides a lot of advantages; some of them are:
- With docker-compose, you can run all your containers in a single host, and you do not need a complex host setup to get started.
- Container volume, network, and ports can be easily configurable in the YAML file
- In docker-compose, all containers will be running in a single host, so containers will take less time to perform tasks.
- As all the containers are isolated from one another, so reduces the security threat.
Installation of docker-compose is straightforward. Before installing docker-compose, make sure Docker is running in your system. You can use the below command to verify if Docker is running:
docker --version Docker version 20.10.3, build 48d30b5
Now you are ready to install docker-compose. Please install docker-compose from this link based on your operating system. I am using a mac to install docker-compose. So let’s run the below command to install docker-compose:
pip uninstall docker-compose
Now let’s verify the docker-compose installation.
docker-compose --version docker-compose version 1.28.5, build c4eb3a1f
If you are getting similar output, your docker installation is successful.
Docker vs docker-compose
Now we have a basic understanding of various docker terminologies. Let’s proceed further and finally see the difference between Docker and docker-compose.
- Docker manages a single container, but with docker-compose, we can manage more than one container.
- To build a docker container, you run the command docker run, while to build containers from docker-compose, you type docker-compose up.
- Docker is used for building a simple application, but we generally use docker-compose for the production-grade application.
- The sample dockerfile looks like this:
FROM scratch ADD busybox.tar.xz / CMD ["sh"]
- While the sample docker-compose files look like this:
services: vote: build: ./vote # use python rather than gunicorn for local dev command: python app.py depends_on: redis: condition: service_healthy volumes: - ./vote:/app ports: - "5000:80" networks: - front-tier - back-tier result: build: ./result # use nodemon rather than node for local dev command: nodemon server.js depends_on: db: condition: service_healthy volumes: - ./result:/app ports: - "5001:80" - "5858:5858" networks: - front-tier - back-tier worker: build: context: ./worker depends_on: redis: condition: service_healthy db: condition: service_healthy networks: - back-tier redis: image: redis:5.0-alpine3.10 volumes: - "./healthchecks:/healthchecks" healthcheck: test: /healthchecks/redis.sh interval: "5s" ports: ["6379"] networks: - back-tier db: image: postgres:9.4 environment: POSTGRES_USER: "postgres" POSTGRES_PASSWORD: "postgres" volumes: - "db-data:/var/lib/postgresql/data" - "./healthchecks:/healthchecks" healthcheck: test: /healthchecks/postgres.sh interval: "5s" networks: - back-tier volumes: db-data: networks: front-tier: back-tier:
- In docker, we need to define commands in a text format while in the docker-compose file we have to write the commands in YAML format.
These are a few differences between Docker and docker-compose. Let’s proceed further and see docker-compose in action.
In this session, we will deploy the voting app application using docker-compose. First, clone the official GitHub example repo.
git clone https://github.com/dockersamples/example-voting-app.git Cloning into 'example-voting-app'... remote: Enumerating objects: 971, done. remote: Counting objects: 100% (19/19), done. remote: Compressing objects: 100% (18/18), done. remote: Total 971 (delta 3), reused 13 (delta 1), pack-reused 952 Receiving objects: 100% (971/971), 987.34 KiB | 692.00 KiB/s, done. Resolving deltas: 100% (362/362), done.
Now go inside the example-voting-app folder.
List all the files and folders inside a repo.
ls -ltr total 256 -rw-r--r-- 1 xxxxxx staff 2.0K Jun 12 13:34 ExampleVotingApp.sln -rw-r--r-- 1 xxxxxx staff 11K Jun 12 13:34 LICENSE -rw-r--r-- 1 xxxxxx staff 288B Jun 12 13:34 MAINTAINERS -rw-r--r-- 1 xxxxxx staff 3.7K Jun 12 13:34 README.md -rw-r--r-- 1 xxxxxx staff 54K Jun 12 13:34 architecture.png -rw-r--r-- 1 xxxxxx staff 893B Jun 12 13:34 docker-compose-javaworker.yml -rw-r--r-- 1 xxxxxx staff 598B Jun 12 13:34 docker-compose-k8s.yml -rw-r--r-- 1 xxxxxx staff 485B Jun 12 13:34 docker-compose-simple.yml -rw-r--r-- 1 xxxxxx staff 1.0K Jun 12 13:34 docker-compose-windows-1809.yml -rw-r--r-- 1 xxxxxx staff 994B Jun 12 13:34 docker-compose-windows.yml -rw-r--r-- 1 xxxxxx staff 116B Jun 12 13:34 docker-compose.seed.yml -rw-r--r-- 1 xxxxxx staff 1.5K Jun 12 13:34 docker-compose.yml -rw-r--r-- 1 xxxxxx staff 1.5K Jun 12 13:34 docker-stack-simple.yml -rw-r--r-- 1 xxxxxx staff 1.0K Jun 12 13:34 docker-stack-windows-1809.yml -rw-r--r-- 1 xxxxxx staff 1.3K Jun 12 13:34 docker-stack-windows.yml -rw-r--r-- 1 xxxxxx staff 1.8K Jun 12 13:34 docker-stack.yml drwxr-xr-x 4 xxxxxx staff 128B Jun 12 13:34 healthchecks drwxr-xr-x 12 xxxxxx staff 384B Jun 12 13:34 k8s-specifications -rw-r--r-- 1 xxxxxx staff 3.3K Jun 12 13:34 kube-deployment.yml drwxr-xr-x 12 xxxxxx staff 384B Jun 12 13:34 result drwxr-xr-x 5 xxxxxx staff 160B Jun 12 13:34 seed-data drwxr-xr-x 8 xxxxxx staff 256B Jun 12 13:34 vote drwxr-xr-x 11 xxxxxx staff 352B Jun 12 13:34 worker
Now let’s run the docker-compose command to start all containers.
Meanwhile, grab a coffee. It might take a few minutes to pull all images and start all the containers.
docker-compose up -d Creating network "example-voting-app_back-tier" with the default driver Creating network "example-voting-app_front-tier" with the default driver Creating volume "example-voting-app_db-data" with default driver Pulling redis (redis:5.0-alpine3.10)... ...............<suppressed o/p>............. ...............<suppressed o/p>............. WARNING: Image for service result was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`. Creating example-voting-app_redis_1 ... done Creating example-voting-app_db_1 ... done Creating example-voting-app_vote_1 ... done Creating example-voting-app_result_1 ... done Creating example-voting-app_worker_1 ... done
Let’s verify how many containers the docker-compose file created. Run the below command to verify running containers:
docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e3e9fb7e9e7c example-voting-app_result "docker-entrypoint.s…" 7 minutes ago Up 7 minutes 0.0.0.0:5858->5858/tcp, 0.0.0.0:5001->80/tcp example-voting-app_result_1 200347ca2214 example-voting-app_worker "dotnet Worker.dll" 7 minutes ago Up 7 minutes example-voting-app_worker_1 78552f8dee7b example-voting-app_vote "python app.py" 7 minutes ago Up 7 minutes 0.0.0.0:5000->80/tcp example-voting-app_vote_1 7e35a7aaea5d postgres:9.4 "docker-entrypoint.s…" 7 minutes ago Up 7 minutes (healthy) 5432/tcp example-voting-app_db_1 b0433344b74b redis:5.0-alpine3.10 "docker-entrypoint.s…" 7 minutes ago Up 7 minutes (healthy) 0.0.0.0:51348->6379/tcp example-voting-app_redis_1
It started with five containers. Now go to http://localhost:5000 to access the application.
Fantastic, you have successfully run a production-grade application using docker-compose. Let’s proceed further and see the comparison of docker-compose with Kubernetes.
If you want to stop the voting app application in one go, type the below command, and it will stop all the containers:
docker-compose down Stopping example-voting-app_result_1 ... done Stopping example-voting-app_worker_1 ... done Stopping example-voting-app_vote_1 ... done Stopping example-voting-app_db_1 ... done Stopping example-voting-app_redis_1 ... done Removing example-voting-app_result_1 ... done Removing example-voting-app_worker_1 ... done Removing example-voting-app_vote_1 ... done Removing example-voting-app_db_1 ... done Removing example-voting-app_redis_1 ... done Removing network example-voting-app_back-tier Removing network example-voting-app_front-tier
Docker-compose vs. Kubernetes
Using both docker-compose and Kubernetes, we can deploy the multi-container application. Out of these two Kubernetes provide more features as compared to docker-compose in this session, we will see some significant differences between docker-compose and Kubernetes:
- Docker Compose is designed to run the containers on a single host or cluster, while with Kubernetes, we can deploy the applications on multiple machines.
- It is easy to scale an application that is deployed in Kubernetes as compared to deployed using docker-compose
- From the deployment point deploying an application using docker-compose is quite as compared to deploying applications on Kubernetes.
- Learning Kubernetes concepts will take time and patience, but you can quickly get started with docker-compose in a few days.
Docker-compose vs. Docker swarm
A few differences between Docker Swarm and Docker-Compose:
- Docker-swarm is the additional feature introduced by the docker, using which we can scale our application to more than one server. In contrast, Docker-compose will run your application on a single node.
- Scaling your application with docker-compose does not make any sense as your containers will still run on a single node. In contrast, with Docker swarm, we can quickly scale our application for high availability and fault tolerance.
- Docker Swarm comes inbuilt with the Docker CLI. It is part of the Docker binary you call via your terminal, whereas Docker-Compose is a standalone binary you need to install separately.
Nowadays, with the massive popularity of Kubernetes, only a few companies use docker swarm to deploy their production-grade application.
I hope you have found this article useful. We have started with the basics of Docker and docker-compose, and finally, we have compared Docker with the docker-compose, Kubernetes, and docker swarm. We also deployed a voting app using the docker-compose command. Please do let me know if you need more clarification around docker-compose and related terminologies in the comment box.