ActiveRecord::AdapterNotSpecified: 'development' database is not configured. Available: [] - ruby-on-rails

I am trying to set up my development environment in rails with docker compose. Getting an error saying
ActiveRecord::AdapterNotSpecified: 'development' database is not configured. Available: []
Dockerfile:
# syntax=docker/dockerfile:1
FROM ruby:2.5.8
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN apt-get install cron -y
RUN apt-get install vim -y
RUN export EDITOR="/usr/bin/vim"
RUN addgroup deploy && adduser --system deploy && adduser deploy deploy
USER deploy
WORKDIR /ewagers
RUN (crontab -l 2>/dev/null || true; echo "*/5 * * * * /config/schedule.rb -with args") | crontab -
COPY Gemfile .
COPY Gemfile.lock .
RUN gem install bundler -v 2.2.27
RUN bundle install
COPY . .
USER root
COPY docker-entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/docker-entrypoint.sh
COPY wait-for-it.sh /usr/bin/
RUN chmod +x /usr/bin/wait-for-it.sh
RUN chown -R deploy *
RUN chmod 644 app
RUN chmod u+x app
RUN whenever --update-crontab ewagers --set environment=production
COPY config/database.example.yml ./config/database.yml
RUN mkdir data
ARG RAILS_MASTER_KEY
RUN printenv
EXPOSE 3000
# Configure the main process to run when running the image
CMD ["rails", "server", "-b", "0.0.0.0"]
database.example.yml:
# database.yml
default: &default
adapter: postgresql
encoding: unicode
host: db
username: postgres
password: ewagers
pool: 5
development:
<<: *default
database: postgres
docker compose:
version: "3.9"
services:
app:
build: .
command: docker-entrypoint.sh
ports:
- 4000:3000
environment:
DB_URL: postgres://db/ewagers_dev # db is host, ewagers_dev is db name
RAILS_ENV: development
volumes:
- .:/ewagers # mapping our current directory to ewagers directory in the container
# - ewagers-sync:/ewagers:nocopy
image: ksun/ewagers:latest
depends_on:
- db
db:
image: postgres:12
volumes:
- ewagers_postgres_volume:/var/lib/postgresql/data # default storage location for postgres
environment:
POSTGRES_PASSWORD: ewagers
ports:
- 5432:5432 # default postgres port
volumes: # we specify a volume so postgres does not write data to temporary db of its container
ewagers_postgres_volume:
I have double-checked indentations and spacing, done a docker build to make sure the database.example.yml is being copied to database.yml. However it seems it can't even find my development configuration in database.yml.
What's interesting is if I have what's in my database.example.yml and create a database.yml file locally with the same contents, it will work. But it should work without that, since I am copying database.example.yml to databse.yml in the dockerfile.

Related

Docker - Permission denied # rb_sysopen - Image installation path overwriting a volume - changes not reflected

