Skip to main content

Dive into Docker with Node.js: Building Efficient and Portable Applications with Docker Compose

 Dive into Docker with Node.js: Building Efficient and Portable Applications with Docker Compose

This comprehensive guide takes you through the exciting journey of utilizing Docker and Docker Compose for efficient Node.js development. We'll cover essential aspects like installation prerequisites, Docker Compose configuration, image creation with Dockerfiles and dockerignore files, container management, port exposure, stopping Docker image processes, best practices, and an example file structure.


Setting Up Docker and Docker Compose

On Ubuntu 20.04:


1. Update and Install Required Packages:


sudo apt update

sudo apt install ca-certificates curl gnupg lsb-release


2. Add Docker GPG Key:


curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg


3. Add Docker Repository:


echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null


4. Install Docker Engine:


sudo apt update

sudo apt install docker-ce docker-ce-cli containerd.io


5. Verify Docker Installation:


docker version


6. Install Docker Compose (Optional):

Using the Official Docker Repository:


sudo apt install docker-compose-plugin


7. Make Docker Compose Executable:


sudo chmod +x /usr/local/bin/docker-compose

Be very cautious while executing these commands!


8. Verify Docker Compose Installation:


docker-compose version


Additional Notes:

The recommended version of docker-compose is 2.4.1 or later.

Consider adding your user to the docker group if necessary:

sudo usermod -aG docker $USER

Be very cautious while executing these commands!

Restart your system if prompted and enjoy using Docker and Docker Compose!


Troubleshooting:

If you encounter any issues during installation, refer to the official Docker and Docker Compose documentation for troubleshooting guides:


On Windows:


On macOS:


Creating Docker Images with Dockerfile and Dockerignore

Dockerfile with Node.js and Dockerignore:


# Base Image

FROM node:lts-alpine


# Working Directory

WORKDIR /app


# Copy package.json

COPY package*.json ./


# Install Dependencies

RUN npm install


# Copy Application Files

COPY . .


# Dockerignore File

.dockerignore

node_modules/


# Expose Port

EXPOSE 3000


# Start Command

CMD [ "node", "server.js" ]


Explanation:

  • Base Image: Specifies the base image for your container. We're using node:lts-alpine, a lightweight Node.js image based on Alpine Linux.
  • Working Directory: Sets the working directory within the container to /app.
  • Copy package.json: Copies the package.json and package-lock.json files from your project directory to the /app directory within the container.
  • Install Dependencies: Runs the npm install command to install the Node.js dependencies specified in the package.json file.
  • Copy Application Files: Copies all files and directories from your project directory to the /app directory within the container, except for files and directories mentioned in the .dockerignore file.
  • Dockerignore File: Tells Docker to ignore the .dockerignore file itself and the node_modules directory when building the image.
  • Expose Port: Exposes port 3000 within the container.
  • Start Command: Defines the default command to run when the container starts (in this case, node server.js).


File Structure and server.js:


project_root/

├── Dockerfile

├── .dockerignore

├── package.json

└── server.js


// server.js

const express = require('express');

const app = express();

const port = process.env.PORT || 3000;


app.get('/', (req, res) => {

  res.send('Hello from your Dockerized Node.js application!');

});


app.listen(port, () => {

  console.log(`Server listening on port ${port}`);

});


Explanation:

server.js is included in the image and executed by the CMD instruction in the Dockerfile.
This file starts the Node.js server and listens on port 3000.


Building and Running the Docker Image:


docker build -t my-node-app .

docker run -d -p 3000:3000 my-node-app

These commands build and run the image, exposing port 3000 and making the application accessible at http://localhost:3000.


Exposing Ports and Dockerfile Best Practices:

  • Use the EXPOSE instruction in the Dockerfile or the -p flag during container creation to expose ports.
  • The default port for Node.js applications is 3000.
  • Consider using volumes to mount specific directories from your host machine into the container for easier development and code updates.
  • Define environment variables for configuration using the ENV instruction.
  • Use multi-stage builds to optimize image size and improve build times.


Stopping the Running Docker Image Process:

Once you have built and are running your Docker image, there are several ways to stop its container:


Using Docker Stop:

This is the most common method, and you can stop a container by its container ID or name:


# Stop the container by ID:

docker stop <container-id>


# Stop the container by name:

docker stop my-node-app

You can stop multiple containers at once:


docker stop $(docker ps -q)


Using Docker Kill:

The docker kill command stops a container immediately, without waiting for the container to gracefully exit:


# Stop the container by ID:

docker kill <container-id>


# Stop the container by name:

docker kill my-node-app


Use docker kill -s SIGKILL <container-id>

#for immediate termination without any cleanup actions.

Checking Container Status:

To verify if a container is stopped, use the docker ps command with the -a flag to list all containers, including stopped ones.


Additional Tips:

You can restart a stopped container using the docker start command with the container ID or name.

To remove a stopped container, use docker rm <container-id>.


Restart Policy:

When creating Docker containers, you can set a restart policy to determine how the container should be restarted automatically in case of unexpected termination.


Supported policies include:

  • no: Do not restart the container.
  • on-failure: Restart the container only if the previous process exited with a non-zero exit code.
  • always: Always restart the container regardless of the exit code.
  • unless-stopped: Restart the container only if it was not stopped intentionally.


Example with Restart Policy:


docker run --name my-node-app -d --restart unless-stopped -p 3000:3000 my-node-app

This command starts the my-node-app container with the following settings:

  • -d: Run in detached mode.
  • --restart unless-stopped: Automatically restart the container if it stops unexpectedly.
  • -p 3000:3000: Expose port 3000 inside the container to the host machine on port 3000.
  • my-node-app: The name of the image to use.

Remember that restarting a container may not be appropriate in all situations, and you should carefully consider the implications of using a restart policy before applying it.


Configuring Docker Compose:

Create a file named docker-compose.yml in the root directory of your existing Node.js project. This file defines the services, networks, and volumes for your application.


Example docker-compose.yml for Node.js Application:


version: '3.8'


services:


  node:

    build: .

    ports:

      - "3000:3000"

    volumes:

      - ./app:/app

    environment:

      - NODE_ENV=development


Explanation:

  • version: Specifies the Docker Compose file format version.
  • services: Defines the services in your application:
  • node: The Node.js application service:
  • build: instructs Docker Compose to build the image from the current directory (.).
  • ports: maps the container's port 3000 to the host's port 3000, making the application accessible.
  • volumes: mounts the app directory from the host to the /app directory within the container.
  • environment: sets the `NODE_ENV` environment variable to development.


Scaling and Stopping Services with Docker Compose:


Scale the Node.js service:


docker-compose scale node=3


Stop the Node.js service:


docker-compose stop node


Start stopped services:


docker-compose start node


Conclusion

Docker Compose provides a convenient and efficient way to manage multi-container applications, even when focusing solely on a single service like a Node.js application. By leveraging Docker and Docker Compose, you can streamline your development workflow and deploy your applications with greater flexibility.


Remember to further customize your docker-compose.yml file to match your specific project requirements and explore additional Docker Compose features to optimize your deployment process.


Additional Resources:

Comments

Topics

Show more