Docker Behind Small SaaS

As a small SaaS who is pursing for quick iteration, we are using docker heavily for the deployment, it for sure makes our lives easier.

You can find kinds of beginning tutorial for Docker on the internet, and we’re sharing the instance how we use docker so that you can get a better view of it.

Tech Stacks

we are using node.js to build the backend with the framework express.js, sequelize.js for ORM, redis for session storage, postgres for the database, and docker-compose for organizing docker containers.

Dockerfile

FROM node:8.9
RUN apt-get update && apt-get install make
WORKDIR /app
COPY package.json /app
COPY yarn.lock /app
RUN yarn
COPY . /app
RUN make build // For building frontend assets
EXPOSE 3000
CMD ["node", "server/index.js"]

Here we copy the project into the /app folder of the container, generating frontend-needed files and start the node application.

We copy package.json and yarn.lock first so that the docker can use node_modules caches in next building if we didn’t update the dependencies.

docker-compose.yml

We modified some values for security
version: '2'
services:
web:
build: .
ports:
- "3000:3000"
depends_on:
- redis
- postgres
environment:
- NODE_ENV=production
- PORT=3000
- REDIS_HOST=redis
- DB_HOST=postgres
- DB=production_db
- DB_USERNAME=cominsoon
- DB_PASSWORD=cominsoon
volumes:
- /home/cominsoon/userFiles:/app/server/userFiles
postgres:
image: "postgres:9.5"
ports:
- "5432:5432"
environment:
- POSTGRES_DB=production_db
- POSTGRES_USER=cominsoon
- POSTGRES_PASSWORD=cominsoon
volumes:
- /home/cominsoon/postgresql:/var/lib/postgresql/data
redis:
image: 'redis:alpine'

As you can see in the file, we called our app container as web, linking each container by setting up depends_on, the environment of web container is available as process.env and environment of postgres container can initialize a new database with the pointed database name, username, and password.

Volumes used for data persistence. We stored user generated files(e.g., user uploaded files) and database data into the server disk so that we keep the data after restart the container.

DB migration

After running `docker-compose up -d`, we have started the app, initialized the database, but we still need to initialize the schemas of the database which can be done using sequelize.js:

$ docker-compose run web ./node_modules/.bin/sequelize db:migrate

you may have to add a correct config path and migration files path for the command, just check sequelize doc for more info.

Redeployment

We need to rebuild our docker every time we deploy a new feature with only 2 steps on the server:

/* Rebuild the web container */
$ docker-compose build web
/* Only restart the web service inside the docker-compose network */
$ docker-compose up --no-deps -d web

Thanks to the Docker cache, everything is ready in a few minutes, and the app has updated online.

That is all

We doubt if docker is worthy of learning at the beginning because it looks like a tool for professional devops, but in fact, docker makes the deployment much more accessible and has worked quite stable so far.