What's the difference between Docker Compose vs. Dockerfile

252,468

Solution 1

The answer is neither.

Docker Compose (herein referred to as compose) will use the Dockerfile if you add the build command to your project's docker-compose.yml.

Your Docker workflow should be to build a suitable Dockerfile for each image you wish to create, then use compose to assemble the images using the build command.

You can specify the path to your individual Dockerfiles using build /path/to/dockerfiles/blah where /path/to/dockerfiles/blah is where blah's Dockerfile lives.

Solution 2

Dockerfile

enter image description here

A Dockerfile is a simple text file that contains the commands a user could call to assemble an image.

Example, Dockerfile

FROM ubuntu:latest
MAINTAINER john doe 

RUN apt-get update
RUN apt-get install -y python python-pip wget
RUN pip install Flask

ADD hello.py /home/hello.py

WORKDIR /home

Docker Compose

enter image description here

Docker Compose

  • is a tool for defining and running multi-container Docker applications.

  • define the services that make up your app in docker-compose.yml so they can be run together in an isolated environment.

  • get an app running in one command by just running docker-compose up

Example, docker-compose.yml

version: "3"
services:
  web:
    build: .
    ports:
    - '5000:5000'
    volumes:
    - .:/code
    - logvolume01:/var/log
    links:
    - redis
  redis:
    image: redis
    volumes:
      logvolume01: {}

Solution 3

docker-compose exists to keep you having to write a ton of commands you would have to with docker-cli.

docker-compose also makes it easy to startup multiple containers at the same time and automatically connect them together with some form of networking.

The purpose of docker-compose is to function as docker cli but to issue multiple commands much more quickly.

To make use of docker-compose, you need to encode the commands you were running before into a docker-compose.yml file.

You are not just going to copy paste them into the yaml file, there is a special syntax.

Once created, you have to feed it to the docker-compose cli and it will be up to the cli to parse the file and create all the different containers with the correct configuration we specify.

So you will have separate containers, let's say, one is redis-server and the second one is node-app, and you want that created using the Dockerfile in your current directory.

Additionally, after making that container, you would map some port from the container to the local machine to access everything running inside of it.

So for your docker-compose.yml file, you would want to start the first line like so:

version: '3'

That tells Docker the version of docker-compose you want to use. After that, you have to add:

version: '3'
services: 
  redis-server: 
    image: 'redis'
  node-app:
    build: .

Please notice the indentation, very important. Also, notice for one service I am grabbing an image, but for another service I am telling docker-compose to look inside the current directory to build the image that will be used for the second container.

Then you want to specify all the different ports that you want open on this container.

version: '3'
services: 
  redis-server: 
    image: 'redis'
  node-app:
    build: .
    ports:
      -

Please notice the dash, a dash in a yaml file is how we specify an array. In this example, I am mapping 8081 on my local machine to 8081 on the container like so:

version: '3'
services: 
  redis-server: 
    image: 'redis'
  node-app:
    build: .
    ports:
      - "8081:8081"

So the first port is your local machine, and the other is the port on the container, you could also distinguish between the two to avoid confusion like so:

version: '3'
services:
  redis-server:
    image: 'redis'
  node-app:
    build: .
    ports:
      - "4001:8081"

By developing your docker-compose.yml file like this, it will create these containers on essentially the same network and they will have free access to communicate with each other any way they please and exchange as much information as they want.

When the two containers are created using docker-compose, we do not need any port declarations.

Now in my example, we need to do some code configuration in the Nodejs app that looks something like this:

const express = require('express');
const redis = require('redis');

const app = express();
const client = redis.createClient({
  host: 'redis-server'
});

I use this example above to make you aware that there may be some specific configuration you would have to do in addition to the docker-compose.yml file that may be specific to your project.

Now, if you ever find yourself working with a Nodejs app and redis, you want to ensure you are aware of the default port Nodejs uses, so I will add this:

const express = require('express');
const redis = require('redis');

