docker-compose Rails PG Redis Sidekiq Travis-CI
Table of Contents
:ID: 19CD4732-5A20-43B9-BAC4-FEB736D190ED
# Instructions
This is a generator for Rails project setup with docker, Postgres, Redis, Sidekiq; with container orchestration using docker-compose. The goal of this is to do everything in Docker including the initial project setup in order to eliminate the need to install anything locally.
- Set the
:HEADER-ARGS:property for each file with the:tanglepath. This is where the generated file will be written. See also Using Header Arguments. - Edit the
configAssociation List below. Select the desired versions and app name. - call
org-babel-tangleto generate the files in your chosen tangle directory. - Run the setup script as an entry point to a temp container based on the
selected image. The command is generated in a
Usagecomment insetup.sh. - Add a
.envfile - Add a
.dockerignore. See this gist for ideas of what to ignore. TODO: just generate this, dummy. - Update
Procfile.devto bind the server to0.0.0.0web: unset PORT && bin/rails server -p 3000 -b '0.0.0.0' - Build container image
docker-compose build - Start the app with
docker-compose up
# Skip all the confirm prompts
This will run the config elisp block below several times. Set the
org-confirm-babel-evaluate variable to nil to skip prompting.
# Config
(setq config '(("ruby-version" . "3.2.2") ("node-major" . "20") ("pg-version" . "latest") ("redis-version" . "latest") ("app-name" . "tmp"))) (cdr (assoc key config))
# Dockerfile
This is a multistage docker build. The advantage is having yarn and bundle dependencies being a step that is cached independently.
ARG RUBY_VERSION=<<config("ruby-version")>>
FROM ruby:$RUBY_VERSION-slim as base
RUN apt-get update -qq \
&& apt-get install --no-install-recommends -y build-essential ca-certificates curl gnupg locales libvips libpq-dev \
libwebp-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists /var/cache/apt/archives
WORKDIR /rails
# Install Node and Yarn JS package manager
# See also https://github.com/nodesource/distributions#installation-instructions
ARG NODE_MAJOR=<<config("node-major")>>
ARG YARN_VERSION=1.22.19
RUN mkdir -p /etc/apt/keyrings && \
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" | \
tee /etc/apt/sources.list.d/nodesource.list && \
apt-get update && \
apt-get install nodejs -y && \
npm install -g yarn@$YARN_VERSION
# Install JS dependencies
FROM base as node
COPY package.json yarn.lock ./
RUN yarn install
# Install Ruby dependencies
FROM base as gems
COPY Gemfile Gemfile.lock ./
RUN gem install bundler && bundle install --jobs 20 --retry 5
# Final build
FROM base as build
WORKDIR /rails
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
COPY . ./
# Copy ruby and JS dependencies
COPY --from=gems /usr/local/bundle /usr/local/bundle
COPY --from=node /rails/node_modules /rails/node_modules
EXPOSE 3000
CMD ["bin/dev"]
# docker-compose
This orchestrates the following containers:
- web
- database
- redis
- sidekiq
The sidekiq
commandis basic in this example. To specify queues for example usebundle exec sidekiq -q default -q other. Dosidekiq --helpto see all the options.
Environment variables are provided via a .env file in the project root. This
file is automatically generated by the setup script below.
version: "3.6"
services:
web:
tty: true
stdin_open: true
build: .
command: bash -c "rm -f tmp/pids/server.pid && /app/bin/dev"
volumes:
- ".:/app"
- "/app/node_modules" # don't mount node_modules dir
ports:
- "3000:3000"
links:
- "database"
- "redis"
env_file:
- ".env"
database:
image: postgres:<<config("pg-version")>>
volumes:
- 'postgres:/var/lib/postgresql/data'
ports:
- "5432"
env_file:
- ".env"
redis:
image: redis:<<config("redis-version")>>
volumes:
- "redis:/data"
ports:
- "6379"
sidekiq:
depends_on:
- "database"
- "redis"
build: .
volumes:
- ".:/app"
- "/app/tmp" # don't mount tmp dir
command: "bundle exec sidekiq"
env_file:
- ".env"
volumes:
redis:
postgres:
# Setup the project
After generating the files we still don’t have a Gemfile, Gemfile.lock or any of the Rails’ framework files, etc. But we can still do all the project setup within a docker container and mounting the project directory as a volume and running a few commands.
See Usage comment in the script for how to run it
# setup.sh
This is a one time setup script. It can be deleted after it is run.
- This is for rails v ~>7
- See also nodesource.
# Usage: # docker run --rm -it -v "$PWD":/app -w /app ruby:<<config("ruby-version")>> sh setup.sh # Install dependencies gem install rails -v "~> 7" # Install node from nodesource https://github.com/nodesource/distributions/blob/master/README.md#installation-instructions curl -fsSL https://deb.nodesource.com/setup_<<config("node-major")>>.x | bash - && apt-get install -y nodejs # Install yarn curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list apt update && apt install -y yarn # Setup rails app rails new . --database=postgresql --javascript=esbuild --css=bootstrap --name=<<config("app-name")>> bundle add sidekiq --skip-install bundle add rubocop --group development --require false --skip-install bundle add rubocop-performance --group development --require false --skip-install bundle add rubocop-rails --group development --require false --skip-install bundle add rubocop-rspec --group development --require false --skip-install bundle add rspec-rails --group "development, test" --skip-install bundle add factory_bot_rails --group "development, test" # Configure database DBCONFIG=$(cat <<EOF default: &default adapter: postgresql encoding: unicode host: <%= ENV['POSTGRES_HOST'] %> user: <%= ENV['POSTGRES_USER'] %> password: <%= ENV['POSTGRES_PASSWORD'] %> pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> development: <<: *default database: <<config("app-name")>>_development test: <<: *default database: <<config("app-name")>>_test production: <<: *default database: <<config("app-name")>>_production username: <<config("app-name")>> password: <%= ENV['SUPER_SECRET_DATABASE_PASSWORD'] %> EOF ) echo "$DBCONFIG" > config/database.yml # Add env vars for development touch .env echo "POSTGRES_DB=<<config("app-name")>>_development" >> .env echo "POSTGRES_USER=postgres" >> .env echo "POSTGRES_PASSWORD=postgres" >> .env echo "POSTGRES_HOST=database" >> .env echo "PGUSER=postgres" >> .env echo "REDIS_URL=redis://redis:6379/1" >> .env
# Run it
After completing the project setup, run:
docker-compose build to build the image
docker-compose up to run the containers
Tear it down with:
docker-compose down
See https://github.com/apmiller108/astronomania-api README for example of more commands like debugged with pry and running tests.
# Travis-CI
This is the travis.yml. Most of this is boiler plate from Travis’ docs. The
env stuff I had to figure out becuase I am using a .env file to pass config
vars into containers with docker-compose. First I had to add the env vars to
Travis’ project settings. Then echo them into a .env file for docker-compose
to read from.
NOTE: the COMPOSE_VERSION is NOT the docker-compose file version, but
the docker-compose release version:
Releases · docker/compose · GitHub
NOTE: this file doesn’t get generated. Use it if you want.
language: bash
sudo: required
services:
- docker
env:
COMPOSE_VERSION: 1.26.2
before_install:
- sudo rm /usr/local/bin/docker-compose
- curl -L https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
- chmod +x docker-compose
- sudo mv docker-compose /usr/local/bin
- docker --version
- docker-compose --version
script:
- touch .env
- echo "POSTGRES_DB=${POSTGRES_DB}" >> .env
- echo "POSTGRES_USER=${POSTGRES_USER}" >> .env
- echo "POSTGRES_PASSWORD=${POSTGRES_PASSWORD}" >> .env
- echo "POSTGRES_HOST=${POSTGRES_HOST}" >> .env
- echo "NASA_API_KEY=${NASA_API_KEY}" >> .env
- docker-compose up --detach --build
- docker ps -a
- docker-compose exec web bin/rails db:schema:load RAILS_ENV=test
- docker-compose exec web bundle exec rspec
after_script:
- docker-compose down
- rm .env
notifications:
email: false
# Resources
- Setup a Ruby on Rails 6 API project with Docker Compose \| Yi Zeng’s Blog
- Add Sidekiq to a Docker Compose managed Rails project \| Yi Zeng’s Blog
- Part I. Development - Docker for Rails Developers [Book]
- Compose file version 3 reference | Docker Documentation
- https://evilmartians.com/chronicles/ruby-on-whales-docker-for-ruby-rails-development