Categories
Programming

Tutorial: Getting Up and Running with Ruby on Rails, Angular, MariaDB, and Redis Using Docker-Compose

Get started with Ruby on Rails APIs on any platform using Docker and Docker-Compose.

When I was first getting started with Rails, getting everything set up was a massive pain. This post aims to show how to use Docker and Docker-Compose to generate and run a production-ready Rails API with an Angular frontend, a Redis cache, and a MariaDB database, all served by NGINX, with a development-only phpMyAdmin container. It also contains some notes about resources, best practices, developer tools, and developer workflow.

Generating the Project

First you need a Rails project! If you have one, skip this. You’ll want to go here and find the newest version of Ruby: https://hub.docker.com/_/ruby
You may also want to look at the Rails new generator options:
https://gist.github.com/eliotsykes/ace0222174804372b51a

cd projectlocation
docker run -it --rm -v ${PWD}:/usr/src/app ruby:latest bash
cd /usr/src/app
gem install rails
rails new backendname --api --database=mysql
exit

Similarly, to create your Angular project:

docker run -it --rm -v ${PWD}:/usr/src/app node:latest bash
cd /usr/src/app
npm install -g @angular/cli
ng new frontendname --routing=true --style=sass
exit

Running Your Project

Now create a docker-compose.yml to your project location folder, and copy and paste the following in:

version: '3'

services:
  rails:
    build:
      context: ./backendname
      dockerfile: ../docker/rails/Dockerfile
    volumes:
      - ./backendname:/backendname
    ports:
      - 3000:3000
    expose:
      - 3001
    depends_on:
      - db
      - rabbitmq
      - memcached
      - selenium
    tty: true
    stdin_open: true
    environment:
      SELENIUM_HOST: selenium
      SELENIUM_PORT: 4444
      MYSQL_HOST: db
      REDIS_HOST: redis

  web:
    build:
      context: ./frontendname
      dockerfile: ../docker/web/Dockerfile
    volumes:
      - ./frontendname:/frontendname
    ports:
      - 4200:4200
    depends_on:
      - rails
    tty: true
    stdin_open: true

  db:
    image: mariadb:10.4.11-bionic
    restart: always
    ports:
      - 3306:3306
    volumes:
      - db:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: development
      MYSQL_USER: development
      MYSQL_PASSWORD: development

  redis:
    image: redis:latest
    ports:
      - 6379:6379

  selenium:
    image: selenium/standalone-firefox
    ports:
      - 4444:4444
    volumes:
      - .:/insite
    environment:
      TZ: US/New_York

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    ports:
      - '8000:80'
    restart: always
    depends_on:
      - db
    environment:
      PMA_PORT: 3306
      PMA_HOST: db
      PMA_USER: root
      PMA_PASSWORD: development

volumes:
  db:

Now we need our Dockerfiles. First, the ./docker/rails/Dockerfile

FROM ruby:2.7

RUN apt-get update -yqq && \
    apt-get install -yqq git vim man-db bash-completion nodejs npm

RUN npm i -g yarn

RUN mkdir -p /frontendname
WORKDIR /frontendname

COPY Gemfile /frontendname
COPY Gemfile.lock /frontendname
RUN bundle install

EXPOSE 3000

COPY . /frontendname

CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0", "-p", "3000"]

Now ./docker/web/Dockerfile.

FROM ubuntu:20.04

RUN apt-get update -yqq && \
    apt-get install -yqq nodejs npm git vim man-db bash-completion

RUN mkdir /frontendname
WORKDIR /frontendname

COPY ./package.json /frontendname/package.json
COPY ./package.lock.json /frontendname/package.lock.json
RUN npm install

RUN npm install -g @angular/cli

COPY . /frontendname

EXPOSE 4200

CMD ["ng", "serve", "--host", "0.0.0.0"]

Now we want to take care of deployment. What we’re going to do is use the excellent docker-letsencrypt-nginx-proxy-companion project: https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion

Basically we’ll start our application and register it with a container that automatically adds SSL certificates and encryption and serves it to any visitors.

Make a file called docker-compose.nginx.yml and put the following in it:

version: "3"
services:
  nginx-proxy:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - /etc/nginx/certs
      - /etc/nginx/vhost.d
      - /usr/share/nginx/html

  companion:
    image: jrcs/letsencrypt-nginx-proxy-companion
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /etc/nginx/certs
      - /etc/nginx/vhost.d
      - /usr/share/nginx/html
    environment:
      DEFAULT_EMAIL: youremailaddress@example.com

networks:
  default:
    external:
      name: nginx-proxy

Make a docker-compose.production.yml file and insert the following:

version: '3'

services:
  web:
    restart: always
    ports:
      - '80:4200'
    environment:
      VIRTUAL_HOST: appname.com
      LETSENCRYPT_HOST: appname.com

  db:
    environment:
      MYSQL_ROOT_PASSWORD: something_more_secure
      MYSQL_USER: production
      MYSQL_PASSWORD: something_also_secure

  selenium:
    image: hello-world:latest
    logging:
      driver: none

  phpmyadmin:
    image: hello-world:latest
    logging:
      driver: none

networks:
  default:
    external:
      name: nginx-proxy

This way to run your app in production you just have to run the following:

docker network create nginx-proxy
docker-compose -f ./docker-compose.nginx.yml
docker-compose -f ./docker-compose.yml -f ./docker-compose.production.yml up --build

To develop simply run docker-compose up --build. You can access the frontend at localhost:4200 and the backend at localhost:3000.

You’ll want the following config/database.yml settings for the default:

username: development
password: development
host: db

Production can be similarly configured with the special production docker-compose database values. Whenever you need the Redis container, its hostname is simply redis.

Congratulations! You have a running Single-Page-Application powered by a Ruby on Rails API. And it’ll work anywhere: your server, your Mac, your PC, etc.

Leave a Reply

Your email address will not be published. Required fields are marked *