const app = express();
const client = redis.createClient({
  host: 'redis-server',
  port: 6379
});

So Docker is going to see that the Node app is looking for redis-server and redirect that connection over to this running container.

The whole time, the Dockerfile only contains this:

FROM node:alpine

WORKDIR '/app'

COPY /package.json ./
RUN npm install
COPY . .

CMD ["npm", "start"]

So, whereas before you would have to run docker run myimage to create an instance of all the containers or services inside the file, you can instead run docker-compose up and you don't have to specify an image because Docker will look in the current working directory and look for a docker-compose.yml file inside.

Before docker-compose.yml, we had to deal with two separate commands of docker build . and docker run myimage, but in the docker-compose world, if you want to rebuild your images, you write docker-compose up --build. That tells Docker to start up the containers again but rebuild it to get the latest changes.

So docker-compose makes it easier for working with multiple containers. The next time you need to start this group of containers in the background, you can do docker-compose up -d; and to stop them, you can do docker-compose down.

Solution 4

Docker compose file is a way for you to declaratively orchestrate the startup of multiple containers, rather than run each Dockerfile separately with a bash script, which would be much slower to write and harder to debug.

Solution 5

Dockerfile and Docker Compose are two different concepts in Dockerland. When we talk about Docker, the first things that come to mind are orchestration, OS level virtualization, images, containers, etc.. I will try to explain each as follows:

Image: An image is an immutable, shareable file that is stored in a Docker-trusted registry. A Docker image is built up from a series of read-only layers. Each layer represents an instruction that is being given in the image’s Dockerfile. An image holds all the required binaries to run.

enter image description here

Container: An instance of an image is called a container. A container is just an executable image binary that is to be run by the host OS. A running image is a container.

enter image description here

Dockerfile: A Dockerfile is a text document that contains all of the commands / build instructions, a user could call on the command line to assemble an image. This will be saved as a Dockerfile. (Note the lowercase 'f'.)

enter image description here

Docker-Compose: Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services (containers). Then, with a single command, you create and start all the services from your configuration. The Compose file would be saved as docker-compose.yml.

Share:
252,468
Aaron Lelevier
Author by

Aaron Lelevier

Python, Django, EmberJs, AngularJs, and some Dev Ops. Prior to being a full-time python/django backend developer, I was a senior database analyst with the Microsoft stack, and MSSQL. "If it was easy, everybody would do it!" -Eric Thomas Last, but not least... a little inspiration for those of you who are interested! #YouOweYou Eric Thomas video

Updated on August 02, 2022

