Docker is a powerful tool that allows you to create, deploy, and run applications in containers. In this post, we will show you how to Dockerize an Express.js API with separate PostgreSQL databases for testing and production, and how to configure the environment so that local changes are reflected in the container.
Prerequisites
- Node.js installed
- Docker installed
- Docker Compose installed
- An existing Node.js API (or a new project)
Creating an Express.js API
First, create a new Express.js project.
mkdir node-docker-api
cd node-docker-api
npm init -y
npm install express
npm install -D nodemon
Create an index.js
file:
const express = require('express');
const app = express();
const port = 3333;
app.use(express.json());
app.get('/', (req, res) => {
res.send(`Hello, Docker from ${process.env.NODE_ENV} server!`);
});
app.listen(port, () => {
console.log(`API of ${process.env.NODE_ENV} listening at http://localhost:${port}`);
});
Enhancing your package.json
Create two scripts in your package.json: one for "dev":"NODE_ENV=development nodemon src/index.js"
for development/testing, and another one for "start": "NODE_ENV=production node src/index.js"
for production.
{
"name": "node-docker-api",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "NODE_ENV=development nodemon src/index.js",
"start": "NODE_ENV=production node src/index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"express": "^4.19.2"
},
"devDependencies": {
"nodemon": "^3.1.4"
}
}
Creating the Dockerfile
Create a Dockerfile in the root of your project.
# Using an official Node.js base image
FROM node:20-alpine
# Working directory inside the container
WORKDIR /app
# Copying package.json and package-lock.json
COPY package*.json ./
# Installing project dependencies based on NODE_ENV
ARG NODE_ENV
RUN if [ "$NODE_ENV" = "production" ]; then npm install --omit=dev; else npm install; fi
# Copying the rest of the application
COPY . .
# Exposing the port where the application will run
EXPOSE 3333
# Setting the environment variable for development or production
ENV NODE_ENV $NODE_ENV
# Command to run the application
CMD ["sh", "-c", "if [ \"$NODE_ENV\" = 'production' ]; then npm start; else npm run dev; fi"]
Creating a .dockerignore
Create a .dockerignore
file to avoid copying unnecessary files to the Docker image:
node_modules
npm-debug.log
.dockerignore
Creating Docker Compose Files
Let's create two Docker Compose files: one for development/testing (docker-compose.dev.yaml
) and another for production (docker-compose.prod.yaml
).
docker-compose.dev.yaml
This file will contain the configuration for the development and testing environment.
services:
api:
build: .
ports:
- "3333:3333"
volumes:
- .:/app
- /app/node_modules
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://postgres:postgres@postgres:5432/devdb
depends_on:
- postgres
postgres:
image: postgres:latest
ports:
- "5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: devdb
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
docker-compose.prod.yaml
This file will contain the configuration for the production environment.
services:
api:
build: .
ports:
- "3333:3333"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://postgres:postgres@postgres:5432/proddb
depends_on:
- postgres
postgres:
image: postgres:latest
ports:
- "5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: proddb
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Setting Up the Development Environment
To reflect local changes in the container, we will use Docker Compose with volumes. The docker-compose.dev.yaml
file is already configured to mount the local working directory (.) in the container (/app), except for node_modules, which will be kept inside the container to avoid dependency conflicts.
Running the Application
Development/Testing Environment
For the development/testing environment, use the following command:
docker-compose -f docker-compose.dev.yaml up --build
Production Environment
For the production environment, use the following command:
docker-compose -f docker-compose.prod.yaml up --build
Testing the Application
Open your browser and access http://localhost:3333. You should see the message "Hello, Docker!".
Conclusion
Congratulations! You have successfully Dockerized your Express.js API, set up different PostgreSQL databases for testing and production, and configured the development environment to reflect local changes in the container. Dockerizing your applications makes the development, testing, and deployment process more consistent and easier to manage. Keep exploring Docker's features to further improve your workflow.
If you have any questions or suggestions, feel free to leave a comment below!
Thanks for reading !
Top comments (0)