Deploying a Web App, Redis, Postgres and Nginx with Docker

Why Docker

Install Docker on the host

sudo su
curl -sSL https://get.docker.com/ | sh
# Add theuser to docker group to run docker as a non-root user
# MUST logout and re-login to let it effective
usermod -aG docker theuser
# Start docker service
systemctl enable docker.service
systemctl start docker.service

Prepare

cd / git clone
https://github.com/vinceyuan/DockerizingWebAppTutorial.git
cd / && mkdir mydata && cd myata
mkdir redis_data && mkdir postgres_data && mkdir nginx_data
root@pophubserver:/mydata# mkdir log_mynodeapp && mkdir log_nginx

Redis

docker run -d -v /mydata/redis_data:/data --name myredis --restart=always redis
$ docker run -d -v /mydata/redis_data:/data --name myredis --restart=always redis
Unable to find image 'redis:latest' locally
latest: Pulling from redis
7a3e804ed6c0: Pull complete
b96d1548a24e: Pull complete
5ba9a5b9710f: Pull complete
37f07aacbfe5: Pull complete
ec7f3a6b5dc6: Pull complete
499b313c4d4e: Pull complete
4416945429c6: Pull complete
0daf71066555: Pull complete
1f86439b265d: Pull complete
9e6288fa06c0: Pull complete
3c083702089f: Pull complete
71cc4c7123fc: Pull complete
91e5e3734476: Pull complete
8d7fb9bd09ab: Pull complete
e6b7cf8bf1b1: Pull complete
96182c1bd121: Pull complete
4b7672067154: Already exists
redis:latest: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security.
Digest: sha256:01b59520487a9ada4b8e31558c0580930a4e5f2a565a1cb85b66efe7c6ce810d
Status: Downloaded newer image for redis:latest
a96b6d2555e9f9fb1f70fea60f8cf75326cd331ebef9d4b667e322cea899d48c
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a96b6d2555e9 redis:latest "/entrypoint.sh redi 16 minutes ago Up 16 minutes 6379/tcp myredis
$ docker exec -i -t myredis bash
root@a96b6d2555e9:/data# redis-cli
127.0.0.1:6379> set number 1
OK
127.0.0.1:6379> save
OK
127.0.0.1:6379> exit
root@a96b6d2555e9:/data# exit

Postgres

docker run -d --name mypostgres -e POSTGRES_PASSWORD=postgres -v /mydata/postgres_data:/var/lib/postgresql/data --restart=always postgres
$ docker exec -i -t mypostgres bash
root@11602c44f706:/# psql -U postgres
psql (9.4.2)
Type "help" for help.
postgres=# create database mynodeappdb;
CREATE DATABASE
postgres=# \q
root@11602c44f706:/# exit
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
11602c44f706 postgres:latest "/docker-entrypoint. About a minute ago Up About a minute 5432/tcp mypostgres
a96b6d2555e9 redis:latest "/entrypoint.sh redi 32 minutes ago Up 32 minutes 6379/tcp myredis

Redis client and Postgres client

