I tried to build a development environment for Ruby on Rails using Docker. By using Docker, you can build a development environment regardless of the local environment, and you can migrate from the development environment to the production environment without changing the settings, so it is used in many development sites. This is the final setting I created after studying Docker on my own.
Ruby 2.6.3 Ruby on Rails 5.2.0 Docker 19.03.13 docker compose 1.27.4 MySQL 5.7 Nginx 1.15.8
Directory structure
./myapp
├── containers
│ └── nginx
│ ├── Dockerfile
│ └── nginx.conf
├── .env
├── docker-compose.yml
├── Dockerfile
├── Gemfile
└── Gemfile.lock
** Dockerfile for Rails **
Dockerfile
FROM ruby:2.6.3
RUN apt-get update\
&& apt-get install -y --no-install-recommends\
libpq-dev\
nodejs\
vim\
mariadb-client\
build-essential\
&& apt-get clean\
&& rm -rf /var/lib/apt/list/*
RUN mkdir /myproject
WORKDIR /myproject
COPY Gemfile /myproject/Gemfile
COPY Gemfile.lock /myproject/Gemfile.lock
RUN gem install bundler
RUN bundle install
COPY . /myproject
RUN mkdir -p tmp/sockets
RUN mkdir -p tmp/pids
Gemfile
Gemfile
source 'https://rubygems.org'
gem 'rails', '5.2.0'
Gemfile.lock The contents are empty and OK
** Dockerfile for Nginx **
Dockerfile
FROM nginx:1.15.8
RUN rm -f /etc/nginx/conf.d/*
ADD nginx.conf /etc/nginx/conf.d/myproject.conf
CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
** Nginx.conf file **
nginx.conf
upstream myproject {
server unix:///myproject/tmp/sockets/puma.sock;
}
server {
listen 80;
server_name IP address[or localhost];
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
root /myproject/public;
client_max_body_size 100m;
error_page 404 /404.html;
error_page 505 502 503 504 /500.html;
try_files $uri/index.html $uri @myproject;
keepalive_timeout 5;
location @myproject {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://myproject;
}
}
** .env file **
.env
MYSQL_ROOT_PASSWORD=password
MYSQL_USER=username
MYSQL_PASSWORD=password
MYSQL_DATABASE=docker_database
** docker-compose.yml file **
docker-compose.yml
version: '3'
services:
db:
image: mysql:5.7
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
env_file:
- ./.env
volumes:
- mysql-data:/var/lib/mysql
ports:
- "4306:3306"
app:
build: .
env_file:
- ./.env
command: bundle exec puma -C config/puma.rb
init: true
volumes:
- .:/myproject
- public-data:/myproject/public
- tmp-data:/myproject/tmp
- log-data:/myproject/log
depends_on:
- db
web:
build:
context: containers/nginx
init: true
volumes:
- public-data:/myproject/public
- tmp-data:/myproject/tmp
ports:
- 80:80
depends_on:
- app
volumes:
mysql-data:
public-data:
tmp-data:
log-data:
First, create a Rails application with rails new.
terminal
$ docker-compose run --rm app bundle exec rails new . --force --database=mysql --skip-bundle
Then edit the puma file in the config directory.
puma.rb
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i
threads threads_count, threads_count
port ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
plugin :tmp_restart
app_root = File.expand_path("../..", __FILE__)
bind "unix://#{app_root}/tmp/sockets/puma.sock"
stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", true
Edit database.yml.
database.yml
default: &default
adapter: mysql2
charset: utf8
encoding: utf8
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: <%= ENV.fetch("MYSQL_USER") { 'root' } %>
password: <%= ENV.fetch("MYSQL_PASSWORD") { 'password' } %>
host: db
development:
<<: *default
database: docker_database
test:
<<: *default
database: myproject_test
production:
<<: *default
database: myproject_production
username: myproject
password: <%= ENV['MYPROJECT_DATABASE_PASSWORD'] %>
When you're ready, start the container.
terminal
$ docker-compose build
When the build is complete
$ docker-compose up
If you access localhost and the Rails page is launched, you're done.
Add the following directories and files to the application folder. (File settings are the same as when creating from scratch.)
Directory structure
./myapp
├── containers
│ └── nginx
│ ├── Dockerfile
│ └── nginx.conf
│
│ Other files
│
├── .env
├── docker-compose.yml
└── Dockerfile
Then build. You don't need to run the rails new command because you already have the application. The database needs to be migrated once, so migrate it after the build.
terminal
$ docker-compose build
When the build is complete
$ docker-compose up -d
$ docker-compose exec app rails db:migrate
With the above, if you access localhost, you can install docker in your existing application.
I was still lacking in study, and I had a hard time getting an error on the way. Each time, I searched online and solved it.
On the reference page
python
$ docker-compose run --rm app rails new . --force --database=mysql --skip-bundle
It was, but
python
$ docker-compose run --rm app bundle exec rails new . --force --database=mysql --skip-bundle
I was able to install the Rails files.
$ docker-compose build
...
Bundler could not find compatible versions for gem "sprockets":
In snapshot (Gemfile.lock):
sprockets (= 4.0.2)
In Gemfile:
sass-rails (~> 5.1) x86_64-linux was resolved to 5.1.0, which depends on
sprockets (>= 2.8, < 4.0)
rails (~> 5.2.0) x86_64-linux was resolved to 5.2.0, which depends on
sprockets-rails (>= 2.0.0) x86_64-linux was resolved to 3.2.2, which
depends on
sprockets (>= 3.0.0)
Running `bundle update` will rebuild your snapshot from scratch, using only
the gems in your Gemfile, which may resolve the conflict.
ERROR: Service 'app' failed to build : The command '/bin/sh -c bundle install' returned a non-zero code: 6
I'm told to do a bundle update, so I'll do a bundle update.
python
$ docker-compose run app bundle update
afterwards
$ docker-compose build
I managed to build an environment with docker, but I still struggled due to lack of study. When I first started using docker, I made an existing application docker. After that, I tried to install docker from building a new environment, but I stumbled many times. I would like to study the detailed settings again and give explanations for each one someday.
Docker + Rails + Puma + Nginx + MySQL # Error resolution rails new can't run bundle update will rebuild your snapshot from scratch, using only the gems in your Gemfile, which may resolve the conflict.
Recommended Posts