├── .gitignore ├── .dockerignore ├── Dockerfile ├── docker-compose.yml ├── index.js ├── nginx.conf ├── package.json ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .git 3 | .vscode 4 | node_modules 5 | *Dockerfile* 6 | *docker-compose* 7 | .dockerignore 8 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:latest 2 | 3 | USER node 4 | RUN mkdir /home/node/app 5 | WORKDIR /home/node/app 6 | COPY --chown=node:node package.json package-lock.json ./ 7 | RUN npm ci 8 | COPY --chown=node:node . . 9 | 10 | CMD ["node", "index.js"] 11 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | app: 3 | build: . 4 | init: true 5 | nginx: 6 | image: nginx:latest 7 | ports: 8 | - "80:80" 9 | volumes: 10 | - ./nginx.conf:/etc/nginx/nginx.conf:ro 11 | depends_on: 12 | - app 13 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const os = require('os'); 3 | 4 | const PORT = 3000; 5 | const hostname = os.hostname(); 6 | 7 | const server = http.createServer(async (req, res) => { 8 | return res.end(`Hello world! My hostname/container ID is: ${hostname}`); 9 | }); 10 | 11 | server.listen(PORT, () => { 12 | console.log('Server started at', PORT); 13 | }); 14 | -------------------------------------------------------------------------------- /nginx.conf: -------------------------------------------------------------------------------- 1 | user nginx; 2 | worker_processes 1; 3 | 4 | error_log /var/log/nginx/error.log warn; 5 | pid /var/run/nginx.pid; 6 | 7 | events { 8 | worker_connections 1024; 9 | } 10 | 11 | http { 12 | server { 13 | listen 80; 14 | 15 | location = /favicon.ico { 16 | return 404; 17 | } 18 | 19 | location / { 20 | proxy_pass http://app:3000; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scaling-nodejs-with-docker", 3 | "version": "1.0.0", 4 | "description": "Sample Node.js project showing how to horizontally scale with Docker", 5 | "author": "Maxim Orlov (https://github.com/Maximization)", 6 | "main": "index.js", 7 | "license": "MIT", 8 | "scripts": { 9 | "start": "node index.js" 10 | }, 11 | "dependencies": {}, 12 | "devDependencies": {} 13 | } 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Scaling Node.js with Docker 2 | 3 | This project shows how to scale a Node.js application with Docker Compose and use multiple CPU cores. It's similar to cluster mode in PM2, but with a few fundemantal differences. Read more in the accompanying article — [From PM2 to Docker: Cluster Mode](https://maximorlov.com/from-pm2-to-docker-cluster-mode/). 4 | 5 | ## Getting started 6 | 7 | 1. Clone this repository `git clone https://github.com/Maximization/scaling-nodejs-with-docker.git && cd scaling-nodejs-with-docker` 8 | 9 | 2. Start the application stack scaled to four app instances `docker-compose up -d --scale app=4` 10 | 11 | 3. Visit `http://localhost` in your browser 12 | 13 | 4. Hit refresh and you will see sequential responses from each application instance 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Maxim Orlov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | --------------------------------------------------------------------------------