Docker-compose二次启动触发ActiveRecord::ProtectedEnvironmentError求助
问题描述
首次执行docker-compose up时应用可正常运行,但后续启动容器时出现如下报错:
Database 'time_distribution_production' already exists. ActiveRecord::ProtectedEnvironmentError: You are attempting to run a destructive action against your 'production' database. If you are sure you want to continue, run the same command with the environment variable: DISABLE_DATABASE_ENVIRONMENT_CHECK=1
执行docker compose down -volumes重置卷后报错消失,但仅重启容器无法解决问题。
相关配置文件
Dockerfile
FROM ruby:3.1.2 ENV BUNDLER_VERSION=2.3.24 RUN apt update -qq && apt install -y libmsgpack-dev postgresql-client RUN gem install bundler -v 2.3.24 RUN mkdir /time-distribution WORKDIR /time-distribution ENV RAILS_ENV production COPY Gemfile . COPY Gemfile.lock . RUN bundle install COPY . . EXPOSE 3000 RUN chmod +x docker.sh CMD ./docker.sh
docker.sh
#!/bin/bash set -e rm -f tmp/pids/server.pid bundle exec rails db:setup bundle exec rails db:migrate bundle exec rails assets:precompile bundle exec rails server -p 3000 -b '0.0.0.0'
docker-compose.production.yml
version: '3' services: app: image: $IMAGE_NAME restart: always database: restart: always
生产环境database.yml
default: &default adapter: postgresql encoding: unicode pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> production: <<: *default database: <%= Rails.application.credentials.dig(:production, :postgres_name) %> username: <%= Rails.application.credentials.dig(:production, :postgres_username) %> password: <%= Rails.application.credentials.dig(:production, :postgres_password) %> host: database
解决方案
问题根源是每次容器启动时都会执行bundle exec rails db:setup,而db:setup包含db:create(创建数据库)操作,当数据库已存在时,该操作就会触发保护性报错。
方法一:使用安全的数据库创建命令
修改docker.sh,将bundle exec rails db:setup替换为bundle exec rails db:create --skip-if-exists,该命令仅在数据库不存在时执行创建操作:
# 替换前 bundle exec rails db:setup # 替换后 bundle exec rails db:create --skip-if-exists
后续启动容器时,只会检查数据库是否存在,不存在才创建,不会触发报错。
方法二:仅首次初始化时执行完整setup
如果需要保留db:setup的完整逻辑(比如加载seed数据),可以通过判断数据库状态来分支执行:
修改docker.sh中的数据库操作部分:
rm -f tmp/pids/server.pid # 检查数据库是否已存在 bundle exec rails db:exists if [ $? -ne 0 ]; then bundle exec rails db:setup else bundle exec rails db:migrate fi bundle exec rails assets:precompile bundle exec rails server -p 3000 -b '0.0.0.0'
首次启动时数据库不存在,执行db:setup完成初始化;后续启动时直接执行db:migrate处理新的迁移脚本即可。
内容的提问来源于stack exchange,提问作者Irina Egorova
相关产品推荐
相关产品推荐

