以下の手順で構築した環境で開発を進めようとした際に権限エラーにより Controller などが作成できなかったため対応しました。
環境構築
Winows11にDocker、ruby、rails、postgresql をインストールし rails new
で環境を作成する。
> rails new myapp -G -d postgresql
初期のDockerfile
作成された環境には Dockerfile が含まれていて実行することができます。
# syntax = docker/dockerfile:1
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.2.3
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
# Rails app lives here
WORKDIR /rails
# Set production environment
ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development"
# Throw-away build stage to reduce size of final image
FROM base as build
# Install packages needed to build gems
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libpq-dev libvips pkg-config
# Install application gems
COPY Gemfile Gemfile.lock ./
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile
# Copy application code
COPY . .
# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/
# Adjust binfiles to be executable on Linux
RUN chmod +x bin/* && \
sed -i "s/\r$//g" bin/* && \
sed -i 's/ruby\.exe$/ruby/' bin/*
# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
# Final stage for app image
FROM base
# Install packages needed for deployment
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libvips postgresql-client && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Copy built artifacts: gems, application
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build /rails /rails
# Run and own only the runtime files as a non-root user for security
RUN useradd rails --create-home --shell /bin/bash && \
chown -R rails:rails db log storage tmp
USER rails:rails
# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]
conpose.yaml を作成
services:
web:
build: .
command: bash -c "bundle e rails s -b '0.0.0.0'"
volumes:
- .:/usr/src/app
- gem_cache:/gems
ports:
- "3000:3000"
env_file:
- .env/development/web
- .env/development/database
depends_on:
- db
db:
image: postgres:16
ports:
- "5433:5432"
env_file:
- .env/development/database
volumes:
- "db_data:/var/lib/postgresql/data"
volumes:
db_data:
gem_cache:
database.yml を修正
default: &default
adapter: postgresql
encoding: unicode
host: db # compose.yaml の DB コンテナ名を指定する
username: <%= ENV['POSTGRES_USER'] %> # 追加
password: <%= ENV['POSTGRES_PASSWORD'] %> # 追加
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
development:
<<: *default
database: myapp_development
環境設定ファイルを追加する
.env/development/database
POSTGRES_DB=myapp_development
POSTGRES_USER=postgres
POSTGRES_PASSWORD=password
.env/development/web
RAILS_ENV=development
ディレクトリ構造
myapp
└── .env
├── development
│ ├── database
│ └── web
# その他のプロジェクトファイル
DBを作成
> docker compose run web bundle exec rake db:create
> docker compose run web bundle exec rake db:migrate
環境構築ここまで
コンテナを作成して実行できることを確認します。
サーバーは問題なく起動するはずですが開発を進めようとした際に詰まります。
> docker compose build
> docker compose up
エラーの内容
初期の状態で作成したコンテナでは rails コマンドで Controller の作成などを行おうとすると権限エラーなります。
> docker compose run web bin/rails g controller Posts
[+] Creating 1/0
✔ Container myapp-db-1 Created 0.0s
[+] Running 1/1
✔ Container myapp-db-1 Started 1.1s
/usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/actions/create_file.rb:64:in `initialize': Permission denied @ rb_sysopen - /rails/app/controllers/posts_controller.rb (Errno::EACCES)
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/actions/create_file.rb:64:in `open'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/actions/create_file.rb:64:in `block in invoke!'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/actions/empty_directory.rb:117:in `invoke_with_conflict_check'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/actions/create_file.rb:61:in `invoke!'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/actions.rb:93:in `action'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/actions/create_file.rb:25:in `create_file'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/actions/file_manipulation.rb:124:in `template'
from /usr/local/bundle/ruby/3.2.0/gems/railties-7.1.3.2/lib/rails/generators/named_base.rb:25:in `block in template'
from /usr/local/bundle/ruby/3.2.0/gems/railties-7.1.3.2/lib/rails/generators/named_base.rb:45:in `inside_template'
from /usr/local/bundle/ruby/3.2.0/gems/railties-7.1.3.2/lib/rails/generators/named_base.rb:24:in `template'
from /usr/local/bundle/ruby/3.2.0/gems/railties-7.1.3.2/lib/rails/generators/rails/controller/controller_generator.rb:14:in `create_controller_files'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/command.rb:28:in `run'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/invocation.rb:127:in `invoke_command'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `block in invoke_all'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `each'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `map'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `invoke_all'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/group.rb:232:in `dispatch'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/base.rb:584:in `start'
from /usr/local/bundle/ruby/3.2.0/gems/railties-7.1.3.2/lib/rails/generators.rb:261:in `invoke'
from /usr/local/bundle/ruby/3.2.0/gems/railties-7.1.3.2/lib/rails/commands/generate/generate_command.rb:26:in `perform'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/command.rb:28:in `run'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor/invocation.rb:127:in `invoke_command'
from /usr/local/bundle/ruby/3.2.0/gems/railties-7.1.3.2/lib/rails/command/base.rb:178:in `invoke_command'
from /usr/local/bundle/ruby/3.2.0/gems/thor-1.3.1/lib/thor.rb:527:in `dispatch'
from /usr/local/bundle/ruby/3.2.0/gems/railties-7.1.3.2/lib/rails/command/base.rb:73:in `perform'
from /usr/local/bundle/ruby/3.2.0/gems/railties-7.1.3.2/lib/rails/command.rb:71:in `block in invoke'
from /usr/local/bundle/ruby/3.2.0/gems/railties-7.1.3.2/lib/rails/command.rb:149:in `with_argv'
from /usr/local/bundle/ruby/3.2.0/gems/railties-7.1.3.2/lib/rails/command.rb:69:in `invoke'
from /usr/local/bundle/ruby/3.2.0/gems/railties-7.1.3.2/lib/rails/commands.rb:18:in `<main>'
from <internal:/usr/local/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
from <internal:/usr/local/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
from /usr/local/bundle/ruby/3.2.0/gems/bootsnap-1.18.3/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
from /rails/bin/rails:4:in `<main>'
Dockerfileを変更する
Dockerfile の後半の RUN useradd
の箇所を以下の内容に変更します。
RUN useradd -m -s /bin/bash rails && \
chown -R rails:rails /rails
USER rails
-
/rails
ディレクトリの所有権を rails ユーザーに明示的に設定し、コンテナ内でこのユーザーとして実行するようにUSER
命令を配置しています。これにより、rails コマンドを使用して新しいファイルを作成する際に必要な適切な権限が保証されます。 -
useradd
コマンドに-m
オプション(ホームディレクトリの作成)と-s
オプション(デフォルトシェルの指定)を追加しました。これにより、rails ユーザーの環境がより完全なものになります。
終わり
ひとまずこれで Controller などの作成時に権限エラーが発生することは無くなりました。
指摘や他のやり方があればコメントください。