This is in continuation of our previous blog, where we deployed a simple app using docker. In this blog, we will see how to use docker-compose and whats the purpose of the same.
To continue from the previous blog, let’s assume we need to add a database like MongoDB to our Node.js app.
To setup mongo, we need a separate image https://hub.docker.com/_/mongo
Just to clarify, there is another option you can think of that is to install MongoDB using apt-get in our previous container itself. But this a very bad practice in docker. Docker images should be as small as possible, and one image should only have one process.
So the first task is to install docker-compose https://docs.docker.com/compose/install/
Once you have installed, create a docker-compose.yml file. This file has various instructions which, you can see here https://docs.docker.com/compose/compose-file/
version: '3.7'
services:
api:
image: api
build: .
ports:
- 5000:3000
volumes:
- ./src:/workspace/src
mongodb:
image: mongo
restart: always
Here we define two services; the first is API, which is our app, and the second one is MongoDB, which is the mongo image.
We also define the ports and volume in this.
Next, in our Dockerfile we add mongo to our Node.js app.
FROM node:13
WORKDIR /workspace
COPY package.json /workspace
#COPY index.js /workspace
VOLUME [ "/workspace/src" ]
RUN npm install
RUN npm install -g nodemon
RUN npm install mongodb --save
EXPOSE 3000
CMD [ "nodemon" ,"src/index.js" ]
const express = require('express')
const app = express()
const port = 3000
const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
// Connection URL
const url = 'mongodb://mongodb:27017';
// Database Name
const dbName = 'myproject';
// Use connect method to connect to the server
MongoClient.connect(url, function(err, client) {
assert.equal(null, err);
console.log("Connected successfully to server");
const db = client.db(dbName);
client.close();
});
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
P.S right now, I am installing packages directly via Dockerfile, but this not a proper practice at all. It would be best if you do this via package.json only.
Once you have completed the above procedure you are now ready to build.
sudo docker-compose build
This will build your image and also fetch MongoDB.
Next
sudo docker-compose up
If you notice the logs.
You can also run the container in background using
sudo docker-compose up -d
sudo docker-compose logs api
Sometime you can get this error
This is because your Node.js app started before mongo got started. To fix this using “depends_on” in docker-compose.yml.
version: '3.7'
services:
api:
image: api
build: .
ports:
- 5000:3000
volumes:
- ./src:/workspace/src
depends_on:
- mongodb
mongodb:
image: mongo
restart: always
So as you can see, you can very easily manage multiple images via docker-compose and use this for development as well as production.
There are many other advanced configurations possible with docker-compose like using a password for MongoDB, how to expose a port for MongoDB, and access it via UI tools, etc. You can pass environment variables using docker-compose.yml as well.
Also, it is to note that in the above docker-compose, we never exposed MongoDB port to an external system. So the MongoDB is local only in the apps internal network!