For text instructions scroll down
In this very first screencast (yay!) I will show you how to set up your local web development environment with Docker and docker-compose.
Watch the screencast directly on YouTube
You can find this and future videos on our YouTube channel.
Introduction
In this first post of our little “Rails on Docker” series, we will set
up a development environment using Docker
and docker-compose
.
You will first need to install both tools. Docker can be obtained by following instructions on https://www.docker.com/. You will also need to install docker-compose.
When you have Docker installed and running on your local machine, you
should see something like that when you run docker ps
:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Docker
is a tool that will allow us to spawn virtual machine
“containers”. docker-compose
allows us to orchestrate those virtual
machines: start them up, link together, forward ports etc.
Create project structure
Our project will consist of main directory, where we will put a
docker-compose.yml
file, and a webapp
directory, where we will put
source code of our Rails application. Let’s get those set up:
$ mkdir rails_and_docker_template
$ cd rails_and_docker_template
$ mkdir webapp
$ vim docker-compose.yml
The contents of our docker-compose.yml
should be:
version: '3'
services:
db:
image: postgres
webapp:
build: ./webapp
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- ./webapp:/webapp
ports:
- "3000:3000"
depends_on:
- db
In this configuration file we define two services: a db
service that
will be based on official PostgreSQL Docker image, and webapp
which
will be our Ruby on Rails application.
We specify the command that docker-compose
will use when starting our
application - in our case we start standard Rails server on port 3000.
Volumes are directories that will be shared between our host system and
a container. Our local webapp
directory will be mounted as /webapp
inside Docker container.
The Dockerfile
Dockerfile is a recpie that gets executed from top to bottom to build our image. In the first line we specify the base image - I chose Phusion’s baseimage-docker since it is pretty standard Ubuntu, but has some nice tweaks for better Docker support.
In the following lines we install development dependencies, Ruby, Node, Bundler and execute commands to install Ruby dependencies from Gemfile.
FROM phusion/baseimage:0.9.22
CMD ["/sbin/my_init"]
RUN add-apt-repository -y ppa:brightbox/ruby-ng
RUN apt-get update
RUN apt-get install -y libpq-dev git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libxml2-dev libxslt1-dev libcurl4-openssl-dev software-properties-common libffi-dev nodejs wget autoconf tzdata ruby2.4 ruby2.4-dev rubygems ruby-switch
RUN ruby-switch --set ruby2.4
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN rm -rf /var/lib/gems/2.4.1/cache/*
RUN adduser --disabled-password --gecos "" webapp
RUN mkdir /webapp
WORKDIR /webapp
ADD Gemfile /webapp/Gemfile
ADD Gemfile.lock /webapp/Gemfile.lock
RUN chown -R webapp.webapp /webapp
USER webapp
WORKDIR /webapp
RUN echo "gem: --user-install --env-shebang --no-rdoc --no-ri" > /home/webapp/.gemrc
ENV PATH /home/webapp/.gem/ruby/2.4.0/bin:$PATH
ENV GEM_HOME /home/webapp/.gem/ruby/2.4.0
RUN gem install bundler
RUN gem install rake
RUN bundle install
ADD . /webapp
We also need to add a Gemfile and add empty Gemfile.lock files for now.
$ touch Gemfile.lock
$ vim Gemfile
Our temporary Gemfile will only require one dependency: rails
. We need
to initially build image that has rails
command installed. We will use
this command to generate Ruby on Rails project scaffold inside webapp
directory. The minimal Gemfile I added has just two lines:
sources https://rubygems.org
gem "rails", "5.1.1"
Let’s build our project:
$ docker-compose build
db uses an image, skipping
Building webapp
Step 1/23 : FROM phusion/baseimage:0.9.22
---> 877509368a8d
Step 2/23 : CMD /sbin/my_init
---> Using cache
...
Step 23/23 : ADD . /webapp
---> 56078ba4194b
Removing intermediate container 4093e813aad3
Successfully built 56078ba4194b
Successfully tagged railsanddockertemplate_webapp:latest
Now we can generate our Rails application:
$ docker-compose run webapp rails new . --force --database=postgresql
Starting railsanddockertemplate_db_1 ...
Starting railsanddockertemplate_db_1 ... done
exist
create README.md
create Rakefile
create config.ru
create .gitignore
...
create vendor/.keep
create package.json
remove config/initializers/cors.rb
remove config/initializers/new_framework_defaults_5_1.rb
run bundle install
...
If we look inside our webapp
folder now, we will see that it contains
standard Rails project scaffold. Next step involves correctly
configuring the database for our project. Let’s edit
webapp/config/database.yml
:
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
host: db
username: postgres
password:
development:
<<: *default
database: webapp_development
test:
<<: *default
database: webapp_test
We need to build our docker image now to include all the added depndencies Rails added to Gemfile:
$ docker-compose build
And finally, create the database:
$ docker-compose run webapp rake db:create
In the next steps, we can start building our application. I will generate some scaffold, and run migrations:
$ docker-compose run webapp rails g scaffold User first_name:string
last_name:string email:string
$ docker-compose run webapp rake db:migrate
We can now start our project and navigate to http://localhost:3000/users to enjoy our first Rails application running inside Docker-based development environment:
$ docker-compose up
We can also run the tests:
$ docker-compose run webapp rake test
Our development environment is ready now. We need to remember to rebuild
our docker container image with docker-compose build
every time we
install new system packages in Dockerfile, or install new dependencies
using Gemfile. Otherwise, the changes we make to the source code of
application are included immediately in our container.
In the next episode & article I will show you how to deploy our application to Heroku. Stay tuned!
Post by Hubert Łępicki
Hubert is partner at AmberBit. Rails, Elixir and functional programming are his areas of expertise.