FROM debian:7RUN apt-get update \
&& apt-get install -y redis-server \
&& apt-get clean \
&& apt-get autoremove \
&& rm -rf /var/lib/apt/lists/*
RUN service redis-server stop
cd /DockerizingWebAppTutorial/dockerfiles/myredisclient
docker build -t myredisclient .
FROM myredisclientRUN apt-get update \
&& apt-get install -y wget \
&& echo 'deb http://apt.postgresql.org/pub/repos/apt/ wheezy-pgdg main' >> /etc/apt/sources.list.d/pgdg.list \
&& wget --no-check-certificate --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
&& apt-get update \
&& apt-get install -y --force-yes postgresql-client \
&& apt-get clean \
&& apt-get autoremove \
&& rm -rf /var/lib/apt/lists/*
cd /DockerizingWebAppTutorial/dockerfiles/myredispgclient
docker build -t myredispgclient .
$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
myredispgclient latest 78b18351c561 6 minutes ago 132.5 MB
myredisclient latest bb2ac4846244 8 minutes ago 87.7 MB
postgres latest 1636d90f0662 2 days ago 214 MB
redis latest 4b7672067154 4 days ago 111 MB
debian 7 b96d1548a24e 9 days ago 84.97 MB

Node.js

FROM myredispgclientRUN apt-get update \
&& apt-get install -y --force-yes --no-install-recommends \
apt-transport-https \
build-essential \
curl \
ca-certificates \
git \
lsb-release \
python-all \
rlwrap \
&& apt-get clean \
&& apt-get autoremove \
&& rm -rf /var/lib/apt/lists/*
RUN curl https://deb.nodesource.com/node/pool/main/n/nodejs/nodejs_0.10.30-1nodesource1~wheezy1_amd64.deb > node.deb \
&& dpkg -i node.deb \
&& rm node.deb
RUN npm install -g express@3.4.7 \
&& npm install -g forever \
&& npm cache clear
ENV NODE_ENV production
cd /DockerizingWebAppTutorial/dockerfiles/mynodejs
docker build -t mynodejs .

mynodeapp

FROM mynodejsCOPY . /src
RUN cd /src && npm install
VOLUME /log
CMD ["forever", "-l", "/log/forever.log", "-o", "/log/out.log", "-e", "/log/err.log", "/src/app.js"]
cd /DockerizingWebAppTutorial/mynodeapp
docker build -t mynodeapp .
var conString;if ('development' == app.get('env')) {
app.use(express.errorHandler());
conString = "postgres://vince:@localhost/mynodeappdb"; // Use your db, user and password
} else {
conString = "postgres://postgres:postgres@localhost/mynodeappdb"; // Use your db, user and password
}
var pgClient = new pg.Client(conString);pgClient.connect(function(err) {
if(err) return console.error('Could not connect to postgres', err);
console.log('Connected to postgres');
});
var redisClient = redis.createClient(6379, '127.0.0.1', {})app.get('/', function(req, res) {
pgClient.query('SELECT NOW() AS "theTime"', function(err1, result) {
redisClient.get("number", function(err2, reply) {
res.render('index', { pgTime: result.rows[0].theTime, number: reply });
});
}); // Errors Ignored in this example. You should check errors in a real project.
});
http.createServer(app).listen(app.get('port'), function() {
console.log('Express server listening on port ' + app.get('port'));
});
var redis_host = process.env.REDIS_PORT_6379_TCP_ADDR || '127.0.0.1';
var redis_port = process.env.REDIS_PORT_6379_TCP_PORT || 6379;
var db_host = process.env.POSTGRES_PORT_5432_TCP_ADDR || 'localhost';
docker run -d --name mynodeapp --link mypostgres:postgres --link myredis:redis -v /mydata/log_mynodeapp:/log -p 3000:3000 --restart=always mynodeapp
$ curl localhost:3000
<!DOCTYPE html><html><head><title></title><link rel="stylesheet" href="/stylesheets/style.css"></head><body><H1>mynodeapp</H1><p>Number from Redis: 1</p><p>Time from Postgres: Fri May 29 2015 09:47:54 GMT+0000 (UTC)</p></body></html>

Nginx

FROM nginx# Create folder for static files
RUN mkdir /mynodeapp && mkdir /mynodeapp/public
# copy sslcert files to /etc/nginx/ for https
#COPY mydomain.* /etc/nginx/
# copy conf
COPY nginx-docker.conf /etc/nginx/nginx.conf
    upstream mynodeapp_upstream {
server mynodeapp:3000;
keepalive 64;
}
cd /DockerizingWebAppTutorial/dockerfiles/mynginx
docker build -t mynginx .
docker run -d --name mynginx --link mynodeapp:mynodeapp -v /mydata/nginx_data:/var/cache/nginx -v /mydata/log_nginx:/var/log/nginx -v /DockerizingWebAppTutorial/mynodeapp/public:/mynodeapp/public -p 80:80 -p 443:443 --restart=always mynginx
# curl localhost
<!DOCTYPE html><html><head><title></title><link rel="stylesheet" href="/stylesheets/style.css"></head><body><H1>mynodeapp</H1><p>Number from Redis: 1</p><p>Time from Postgres: Fri May 29 2015 10:12:35 GMT+0000 (UTC)</p></body></html>
root@pophubserver:/DockerizingWebAppTutorial/dockerfiles/mynginx#
root@pophubserver:/DockerizingWebAppTutorial/dockerfiles/mynginx# curl localhost/stylesheets/style.css
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}
a {
color: #00B7FF;
}

--

--

--

iOS/Android/Web developer. UX engineering lead at Grab. Singapore/Hong Kong/Shanghai

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Aijin Yuan (Vince)

Aijin Yuan (Vince)

iOS/Android/Web developer. UX engineering lead at Grab. Singapore/Hong Kong/Shanghai

More from Medium

Hello World from Docker

Orchestrating Microservices in Nodejs using Kubernetes

Deploy WordPress on Docker

Pass Environment variables to a NodeJS Project & deploy docker image to Kubernetes