Setup a Ruby on Rails Application with Docker from Scratch
This is a basic development environment setup for Ruby on Rails application with MySQL using Docker and Docker Compose.
You can find the instructions on how to install Docker from here. If you are using Docker for Mac/Windows, then Docker Compose is already installed as a part of the desktop installs. If not, you can get the installation instructions here.
Getting Started: Creating a new Rails App
The method we’re going to use for generating a new Rails app is going to be quite different. In this example, I’m not going to require you from installing Ruby on your local machine. We will be running Ruby on a docker container with the command below:
docker run -it -v "$PWD:/app" -w /app --rm ruby:2.6 bash
-it | This is actually 2 flags, -i and -t being combined. With these flags, we can run the image in interactive mode. |
-v "PWD:/app" | This will share the current folder ($PWD ) with the folder inside the container which is /app . |
-w /app | This will set the default working directory to /app |
--rm | This flag means to remove/destroy the container when we exit the container. |
ruby:2.6 | This will tell docker to use the Ruby 2.6 official image. |
bash | This will let us start a bash session. |
The command above will automatically pull the official image from the Docker Hub registry if the image does not exist in your local machine.
After running the command above, you will now be inside a container with Ruby 2.6 installed.
Next, we’re going to install the rails
gem inside the Ruby container.
gem install rails
Once the installation is complete, we can now generate new rails application inside the container.
rails new blog -d mysql --skip-bundle
We’ll be using mysql
as our database so we added the flag -d mysql
. And we also told it to skip the process for running bundle install
. We’ll do that later.
Since we already have our rails application, we can now exit the container by running:
exit
If you do a quick ls
on your current directory, you can see the blog
rails app that we just generated seconds ago.
Writing the Dockerfile
Now we can move into our blog
app directory and create the Dockerfile.
cd blog && touch Dockerfile
Open the Dockerfile
with the text editor of your choice and paste the following configuration.
FROM ruby:2.6 # Install the required packages and remove the apt cache. RUN apt-get update -yqq \ && apt-get install -yqq --no-install-recommends \ default-mysql-client \ nodejs \ && rm -rf /var/lib/apt/lists # Set your work directory WORKDIR /app # Set the default Yarn version to install ARG YARN_VERSION=1.19.2 # Copy Gemfile to the container COPY Gemfile* ./ # Install dependencies RUN bundle install # Copy everything in current directory (blog/) to the WORKDIR COPY . . # Install Yarn. This is needed for webpacker. RUN curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version ${YARN_VERSION}ENV PATH="/root/.yarn/bin:/root/.config/yarn/global/node_modules/.bin:$PATH"# Expose port 3000 to allow us to access the site in our broser with localhost:3000 EXPOSE 3000 # Start rails server CMD ["rails", "s", "-b", "0.0.0.0"]
Docker Compose configuration
Still inside the blog
directory, we’ll now create the docker-compose.yml
file.
touch docker-compose.yml
And add the configuration below:
version: "3" services: db: image: mysql:5 env_file: .env volumes: - mysql-data:/var/lib/mysql app: build: . env_file: .env volumes: - .:/app ports: - 3000:3000 depends_on: - db volumes: mysql-data: external:false
We have specified 2 services: db
and app
. These services will be running on their own separate containers. The db
container will be running mysql, and the app
container will be running the Rails app.
Let’s first look at the db
service. We’ll create the .env
file later, that’s going to be used on both services. We also specified volumes
for the mysql data. This is to persist the mysql data, so that the data won’t disappear when we stop or destroy the containers.
As for the app
service, note that we created a Dockerfile
a while ago. With the build: .
option, it will instruct it later to build the image using the Dockerfile
we’ve created.
We also share the application source code using volumes
, and set the ports
. depends_on
will instruct it to wait for the db
service container to start first, before starting the app
container.
Now let’s create the .env
file which will contain the environment variables.
touch .env
MYSQL_HOST=db MYSQL_ALLOW_EMPTY_PASSWORD=yes
Don’t forget to include .env
to your .gitignore
file, as you may not want to commit this file. I would recommend creating a sample file .env.example
to give a hint for other developers on what is needed to be inside the .env
file, and commit that instead of the actual .env
file.
Next, we’ll have to edit our development database configuration in config/database.yml
. We’ll set the host
to use the environment variable.
config/database.yml // ... default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: host: <%= ENV['MYSQL_HOST'] %> // ...
Build the image
Now we have the Dockerfile
and the docker-compose.yml
file. We can build the image using the command below:
docker-compose build
Initial Setup
These commands are only required when running the app for the first time.
Install and Setup Webpacker
docker-compose run --rm --no-deps app rails webpacker:install
Create the database
docker-compose run --rm --no-deps app rails db:create
Start up the containers
Now you can start up the containers simply by running the command below:
docker-compose up -d
Note: When you update something in Dockerfile
, it is recommended to add the build flag (--build
) to rebuild the image. Eg., docker-compose up -d --build
Open up your browser and visit http://localhost:3000
Now if you want run some other rails commands, you just have to run docker-compose run --rm --no-deps app [command]
:
docker-compose run --rm --no-deps app rails g Home index
To stop all the containers:
docker-compose down