Welcome, this is a tutorial on Docker
-ising a WebApp.
If you're curious about the tutorial's context, check out the presentation slides.
The tutorial consists of 5 main parts:
- Running the example app locally
- Create the Dockerfile
- Deploying the app to the cloud and have it built using the Dockerfile
- Running the example app locally in a Docker container (Production Mode)
- Running the example app in a Docker container listening for code changes (Development Mode)
git clone https://github.com/cassilup/express-cowsay
npm install
If all went well, you now have a new folder named node_modules/
.
node index.js
You should see the following in your terminal:
1.4. Open http://localhost:8080 in your browser.
We want to reset the project to its original state, without any npm
packages installed. That is because we will start the server inside a Docker container and the node_modules/
folder will be created inside the container, without our
First, we will stop the server by hitting CTRL
+C
.
Secondly, we will delete the node_modules/
. We will later generate it from inside of our Docker container.
This is the magical part. Dockerfile
is like a recipe. It builds our project environment based on the ingredients (instructions) we specify here.
Here is the Dockerfile
that we'll be using for this tutorial:
FROM node:boron
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json /usr/src/app
RUN npm install
COPY . /usr/src/app
EXPOSE 8080
CMD [ "npm", "start" ]
Each step in the Dockerfile
generates an intermediate container.
This is the strategy that allows Docker to be fast.
Few Dockerfile
keywords that you should be aware of:
FROM
: Image that our container will be built from. (Note: you can build/package/deploy your own images.)RUN
: Execute a command in the bash of our Linux container.WORKDIR
: Equivalent ofcd <path/to/folder>
COPY
: Copies files from the host machine (your native OS) to the container's filesystem.EXPOSE
: Opens up a port so that we can access our container.CMD
: Special command that is run every time the container is started.
For more info about possible keywords, click here.
3.1. Install now.sh
Follow the official instructions.
now --docker
Notice the new URL for our deployed app in the command line:
Accessing that URL returns information about our deployment:
Notice that the local terminal mirrors the same logs we can see in the browser:
Once the deployment is ready, we can see our app running from a Docker
container in the app's URL:
Awesome!
Note: Make sure you have Docker for Mac/Win installed.
For more information on the VM used by Docker, click here.
Steps to generate a Docker
image out of our Dockerfile
:
docker build -t cowsay-express .
Notice the intermediate containers being created.
docker run -p 10080:8080 -d cowsay-express
4.3. Navigate to http://localhost:10080 and voilá!
Very Important: Notice that there's no node_modules/
in our code. This means that the app is actually running in the Docker
container.
docker exec -it <container id> sh
Now list the contents of the app's folder and notice the node_modules/
folder being present:
ls -l /usr/src/app
Other useful commands:
docker images
—> lists all images on systemdocker ps
—> lists running containers on systemdocker ps -a
—> lists all containersdocker stop <container id>
-> stop a containerdocker rm <container id>
-> remove a containerdocker image rm <image name>
-> remove an image
For more info, click here
By default, node
doesn't "listen" for code changes. So when you make code changes, you need to restart the node
process in order to have it take changes into account.
nodemon
is a tool that fixes that and is commonly used in development of node
projects.
In order to be able to develop in our own host OS and have the code changes reflected inside and served through the Docker
container, we have to:
- Install
nodemon
into the container at build time (by adding it to ourDockerfile
). - Mount the source of the app as a shared folder from our host OS to the
Docker
container (by usingdocker-compose
).
The steps we need to take are:
version: "2"
services:
web:
build: .
command: nodemon --inspect=5858
volumes:
- .:/usr/src/app
- /usr/src/app/node_modules
ports:
- "10080:8080"
- "5858:5858"
Through this file, we're telling Docker
to mount our current folder as a shared folder in the container's filesystem.
Mounting our current folder enables us to make changes and have them be served directly from the container as they occur.
Note: We need the - /usr/src/app/node_modules
line in order to have the node_modules/
folder persisted as intermediate containers are being built.
Add the following line to the Dockerfile
:
FROM node:boron
RUN npm i -g nodemon # <-- New Line
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json /usr/src/app
RUN npm install
COPY . /usr/src/app
EXPOSE 8080
CMD [ "npm", "start" ]
5.3. Run docker-compose up
in order to bring up the project with the mounted folder and nodemon
listening for changes:
5.4. Navigate to http://localhost:10080
5.5. Make a change in the code and reload http://localhost:10080
Bonus: You can debug the Node app directly in the browser.
Congrats. You're now a Docker guru (almost). 😎
Thanks for reading so far down! If you find any inconsistencies, please be sure to let me know. I hope this tutorial got you on the right track, Docker
-wise.
If you enjoyed this, drop me a line! I'd love to hear from you.