First, clone from the following URL to Ubuntu VM:
https://github.com/potikanond/docker-node-sample2
On Ubuntu VM run the following command:
$ git clone https://github.com/potikanond/docker-node-sample2
This will clone the application from GitHub to docker-node-sample2 directory.
First, create a Dockerfile
inside the docker-node-sample2
directory.
Dockerfile:
# Instructions from the app developer # - you should use the 'node' official image, with the alpine 6.x branch FROM node:6-alpine # - this app listens on port 3000, but the container should launch on port 8080 # so it will respond to http://localhost:80 on your computer EXPOSE 3000 # - then it should use alpine package manager to install tini: 'apk add --update tini' RUN apk add --update tini # - then it should create directory /usr/src/app for app files with 'mkdir -p /usr/src/app' RUN mkdir -p /usr/src/app # - Node uses a "package manager", so it needs to copy in package.json file WORKDIR /usr/src/app COPY package.json package.json # - 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 above RUN npm install && npm cache clean # - then it needs to copy in all files from current directory COPY . . # - then it needs to start container with command '/sbin/tini -- node ./bin/www' CMD [ "/sbin/tini", "--", "node", "./bin/www" ] # - in the end you should be using FROM, RUN, WORKDIR, COPY, EXPOSE, and CMD commands
For more detail on dockerizing a Node.js web app, see the following link: https://nodejs.org/en/docs/guides/nodejs-docker-webapp/
.dockerignore:
node_modules npm-debug.log
This will prevent local_modules and debug logs from being copied onto your Docker image and overwriting modules installed within your image.
Use the docker image build ...
command to build and tag image.
$ docker image build -t cpe405/example32 . Sending build context to Docker daemon 441.9kB Step 1/9 : FROM node:6-alpine ---> bd44e728e149 Step 2/9 : EXPOSE 3000 ---> Running in 92771260a610 Removing intermediate container 92771260a610 ---> 44f47b1f6c53 Step 3/9 : RUN apk add --update tini ---> Running in ffafd075394b fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/main/x86_64/APKINDEX.tar.gz fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/community/x86_64/APKINDEX.tar.gz (1/1) Installing tini (0.9.0-r1) Executing busybox-1.24.2-r14.trigger OK: 6 MiB in 14 packages Removing intermediate container ffafd075394b ---> fb979adbbed9 Step 4/9 : RUN mkdir -p /usr/src/app ---> Running in 660d7418de0b Removing intermediate container 660d7418de0b ---> 09865e1827cc Step 5/9 : WORKDIR /usr/src/app ---> Running in d6410224d07c Removing intermediate container d6410224d07c ---> 84b7b6f1f717 Step 6/9 : COPY package.json package.json ---> a69ce9fd01a3 Step 7/9 : RUN npm install && npm cache clean ---> Running in 83a78d40e7d7 dockerfile-assignment-1@0.0.0 /usr/src/app +-- body-parser@1.16.1 | +-- bytes@2.4.0 | +-- content-type@1.0.4 | +-- debug@2.6.1 | +-- depd@1.1.2 | +-- http-errors@1.5.1 | | +-- inherits@2.0.3 | | +-- setprototypeof@1.0.2 | | `-- statuses@1.5.0 | +-- iconv-lite@0.4.15 | +-- on-finished@2.3.0 | | `-- ee-first@1.1.1 | +-- qs@6.2.1 | +-- raw-body@2.2.0 | | `-- unpipe@1.0.0 | `-- type-is@1.6.16 | +-- media-typer@0.3.0 | `-- mime-types@2.1.20 | `-- mime-db@1.36.0 +-- cookie-parser@1.4.3 | +-- cookie@0.3.1 | `-- cookie-signature@1.0.6 +-- debug@2.6.9 | `-- ms@2.0.0 +-- express@4.14.1 | +-- accepts@1.3.5 | | `-- negotiator@0.6.1 | +-- array-flatten@1.1.1 | +-- content-disposition@0.5.2 | +-- debug@2.2.0 | | `-- ms@0.7.1 | +-- encodeurl@1.0.2 | +-- escape-html@1.0.3 | +-- etag@1.7.0 | +-- finalhandler@0.5.1 | | +-- debug@2.2.0 | | | `-- ms@0.7.1 | | `-- statuses@1.3.1 | +-- fresh@0.3.0 | +-- merge-descriptors@1.0.1 | +-- methods@1.1.2 | +-- parseurl@1.3.2 | +-- path-to-regexp@0.1.7 | +-- proxy-addr@1.1.5 | | +-- forwarded@0.1.2 | | `-- ipaddr.js@1.4.0 | +-- qs@6.2.0 | +-- range-parser@1.2.0 | +-- send@0.14.2 | | +-- debug@2.2.0 | | | `-- ms@0.7.1 | | +-- destroy@1.0.4 | | +-- mime@1.3.4 | | `-- statuses@1.3.1 | +-- serve-static@1.11.2 | +-- utils-merge@1.0.0 | `-- vary@1.1.2 +-- hbs@4.0.1 | +-- handlebars@4.0.5 | | +-- async@1.5.2 | | +-- optimist@0.6.1 | | | +-- minimist@0.0.10 | | | `-- wordwrap@0.0.3 | | +-- source-map@0.4.4 | | | `-- amdefine@1.0.1 | | `-- uglify-js@2.8.29 | | +-- source-map@0.5.7 | | +-- uglify-to-browserify@1.0.2 | | `-- yargs@3.10.0 | | +-- camelcase@1.2.1 | | +-- cliui@2.1.0 | | | +-- center-align@0.1.3 | | | | +-- align-text@0.1.4 | | | | | +-- kind-of@3.2.2 | | | | | | `-- is-buffer@1.1.6 | | | | | +-- longest@1.0.1 | | | | | `-- repeat-string@1.6.1 | | | | `-- lazy-cache@1.0.4 | | | +-- right-align@0.1.3 | | | `-- wordwrap@0.0.2 | | +-- decamelize@1.2.0 | | `-- window-size@0.1.0 | `-- walk@2.3.9 | `-- foreachasync@3.0.0 +-- morgan@1.7.0 | +-- basic-auth@1.0.4 | +-- debug@2.2.0 | | `-- ms@0.7.1 | `-- on-headers@1.0.1 `-- serve-favicon@2.3.2 `-- ms@0.7.2 Removing intermediate container 83a78d40e7d7 ---> 18949fa31b43 Step 8/9 : COPY . . ---> 994e49aedc4a Step 9/9 : CMD [ "/sbin/tini", "--", "node", "./bin/www" ] ---> Running in 84db1bfb7480 Removing intermediate container 84db1bfb7480 ---> ad4794043057 Successfully built ad4794043057 Successfully tagged cpe405/example32:latest
# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE cpe405/example32 latest ad4794043057 2 minutes ago 63MB ...
Now we start a new container with --rm
option so that after exit the container will be removed automatically.
Note: we start the container without -d
option
We can access the application with the URL: http://localhost:8080.
$ docker container run -p 8080:3000 --rm cpe405/example32 GET / 200 161.035 ms - 290 GET /stylesheets/style.css 200 42.941 ms - 111 GET /images/picard.gif 200 51.667 ms - 417700 GET /favicon.ico 404 20.711 ms - 970