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

I am struggling hard with bundler: command not found: rails

I am also unable to see these echo logs (I don’t know where they go).

fly deploy

==> Verifying app config
Validating /Users/dilraj/Documents/SPG/spg2/fly.toml
Platform: machines
✓ Configuration is valid
--> Verified app config
==> Building image
Remote builder fly-builder-still-snowflake-1492 ready
==> Creating build context
--> Creating build context done
==> Building image with Docker
--> docker host: 20.10.12 linux x86_64
[+] Building 9.0s (0/1)
[+] Building 43.3s (20/20) FINISHED
 => [internal] load remote build context                                     0.0s
 => copy /context /                                                          0.5s
 => [internal] load metadata for docker.io/library/ruby:3.2.1-alpine         0.3s
 => [stage-1 1/4] FROM docker.io/library/ruby:3.2.1-alpine@sha256:04ad49303  0.0s
 => CACHED [builder  2/13] RUN apk --update add     build-base     sqlite-d  0.0s
 => CACHED [builder  3/13] WORKDIR /app                                      0.0s
 => CACHED [builder  4/13] COPY Gemfile Gemfile.lock ./                      0.0s
 => [builder  5/13] RUN ls                                                   0.3s
 => [builder  6/13] RUN echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"    0.3s
 => [builder  7/13] RUN gem install bundler:2.4.7                            1.0s
 => [builder  8/13] RUN bundler install  || echo "bundler install failed"   18.3s
 => [builder  9/13] RUN bundle config set path 'vendor/bundle'               0.5s
 => [builder 10/13] RUN bundle config set deployment 'true'                  0.4s
 => [builder 11/13] RUN bundle install --jobs=4 --without development test  16.8s
 => [builder 12/13] RUN bundle show rails || echo "Rails not installed"      0.5s
 => [builder 13/13] COPY . .                                                 0.3s
 => CACHED [stage-1 2/4] RUN apk --update add     sqlite-libs     nodejs     0.0s
 => CACHED [stage-1 3/4] WORKDIR /app                                        0.0s
 => [stage-1 4/4] COPY --from=builder /app /app                              0.8s
 => exporting to image                                                       1.5s
 => => exporting layers                                                      1.5s
 => => writing image sha256:bace840321c937c81b33e313adb6a39a1e605c2941d27be  0.0s
 => => naming to registry.fly.io/spg2:deployment-01H238HQMGG2QHFDTGQ7QB40NT  0.0s
--> Building image done
==> Pushing image to fly
The push refers to repository [registry.fly.io/spg2]
e092f271ea75: Pushed
ce945830ff45: Pushed
18b927b1a9aa: Pushed
0db7f5871350: Pushed
a15ec33dce4d: Pushed
ea00212692e8: Pushed
e9a920ef7757: Pushed
f1417ff83b31: Pushed
deployment-01H238HQMGG2QHFDTGQ7QB40NT: digest: sha256:a2896fdb39c6bc6946744321b3f6ce48391110dc3d2867d63d59bf13b6f86f72 size: 1996
--> Pushing image done
image: registry.fly.io/spg2:deployment-01H238HQMGG2QHFDTGQ7QB40NT
image size: 393 MB

Watch your app at https://fly.io/apps/spg2/monitoring

Provisioning ips for spg2
  Dedicated ipv6: 2a09:8280:1::37:2555
  Shared ipv4: 66.241.125.164
  Add a dedicated ipv4 with: fly ips allocate-v4
This deployment will:
 * create 2 "app" machines

No machines in group app, launching a new machine
  Machine 6e82dd00f11687 [app] has state: started
  [1/1] Checking that 6e82dd00f11687 [app] is up and running
Smoke checks for 6e82dd00f11687 failed: the app appears to be crashing
Check its logs: here's the last lines below, or run 'fly logs -i 6e82dd00f11687':
  Successfully prepared image registry.fly.io/spg2:deployment-01H238HQMGG2QHFDTGQ7QB40NT (6.953400624s)
  Starting init (commit: 8af0ddf)...
  Preparing to run: `bundle exec rails server -b 0.0.0.0` as root
  2023/06/04 13:13:17 listening on [fdaa:2:4ebf:a7b:f2:5840:9f4e:2]:22 (DNS: [fdaa::3]:53)
  bundler: command not found: rails
  Install missing gem executables with `bundle install`
  Starting clean up.
  hallpass exited, pid: 514, status: signal: 15
  2023/06/04 13:13:18 listening on [fdaa:2:4ebf:a7b:f2:5840:9f4e:2]:22 (DNS: [fdaa::3]:53)
  [    2.116338] reboot: Restarting system
  machine did not have a restart policy, defaulting to restart
  Starting init (commit: 8af0ddf)...
  Preparing to run: `bundle exec rails server -b 0.0.0.0` as root
  2023/06/04 13:13:19 listening on [fdaa:2:4ebf:a7b:f2:5840:9f4e:2]:22 (DNS: [fdaa::3]:53)
  bundler: command not found: rails
  Install missing gem executables with `bundle install`
  Starting clean up.
  hallpass exited, pid: 514, status: signal: 15
  2023/06/04 13:13:20 listening on [fdaa:2:4ebf:a7b:f2:5840:9f4e:2]:22 (DNS: [fdaa::3]:53)
Error: smoke checks for 6e82dd00f11687 failed: the app appears to be crashing

My Dockerfile

# Stage 1: Build stage
FROM ruby:3.2.1-alpine AS builder

RUN apk --update add \
    build-base \
    sqlite-dev \
    nodejs

WORKDIR /app

COPY Gemfile Gemfile.lock ./

RUN ls
RUN echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
RUN gem install bundler:2.4.7
RUN bundler install  || echo "bundler install failed"
RUN bundle config set path 'vendor/bundle'
RUN bundle config set deployment 'true' 
RUN bundle install --jobs=4 --without development test || echo "bundle install failed"
RUN bundle show rails || echo "Rails not installed"

COPY . .

# Stage 2: Final image
FROM ruby:3.2.1-alpine

RUN apk --update add \
    sqlite-libs \
    nodejs

WORKDIR /app

COPY --from=builder /app /app

EXPOSE 3000

CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]