Docker - Dockerizing a Simple Node.js App
Tags: tutorial, showdev, docker, beginners
Published: 2022-11-30 03:45:11

##🥅Goal

The goal here was to follow the basics of what I had learned and follow instructions from an "app developer" to take and turn a Node.js app into a container image. I want to gain experience building the layers of an image so that I can make edits to layers in the future if need be.

##💯Success Criteria
Success in this case will be a Node.js application that I am able to deploy by running a single `docker container run` command.

##🧑‍🏫Instructions
I have no knowledge of Node.js, so some of it is explicitly given to me. The instructions are as follows:

> - you should use the `node` official image, with the alpine 6.x branch
> - This app listens on port 3000, but the container should listen on port 80 of the Docker host, so it will respond to [http://localhost:80](http://localhost:80) on your computer
> - Then it should use the alpine package manager to install tini: `apk add --no-cache tini`.
> - Then it should create directory /usr/src/app for app files with `mkdir -p /usr/src/app` or with WORKDIR
> - Node.js uses a "package manager", so it needs to copy in package.json file.
> - Then it needs to run 'npm install' to install dependencies from that file.
> - To keep it clean and small, run `npm cache clean --force` after the above, in the same RUN command.
> - Then it needs to copy in all files from current directory into the image.
> - Then it needs to start the container with the command `/sbin/tini -- node ./bin/www`. Use CMD to do this.

A hefty bit of instructions but also very helpful.

##🧑‍🍳Prerequisites
📍Docker Engine + CLI installed
📍[Node.js files](https://github.com/BretFisher/udemy-docker-mastery/tree/main/dockerfile-assignment-1)

<img width="100%" style="width:100%" src="https://media.giphy.com/media/wNDa1OZtvl6Fi/giphy.gif">

##⏰Time to Start
######Step 1: FROM & EXPOSE
`FROM node:6-alpine`

`FROM` initializes a new build stage and sets the base image. _This command will always be used._ In this case, we're grabbing the alpine version of Node.js v6. _Alpine builds are typically very small._

`EXPOSE 3000`

`EXPOSE` exposes the container's ports to allow access outside the container. This is needed to access the app with our web browser, since the container needs to communicate with our computer's network.

######Step 2: Install tini & WORKDIR
`RUN apk add --no-cache tini`

[tini](https://github.com/krallin/tini) is used for containerized apps and is actually requested by the app developer here, so no need to really understand it beyond that. To do this, we use the `RUN` instruction, which is used to execute a BASH command.

`WORKDIR /usr/src/app`

`WORKDIR` is a Docker instruction used to set the current working directory. It will also create the directory if it hasn't been created.

######Step 3: Copy package.json & Install Node-related Items
`COPY package.json ./`

We need to copy the package.json file into the layer so that Docker has access to it. The `COPY` instruction lets us do this. We will copy the file to our working directory, `./`

`RUN npm install && npm cache clean --force`

We also need to setup npm, which is a Node-related item requested by the dev. We will use `RUN` to let Docker know we want to run a BASH command.

######Step 4: Copy Files to Directory & Start Container
`COPY . .`

We need to copy all the files to the container so that the application can work correctly. To copy all the files within your working directory, we can use `. .`


`CMD ["/sbin/tini", "--", "node", "./bin/www"]

Lastly, we need to start the app within the container. These are the commands given to use by the application developer to actually start the Node app.

######Step 5: Build the Image
`docker build --tag app-1 .`

Now that we have our Dockerfile, let's actually build it! `docker build -t` tells Docker we're building from a Dockerfile, `app-1` is the name I'm giving it, and `.` tells docker that the Dockerfile is located within the current working directory.

![Success](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zdw62xusc33te4mxj8bt.png)

######Step 6: Run the Image
`docker container run -p 80:3000 app-1`

`docker container run` tells Docker we're starting a container image. `-p 80:3000` lets Docker open up port 80 on the host and listen in on port 3000 and `app-1` tells Docker the image we want to run is named app-1.

![Woohoo!](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vfzrmkj9gdxqfvfaw4je.png)

When all is said and done, this is our Dockerfile. 

`FROM node:6-alpine
EXPOSE 3000
RUN apk add --no-cache tini
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install && npm cache clean --force
COPY . .
CMD ["/sbin/tini", "--", "node",  "./bin/www"]`

##🔥Results
I learned how to manipulate the layers of a Dockerfile using Docker instructions like `FROM`, `RUN`, `EXPOSE`, `COPY`, and `CMD`. I also buffed up my terminal navigate skills and am getting a lot more comfortable working with the command line.