Trying to sort this permission error on Ubuntu, when trying to run my containers using dockerfile and docker-compose.yml
Exiting
/usr/local/bundle/gems/rack-2.2.3/lib/rack/server.rb:433:in `initialize': Permission denied # rb_sysopen - /home/api/limpar/current/tmp/pids/server.pid (Errno::EACCES)
Dockerfile
FROM ruby:2.7.1
ENV LANG C.UTF-8
ENV NODE_VERSION 12
ENV NODE_ENV production
ENV INSTALL_PATH /home/api/limpar/current
.
(...)
RUN mkdir -p $INSTALL_PATH
WORKDIR $INSTALL_PATH
COPY Gemfile Gemfile.lock ./
RUN gem install bundler
RUN bundle install
COPY . $INSTALL_PATH
RUN rm -rf tmp
RUN useradd -Ms /bin/bash api -u 1001
RUN chown -R api:api /home/api /usr/local/bundle
USER api
EXPOSE 3000
CMD rails server -p 3000 -b 0.0.0.0
docker-compose.yml
api:
container_name: limpar-api
image: limpar-api
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
env_file:
- .env
volumes:
- ./:/home/api/limpar/current
ports:
- "3000:3000"
depends_on:
- db
- redis
networks:
- limpar_network
docker build runs with no failures. Dockerfile instal_path overwrites a volume location on docker-compose file. By changing the volume name on my docker-compose.yml file,
I am able to fix the permission errors.
However, the local changes on my code no longer get reflected, meaning I have to rebuild everytime I change anything.
Any missing points on Dockerfile, regarding user permissions?
Thanks in advance
Adding
USER root
to Docker file, RUN chown... fixed the permission issues, and allowed me to keep same path on dockerfile and docker-compose volume, solving the local code changes not reflecting.

How to install new gems in a rails docker image without rebuilding it

I am trying to create my rails application in a docker environment. I have used volumes to mount source directories from the host at a targeted path inside the container. The application is in the development phase and I need to continuously add new gems to it. I install a gem from the bash of my running container, it installs the gem and the required dependencies. But when I removed the running containers(docker-compose down) and then again instantiated them(docker-compose up), my rails web image shows errors of missing gems. I know re-building the image will add the gems but IS THERE ANY WAY TO ADD GEMS WITHOUT REBUILDING THE IMAGE?
I Followed docker-compose docs for setting the rails app
https://docs.docker.com/compose/rails/#define-the-project
DOCKERFILE
FROM ruby:2.7.1-slim-buster
LABEL MAINTAINER "Prayas Arora" "<prayasa#mindfiresolutions.com>"
# Install apt based dependencies required to run Rails as
# well as RubyGems. As the Ruby image itself is based on a
# Debian image, we use apt-get to install those.
RUN apt-get update \
&& apt-get install -qq -y --no-install-recommends \
build-essential \
libpq-dev \
netcat \
postgresql-client \
nodejs \
&& rm -rf /var/lib/apt/lists/*
ENV APP_HOME /var/www/repository/repository_api
# Configure the main working directory. This is the base
# directory used in any further RUN, COPY, and ENTRYPOINT
# commands.
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
# Copy the Gemfile as well as the Gemfile.lock and install
# the RubyGems. This is a separate step so the dependencies
# will be cached unless changes to one of those two files
# are made.
COPY ./repository_api/Gemfile $APP_HOME/Gemfile
COPY ./repository_api/Gemfile.lock $APP_HOME/Gemfile.lock
RUN bundle install
# Copy the main application.
COPY ./repository_api $APP_HOME
# Add a script to be executed every time the container starts.
COPY ./repository_docker/development/repository_api/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
# Expose port 3000 to the Docker host, so we can access it
# from the outside.
EXPOSE 3000
# The main command to run when the container starts. Also
# tell the Rails dev server to bind to all interfaces by
# default.
CMD ["rails","server","-b","0.0.0.0"]
docker-compose.yml
container_name: repository_api
build:
context: ../..
dockerfile: repository_docker/development/repository_api/Dockerfile
user: $UID
env_file: .env
stdin_open: true
environment:
DB_NAME: ${POSTGRES_DB}
DB_PASSWORD: ${POSTGRES_PASSWORD}
DB_USER: ${POSTGRES_USER}
DB_HOST: ${POSTGRES_DB}
volumes:
- ../../repository_api:/var/www/repository/repository_api
networks:
- proxy
- internal
depends_on:
- repository_db
A simple solution is to cache the gems in a docker volume. You can create a volume in docker and attach it to the path to bundle gems. This will maintain a shared state and you will not require to install the gems in every container you spun.
container_name: repository_api
build:
context: ../..
dockerfile: repository_docker/development/repository_api/Dockerfile
user: $UID
env_file: .env
stdin_open: true
environment:
DB_NAME: ${POSTGRES_DB}
DB_PASSWORD: ${POSTGRES_PASSWORD}
DB_USER: ${POSTGRES_USER}
DB_HOST: ${POSTGRES_DB}
volumes:
- ../../repository_api:/var/www/repository/repository_api
- bundle_cache:/usr/local/bundle
networks:
- proxy
- internal
.
.
volumes:
bundle_cache:
Also, a/c to bundler.io, the official Docker images for Ruby assume that you will use only one application, with one Gemfile, and no other gems or Ruby applications will be installed or run in your container. So once you have added all the gems required in your application development, you can remove this bundle_cache volume and rebuild your image with your final Gemfile.

Rails 5 with Docker (Unable to create app)

I'm getting started with docker and following official docker documentation.
When I execute docker-compose run command only a temp folder gets created and no other folder/file.
Dockerfile
FROM ruby:2.5
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN mkdir /payment-api
WORKDIR /payment-api
COPY Gemfile /payment-api/Gemfile
COPY Gemfile.lock /payment-api/Gemfile.lock
RUN bundle install
COPY . /payment-api
# 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"]
docker-compose.yml
version: '3'
services:
db:
image: postgres
volumes:
- ./tmp/db:/var/lib/postgresql/data
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
Command I'm running to create the rails app
docker-compose run web rails new . --force --no-deps --database=postgresql
P.S: Not getting any sort of error and commands are executing normally but nothing except a temp folder gets created.
I know it's a bit late but I faced a similar issue running Docker toolbox on a Windows 10 Home Edition , along with VirtualBox . The key here is to allow "shared folder" access to VirtualBox . Navigate to VirtualBox -> Settings -> Shared Folders . Add your application path to "Shared Folders" . It should work fine now .
Hope this helps!

Docker (rails, postgresql) hanging when started, rather than connecting to DB

I'm new to docker, and trying to workout why my Docker setup is hanging and not connecting like I expect it to.
I'm running
Docker version 18.09.2, build 6247962
docker-compose version 1.23.2, build 1110ad01
OSX 10.14.5
My setup is based on this Gist that I found.
I've reduced it somewhat, to better demonstrate the issue.
Dockerfile
FROM ruby:2.4
ARG DEBIAN_FRONTEND=noninteractive
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main" >> /etc/apt/sources.list.d/postgeresql.list \
&& wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
&& apt-get update \
&& apt-get update \
&& apt-get install -y --no-install-recommends apt-utils \
&& apt-get install -y build-essential \
&& apt-get install -y nodejs \
&& apt-get install -y --no-install-recommends \
postgresql-client-9.6 pv ack-grep ccze unp htop vim \
&& apt-get install -y libxml2-dev libxslt1-dev \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get purge -y --auto-remove
# Set environment
ENV APP_HOME /usr/src/app
ENV BUNDLER_VERSION 2.0.2
# Setup bundler
RUN gem install bundler -v $BUNDLER_VERSION
WORKDIR $APP_HOME
EXPOSE 7051
CMD ["bundle", "exec", "puma", "-p", "7051", "-C", "config/puma.rb"]
docker_compose.yml
version: '3.1'
services:
app: &app_base
build: .
working_dir: /usr/src/app
volumes:
- .:/usr/src/app
# to be able to forward ssh-agent to github through capistrano (bundle on server)
- "~/.ssh/id_rsa:/root/.ssh/id_rsa"
- $SSH_AUTH_SOCK:$SSH_AUTH_SOCK
environment: &app_environment
# to keep bundle effect between container restarts (without rebuild):
BUNDLE_PATH: /usr/src/app/.bundle
BUNDLE_APP_CONFIG: /usr/src/app/.bundle
DATABASE_HOST: db
SSH_AUTH_SOCK: # this left empty copies from outside env
env_file: '.env'
ports:
- "7051:7051"
depends_on:
- db
db:
image: postgres:9.5.17
ports:
- "5432:5432"
environment:
POSTGRES_DB: my_project_development
POSTGRES_USER: root
POSTGRES_PASSWORD: root
config/database.yml
development:
adapter: postgresql
encoding: unicode
pool: 5
database: my_project_development
username: root
password: root
host: db
config/puma.rb
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i
threads threads_count, threads_count
# Specifies the `port` that Puma will listen on to receive requests, default is 3000.
#
port ENV.fetch("PORT") { 7051 }
# Specifies the `environment` that Puma will run in.
#
environment ENV.fetch("RAILS_ENV") { "development" }
# Allow puma to be restarted by `rails restart` command.
plugin :tmp_restart
So what I'm doing is:
Running docker-compose build to first build the images & containers
Running docker-compose run --rm app bundle install to install the gems
Running docker-compose run --rm app bundle exec rake db:create db:migrate db:seed to create/migrate/seed the database
Step 3. is the step I am stuck on. It just hangs there with no feedback:
docker-compose run --rm app bundle exec rake db:create db:migrate db:seed
Starting my_project_db_1 ... done
I know the database is running, as I can connect to it locally.
I can also log into the app container, and connect via psql, so I know that the app container can talk to the db container:
docker exec -it f6d6edadaed4 /bin/bash (52s 699ms)
root#f6d6edadaed4:/usr/src/app# psql "postgresql://root:root#db:5432/my_project_development"
psql (9.6.14, server 9.5.17)
Type "help" for help.
my_project_development=# \dt
No relations found.
If I try to boot the app with docker-compose up, then it also just hangs:
app_1 | Puma starting in single mode...
app_1 | * Version 3.11.4 (ruby 2.4.6-p354), codename: Love Song
app_1 | * Min threads: 5, max threads: 5
app_1 | * Environment: ci
I.e. puma would normally show a 'listening' message once connected:
* Listening on tcp://0.0.0.0:7051
Use Ctrl-C to stop
But it's not getting to that point, it just hangs.
What could be going on? Why can't my Rails container just connect to the PostgreSQL container and have puma boot normally?
MORE INFORMATION:
I've learn't now, if I wait 10+ minutes, it does eventually boot!
During that 10 mins, my CPU fans are spinning like crazy, so it's really thinking about something.
But when it finishes, the CPU fans shut off, and puma has booted and I can access it locally at http://127.0.0.1:7051 like I would expect.
Why would it be so slow to startup? My machine is otherwise pretty fast.
I think Docker on OSX is just extremely slow. I've since read about some performance issues here
Adding a cached option to the volume seems to have reduced the boot time to ~2mins
version: '3.1'
services:
app: &app_base
build: .
working_dir: /usr/src/app
volumes:
- .:/usr/src/app:cached
...
Still not very acceptable in my opinion. Would love to know if there's anything else that can be done?
I found an actual working answer to this, which I also posted here: https://stackoverflow.com/a/58603025/172973
Basically, see the article here to see how to properly setup Dockerfile and docker-compose.yml, so that it performs well on OSX.
The main thing to understand:
To make Docker fast enough on MacOS follow these two rules: use :cached to mount source files and use volumes for generated content (assets, bundle, etc.).
So if anyone else comes across this, just follow the article or see my other answer.

Serving Rails' precompiled assets using nginx in Docker

Currently I'm setting up my app using docker. I've got a minimal rails app, with 1 controller. You can get my setup by running these:
rails new app --database=sqlite --skip-bundle
cd app
rails generate controller --skip-routes Home index
echo "Rails.application.routes.draw { root 'home#index' }" > config/routes.rb
echo "gem 'foreman'" >> Gemfile
echo "web: rails server -b 0.0.0.0" > Procfile
echo "port: 3000" > .foreman
And I have the following setup:
Dockerfile:
FROM ruby:2.3
# Install dependencies
RUN apt-get update && apt-get install -y \
nodejs \
sqlite3 \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
# Configure bundle
RUN bundle config --global frozen 1
RUN bundle config --global jobs 7
# Expose ports and set entrypoint and command
EXPOSE 3000
CMD ["foreman", "start"]
# Install Gemfile in different folder to allow caching
WORKDIR /tmp
COPY ["Gemfile", "Gemfile.lock", "/tmp/"]
RUN bundle install --deployment
# Set environment
ENV RAILS_ENV production
ENV RACK_ENV production
# Add files
ENV APP_DIR /app
RUN mkdir -p $APP_DIR
COPY . $APP_DIR
WORKDIR $APP_DIR
# Compile assets
RUN rails assets:precompile
VOLUME "$APP_DIR/public"
Where VOLUME "$APP_DIR/public" is creating a volume that's shared with the Nginx container, which has this in the Dockerfile:
FROM nginx
ADD nginx.conf /etc/nginx/nginx.conf
And then docker-compose.yml:
version: '2'
services:
web:
build: config/docker/web
volumes_from:
- app
links:
- app:app
ports:
- 80:80
- 443:443
app:
build: .
environment:
SECRET_KEY_BASE: 'af3...ef0'
ports:
- 3000:3000
This works, but only the first time I build it. If I change any assets, and build the images again, they're not updated. Possibly because volumes are not updated on image build, I think because how Docker handles caching.
I want the assets to be updated every time I run docker-compose built && docker-compose up. Any idea how to accomplish this?
Compose preserves volumes on recreate.
You have a couple options:
don't use volumes for the assets, instead build the assets and ADD or COPY them into the web container during build
docker-compose rm app before running up to remove the old container and volumes.

Resources