[Ruby] [Rails] How to build environment with Docker

4 minute read

Development environment

・Docker: 19.03.8 ・Docker-Compose: 1.25.5 ・Ruby: 2.5.7 Rails: 5.2.4 ・Vagrant: 2.2.7 ・VirtualBox: 6.1 ・OS: macOS Catalina

Implementation

1. Create/move working directory

The folder name will proceed as myapp (anything is fine).

terminal


$ mkdir myapp

terminal


$ cd myapp

2. Create/edit Dockerfile

terminal


$ vi Dockerfile

Dockerfile


FROM ruby:2.7.1
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY ./myapp

# Add a script to be executed every time the container starts
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process
CMD ["rails", "server", "-b", "0.0.0.0"]

[Explanation]

★Overview

FROM: Set the image and version to use RUN: Command execution WORKDIR: set working directory COPY: Copy local file to container ENTRYPOINT: Set the first command to be executed EXPOSE: Set the port number that the container listens on CMD: Software execution inside the image

★ Details

** ◎ As the image to be used, obtain the latest stable version as of 19th 2020. **

FROM ruby:2.7.1

** ◎ Install the Node.js and PostgreSQL packages. **

RUN apt-get update -qq && apt-get install -y nodejs postgresql-client

** ◎ Create a myapp directory in the container. **

RUN mkdir /myapp

** ◎ Set the working directory to myapp created above **

WORKDIR /myapp

**◎ Copy the local Gemfile to myapp in the container. **

COPY Gemfile /myapp/Gemfile

**◎ Copy the local Gemfile.lock to myapp in the container. **

COPY Gemfile.lock /myapp/Gemfile.lock

** ◎ Run bundle install. **

RUN bundle install

** ◎ Copy the current directory (local myapp) to myapp in the container. **

  • . = current directory
COPY ./myapp

**◎ Copy the local entrypoint.sh to usr/bin in the container. **

COPY entrypoint.sh /usr/bin/

** ◎ Allow access to the entrypoint.sh copied above. **

RUN chmod +x /usr/bin/entrypoint.sh

** ◎ When starting the container, set entrypoint.sh as the first command to be executed. **

ENTRYPOINT ["entrypoint.sh"]

** ◎ Set the port number to 3000. **

EXPOSE 3000

** ◎ Launch Rails server. **

CMD ["rails", "server", "-b", "0.0.0.0"]

3. Create/edit Gemfile

Specify the Rails version. This time we will make it compatible with Rails 6.

terminal


$ vim Gemfile

Gemfile


source'https://rubygems.org'
gem'rails','~> 6'

4. Create Gemfile.lock

terminal


$ touch Gemfile.lock

5. Create/edit entrypoint.sh

terminal


$ vi entrypoint.sh

entrypoint.sh


#!/bin/bash
set -e

# The file server.pid corresponding to Rails may exist, so delete it.
rm -f /myapp/tmp/pids/server.pid

# Run the container process. (The one set in CMD in Dockerfile.)
exec "[email protected]"

5. Create/edit docker-compose.yml

terminal


$ vi docker-compose.yml

docker-compose.yml


version: '3'
services:
  db:
    image: postgres
    volumes:
      -./tmp/db:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: password
  web:
    build:.
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      -.:/myapp
    ports:
      -"3000:3000"
    depends_on:
      -db

[Explanation]

version: Set the version of docker-compose. services: Create services in the hash below this. You can name it freely, but usually name it web and db. image: image to use (db specifies PostgreSQL) volumes: Directory mount settings (db data etc. can be left) build: Path with Dockerfile etc. (basically the current directory) command: Command (delete the server.pid file and then start the rails server) ports: Port numbers (host:set in container) depends_on: Shows the dependency relationship and the startup order can be specified. Here, it is started from db→web.

6. Check the directory structure

terminal


myapp
- Dockerfile
- Gemfile
- Gemfile.lock
- entrypoint.sh
- docker-compose.yml

7. Build the project

terminal


$ docker-compose run web rails new .--force --no-deps --database=postgresql --skip-bundle

[Explanation]

--force: Overwrite Gemfile --no-deps: do not start linked services --database=postgresql: Specify PostgreSQL for DB --skip-bundle: skip bundle

8. Run bundle install

terminal


Could not find gem'pg (>= 0.18, <2.0)' in any of the gem sources listed in your Gemfile.
Run `bundle install` to install missing gems.

I think that the above error occurred at 7, so execute the following command to solve it. When you build the Docker image, it will do a bundle install.

terminal


$ docker-compose build

9. Edit database.yml

config/database.yml


# Change before
default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") {5} %>

# After change
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: password
  pool: 5

10. Start the container

terminal


$ docker-compose up

*If the following error occurs

terminal


Error: No such file or directory @ rb_sysopen-/myapp/config/webpacker.yml (RuntimeError)

Create/edit webpacker.yml

terminal


touch config/webpacker.yml

webpacker.yml


# Note: You must restart bin/webpack-dev-server for changes to take effect

default: &default
  source_path: app/javascript
  source_entry_path: packs
  public_root_path: public
  public_output_path: packs
  cache_path: tmp/cache/webpacker
  webpack_compile_output: true# Additional paths webpack should lookup modules
  # ['app/assets', 'engine/foo/app/assets']
  additional_paths: []

  # Reload manifest.json on all requests so we reload latest compiled packs
  cache_manifest: false

  # Extract and emit a css file
  extract_css: true

  static_assets_extensions:
    - .jpg
    - .jpeg
    - .png
    - .gif
    - .tiff
    - .ico
    - .svg
    - .eot
    - .otf
    - .ttf
    - .woff
    - .woff2

  extensions:
    - .mjs
    - .js
    - .sass
    - .scss
    - .css
    - .module.sass
    - .module.scss
    - .module.css
    - .png
    - .svg
    - .gif
    - .jpeg
    - .jpg

development:
  <<: *default
  compile: true

  # Set to false if using HMR for CSS
  extract_css: true

  # Reference: https://webpack.js.org/configuration/dev-server/
  dev_server:
    https: false
    host: localhost
    port: 3035
    public: localhost:3035
    hmr: false
# Inline should be set to true if using HMR
    inline: true
    overlay: true
    compress: true
    disable_host_check: true
    use_local_ip: false
    quiet: false
    pretty: false
    headers:
      'Access-Control-Allow-Origin': '*'
    watch_options:
      ignored: '**/node_modules/**'

test:
  <<: *default
  compile: true

  # Compile test packs to a separate directory
  public_output_path: packs-test

production:
  <<: *default

  # Production depends on precompilation of packs prior to booting for performance.
  compile: false

  # Cache manifest.json for performance
  cache_manifest: true

11.データベースを作成

ターミナル


docker-compose run web rake db:create

※下記エラーが出る場合

ターミナル


could not translate host name "db" to address: Name or service not known

ターミナル


Error: Database is uninitialized and superuser password is not specified.

docker-compose.ymlを編集

docker-compose.yml


# 変更前
environment:
  POSTGRES_PASSWORD: password

# 変更後
environment:
  - POSTGRES_HOST_AUTH_METHOD=trust