Use Docker entrypoint /
and env variables

03/06/2024

Understanding Docker Entrypoints, Dockerfiles, and Environment Variables with Node.js

Docker has become an essential tool for developers looking to build, ship, and run applications consistently across different environments. In this article, we will explore how to use Dockerfiles, entrypoints, and environment variables in the context of a Node.js application. We’ll use a specific Dockerfile and entrypoint script as an example to illustrate these concepts.

1. What is a Dockerfile?

A Dockerfile is a script containing a series of instructions on how to build a Docker image. It specifies the base image, software dependencies, configuration settings, and commands to be run in the container.

Example Dockerfile

Here is an example Dockerfile for a Node.js application:

# Use an official Node runtime as a parent image
FROM arm64v8/node:14-alpine

# Set the working directory in the container
WORKDIR /app

# Copy the current directory contents into the container
COPY . .

# Update and upgrade apk package manager
RUN apk update && apk upgrade

# Install curl
RUN apk add curl

# Install ffmpeg
RUN apk add ffmpeg

# Install necessary npm packages
RUN npm install

# Install nodemon globally
RUN npm install -g nodemon

# Copy entrypoint script into the container
COPY entrypoint.sh /usr/local/bin/entrypoint.sh

# Make the entrypoint script executable
RUN chmod +x /usr/local/bin/entrypoint.sh

# Make port 3008 available to the world outside this container
EXPOSE 3008

# Define the entrypoint script to be executed
ENTRYPOINT ["entrypoint.sh"]

2. Entrypoints in Docker

The ENTRYPOINT instruction in a Dockerfile allows you to configure a container to run as an executable. Unlike the CMD instruction, which provides defaults that can be overridden, ENTRYPOINT instructions are always executed when the container starts.

In this example, we have defined an entrypoint script entrypoint.sh which will be executed every time the container starts.

Example Entrypoint Script

Here is an example of what the entrypoint.sh script might look like:

#!/bin/sh

# Check for environment variable and set command accordingly
if [ "$ENV" = "development" ]; then
  COMMAND="nodemon app.js "
elif [ "$ENV" = "production" ]; then
  COMMAND="npm run start"
fi

# Execute the command
exec $COMMAND

This script starts the Node.js application using nodemon, which is a tool that helps develop node.js based applications by automatically restarting the node application when file changes in the directory are detected if $ENV is equal to « development ».

3. Using Environment Variables

Environment variables are a way to pass configuration into your Docker containers. They can be defined in the Dockerfile using the ENV instruction or passed at runtime using the -e flag.

Defining Environment Variables in Dockerfile

In this example, environment variables are not defined in the Dockerfile, but you can easily add them using the ENV instruction:

# Define environment variables
ENV NODE_ENV production
ENV PORT 3008
Passing Environment Variables at Runtime

You can also pass environment variables to your container at runtime:

docker run -e NODE_ENV=development -e PORT=3008 my-node-app

4. Practical Example: Node.js Application

Let’s put everything together in a more concrete example. We’ll create a simple Node.js application that uses environment variables and demonstrates the Dockerfile and entrypoint script provided.

Directory Structure
my-node-app/
│
├── Dockerfile
├── entrypoint.sh
├── app.js
├── package.json
└── package-lock.json
Dockerfile
# Use an official Node runtime as a parent image
FROM arm64v8/node:14-alpine

# Set the working directory in the container
WORKDIR /app

# Copy the current directory contents into the container
COPY . .

# Update and upgrade apk package manager
RUN apk update && apk upgrade

# Install curl
RUN apk add curl

# Install ffmpeg
RUN apk add ffmpeg

# Install necessary npm packages
RUN npm install

# Install nodemon globally
RUN npm install -g nodemon

# Copy entrypoint script into the container
COPY entrypoint.sh /usr/local/bin/entrypoint.sh

# Make the entrypoint script executable
RUN chmod +x /usr/local/bin/entrypoint.sh

# Make port 3008 available to the world outside this container
EXPOSE 3008

# Define the entrypoint script to be executed
ENTRYPOINT ["entrypoint.sh"]
entrypoint.sh
#!/bin/sh

# Check for environment variable and set command accordingly
if [ "$ENV" = "development" ]; then
  COMMAND="echo 'dev mode' "
elif [ "$ENV" = "production" ]; then
  COMMAND="npm run start"
fi

# Execute the command
exec $COMMAND
app.js
const http = require('http');
const port = process.env.PORT || 3000;
const environment = process.env.NODE_ENV || 'development';

const requestHandler = (request, response) => {
    response.end(`Hello, World! Running in ${environment} mode on port ${port}.`);
};

const server = http.createServer(requestHandler);

server.listen(port, (err) => {
    if (err) {
        return console.log('something bad happened', err);
    }
    console.log(`Server is listening on ${port}`);
});
package.json
{
  "name": "my-node-app",
  "version": "1.0.0",
  "description": "A simple Node.js application",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {}
}
Building and Running the Docker Container

Build the Docker Image :


docker build -t my-node-app .

Run the Docker Container :


docker run -p 3008:3008 -e NODE_ENV=development -e PORT=3008 my-node-app

Makefile :

build:
    docker build -t my-node-app . --force-rm;

runprod:
    docker run -e ENV=production PORT=3008 -d -p 3090:3008 my-node-app

rundev:
    docker run -e ENV=development PORT=3008 -d -p 3090:3008 my-node-app

Now, if you navigate to http://localhost:3008, you should see Hello, World! Running in development mode on port 3008.

Conclusion

Understanding Dockerfiles, entrypoints, and environment variables is crucial for building robust and flexible Docker containers. By leveraging these tools, you can create containers that are not only easy to configure and deploy but also capable of handling a wide variety of use cases.

With Docker, you can ensure your Node.js applications run consistently across different environments, making your development and deployment processes more efficient and reliable.

In this example, we used a Dockerfile to set up a Node.js environment, installed necessary dependencies, and defined an entrypoint script to manage the application startup process. By utilizing environment variables, we made the application configuration flexible and easy to manage.