Skip to content

Instantly share code, notes, and snippets.

@mocon
Last active October 13, 2017 18:34
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mocon/0b567f77b693d73c41db5dcc6cacc8be to your computer and use it in GitHub Desktop.
Save mocon/0b567f77b693d73c41db5dcc6cacc8be to your computer and use it in GitHub Desktop.
Dockerfile basics

Node.js on Docker

Dockerfile basics

A Dockerfile is a simple set of instructions that describe how to run an application on a specific operating system (such as Ubuntu). The Dockerfile allows you to package up the following items into a self-contained package called a container:

  • A base image of the preferred operating system (using FROM)
  • Your application code
  • Dependencies
  • Other files
  • Your preferred port to run the application on
  • One command to run your application (using CMD)

Why should I care?

Traditionally, developers have deployed their application code only onto a remote server (such as an AWS EC2 instance, a Heroku "dyno", or a Digital Ocean "droplet") using ssh.

Since the developer only deployed their application code, and not a description of the underlying operating system/environment, they might not know all the specifics of the deployed environment (and its differences from their local one), leading to inconsistent or unexpected application behavior (for example, "it works on my local" but breaks when deployed).

Docker solves this problem by bundling the application code along with a description of the environment to run it in. A container is easy to run and test locally, and if it works on your local computer, you can be sure it will work in production, since the container will be run the exact same way (following the Dockerfile instructions), no matter where it's running.

Goals for the tutorial

  • Set up a very simple Node.js application and run it locally via node index.js
  • Write a Dockerfile describing how to run our application
  • Build a Docker image from our Dockerfile
  • Run our Docker image as a container, and observe that the app works the same as when run locally

Requirements

Example Dockerfile

# Use official Node.js
FROM node:8.6.0

# Install yarn
RUN curl -o- -L https://yarnpkg.com/install.sh | bash

# Copy files
COPY package.json .
COPY yarn.lock .
COPY index.js .

# Install dependencies
RUN yarn install

# Start app on port 8000
EXPOSE 8000
CMD node index.js

Tutorial

1. Set up Node project

Make project directory and cd into it, then initialize git and yarn:

mkdir dockerfile-tutorial && cd $_
git init
yarn init -y

Create the main file index.js:

touch index.js

Create the .gitignore file, and add the node_modules directory to it:

touch .gitignore

2. Add dependencies

Add express (a server, docs here: expressjs.com), and moment (for date formatting, docs here: momentjs.com) as dependencies, using their latest exact versions:

yarn add express moment -E

3. Write simple app

In index.js:

const express = require('express');
const moment = require('moment');

const app = express();
const PORT = 8000;

app.listen(PORT, () => {
    const currentDateTime = Date.now();
    const formattedDate = moment(currentDateTime).format('dddd, MMMM Do YYYY, h:mm:ss a');
    
    console.log(`Example app listening on port ${PORT}, started\n${formattedDate}.`);
});

Run the app with node index.js. The output should look something like this:

Example app listening on port 8000, started
Wednesday, October 11th 2017, 3:28:59 pm.

The app is running locally! Now, let's run it in a Docker container.

4. Write a Dockerfile to describe the app

Now that our app is working locally, we want to describe how to run it in our Dockerfile.

Here are the steps we'll need to follow to get the app working inside a container:

  • Start from a base image containing Node.js
  • Install Yarn package manager inside the container
  • Copy our project's files into the container
  • Use yarn install to install the dependencies inside the container
  • Tell the container to listen to a specific port (for example, 8000)
  • Tell the container to run node index.js to run the project's main file with Node.js

First, create a Dockerfile, making sure to use a capital "D":

touch Dockerfile

Choose a base image to start from. Check hub.docker.com for a base Node image. Search for "node", then find the "official" node images, and select the tag matching your local version.

Note that many different base images are available on Docker Hub, for many different languages and frameworks.

Check local Node version:

node -v

Select the same tagged version of node, and add it to the Dockerfile using FROM (docs here):

# Use official Node.js
FROM node:8.6.0

Install yarn into the container using RUN (docs here) to run a bash command (following instructions here):

# Install yarn
RUN curl -o- -L https://yarnpkg.com/install.sh | bash

Copy our application's files into the container using COPY (docs here):

# Copy files
COPY package.json .
COPY yarn.lock .
COPY index.js .

Install the project's dependencies by running yarn install:

# Install dependencies
RUN yarn install

Tell the container to listen to a port at runtime using EXPOSE (docs here), and run the application using CMD (docs here):

# Start app on port 8000
EXPOSE 8000
CMD node index.js

Our Dockerfile is complete! Time to build it.

5. Use our Dockerfile to build an image

Use docker build (docs here) to build an image called dockerfile-tutorial-image from the instructions in our Dockerfile:

docker build -t dockerfile-tutorial-image .

Note that if we run this command again, it will be extremely fast, since any unchanged layers in the image will use their cached versions.

6. Run our image as a container

Use docker run (docs here) to run our image that we called dockerfile-tutorial-image:

docker run -p 8000:8000 dockerfile-tutorial-image

To stop the container, from another Terminal, run:

docker ps
docker kill <unique_id>

Final notes

This was a brief introduction to Docker and Dockerfiles, and did not cover many of the more advanced features. Some other information to note:

  • Consult Dockerfile best practices for more detailed information
  • Try not to include build tools or unminified source code in the container. For example, if you build your project using yarn build from src to build, consider deleting src once the code has been built.
  • Use environment variables to pass sensitive data into the container, instead of including them inside
  • Read about Amazon ECS / ECR cluster management
  • Read about using IAM roles with containers
  • Experiment with different base images on Docker Hub, or publish your own
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment