Problem running docker-compose with Rails Dockerfile from flyctl

The rails dockerfile from flyctl builds and runs on its own but I’m having trouble getting it to run via docker compose.

docker-compose up
...
web       | bundler: command not found: puma
web       | Install missing gem executables with `bundle install`
web exited with code 127
web       | bundler: command not found: puma
web       | Install missing gem executables with `bundle install`
web exited with code 127
web       | bundler: command not found: puma
web       | Install missing gem executables with `bundle install`
web exited with code 127
^CGracefully stopping... (press Ctrl+C again to force)
[+] Running 0/1
 ⠙ Container web  Stopping                                                                                         0.2s
canceled

.dockerignore

Dockerfile

docker-compose.yml

services:
  web:
    build:
      context: "."
      args:
        - "RAILS_ENV=${RAILS_ENV:-production}"
        - "BUNDLE_WITHOUT="
    depends_on:
      - "postgres"
    env_file:
      - ".env"
    restart: "${DOCKER_RESTART_POLICY:-unless-stopped}"
    stop_grace_period: "3s"
    tty: true
    volumes:
      - ".:/app"
    container_name: web
    ports:
      - "${DOCKER_WEB_PORT_FORWARD:-127.0.0.1:8080}:8080"

  postgres:
    container_name: postgres
    env_file:
      - ".env"
    image: "postgres:14.2-bullseye"
    restart: "${DOCKER_RESTART_POLICY:-unless-stopped}"
    stop_grace_period: "3s"
    volumes:
      - "postgres:/var/lib/postgresql/data"


volumes:
  postgres: {}

Gemfile

source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby "3.1.2"

# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
gem "rails", "~> 7.0.3"

# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
gem "sprockets-rails"

# Use postgresql as the database for Active Record
gem "pg", "~> 1.1"

# Use the Puma web server [https://github.com/puma/puma]
gem "puma", "~> 5.0"

# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
gem "importmap-rails"

# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
gem "turbo-rails"

# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
gem "stimulus-rails"

# Use Tailwind CSS [https://github.com/rails/tailwindcss-rails]
gem "tailwindcss-rails"

# Build JSON APIs with ease [https://github.com/rails/jbuilder]
gem "jbuilder"

# Use Redis adapter to run Action Cable in production
# gem "redis", "~> 4.0"

# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]
# gem "kredis"

# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
# gem "bcrypt", "~> 3.1.7"

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ]

# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false

# Use Sass to process CSS
# gem "sassc-rails"

# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"

group :development, :test do
  # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
  gem "debug", platforms: %i[ mri mingw x64_mingw ]
end

group :development do
  # Use console on exceptions pages [https://github.com/rails/web-console]
  gem "web-console"

  # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
  # gem "rack-mini-profiler"

  # Speed up commands on slow machines / big apps [https://github.com/rails/spring]
  # gem "spring"
end

group :test do
  # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
  gem "capybara"
  gem "selenium-webdriver"
  gem "webdrivers"
end

Thanks for taking a look.

Answering my own question…Here is a docker-compose.yml file that helps with updating gems when in development:

x-app: &default-app
  build:
    context: "."  # expects Dockerfile from flyctl
    args: &ruby-build-args
      - "RAILS_ENV=${RAILS_ENV:-development}"
      - "BUNDLE_WITHOUT=${BUNDLE_WITHOUT:-}"
  restart: "${DOCKER_RESTART_POLICY:-unless-stopped}"
  stop_grace_period: "3s"
  tty: true
  volumes:
    - ".:/app"
  user: "1000:1000"  # avoid permission errors when accessing files generated by a container

services:
  web:
    <<: *default-app
    container_name: web
    environment:
      - DATABASE_URL=postgresql://${POSTGRES_USER:-app}:${POSTGRES_PASSWORD:-password}@postgres
    ports:
      - "8080:8080"
    depends_on:
      - "postgres"

  bundler:
    <<: *default-app
    container_name: bundler
    build:
      context: "."
      target: gems
      args: *ruby-build-args
    profiles:
      - bundler  # add profile so service will not run with `docker-compose up`

  postgres:
    container_name: postgres
    image: "postgres:14.2-bullseye"
    restart: "${DOCKER_RESTART_POLICY:-unless-stopped}"
    stop_grace_period: "3s"
    volumes:
      - "postgres:/var/lib/postgresql/data"
    environment:
      - POSTGRES_USER=${POSTGRES_USER:-app}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-password}

volumes:
  postgres: {}

Link to Dockerfile and .dockerignore: flyctl/internal/sourcecode/templates/rails/standard at master · superfly/flyctl (github.com)

Build Docker image used for installing ruby gems with bundler

The flyct Rails Dockerfile has a gems stage used for installing Ruby dependencies. This Docker Compose configuration will create an image using the gems stage that can be used to run bundle install.

docker-compose build bundler

This command will build an image from the Dockerfile’s gems stage. By default Bundler is set to install without development and test dependencies. Override the default by passing an empty build argument BUNDLE_WITHOUT= to prevent excluding any gem groups.

Use bundler service to bundle install

When the Gemfile is modified use the bundler service to install the new gems on your Docker host and update the Gemfile.lock.

docker-compose run bundler bundle install

Rebuild the web service

Now that the Gemfile.lock has been modified, build the web service to update the image.

docker-compose build web

Run your app

docker-compose up

1 Like