Rails engine apps deployed with docker - ruby

We have a rails app developed with a few rails engine so it looks like
app/ <-- main app
app.json
Gemfile -> config/Gemfile
Gemfile.lock
api/ <-- this is an engine app
integrations/ <-- this is an engine app
other_engine_app/
everything works fine but now I am looking to deployed on docker using docker-compose
I created a simple Dockerfile
FROM ruby:2.3.1
RUN apt-get update -qq && apt-get install -y apt-utils build-essential nodejs
ENV APP_HOME /myapp
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
ADD Gemfile Gemfile.lock $APP_HOME/
RUN gem install bundler
RUN bundle install
ADD . $APP_HOME
The docker-compose.yml file is looking like
app:
build: .
volumes:
- .:/myapp
ports:
- "3000:3000"
links:
- db
- redis
db:
image: mysql:5.6
redis:
image: redis
At this stage when I run docker-compose up I get
$ docker-compose up
Building app
Step 1/10 : FROM ruby:2.3.1
.....
Step 9/10 : RUN bundle install
---> Running in 3748ba73eb9b
The path `/myapp/api` does not exist.
ERROR: Service 'app' failed to build: The command '/bin/sh -c bundle install' returned a non-zero code: 13
I can bypass this error by adding the Gemfile into each engine app from my Dockerfile as
FROM ruby:2.3.1
RUN apt-get update -qq && apt-get install -y apt-utils build-essential nodejs
ENV APP_HOME /myapp
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
ADD Gemfile Gemfile.lock $APP_HOME/
ADD Gemfile Gemfile.lock $APP_HOME/api/
ADD Gemfile Gemfile.lock $APP_HOME/integrations/
ADD Gemfile Gemfile.lock $APP_HOME/other_engine_app/
RUN gem install bundler
RUN bundle install
ADD . $APP_HOME
but now I get the following error
$ docker-compose up
Building app
Step 1/10 : FROM ruby:2.3.1
.......
Step 12/13 : RUN bundle install
---> Running in 3928848ed6e5
Fetching https://github.com/rails-api/active_model_serializers
Fetching https://github.com/activeadmin/activeadmin
Fetching gem metadata from https://rails-assets.org/..
Fetching version metadata from https://rails-assets.org/.
Fetching gem metadata from https://rails-assets.org/..
Fetching gem metadata from http://rubygems.org/..........
Fetching version metadata from https://rails-assets.org/..
Fetching version metadata from http://rubygems.org/...
Fetching dependency metadata from https://rails-assets.org/..
Fetching dependency metadata from http://rubygems.org/..
Could not find gem 'api' in source at `api`.
Source does not contain any versions of 'api'
ERROR: Service 'app' failed to build: The command '/bin/sh -c bundle install' returned a non-zero code: 7
EDIT :
Thanks to gwcodes, I can move forward but still hit an issue
The main Gemfile has dependency defined on the rails engine as
source 'http://rubygems.org'
ruby '2.3.1'
gem 'dotenv-rails', require: 'dotenv/rails-now'
# Engines.
gem 'api', path: 'api/'
gem 'integrations', path: 'integrations'
gem 'other_engine_app', path: 'other_engine_app'
....
in api/ folder we have gemspec defined as `api.gemspec``
$:.push File.expand_path('../lib', __FILE__)
require 'api/version'
Gem::Specification.new do |s|
s.name = 'api'
s.version = Api::VERSION
s.authors = ...
s.email = ...
s.homepage = ...
s.summary = ...
s.files = Dir['{app,config,lib}/**/*'] + ['Rakefile']
s.add_dependency 'rails'
s.add_dependency 'workflow'
s.add_dependency 'will_paginate'
s.add_dependency 'analytics-ruby'
end
I have added the gemspec file from the Dockerfile as
FROM ruby:2.3.1
RUN apt-get update -qq && apt-get install -y apt-utils build-essential nodejs
ENV APP_HOME /myapp
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
ADD Gemfile Gemfile.lock $APP_HOME/
ADD Gemfile Gemfile.lock $APP_HOME/api/
ADD api/api.gemspec $APP_HOME/api/
ADD Gemfile Gemfile.lock $APP_HOME/integrations/
ADD Gemfile Gemfile.lock $APP_HOME/other_engine_app/
RUN gem install bundler
RUN bundle install
ADD . $APP_HOME
and so I get the following error
Step 13/14 : RUN bundle install
---> Running in c7fce6cd25d8
[!] There was an error while loading `api.gemspec`: cannot load such file -- api/version
Does it try to require a relative path? That's been removed in Ruby 1.9. Bundler cannot continue.
# from /myapp/api/api.gemspec:3
# -------------------------------------------
#
> require 'api/version'
#
# -------------------------------------------
ERROR: Service 'app' failed to build: The command '/bin/sh -c bundle install' returned a non-zero code: 14

How are the engines loaded? Do you have a line that looks like this in the Gemfile of the main application:
gem 'api', path: '/api'
If so, you may also need to copy across the .gemspec files.

Related

How to set up ruby on Docker - getting nokogiri error

My Doc Dockerfile has FROM Ubuntu:18.04
I want to use ruby so i did
gem install bundler
However when I try to
bundle
I get an error with nokogiri
Installing nokogiri 1.10.2 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
current directory: /var/lib/gems/2.5.0/gems/nokogiri-1.10.2/ext/nokogiri
/usr/bin/ruby2.5 -r ./siteconf20190414-288-1mfprtc.rb extconf.rb
mkmf.rb can't find header files for ruby at /usr/lib/ruby/include/ruby.h
extconf failed, exit code 1
Gem files will remain installed in /var/lib/gems/2.5.0/gems/nokogiri-1.10.2 for inspection.
Results logged to /var/lib/gems/2.5.0/extensions/x86_64-linux/2.5.0/nokogiri-1.10.2/gem_make.out
An error occurred while installing nokogiri (1.10.2), and Bundler cannot continue.
Make sure that `gem install nokogiri -v '1.10.2' --source 'http://rubygems.org/'` succeeds before bundling.
You have a dependency called nokogiri that has external dependency, usually it's libxml and libxslt.
All you need to do is apt get install libxml2-dev libxslt1-dev
Here's a working example of a Ruby Dockerfile
FROM ruby:2.6.2
RUN apt-get update -qq && apt-get install -y build-essential
RUN apt-get install -y libxml2-dev libxslt1-dev
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY Gemfile* /usr/src/app/
RUN bundle install -j3
ADD . /usr/src/app
ENTRYPOINT ["bundle", "exec"]
CMD ["rails", "server"]

Running ruby project with systemd service cannot find gemfile

I would like to run a ruby project that uses bundle as a systemd service.
The project is: https://github.com/jcs/bitwarden-ruby/
I installed ruby and bundler by running sudo apt-get install ruby-full and sudo gem install bundler
In the project directory I run bundle install --deployment.
In my systemd service I have:
ExecStart=/usr/bin/env RACK_ENV=production ALLOW_SIGNUPS=1 /usr/local/bin/bundle exec rackup -p 4567 /var/lib/bitwarden/bitwarden-ruby/config.ru
Runnning this command in the terminal does work.
However when I start the service I get an error:
bash[7924]: Could not locate Gemfile or .bundle/ directory
The bundle directory is at /var/lib/bitwarden/bitwarden-ruby/.bundle.
Why can it not find it? Thanks!

Bundler locks in docker + can't install gems (Solved- docker CMD vs ENTRYPOINT)

Update: I've narrowed the [or a?] problem down to the line - groupy-gemcache:/usr/local/bundle in my services: app: volumes dictionary. If I remove it, the container runs fine [i think] but presumably i lose my local gem cacheing.
tldr: After running docker-compose build, things seem ok, but I cannot run any gem or bundle inside my running docker container if I add something to my gemfile. for example, after docker-compose build && docker-compose run app bash:
root#2ea58aff612e:/src# bundle check
The Gemfile's dependencies are satisfied
root#2ea58aff612e:/src# echo 'gem "hello-world"' >> Gemfile
root#2ea58aff612e:/src# bundle
Could not find gem 'hello-world' in any of the gem sources listed in your Gemfile.
Run `bundle install` to install missing gems.
root#2ea58aff612e:/src# bundle install
Could not find gem 'hello-world' in any of the gem sources listed in your Gemfile.
Run `bundle install` to install missing gems.
root#2ea58aff612e:/src# gem
Could not find gem 'hello-world' in any of the gem sources listed in your Gemfile.
Run `bundle install` to install missing gems.
root#2ea58aff612e:/src# gem env
Could not find gem 'hello-world' in any of the gem sources listed in your Gemfile.
Run `bundle install` to install missing gems.
I'm still pretty novice with docker, but i've been trying to configure a perfect dockerfile that can build, cache gems and update while still committing its Gemfile.lock to git [maybe this isn't actually perfect and I'm open to suggestions there]. In my use case, I'm using a docker compose file with images for a rails app and sidekiq worker as well as postgres and redis images- very simliar to the setups described here and here.
My Dockerfile [some things commented out that I cobbled from the tutorials above:
FROM ruby:2.3
ENTRYPOINT ["bundle", "exec"]
ARG bundle_path
# throw errors if Gemfile has been modified since Gemfile.lock
# RUN bundle config --global frozen 1
ENV INSTALL_PATH /src
RUN mkdir -p $INSTALL_PATH
WORKDIR $INSTALL_PATH
# Install dependencies:
# - build-essential: To ensure certain gems can be compiled
# - nodejs: Compile assets
# - npm: Install node modules
# - libpq-dev: Communicate with postgres through the postgres gem
# - postgresql-client-9.4: In case you want to talk directly to postgres
RUN apt-get update && apt-get install -qq -y build-essential nodejs npm libpq-dev postgresql-client-9.4 --fix-missing --no-install-recommends && \
rm -rf /var/lib/apt/lists/*
COPY app/Gemfile app/Gemfile.lock ./
# Bundle and then save the updated Gemfile.lock in our volume since it will be clobbered in the next step
RUN echo $bundle_path && bundle install --path=$bundle_path && \
cp Gemfile.lock $bundle_path
# ./app contains the rails app on host
COPY app .
# Unclobber the updated gemfile.lock
RUN mv $bundle_path/Gemfile.lock ./
CMD ["./script/start.sh"]
docker-compose.yml:
version: '2'
volumes:
groupy-redis:
groupy-postgres:
groupy-gemcache:
services:
app:
build:
args:
bundle_path: /usr/local/bundle
context: .
dockerfile: Dockerfile
command: "./script/start.sh"
links:
- postgres
- redis
volumes:
- ./app:/src
- groupy-gemcache:/usr/local/bundle
ports:
- '3000:3000'
env_file:
- .docker.env
stdin_open: true
tty: true
Wow, I figured it out. The problem was coming from my ENTRYPOINT dockerfile command, as explained at the end of this article on CMD vs ENTRYPOINT.
I believe the result of ENTRYPOINT ["bundle", "exec"] with CMD ["./script/start.sh"] OR docker-compose run app bash was to run a command like bundle exec 'bash'. I confirmed this by removing the entrypoint from the dockerfile, entering the shell as above and manually running bundle exec 'bash' and sure enough i landed in a subshell where I couldn't run any bundle or gem commands- had to exit twice to leave.

Bundler can't see gems installed in dockerized environment

I have a pretty basic "app" which i'm trying to dockerize using some examples found on the internet but, for some reason, it seems that bundler can't see the gems installed in my env.
Gemfile
source 'https://rubygems.org'
gem 'streamio-ffmpeg'
Dockerfile
FROM dpsxp/ffmpeg-with-ruby:2.2.1
MAINTAINER mike
RUN apt-get update && apt-get install -y \
build-essential \
cmake
ENV APP_HOME=/app
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
COPY Gemfile* ./
ENV BUNDLE_GEMFILE=$APP_HOME/Gemfile \
BUNDLE_PATH=/bundle
RUN gem install bundler
RUN bundle install --jobs 20 --retry 5 --path=/bundle
COPY . ./
CMD ["rake"]
docker-compose.yml
version: '2'
services:
app:
build:
context: .
volumes:
- '.:/app'
depends_on:
- bundle
bundle:
image: busybox
volumes:
- /bundle
And now, when i'm running $ docker-compose run app gem list, the streamio-ffmpeg gem is not on the list for some reason. Also, when i'm trying to require it inside my ruby app, i'm getting LoadError: cannot load such file
Build logs: https://gist.github.com/mbajur/569b4f221cadb8a85ecc5dae8a595401
When you deal with gems by bundler, all related commands should be run with bundle exec, so in your case, it should work with below command:
docker-compose run app bundle exec gem list
Bundler provides a consistent environment for Ruby projects by tracking and installing the exact gems and versions that are needed.
The command you run directly with gem list is to list the system gems, of course they are not in list.

Running Ruby Sinatra inside a Docker container not able to connect (via Mac host) or find commands (in different scenario)?

I've tried two forms of Dockerfile to get a simple Ruby/Sinatra app running, and in both scenarios it fails for different reasons (I'll explain both in a moment).
Effectively I want to access the Sinatra web server from my host (Mac OS X using Boot2Docker).
The app structure is:
.
├── Dockerfile
├── Gemfile
├── app.rb
├── config.ru
The contents of the files are:
Dockerfile
Version 1...
FROM ruby
RUN mkdir -p /app
WORKDIR /app
COPY Gemfile /app/
RUN bundle install --quiet
COPY . /app
EXPOSE 5000
ENTRYPOINT ["bash"]
CMD ["bundle", "exec", "rackup", "-p", "5000"]
Version 2...
FROM ubuntu:latest
RUN apt-get -qq update
RUN apt-get -qqy install ruby ruby-dev
RUN apt-get -qqy install libreadline-dev libssl-dev zlib1g-dev build-essential bison openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev
RUN gem install bundler
RUN mkdir -p /app
WORKDIR /app
COPY Gemfile /app/
RUN bundle install --quiet
COPY . /app
EXPOSE 5000
CMD ["bundle", "exec", "rackup", "-p", "5000"]
Gemfile
source "https://rubygems.org/"
gem "puma"
gem "sinatra"
app.rb
require "sinatra/base"
class App < Sinatra::Base
set :bind, "0.0.0.0"
get "/" do
"<p>hello world</p>"
end
end
config.ru
require "sinatra"
require "./app.rb"
run App
I build the docker image like so:
docker build --rm -t ruby_app .
I run the container like so:
docker run -d -p 7080:5000 ruby_app
I then try to verify I can connect to the running service (on my Mac using Boot2Docker) like so:
curl $(boot2docker ip):7080
With version 1 of the Dockerfile I get the following error before being able to run the curl command:
/usr/local/bundle/bin/rackup: line 9: require: command not found
/usr/local/bundle/bin/rackup: rackup: line 10: syntax error near unexpected token `('
/usr/local/bundle/bin/rackup: rackup: line 10: `ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../../../../app/Gemfile",'
With version 2 of the Dockerfile it seems to run the rack server fine from inside the container but I'm unable to connect via the host environment and so when running the curl command I get the error:
curl: (7) Failed to connect to 192.168.59.103 port 7080: Connection refused
Does anyone have any idea as to what I'm missing? Seems it shouldn't be this hard to get a very simple Ruby/Sinatra app running inside a Docker container from which I can access via my host (Mac OS X via Boot2Docker).
Change the dockerfile to use this instead:
["bundle", "exec", "rackup", "--host", "0.0.0.0", "-p", "5000"]

Resources