Introduction
Microservices design, in conjunction with containerization and API gateways, provides a scalable and efficient option for modern software development. In this technical article, we will look at how to build microservices with Docker and use Nginx as an API gateway. We'll walk you through creating Dockerfiles for the users and products microservices, creating a docker-compose.yml file, and configuring Nginx as the API gateway.
Prerequisites:
Basic understanding of microservices architecture.
Familiarity with Docker and containerization concepts.
Knowledge of Nginx and API gateway principles.
Docker and Docker Compose are installed on your machine.
Setting up the Project Structure
Before diving into building microservices, let's set up the project structure. Create a root directory for your project and organize it as follows:
project-root/
├── dockerfiles/
│ ├── users/
│ │ └── Dockerfile
│ ├── products/
│ │ └── Dockerfile
│ ├── nginx/
│ │ └── Dockerfile
│ └── mongo/
│
├── nginx.conf
└── docker-compose.yml
Building Microservices with Docker
To containerize each microservice, we will create Dockerfiles. Let's create Dockerfiles for the users and products microservices.
Dockerfile for the Users Microservice:
# /users/Dockerfile
FROM node:latest
RUN npm i -g nodemon
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . /usr/src/app
EXPOSE 3001
CMD ["npm", "run", "dev"]
Dockerfile for the products Microservice:
# /products/Dockerfile
FROM node:latest
RUN npm i -g nodemon
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . /usr/src/app
EXPOSE 3002
CMD ["npm", "run", "dev"]
The Dockerfile provided for the product's microservice is used to create the service's Docker image. Let's go over each step:
FROM node: latest : This line makes the Docker image's base image the most recent version of the official Node.js image. It ensures that the product's microservice is built on a dependable and current Node.js runtime environment.
RUN npm i -g nodemon: This command installs the nodemon package in the Docker image globally. Nodemon is a powerful utility that restarts the Node.js application automatically when changes are detected. It simplifies the development process by removing the requirement for manual restarts.
RUN mkdir -p /usr/src/app: Within the Docker image, this line creates the directory /usr/src/app. This directory acts as the products microservice's working directory. It gives the application code and related files a clean and ordered home.
WORKDIR /usr/src/app : This instruction changes the working directory for subsequent Dockerfile instructions to /usr/src/app. It assures that all following commands execute within this directory environment, which simplifies subsequent file operations and instructions.
COPY package\ .json ./ :* copies the package.json and package-lock.json (if present) files from the current directory to the Docker image's /usr/src/app directory. Docker may take use of layer caching during the build process by copying the dependency files individually, enhancing build performance.
RUN npm install. : This command installs the dependencies specified in the Docker image's package.json file. It enables the installation of all essential packages and libraries, resulting in a self-contained environment for the product's microservice.
COPY . /usr/src/app : copies the full contents of the current directory to the Docker image's /usr/src/app directory. This contains the source code files for the application, allowing the Docker image to contain the whole codebase required to run the product's microservice.
EXPOSE 3001 : This instruction acts as documentation, explaining that the container will listen on port 3001. Although it does not publish the port to the host system, it shows the intended port for contacting the users microservice within the container.
CMD. ["npm", "run", "dev"]: This command specifies the default command to run when the Docker container starts. In this case, it executes the npm run dev script, which is typically used to start the Node.js application in development mode. The development mode enables capabilities such as auto-reloading and improved error logging, which aid in the development and debugging processes.
Configuring Docker Compose for Microservices
Create a docker-compose.yml file in the project root directory to define the composition of microservices. Here's the configuration for users and products microservices with Mongo database and Nginx
docker-compose.yaml
version: "1"
services:
mongo:
container_name: ms_mongo
image: mongo:latest
ports:
- "27017:27017"
volumes:
- "./mongo/db:/data/db"
nginx:
build: ./nginx
container_name: ms_nginx
depends_on:
- users
- products
- shopping
ports:
- "80:80"
users:
build: ./users
container_name: ms_users
env_file:
- .env
environment:
- loglevel = none
- PORT = process.env.PORT
- MONGODB_URI = process.env.MONGODB_URI
volumes:
- "./users:/src/app"
working_dir: "/src/app"
restart: always
ports:
- "3001:3001"
depends_on:
- mongo
products:
build: ./products
container_name: ms_products
env_file:
- .env
environment:
- loglevel = none
- PORT = process.env.PORT
- MONGODB_URI = process.env.MONGODB_URI
volumes:
- "./products:/src/app"
working_dir: "/src/app"
restart: always
ports:
- "3002:3002"
depends_on:
- mongo
Configuring Nginx as an API Gateway
To use Nginx as an API gateway, we need to create a Dockerfile and an Nginx configuration file.
Creating the Dockerfile for Nginx:
FROM nginx
LABEL maintainer="francis"
COPY nginx.conf /etc/nginx/nginx.conf
Creating the Nginx Configuration File
Create a file named nginx.conf
in the project root directory and populate it with the provided Nginx configuration.
nginx.conf
worker_processes 4;
events { worker_connections 1024; }
http {
server {
listen 80;
charset utf-8;
server_name localhost;
location / {
proxy_pass http://products:3002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location /api/v1/users {
rewrite ^/users/(.*)$ /$1 break;
proxy_pass http://users:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
}
Deploying Microservices with Docker and Nginx
With the Dockerfiles, docker-compose.yml, and Nginx configuration ready, we can deploy the microservices.
To run the microservices and Nginx, execute the following command:
docker-compose up --build
Conclusion
We investigated the process of creating microservices with Docker and using Nginx as an API gateway. We learned how to develop Dockerfiles for user and product microservices, as well as how to configure Docker Compose and deploy the system. The combination of Docker and Nginx provides a powerful solution for developing scalable and efficient microservices architectures.