Introduction To Docker Compose
Tags: tutorial, docker, devops, webdev
Published: 2020-12-29 10:12:46

In the [last post](https://dev.to/rinkiyakedad/dockerizing-the-mern-stack-without-docker-compose-17m6), I showed you how you could dockerize a MERN app. The process required configuring three containers and using three different commands to start them. And if you remember, the commands themselves were also quite long. All of this becomes quite troublesome if you have to do it each time you want to start working.

This is where Docker Compose comes into the picture. 

To put it in extremely simple terms Docker Compose will provide us two simple commands which we can use to start and stop all the required containers in the desired way. The commands being `docker-compose up` and `docker-compose down` respectively. Apart from this, we will write a `docker-compose.yaml` file which will have the instructions related to the commands we would like to run.


Now that you have an idea of what docker-compose is let's get into action and see how we can write a docker-compose file. I'll be building upon what I talked about in the previous post, so if you haven't checked that out I highly suggest you do.

So let me first show you what our final file would look like and then I'll go on explaining in detail. Do note that the docker compose file is **not** a replacement for the dockerfiles we wrote earlier. We still would be absolutely needing them to build our images. I'll assume while writing this docker-compose file that our folder structure is something like this:
```
├── frontend
│   ├── Dockerfile
│   └── otherStuff
├── backend
│   ├── Dockerfile
│   └── otherStuff
├── env
│   ├── backend.env
│   └── mongo.env
└── docker-compose.yaml
```

If that is the case then our `docker-compose.yaml` file would look like this:
```
version: '3.8'
services:
  mongodb:
    image: 'mongo'
    volumes:
      - data:/data/db
    env_file:
      - ./env/mongo.env
  backend:
    build: ./backend
    ports:
      - '80:80'
    volumes:
      - ./backend:/app
      - /app/node_modules
    env_file:
      - ./env/backend.env
    depends_on:
      - mongodb
  frontend:
    build: ./frontend
    ports:
      - '3000:3000'
    volumes:
      - ./frontend/src:/app/src
    stdin_open: true
    tty: true
    depends_on:
      - backend

volumes:
  data:
```


Before I start to explain this I recommend you go have a look at how our dockerfiles looked in the [previous post](https://dev.to/rinkiyakedad/dockerizing-the-mern-stack-without-docker-compose-17m6) otherwise you might not be able to understand some stuff. With that let's begin:

1. The very first thing we specify is the version of Docker Compose we want to use. Do remember that this has nothing to do with the version of our app.

2. Then we specify the services (containers). All services are specified at the same indentation level. 
> Indentation does matter in `yaml` files so do take care of that

3. We start off by specifying the name of the service and then the other details.

4. If the service is based on an image we're getting from someplace else, like here we get the MongoDB image from [Docker Hub](https://hub.docker.com/_/mongo), then we use the `image` key else we use `build` and specify the location of the folder in which the dockerfile we want to build from is present.
> We specify the path to the folder containing the dockerfile and not the path to the dockefile itself.

5. After that we use the `ports` key to specify the posts we want to open. This is done in the same way as we do while starting our container from the terminal.
> In the case of MongoDB, we don't need a port since the backend will interact with it via the docker network.

6. We then specify the `volumes` using the same syntax as we used earlier.

7. After that instead of passing environment variables while starting the container like we did earlier, it's better to specify them in a file and then point to the location of that file using the `env_file` key.
> In the case of the React frontend we don't need any environment variables.

8. After that we've specified the `depends_on` key which basically tells docker that the container specified in depends on should be up and running before we start the present one.

9. In the frontend you will also notice two additional keys of `tty` and `stdin_open`. These are specified because we want the frontend container to run in interactive mode. These basically make up the `-it` flag we used earlier while starting the frontend individually.

10. And finally after specifying the services we have to list down all the named volumes we used while specifying volumes in any of our services. This just is something that is required by Docker in order to function. Do note that this only has to be done for the named volumes and not for anonymous volumes and bind mounts.

11. You might be wondering why we haven't specified or created a docker network anywhere here like we did the last time. That is because we don't need to do that as when using Docker Compose, Docker will automatically create a new environment for all the services specified in the compose file and will add those services (containers) to a network. There does exist a `networks` key however if you want to specify some network your container should be a part of.

And voilà! This might be a lot to comprehend if you're using docker-compose for the first time. I suggest you trying re-reading this and the [previous article](https://dev.to/rinkiyakedad/dockerizing-the-mern-stack-without-docker-compose-17m6) again in order to better understand using docker-compose. I do hope you were able to learn something useful from this.

Thanks for reading!
 
If you have any feedback for me or just want to talk feel free to connect with me on [Twitter](https://twitter.com/RinkiyaKeDad). I'll be more than happy to help you out! :D



*EDIT (02/01/2021) :*
## Series Conclusion
This would be the final post for this series. I'm thankful to everyone who took out the time to read the posts. I hope you all learned something that could help you. This was the first time I actively started writing technical blogs and I am extremely grateful for the response I got. I will be starting another series, on Kubernetes this time. If you liked this one, I'm sure you'll find that interesting too. Thank you all once again! :')