DockerでRuby3.1、Rails7.0、MySQL8.0の環境構築
業務でnginxを触っていた中で、より体系的に学んでみたいと思い「nginx実践入門」という書籍を読みました。
当然nginxであれこれする環境を作りたくなったので、まずはアプリケーションとしてrails7系をdockerで構築したメモです。nginxコンテナじゃないんかいとツッコミがありそうですが、nginxコンテナの導入は次の記事で書きます(余力がない)。
環境
- Apple M1 Pro
- macOS Monterey 12.1
- Docker Engine 20.10.12
- Docker Compose v2.2.3
- Ruby 3.1.1
- Ruby on Rails 7.0.2
- nginx 1.21.6
準備
基本的な流れは[railsのコンテナを作るための準備をする → railsのコンテナを作る → DBとつなげる]となります。
まずは準備です。
作業ディレクトリ作成
今回はapp > docker > webと掘ります。こんな構成です。
app └─ docker └─ web ├── Dockerfile ├── entrypoint.sh └── start-server.sh
# ディレクトリ作成 $ mkdir -p /app/docker/web $ cd /app/docker/web # Dockerfile作成 $ touch Dockerfile
Dockerfile
ruby3.1のイメージを使います。
FROM ruby:3.1 ENV LANG C.UTF-8 ENV APP_ROOT /app ENV BUNDLE_JOBS 4 ENV BUNDLER_VERSION 2.2.25 RUN mkdir $APP_ROOT WORKDIR $APP_ROOT COPY Gemfile $APP_ROOT/Gemfile COPY Gemfile.lock $APP_ROOT/Gemfile.lock RUN gem install bundler -v $BUNDLER_VERSION RUN bundle -v RUN bundle install COPY . $APP_ROOT # Add a script to be executed every time the container starts. COPY ./docker/web/entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] EXPOSE 3000 # 起動の度にデフォルトでrails sする(entrypoint.shに持たせても良い) CMD ["sh", "./docker/web/start-server.sh"]
entrypoint.sh
$ vim entrypoint.sh
#!/bin/bash set -e # Remove a potentially pre-existing server.pid for Rails. rm -f /app/tmp/pids/server.pid # Then exec the container's main process (what's set as CMD in the Dockerfile). exec "$@"
start-server.sh
$ vim start-server.sh
#!/bin/sh echo "run start-server.sh" & rails server -p 3000 -b 0.0.0.0
gemfile
railsをbundle installできるようにします。
$ cd ../.. # /app $ bundle init $ vim Gemfile
# frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem 'rails', '~>7.0.2'
gemfile.lock
ファイルの中身は空でOKです。
$ touch gemfile.lock
docker-compose.yml
mysqlは8.0にしてみます。dataの永続化は/volumes/mysql/data/で行いました。環境変数は適当なので真似しないでね。
$ cd ../.. # /app $ mkdir -p /volumes/mysql/data/
version: '3' services: web: build: context: . dockerfile: ./docker/web/Dockerfile volumes: - .:/app # カレントディレクトリ(後のアプリケーションディレクトリ)をマウント ports: - '3000:3000' depends_on: - db stdin_open: true tty: true environment: DB_ROOT_USERNAME: root DB_USERNAME: development DB_PASSWORD: password TZ: Asia/Tokyo DB_HOST: db db: platform: linux/x86_64 image: mysql:8.0 environment: - MYSQL_DATABASE=development - MYSQL_USER=development - MYSQL_PASSWORD=password - MYSQL_ROOT_PASSWORD=passwordpassword - TZ=Asia/Tokyo ports: - '3306:3306' command: --default-authentication-plugin=mysql_native_password volumes: - ./volumes/mysql/data/:/var/lib/mysql
railsアプリの作成
ここまでくればdocker-compose runにてビルドし、railsアプリを作成することが可能です。データベースはmysqlを指定します。
$ docker-compose run web rails new . --force --database=mysql
rails newによりGemfileが更新されたので、再度イメージをビルドし、railsアプリとしてのイメージを作成します。
$ docker-compose build
mysqlとの繋ぎ込み
この時点でdocker-compose upをしてからlocalhost:3000でアプリケーションにアクセスすることは可能になっていますが、DBとの繋ぎ込みができていないため、ActiveRecord::DatabaseConnectionErrorが返ってきているはずです。
docker-compose.ymlのwebコンテナに記載した環境変数に合わせて、database.ymlを編集していきましょう。dbコンテナでMYSQL_DATABASE、MYSQL_USER、MYSQL_PASSWORDを指定していたため、データベースとともに権限を持ったユーザーも作成されているはずなので、そちらを指定していきます。
$ vim config/database.yml
default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: <%= ENV["DB_USERNAME"] %> password: <%= ENV["DB_PASSWORD"] %> host: db # コンテナ名(db)で名前解決 development: <<: *default database: development
本格的な開発フェーズに入ったら、ENV.fetchやcredentialsを組み合わせて設定するようにします(割愛します)。
動作確認
コンテナを起動します。
$ docker-compose up -d
localhost:3000にアクセスします。
お疲れさまでした!
mysqlコンテナの環境変数について
補足です。
上記docker-compose.ymlのmysqlコンテナで、MYSQL_DATABASE、MYSQL_USER、MYSQL_PASSWORD、MYSQL_ROOT_PASSWORDを設定しています。
mysqlのdockerのドキュメントを見ればわかりますが、特にMYSQL_USER、MYSQL_PASSWORDを設定しておくと、MYSQL_DATABASEで指定したデータベースに対するスーパーユーザー権限が付与されたユーザーを作ってくれます。
$ docker-compose exec db bash -c 'mysql -u root -p${MYSQL_ROOT_PASSWORD}' mysql> select user, host from mysql.user; +------------------+-----------+ | user | host | +------------------+-----------+ | development | % | | root | % | | mysql.infoschema | localhost | | mysql.session | localhost | | mysql.sys | localhost | | root | localhost | +------------------+-----------+ 6 rows in set (0.04 sec) mysql> show grants for development; +--------------------------------------------------------------+ | Grants for development@% | +--------------------------------------------------------------+ | GRANT USAGE ON *.* TO `development`@`%` | | GRANT ALL PRIVILEGES ON `development`.* TO `development`@`%` | +--------------------------------------------------------------+ 2 rows in set (0.00 sec)
次回はnginxコンテナです。
書きました↓
参考記事
Rails 7 + MySQLの環境構築をDocker composeで作る - Qiita