初めに
初学者です。
webアプリを個人で開発するために、dockerを使用してruby on railsでの開発環境構築を実施した際の記録を共有します。
公開日時点での最新安定版を使用しています。
本記事ではdockerを使いherokuへのデプロイをgithub actionsで自動化するところまで行いますが、最終的にエラーで行き詰まり、別記事にて再度環境構築をやり直します。
成功した手順のみを参考にしたい方は、こちらの記事を読んでください。
https://qiita.com/tkhero555/items/a1811369c59021077d62
構築したい技術構成
カテゴリ | 技術 |
---|---|
フロントエンド | javascript/Hotwire/bootstrap |
バックエンド | ruby3.3.0/rails7.1.3.2 |
データベース | PostgreSQL16.2 |
認証 | devise |
環境構築 | Docker / docker-compose |
CI/CD | Github Actions |
インフラ | heroku |
docker関係のファイルを作成~rails newまで
作業するディレクトリを作成した後、docker関係のファイルを作成します。
- compose.yml
- Dockerfile
- Gemfile
- Gemfile.lock
各ファイルの構成
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
Dockerfile
FROM ruby:3.3.0
# データベース用にPostgreSQLをインストール
RUN apt-get update -qq && apt-get install -y postgresql-client
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
COPY . /myapp
# Rails サーバ起動
CMD ["rails", "server", "-b", "0.0.0.0"]
Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 7.1', '>= 7.1.3.2'
イメージをbuildする
docker compose build
rails newを実行する。
$ docker compose run --rm web rails new . --force --no-deps --database=postgresql
上手くいかずログを確認すると、
! db The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested 0.0s
Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "rails": executable file not found in $PATH: unknown
dockerが実行しようとするプラットフォームと、ホストのプラットフォームが違うよ〜というエラーと、railsが$path内に見つからないよとのエラーが出ている。
Dockerfileにbundle installを追記
FROM ruby:3.3.0
RUN apt-get update -qq && apt-get install -y postgresql-client
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp/
CMD ["rails", "server", "-b", "0.0.0.0"]
コマンドにプラットフォームオプションを追加して再実行
docker compose run --platform linux/amd64 --rm web rails new . --force --no-deps --database=postgresql
下記の表示が返ってきて上手くいかない
unknown flag: --platform
compose.yamlにplatformの指定を追記する
services:
db:
image: postgres
volumes:
- ./tmp/db:/var/lib/postgresql/data
platform: linux/amd64
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
再度rails newを実行
docker compose run web rails new . --force --no-deps --database=postgresql
rails関係のファイルが作成されたことが確認できた。
データベースの作成をしようとしたらエラー発生
rails newで作成されたファイルの中から、データベースのymlファイルを編集する。
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
host: db
username: postgres
password: password
development:
<<: *default
database: myapp_development
test:
<<: *default
database: myapp_test
データベースを作成する
docker compose run web rails db:create
エラーが発生したので、実行ログを見てみる。
Could not find sprockets-rails-3.4.2, pg-1.5.6, puma-6.4.2, importmap-rails-2.0.1, turbo-rails-2.0.5, stimulus-rails-1.3.3, jbuilder-2.11.5, bootsnap-1.18.3, debug-1.9.2, web-console-4.2.1, capybara-3.40.0, selenium-webdriver-4.19.0, sprockets-4.2.1, msgpack-1.7.2, bindex-0.8.1, addressable-2.8.6, regexp_parser-2.9.0, xpath-3.2.0, rubyzip-2.3.2, websocket-1.2.10, public_suffix-5.0.4 in locally installed gems
Run `bundle install --gemfile /myapp/Gemfile` to install missing gems.
必要なgemが存在しないとのこと。
先ほどrails newをした際にgemfileに追記されたgemがinstallされていないのが原因とか?
bundle installしてみる
docker compose run web bundle install
再度データベースを作成してみるが、同じエラーが継続
Gemfileの変更内容がdockerイメージに反映されておらず、ローカルとコンテナのファイルに差異があるとか?
buildして、再度データベースを作成してみる。
実行結果
$ docker compose run web rails db:create
[+] Creating 1/0
✔ Container runteq_graduation_exam-db-1 R... 0.0s
/rails/bin/docker-entrypoint: line 8: exec: rails: not found
ダメそう。
また、docker compose upしてみるとエラーが発生している。
/usr/local/bundle/ruby/3.3.0/gems/railties-7.1.3.2/lib/rails/application.rb:658:in `validate_secret_key_base': Missing `secret_key_base` for 'production' environment, set this string with `bin/rails credentials:edit` (ArgumentError)
web-1 |
web-1 | raise ArgumentError, "Missing `secret_key_base` for '#{Rails.env}' environment, set this string with `bin/rails credentials:edit`"
本番環境で使うsecret_key_baseが不足している?
この時点では開発環境の設定で環境を用意したつもりなのだけど、どういうことだ?
調べるとDockerfileの記述がいつの間にか変わっており、railsの環境がproduction設定になっていた。
# Set production environment
ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development"
どうやらrails7.1の機能で、rails newの際に自動的に本番環境用のDockerfileを生成するようになっているらしい。
この機能で用意していたDockerfileが上書きされておかしくなったようだ。
development指定に変更して、BUNDLE_WITHOUTを削除してみる。
buildしてupしたところ、無事にコンテナが起動した。
再度データベース作成したらエラー
$ docker compose exec web rails db:create
OCI runtime exec failed: exec failed: unable to start container process:
exec: "rails": executable file not found in $PATH: unknown
railsコマンドの前にbundle execをつけてみる。
$ docker compose exec web bundle exec rails db:create
Created database 'myapp_development'
Created database 'myapp_test'
行けたっぽい。
localhost::3000にブラウザでアクセスして、Railsアプリのページが表示されていることを確認できた!
herokuへのデプロイ設定
参考記事に従って、docker関連ファイルに変更を加える。
※後から気づいたが、herokuCLIを利用してデプロイする場合、ここでの本番環境に関する設定変更は不要だった。
Dockerfile
ENV設定をproductionに変更
# Set production environment
ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle"
いつの間にか追記されていた下2行は一旦コメントアウト
production:
<<: *default
database: myapp_production
# username: myapp
# password: <%= ENV["MYAPP_DATABASE_PASSWORD"] %>
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = true # false
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
config.public_file_server.enabled = true # ENV["RAILS_SERVE_STATIC_FILES"].present?
herokuに会員登録して、月額費用を支払う設定を完了しておく。
Heroku CLIをインストールする。
macなのでhomebrew
brew tap heroku/brew && brew install heroku
heroku loginコマンドでアカウントログインを完了する。
作業中のアプリのディレクトリで、herokuのアプリケーションを作成する。
heroku create -a アプリ名
デプロイする。
git push heroku main
デプロイしたアプリにアクセスする。
heroku open
github actionsでデプロイを自動化
herokuのAPIキーをサイトから取得する。
githubにアクセスし、リポジトリのメニューからsettingsタブ、secrets and variablesのactionsでnew repository secretをクリック
2つのsecretを作成する。
- HEROKU_API_KEY: herokuのAPIキーを内容に入れておく
- HEROKU_APP_NAME:デプロイ先のherokuアプリ名を入れておく
ローカルの作業ディレクトリで.github/workflowsディレクトリを作成し、その中でdeploy.ymlファイルを作成する。
name: Deploy to Heroku
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Login to Heroku
uses: akhileshns/heroku-deploy@v3.12.12 # This is the action
with:
heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
heroku_app_name: ${{ secrets.HEROKU_APP_NAME }}
heroku_email: "nmt.1727@gmail.com"
作成したワークフローファイルをリモートリポジトリにプッシュすれば設定完了
mainブランチに変更を加えた際に自動でherokuへのデプロイを実行する設定にしている。
githubのリポジトリに行ってactionsタブから動作を確認できる。
controllerを作成しようとした際にエラー発生
コントローラーを作成しようとしたところ、エラー発生
/usr/local/bundle/ruby/3.3.0/gems/thor-1.3.1/lib/thor/actions/
create_file.rb:64:in `initialize': Permission denied @ rb_sysopen -
/rails/app/controllers/line_bot_controller.rb (Errno::EACCES)
コントローラーを作成しようとした時に、書き込み権限が無いエラー
ディレクトリの所有者をls -laで確認してみる。
$ cd app/controllers/
mynameMacBook-Air:controllers myname$ ls -la
total 8
drwxr-xr-x 4 myname staff 128 4 1 14:13 .
drwxr-xr-x 11 myname staff 352 4 1 14:13 ..
-rw-r--r-- 1 myname staff 57 4 1 14:13 application_controller.rb
drwxr-xr-x 3 myname staff 96 4 1 14:13 concerns
dockerのコンテナの中に入ってから、ls -laで確認してみる。
rails@f1bf5a5f353c:/rails$ cd app/
rails@f1bf5a5f353c:/rails/app$ cd controllers/
rails@f1bf5a5f353c:/rails/app/controllers$ ls -la
total 16
drwxr-xr-x 3 root root 4096 Mar 31 09:18 .
drwxr-xr-x 11 root root 4096 Mar 31 09:18 ..
-rw-r--r-- 1 root root 57 Mar 31 09:18 application_controller.rb
drwxr-xr-x 2 root root 4096 Mar 31 09:18 concerns
rootが所有者になっている。
rails@f1bf5a5f353c:/rails/app/controllers$ whoami
rails
コンテナ内での作業者はrailsになっている。
rootが所有しているディレクトリでrailsが作業しようとして、権限が無いというのが現状?
DockerfileにUSER rails:railsという記述があり、これによって作業者がrailsになっているんだと思う。
この記述はRails7で自動的に追加されるもので、セキュリティ的にいい効果があるようだが、動くこと優先で削除してみる。
docker compose build
docker compose up
コンテナ起動中にエラー発生
/usr/local/bundle/ruby/3.3.0/gems/railties-7.1.3.2/lib/rails/application.rb:658:in `validate_secret_key_base': Missing `secret_key_base` for 'production' environment, set this string with `bin/rails credentials:edit` (ArgumentError)
web-1 |
web-1 | raise ArgumentError, "Missing `secret_key_base` for '#{Rails.env}' environment, set this string with `bin/rails credentials:edit`"
herokuへのデプロイ設定の時に変更していた本番環境の指定が原因なので、変更前に戻す。
Dockerfile
# Set production environment
ENV RAILS_ENV="development" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle"
# Disable serving static files from `public/`, relying on NGINX/Apache to do so instead.
#config.public_file_server.enabled = true
# Do not fall back to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
buildしてupすると無事にコンテナが起動した。
コンテナ内の所有者と作業者を再確認
root@b961a7cb106f:/rails/app# cd controllers/
root@b961a7cb106f:/rails/app/controllers# ls -la
total 16
drwxr-xr-x 3 root root 4096 Apr 3 04:26 .
drwxr-xr-x 11 root root 4096 Mar 31 09:18 ..
-rw-r--r-- 1 root root 57 Apr 1 05:13 application_controller.rb
drwxr-xr-x 2 root root 4096 Apr 2 11:46 concerns
root@b961a7cb106f:/rails/app/controllers# whoami
root
ディレクトリの所有者と作業者、両方ともrootになっている。
gemfileにgemを追加してbundle installをしようとすると、gemが追加されない。
どういうことだろうか?
gemfileに追記した状態でbuildしなおしてみるとエラー
=> ERROR [web build 3/6] RUN bundle install && rm -rf ~/.bundle/ "/usr/ 0.3s
------
> [web build 3/6] RUN bundle install && rm -rf ~/.bundle/ "/usr/local/bundle"/ruby/*/cache "/usr/local/bundle"/ruby/*/bundler/gems/*/.git && bundle exec bootsnap precompile --gemfile:
0.264 The dependencies in your gemfile changed, but the lockfile can't be updated
0.264 because frozen mode is set
0.264
0.264 You have added to the Gemfile:
0.264 * line-bot-api
0.264
0.264 Run `bundle install` elsewhere and add the updated Gemfile to version control.
0.264 If this is a development machine, remove the Gemfile.lock freeze by running
0.264 `bundle config set frozen false`.
------
failed to solve: process "/bin/sh -c bundle install && rm -rf ~/.bundle/ \"${BUNDLE_PATH}\"/ruby/*/cache \"${BUNDLE_PATH}\"/ruby/*/bundler/gems/*/.git && bundle exec bootsnap precompile --gemfile" did not complete successfully: exit code: 16
frozenモードを削除しようとしてみる。
bundle config set frozen false
効果なし。
解決を諦める
参考にした記事と使用するrailsのバージョンが違ったことで、Rails7.1で自動生成されるDockerfileとのぶつかり合いが起こり、そこからよく分からなくなった。
今の状況からどこを修正すれば解決できるか、悩んでも思いつかなかった為、別ディレクトリで新しく環境を作り直そうと思います。
参考記事・サイト