Test a Node application with Docker (while understanding Docker functions)
I was getting to know some differences between Dockerfile and docker-compose.yml and how to test it with existing node app.
At first I made dev-vhosts Docker to create Nginx Virtual Hosts. It has only Nginx and PHP7-fpm. And it work really well, but that’s too basic. How do you link database was the next step and everything should use Alpine Linux where possible for creating small images.
First I made a script that destroys all docker images
file: ~/bin/destroy_docker_images.sh
#!/bin/bash
# Delete all containers
docker rm -f $(docker ps -a -q)
# Delete all images
docker rmi $(docker images -q)
docker images | awk '{print $1 ":" $2}' | xargs docker rmi -f
Seems a bit harsh command, but since I’m learning Docker since 3 days ago and want to build perfect images, it's all okay.
So after I made that tutorial. I want to add mysql database. I've used the normal one, then searched someone's image with alpine (and found some errors) and end up making an image for myself.
I created a folder db
and put the files inside
Here is a snippet code from my docker-compose.yml
db:
build:
context: ./db
dockerfile: Dockerfile
volumes:
- ./db/storage:/var/lib/mysql
see
context
where withdocker-compose
command should look up for the./db
directory to look that dockerfile name.
with Dockerfile
FROM alpine
MAINTAINER Harianto van Insulinde <hariantoatwork@gmail.com>
EXPOSE 3306
RUN apk add --update mysql mysql-client && \
mkdir -p /var/lib/mysql && \
mkdir -p /etc/mysql/conf.d && \
{ \
echo '[mysqld]'; \
echo 'expire-logs-days = 3'; \
echo 'user = root'; \
echo 'datadir = /var/lib/mysql'; \
echo 'port = 3306'; \
echo 'log-bin = /var/lib/mysql/mysql-bin'; \
echo 'socket = /var/lib/mysql/mysql.sock'; \
echo '!includedir /etc/mysql/conf.d/'; \
} > /etc/mysql/my.cnf && \
rm -rf /var/cache/apk/*
VOLUME ["/var/lib/mysql", "/etc/mysql/conf.d/"]
ENTRYPOINT ["mysqld"]
CMD ["--skip-grant-tables"]
There I can create MySQL Alpine image now.
But it wasn't enough and sure it needs to be linked somehow.
So I need admin app for the database and thought phpmyadmin would do the trick and luckily there is Docker image. phpmyadmin/phpmyadmin
With this snippet:
dbadmin:
image: phpmyadmin/phpmyadmin
links:
- db
ports:
- "8080:80"
See
links
that points todb
; the title
Then I start docker-compose up
after destroy_docker_images.sh
.
And I can open up the browser http://localhost:8080
and that's it.
Test in action
The next journey would be to use Node mysql admin.
I searched and I found hegdeashwin/nodemyadmin GitHub repo. But it hasn't got Dockerfile or docker-compose.yml.
Let's create Docker Compose project
So my directory structure would be like this
.\nodemyadmin
.\app
.\db
# make work directory and CD it
mkdir nodemyadmin && cd nodemyadmin
# clone the repo and name directory as 'app'
git clone https://github.com/hegdeashwin/nodemyadmin.git app
# create 'db' directory too
mkdir db
From now on this guide below will points to
./nodemyadmin
So now we've got the basics. We need to know which port we should expose and probably point to the right host.
- Searching through the files:
./app/configs/stack.conf.js
we see the exposing port would be9000
. But the server host points tolocalhost
, let’s change them to0.0.0.0
same with address. - Searching through other files:
./app/config/mysql.conf.js
we see MySQL host points tolocalhost
, that’s wrong since we using Docker system we have to point them todb
. - How does the app start? The standard
node index.js
or.. wait this app usenpm start
, got it frompackage.json
In short this node app should set to:
mysql:
host: db
server:
host: 0.0.0.0
port: 9000
address: 0.0.0.0
command: npm start
Create file: ./docker-compose.yml
</small
version: '2'
services:
db:
build:
context: ./db
dockerfile: Dockerfile
volumes:
- ./db/storage:/var/lib/mysql
node:
build: .
command: npm start
environment:
NODE_WORKDIR: /home/node/app
NODE_ENV: development
links:
- db
ports:
- '9000:9000'
volumes:
- ./app:/home/node/app
- /home/node/app/node_modules
Create file: ./Dockerfile
FROM mhart/alpine-node:4
ENV HOME=/home/node
ENV NODE_WORKDIR=$HOME/app
RUN apk --update add \
git \
bash \
python \
openssl \
libgcc \
make \
libstdc++ \
g++
RUN rm -rf /var/cache/apk/*
RUN addgroup node &&\
adduser -h /home/node -s /bin/false -G node -D node &&\
npm install --global npm@3.7.5
COPY ./app/package.json $NODE_WORKDIR/
RUN chown -R node:node $HOME
USER node
WORKDIR $NODE_WORKDIR
RUN npm shrinkwrap
RUN npm install && npm cache clean
CMD ["npm", "start"]
See
CMD
asnpm start
to start the node app. Usually on my own projects would be:node index.js
Create file: ./db/Dockerfile
FROM alpine
MAINTAINER Harianto van Insulinde <hariantoatwork@gmail.com>
EXPOSE 3306
RUN apk add --update mysql mysql-client && \
mkdir -p /var/lib/mysql && \
mkdir -p /etc/mysql/conf.d && \
{ \
echo '[mysqld]'; \
echo 'expire-logs-days = 3'; \
echo 'user = root'; \
echo 'datadir = /var/lib/mysql'; \
echo 'port = 3306'; \
echo 'log-bin = /var/lib/mysql/mysql-bin'; \
echo 'socket = /var/lib/mysql/mysql.sock'; \
echo '!includedir /etc/mysql/conf.d/'; \
} > /etc/mysql/my.cnf && \
rm -rf /var/cache/apk/*
VOLUME ["/var/lib/mysql", "/etc/mysql/conf.d/"]
ENTRYPOINT ["mysqld"]
CMD ["--skip-grant-tables"]
Now run the command:
docker-compose build
docker-compose up
Some directories been created like: ./db/storage
and a linked directory in: ./app/node_modules
It's possible to go inside docker container image and access mysql to run queries. From the command line type:
docker-compose run --rm --entrypoint="mysql -h db -u root" db
.
To clear logs and enter:
PURGE BINARY LOGS BEFORE NOW();\q
End
This concludes the guide.
Thanks