There are many articles on the internet about setting up a rails app with docker. You might be wondering, "why write another one?". I asked myself the same question. The reason I went ahead to do it is because as I learned how to use Docker, I tried to set up a rails app in it. Most of the resources I came across were using Docker Compose. That didn't help me with practising Docker very much because I wanted to be able to write those long docker commands and follow exactly what happens in that docker-compose.yml
file. I write this article for me and anyone who might have the same need. In case you get stuck on the quest, you might pick up a cent or two from here. Let's dive into it!
-
Create the directory where you will be working from and
cd
into the
directory. I am going to name the appdockerapp
.mkdir dockerapp && cd $_
-
Then create the initial files.
touch {Gemfile,Dockerfile}
-
In the
Gemfile
, put in the code below.source 'https://rubygems.org' gem 'rails', '~> 5.2'
-
In the
Dockerfile
FROM ruby:2.6-alpine RUN apk update -qq && apk add --update alpine-sdk postgresql-dev nodejs yarn tzdata RUN mkdir /app WORKDIR /app COPY Gemfile Gemfile RUN bundle install COPY . . LABEL maintainer="Lorna Tumuhairwe <lornatumuhairwe@gmail.com>" version="1.0" EXPOSE 3000 CMD rails s --port=3000 -b='0.0.0.0'
-
Build the image.
docker image build -t dockerapp .
-
Now your image has both ruby and rails installed. So we now use
the installed rails to generate a new rails project.docker container run -it -v ${PWD}:/app dockerapp rails new . --database=postgresql -f -T
-
At this point you should have the rails app in the folder since you
mounted the volume with-v ${PWD}:/app
. Update the
config/database.yml
file to contain the code below. I have made
changes to thehostname
,username
anddatabase
names to match
the postgres name we are going to use when we run the postgresql
container and the application name respectively.default: &default adapter: postgresql encoding: unicode host: postgres username: postgres pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> development: <<: *default database: dockerapp_development test: <<: *default database: dockerapp_test production: <<: *default database: dockerapp_production username: app password: <%= ENV['APP_DATABASE_PASSWORD'] %>
-
Rebuild your docker image since the Gemfile has changed.
docker image build -t dockerapp .
-
Create a network that you'll use to connect the app container and the
postgres container.docker network create dockerapp-network
-
Run a postgresql container with the command below. Even if you don't
have it pulled already, it will be downloaded and used.docker container run -it --rm -v pgdata:/var/lib/postgresql/data --name postgres --net dockerapp-network -p 5432:5432 postgres:9.6-alpine
-
Run the app as well in the same network.
docker container run --rm -it -v ${PWD}:/app -p 3000:3000 --name dockerapp --net dockerapp-network dockerapp
-
Open another terminal and create the database.
docker exec dockerapp rails db:create
In your browser visit
localhost:3000
, you should be on the rails
welcome page!
You might have already noticed, you always have to run two long commands to run your application (step 10 and 11). But to do all that in one command, you can use Docker compose.
Docker compose to the rescue.
Create a docker-compose.yml file.
version: '3'
services:
postgres:
image: postgres:9.6-alpine
volumes:
- ./tmp/db:/var/lib/postgresql/data
dockerapp:
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- .:/app
ports:
- "3000:3000"
depends_on:
- postgres
To follow from the above, make sure your containers are all stopped. By running,
docker container stop dockerapp postgres
In the same directory, run your app with
docker-compose up
This will run both the postgresql and application image at the same time. In case you run into any problems with the dockerapp container exiting, please ensure you don't have a server.pid file in temp/pids/server.pid
. That's a rails specific issue that can be resolved by deleting the file. Or you can write a script to always delete it if it exists when the app is started. That's well documented in the docker documentation.
Thank you for reading!
The steps outlined in this article are only tested on a MacOS.
On a light note, this is my first post on the platform, I have learned a lot being here, I glad to share what I have learned as well. I hope it helps someone. ❤️
Top comments (0)