I'm trying to set up a Node.js app on Docker multiple containers. My app is currently on one Ubuntu DO droplet & uses:
I need to dockerize the different parts, one for each container obviously, then use Docker-Compose (Previously known as Fig) to simply describe the different containers & setup the links between them.
I'm steal unclear about the multi-container appraoch.
One for nginx
one for Node.js & my express app
one for MySql
and one for Redis
How would the Docker-compose.yml will look like? I'm guessing the nginx, mysql & redis will be unmodified official images? While the node.js will have a build directive to point to a Dockerfile, which will note it is based on the node.js official image along with configuration instructions? I will need to configure / provision mysql & redis for example so does it mean that each needs to be separate with its own Dockerfile?
What would be the way to link between the containers? use volumes to copy files into them, setting ports, adjusting the hosts file to map some.domain.com to the nginx ip?
I will then need to install globally some npm packages like nodemon & PM2 and set some cron jobs... (on the Node.js container?)
here is a first draft, I would appreciate any help to better understand this new setup:
Docker-compose.yml
nginx:
image: nginx
links:
- "node"
node:
build: .
volumes:
- "app:/src/app"
ports:
- "3030:3000"
links:
- "db:mysql"
db:
image: mysql:5.6
environment:
- MYSQL_ROOT_PASSWORD=mypassword
Dockerfile
FROM node:0.12
RUN mkdir /src
RUN npm install nodemon pm2 -g
WORKDIR /src
ADD app/package.json /src/package.json
RUN npm install
ADD app/nodemon.json /src/nodemon.json
EXPOSE 3000
CMD npm start
I'm using this simple project as a base, though my app needs
Before the configuration of docker-compose part, you must decide on the architecture of the system.
The parts you have -
Additional infrastructure considerations -
For a single instance that will run all the components, you probably don't even need a load balancer - so unless you need to serve static files alongside your application, there is little sense here to have nginx because it wouldn't be doing anything useful.
When you have multiple containers running your express.js application either on one instance (for multi-core/CPU) or multiple instances then you need to have some kind of load balancing going on, maybe using nginx.
Handling data inside the container is not recommended since the container filesystem is not very good at handling highly mutating data. So for MySQL and Redis you probably want to have external mount points where the data resides.
Your Express.js application needs configuration of which Redis and MySQL servers it needs to connect with, this can be done using Docker links.
Thus, your Docker Compose will look something like this -
redis:
image: redis
volumes:
- /data/redis:/data
mysql:
image: mysql:5.6
environment:
- MYSQL_ROOT_PASSWORD=verysecret
volumes:
- /data/mysql:/var/lib/mysql
application:
image: node:0.12
working_dir: /usr/src/myapp
volumes:
- /src/app:/usr/src/myapp
ports:
- 80:3000
links:
- redis
- mysql
This assumes you will store the data of MySQL and Redis on the host filesystem in /data
, and your application on the host filesystem is at /src/app
.
I recommend you look for the Docker Compose YAML file reference for all the various options that can be used https://docs.docker.com/compose/yml/.
Since the images used are the blessed images from Docker HUB, their readme files are important to take note of for more configuration -
Adding more instances of the application is easy, but then you will need to add nginx to load balance the incoming traffic to the multiple application containers.
Then when you want to run this kind of setup using multiple hosts, it becomes much more complex since docker-links will not work and you need another way to discover the container IP addresses and ports. And a load balancer will be required to have a single endpoint that accepts traffic for multiple instances of the application. Here I would recommend to take a good look on https://consul.io for help.