Docker Setup for Service Based Architecture Application

Content posted here with the permission of the author Anil Kumar Maurya, who is currently employed at Josh Software. Original post available here.

What is Service Based Architecture ?

At first Micro Service Architecture & Service Based Architecture looks similar but both are different from each other.

Micro service architecture advocates smaller components. An application can consist of hundred or thousands of micro services whereas Service based architecture advocates breaking the code apart in the domain-centric way. An application can consist of 10–12 deployable services. These services may have separate database or they may share same database.

Managing few micro services is easy but as number of micro services increases, challenges to manage them is not an easy task. Number of network calls also increases.

In case of Service based architecture, number of services are limited therefore managing it is not a challenge. Also number of network call is less therefore should give better performance.

ThoughtWorks director Neal Ford argued in a talk that organizations transition more easily from a monolithic architecture to a service-based architecture than to a microservices architecture

Ref: https://www.infoq.com/news/2016/10/service-based-architecture

Why we chose Service Based Architecture Over Micro Services

Background: We are building an ERP Software. It is going to use by 50–100 people at a time. We are team of 3 developer and we need to deliver first release in 3 months.

We aim to build scalable and maintainable product. Monolith is out of option. We had 2 options, Micro Service OR Service Based Architecture. Micro Service requires complex setup and will double our efforts. As we have limited team size and our timelines are fixed therefore Service Based Architecture with common database made more sense for us.

Challenges we faced

We had 8 repository, one for each services. Setting up project on local for new developer is very time consuming. Every service needed to setup separately.

Apart from setting up all services. We need to install postgres, redis & elasticsearch. If you are stuck while installing any one of it then it may eat up whole day.

Also starting up application required starting all 8 services manually (which is not interesting thing to do everyday)

Docker for our rescue

We created a single repository for all services. Now getting all changes on local is just a git pull command away.

With docker, we can setup all services with all dependency with just one command.

docker-compose build

And we start our application (all services) by

docker-compose up

Setting up docker compose for an application which consist of 8 services (4 Rails-Api Backend & 4 React Frontend)

Application Directory structure looks like:

project
│
│
└───service-1-api
│
|───service-1-web
│   
└───service-2-api
│
|───service-2-web
│
└───service-3-api
│
|───service-3-web
│
└───service-4-api
│
|───service-4-web
│
└───docker-compose.yml
│
└───Dockerfile
│
└───Dockerfile-React

* Dockerfile is for api images
* Dockerfile-React is for react application images

Of course our services are not named as service-1 & service-2. 
I have changed it deliberately for privacy.

Our docker-compose.yml:

version: '3.6'

services:
  db:
    image: postgres

redis:
    image: 'redis:latest'

elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:6.5.4
    container_name: elasticsearch
    environment:
      - cluster.name=docker-cluster
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
      - "discovery.zen.ping.unicast.hosts=elasticsearch"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - esdata1:/usr/share/elasticsearch/data
    ports:
      - 9200:9200

service-1-api:
    build:
      context: './service-1-api'
      dockerfile: $PWD/Dockerfile
    volumes:
      - $PWD/service-1-api:/app
    command: bundle exec puma -p 3000
    ports:
      - 3000:3000
    depends_on:
      - db

service-1-web:
    build:
      context: './service-1-web'
      dockerfile: $PWD/Dockerfile-React
    volumes:
      - $PWD/service-1-web/:/app/
    ports:
      - 3001:3001
    environment:
      NODE_ENV: development
      CHOKIDAR_USEPOLLING: 'true'

service-2-sidekiq:
    depends_on:
      - db
      - redis
      - elasticsearch
    build:
      context: './service-2-api'
      dockerfile: $PWD/Dockerfile
    command: bundle exec sidekiq -C config/sidekiq.yml
    volumes:
      - $PWD/service-2-api:/app

service-2-api:
    build:
      context: './service-2-api'
      dockerfile: $PWD/Dockerfile
    volumes:
      - $PWD/service-2-api:/app
    command: bundle exec puma -p 3002
    ports:
      - 3002:3002
    depends_on:
      - db
      - elasticsearch
      - service-2-sidekiq
    stdin_open: true
    tty: true

service-2-web:
    build:
      context: './service-2-web'
      dockerfile: $PWD/Dockerfile-React
    volumes:
      - $PWD/service-2-web/:/app/
    command: npm start
    ports:
      - 3003:3003
    environment:
      - NODE_ENV=development
      - CHOKIDAR_USEPOLLING=true

service-3-sidekiq:
    depends_on:
      - db
      - redis
      - elasticsearch
    build:
      context: './service-3-api'
      dockerfile: $PWD/Dockerfile
    command: bundle exec sidekiq -C config/sidekiq.yml
    volumes:
      - $PWD/service-3-api:/app

service-3-api:
    build:
      context: './service-3-api'
      dockerfile: $PWD/Dockerfile
    volumes:
      - $PWD/service-3-api:/app
    command: bundle exec puma -p 3004
    ports:
      - 3004:3004
    depends_on:
      - db
      - elasticsearch
      - service-3-sidekiq
    stdin_open: true
    tty: true

service-3-web:
    build:
      context: './service-3-web'
      dockerfile: $PWD/Dockerfile-React
    volumes:
      - $PWD/service-3-web/:/app/
    command: npm start
    ports:
      - 3005:3005
    environment:
      - NODE_ENV=development
      - CHOKIDAR_USEPOLLING=true

service-4-api:
    build:
      context: './service-4-api'
      dockerfile: $PWD/Dockerfile
    volumes:
      - $PWD/service-4-api:/app
    command: bundle exec puma -p 3006
    ports:
      - 3006:3006
    depends_on:
      - db
    stdin_open: true
    tty: true

service-4-web:
    build:
      context: './service-4-web'
      dockerfile: $PWD/Dockerfile-React
    volumes:
      - $PWD/service-4-web/:/app/
    working_dir: /app
    command: npm start
    ports:
      - 3007:3007
    environment:
      - NODE_ENV=development
      - CHOKIDAR_USEPOLLING=true

volumes:
  esdata1:
    driver: local

*using this docker-compose.yml configuration, service restart is not required on code change.

Dockerfile:

FROM ruby:2.5.3-alpine

RUN apk add --update bash build-base postgresql-dev tzdata
RUN gem install rails -v '5.1.6'

WORKDIR /app
ADD Gemfile Gemfile.lock /app/
RUN bundle install
COPY . /app/

Dockerfile-React

FROM node:11.6.0-alpine

WORKDIR '/app'

# Install yarn and other dependencies via apk
RUN apk update && apk add yarn python g++ make && rm -rf /var/cache/apk/*

COPY package.json yarn.lock /app/

RUN yarn install
RUN yarn global add react-scripts

COPY . ./

CMD ["npm", "run", "start"]

For adding new gems in rails api service, add gem in Gemfile and build new image for that service, example:

docker-compose build service-1-api

For adding new package in react app service, use

docker-compose run service-1-web yarn add `package-name`

Conclusion:

Service Based Architecture is good alternative for applications where Manpower & Time are constraints.

In Next Blog I will write about deploying this Application on Amazon ECS(Elastic Container Service).

Advertisements

About Sachin Shintre

Director, Josh Software
This entry was posted in General. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s