Comments

  • Aaron Lelevier
    Aaron Lelevier almost 2 years

    I have been reading up and learning about Docker, and am trying to correctly choose the Django setup to use. So far there is either:

    Docker Compose or Dockerfile

    I understand that Dockerfiles are used in Docker Compose, but I am not sure if it is good practice to put everything in one large Dockerfile with multiple FROM commands for the different images?

    I want to use several different images that include:

    uwsgi
    nginx
    postgres
    redis
    rabbitmq
    celery with cron
    

    Please advise on what are best practices in setting up this type of environment using Docker.

    If it helps, I am on a Mac, so using boot2docker.

    Some Issues I've had:

    1. Docker Compose is not compatible with Python3
    2. I want to containerize my project, so if one large Dockerfile is not ideal, then I feel I'd need to break it up using Docker Compose
    3. I am ok to make the project Py2 & Py3 compatible, so am leaning towards django-compose
  • Aaron Lelevier
    Aaron Lelevier about 9 years
    do you use docker-compose in production or only dev? Thanks for your help.
  • Martin Thoma
    Martin Thoma almost 7 years
    @booyaa Could you please elaborate on that?
  • mpowered
    mpowered over 6 years
    @sg the answer is that the question is ill-formed based on lack of understanding of Docker vs Docker Compose. Succinctly explaining how the two interact is probably the best answer I can think of.
  • M A Hossain Tonu
    M A Hossain Tonu over 6 years
    Thanks for bringing up the issue. Can you please add some more of what was fixed for production safety at 1.11?
  • Peter Branforn
    Peter Branforn about 6 years
    I see this kind of docs missing in most recently released tools/solutions/frameworks on the web. I guess it is hard to see why someone needs it in case you already know/invented the solution yourself.
  • Joe Phillips
    Joe Phillips about 6 years
    What's missing from this answer is more info about compose. Does the compose script call the dockerfile? How does it know what to compose? The example shows image: redis but is that from dockerhub? local directory? etc... this makes it confusing for a newb like me to understand what's really going on
  • Amiga500
    Amiga500 almost 6 years
    Could you elaborate more on accessing the db by the name?
  • n2o
    n2o almost 6 years
    On which part? In docker-compose it is trivial, because it is the normal way when defining your services to give it a name and have it accessible without needing to configure it. In our CI I am creating a network, create the container in this network and give them a name. Then you have them also accessible by their name inside the containers (not from the host)
  • Amiga500
    Amiga500 almost 6 years
    In composer I mean. So I link the images in composer, and in my App config instead of IP, I targer the MySQL by whatever name I gave it in composer file?
  • n2o
    n2o almost 6 years
    That's correct. You don't even have to specify a link. They are linked by default if the network is not differently specified. In this example the service "web" can ping the host "redis" by its name "redis"
  • Naruto Sempai
    Naruto Sempai over 5 years
    @Chris It's almost as if there is 3 years worth of knowledge between this and the accepted answer.
  • Pansoul
    Pansoul about 5 years
    This response insists on the multi-container purpose of docker compose but there are probably many other scenarios you want to use docker compose even with only one container such as specifying the port you want your container run on (not possible in dockerfile afaik).
  • kalehmann
    kalehmann almost 5 years
    @omidrezabagheri your edit moved the declaration of the logvolume01 inside the redis service - resulting in an invalid config. If you are not familar with volume declarations outside of service definitions, take a look at: docs.docker.com/compose/compose-file/… You may want to rollback that edit.
  • atline
    atline over 4 years
    I wonder if any good reason for me to use docker-compose up if just one service in my situation? Another word, compare with docker run xxx, any benefit if I use docker-compose up?
  • Oldyoung
    Oldyoung over 4 years
    Thanks for the answer! Dockerfile specify config for image, and docker-compose.yml assemble images together.. One thing I want to point out is that, If docker-compose.yml only use public image (pulling image from the internet/docker hub), then one don't need a Dockerfile to run command docker-compose up.
  • go2null
    go2null over 4 years
    @atline see Pansoul's response to stackoverflow.com/a/45549372/3366962 on the benefits of using docker-compose for single containers
  • Paul Razvan Berg
    Paul Razvan Berg over 4 years
    If you connect the local machine and the container via the 4001 port, how come you can connect redis via 6379? Or is it that inside the node app, you are already in the container, and you're calling the redis server from within the container?
  • KrishPrabakar
    KrishPrabakar over 4 years
    @PaulRazvanBerg you "Or" part is correct (and 6379 is the default port of Redis).
  • maulik13
    maulik13 about 4 years
    The examples for docker-compose.yml helped me answer some of the questions I had about docker-compose. The accepted answer is not useful, especially for people who are new to docker.
  • Vishnu
    Vishnu almost 4 years
    Oh Mahn, you should deserve the accepted answer.. crystal clear explanation. Thanks a ton.
  • Satish Patro
    Satish Patro about 3 years
    does docker-compose internally creates dynamic 'docker pull' & 'docker run' etc to run a service?
  • acat
    acat over 2 years
    one gotcha I think is worth highlighting, especially in response to the question "is compose for production or dev?" (answer IMO: depends on use-case, but usually dev). docker-compose is what you want to use for managing multiple containers on a single VM. If you need to manage and network containers across multiple VMs, you want something like kubernetes or docker swarm. Check out some common use-cases of docker-compose on the docker website