Introduction

Docker is a platform for developing, shipping and running applications. Docker helps solve the issue of "It worked on my machine, don't know what happened here." as it bundles up the application and its associated dependencies together as a container.

Why Docker ?

In general, multiple computers running the same appliation are susceptible to errors related to dependency version differences, enviornment configuration issues etc.

By using Docker, we can easily avoid errors related to versioning, missing dependencies. Files similar to requirements.txt, package.json, gemfiles are always coined together (Context of Web Apps). This ensures consistency on every build on every system.

The enviornment setup is easier using docker as it is lightweight, portable, testable on various operating systems. Also, Docker container runs on any machine that supports the container’s runtime environment.

Dockerfile

A Dockerfile is a blueprint for buiding a docker image.

Note: This post is in context for Node.js applications.

  • First, we must define from which image we would like to build using the FROM instruction.
FROM node:14

# Alternate
FROM node:version-alpine
  • Define the working directory for your application (where the code resides) using WORKDIR instruction.
WORKDIR /app
  • Now we need to install all dependencies from the package.json file. We need to copy the package.json and the lockfile to our WORKDIR.
# A wildcard to include both package.json and package-lock.json
# Second argument indicates the workdir
COPY package\*.json .

RUN npm install
  • Now we need to copy the source code using COPY instruction. COPY . . copies all the files in the present directory (except the ones defined in .dockerignore) to the WORKDIR.
COPY . .
  • Expose the PORT that your app uses.
EXPOSE 8000
  • Define the command to run your app using CMD
CMD ["node","app.js"]

Difference between CMD and RUN

RUN

This is an image build step. The state of the container after a RUN command is committed to the container image. A dockerfile can have multiple RUN steps that layer on top of one another in the build process.

Eg. RUN npm install command would install all dependencies inside the container, this final state is committed to the container image.

CMD

Lets you define a default command to run when your container starts. This is a run-time operation. Docker uses the final CMD defined in the dockerfile to run.

.dockerignore file

We need to create a .dockerignore file in the same directory as your Dockerfile to prevent your local modules, debug logs, lint files, etc. from being copied onto our Docker image.

Node.js Dockerfile

# Specify Image
FROM node:alpine

# Create App Directory
WORKDIR /app

# Copy Dependencies
COPY package*.json ./

# Install App Dependencies
RUN npm install

# Copy App Source Code
COPY . .

# Expose port
EXPOSE 8080

# Start Application
CMD [ "npm", "start" ]

To build the docker file use,

docker build .

# With Tags
docker build . -t <your username>/node-app

To view created images,

docker images

# Example
REPOSITORY                      TAG        ID              CREATED
node                            alpine     xxxxxxxxxxxx    5 days ago
<your username>/node-app    latest     xxxxxxxxxxxx    1 minute ago

To run the image use,

  • -p flag redirects a public port to a private port inside the container.
  • -d runs the container in detached mode, leaving the container running as a daemon process.
docker run -p 5000:8000 -d <your username>/node-app

To see logs,

docker logs <container-id>

Cheers!

Pic Credits: Photo by Victoire Joncheray