kubo / ruby-oci8

Ruby-oci8 - Oracle interface for ruby
Other
169 stars 75 forks source link

Failed when installing in a Docker container #196

Closed belgoros closed 6 years ago

belgoros commented 6 years ago

I added the following 2 gems to my Gemfile:

group :development, :test, :mystore do
...
  gem 'activerecord-oracle_enhanced-adapter', '~> 5.2.0'
  gem 'ruby-oci8'
end

When starting a Docker container, it failed as follows:

Fetching rspec-mocks 3.7.0
Installing rspec-mocks 3.7.0
Fetching rspec-rails 3.7.2
Installing rspec-rails 3.7.2
Fetching ruby-oci8 2.2.5.1
Installing ruby-oci8 2.2.5.1 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8
/usr/local/bin/ruby -r ./siteconf20180711-7-11cf4dv.rb extconf.rb
checking for load library path... 
  LD_LIBRARY_PATH is not set.
  checking ld.so.conf... no
checking for cc... ok
checking for gcc... yes
checking for LP64... yes
checking for sys/types.h... yes
checking for ruby header... ok
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
    --with-opt-dir
    --without-opt-dir
    --with-opt-include
    --without-opt-include=${opt-dir}/include
    --with-opt-lib
    --without-opt-lib=${opt-dir}/lib
    --with-make-prog
    --without-make-prog
    --srcdir=.
    --curdir
    --ruby=/usr/local/bin/$(RUBY_BASE_NAME)
    --with-instant-client
    --without-instant-client
/usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8/oraconf.rb:909:in `get_home':
RuntimeError (RuntimeError)
from /usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8/oraconf.rb:728:in
`initialize'
    from /usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8/oraconf.rb:269:in `new'
    from /usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8/oraconf.rb:269:in `get'
    from extconf.rb:22:in `<main>'
---------------------------------------------------
Error Message:
  Set the environment variable ORACLE_HOME if Oracle Full Client.
Append the path of Oracle client libraries to LD_LIBRARY_PATH if Oracle
Instant Client.

Backtrace:
  /usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8/oraconf.rb:909:in `get_home'
/usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8/oraconf.rb:728:in
`initialize'
  /usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8/oraconf.rb:269:in `new'
  /usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8/oraconf.rb:269:in `get'
  extconf.rb:22:in `<main>'
---------------------------------------------------

The dockerized app works as needed, but fails just after adding these 2 gems to Gemfile. It works also when running locally in 'standard' way with bundle install, then rails s. I'm using a standard Ruby image in Dockerfile:

#Dockerfile
FROM ruby:2.5.0
...

What's wrong here ?

Thank you.

kubo commented 6 years ago

What type of Oracle client do you use? If it is Oracle instant client, set the environment variable LD_LIBRARY_PATH=/path/to/instant/client/directory and then build ruby-oci8. https://www.rubydoc.info/github/kubo/ruby-oci8/file/docs/install-instant-client.md

belgoros commented 6 years ago

@kubo I have no Oracle client installed at all. I'm on macOS and running a Rake task locally to query the Oracle DB:

Database: Oracle (ver. Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bit Production With the Partitioning, OLAP, Data Mining and Real Application Testing options) Identifier case sensitivity: upper (plain), exact (delimited) Driver (JDBC4.0): Oracle JDBC driver (ver. 12.1.0.2.0)

I just set up connection details in database.yml file of a Rails app:

mystore:
  adapter: oracle_enhanced
  host: <%= ENV['mystore_db_host']%>
  port: <%= ENV['mystore_db_port']%>
  database: <%= ENV['mystore_db_name']%>
  username: <%= ENV['mystore_db_user']%>
  password: <%= ENV['mystore_db_password']%>

and connect a model like that:

module MystoreMigration
  class MystoreModel < ApplicationRecord
    establish_connection(:mystore) unless Rails.env.test?
  end
end

It works just fine. But when rebuilding the docker container it fails to install the gems.

kubo commented 6 years ago

Database: Oracle (ver. Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bit Production With the Partitioning, OLAP, Data Mining and Real Application Testing options) Identifier case sensitivity: upper (plain), exact (delimited) Driver (JDBC4.0): Oracle JDBC driver (ver. 12.1.0.2.0)

Do you use JRuby and Oracle JDBC on macOS? If so, it is better to use JRuby and Oracle JDBC also in the docker container.

Ruby-oci8 doesn't run without Oracle client.

belgoros commented 6 years ago

No, I use MRI:

#macOS
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin17]

#Docker container
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]

How can you explain that I can run the rake task and just ruby code from a simple Ruby file if

Ruby-oci8 doesn't run without Oracle client.

kubo commented 6 years ago

Ruby-oci8 uses functions in Oracle client library. I bet that Oracle instant client is somewhere on the macOS.

belgoros commented 6 years ago

Not sure, I've already checked homebrew formulas and the list of installed apps, there is no instantclient found. But running sqlplus displays the following:

sqlplus

SQL*Plus: Release 12.1.0.2.0 Production on Wed Jul 11 16:17:37 2018

Copyright (c) 1982, 2016, Oracle.  All rights reserved.
Enter user-name:
kubo commented 6 years ago

I cannot explain how it works on your macOS. However ruby-oci8 depends on Oracle client. You need Oracle client in the docker image.

belgoros commented 6 years ago

It is confirmed, - I have Instant Client installed with Homebrew:

 ~ locate sqlplus
/Users/Serguei/soft/instantclient-sqlplus-macos.x64-12.1.0.2.0.zip
/usr/local/Cellar/instantclient-sqlplus
/usr/local/Cellar/instantclient-sqlplus/12.1.0.2.0
/usr/local/Cellar/instantclient-sqlplus/12.1.0.2.0/.brew
/usr/local/Cellar/instantclient-sqlplus/12.1.0.2.0/.brew/instantclient-sqlplus.rb
/usr/local/Cellar/instantclient-sqlplus/12.1.0.2.0/INSTALL_RECEIPT.json
/usr/local/Cellar/instantclient-sqlplus/12.1.0.2.0/bin
/usr/local/Cellar/instantclient-sqlplus/12.1.0.2.0/bin/sqlplus
/usr/local/Cellar/instantclient-sqlplus/12.1.0.2.0/lib
/usr/local/Cellar/instantclient-sqlplus/12.1.0.2.0/lib/libsqlplus.dylib
/usr/local/Cellar/instantclient-sqlplus/12.1.0.2.0/lib/libsqlplusic.dylib
/usr/local/Homebrew/Library/Taps/instantclienttap/homebrew-instantclient/Formula/instantclient-sqlplus.rb
/usr/local/Homebrew/Library/Taps/instantclienttap/homebrew-instantclient/Formula/instantclient-sqlplus11.rb
/usr/local/bin/sqlplus
/usr/local/lib/libsqlplus.dylib
/usr/local/lib/libsqlplusic.dylib
/usr/local/opt/instantclient-sqlplus
/usr/local/var/homebrew/linked/instantclient-sqlplus
/usr/local/var/homebrew/locks/instantclient-sqlplus.formula.lock

I'll close the issue. Thank you.

belgoros commented 6 years ago

So event after installing Instant Client, it fails to install and I have the following error message:

Installing ruby-oci8 2.2.5.1 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8
/usr/local/bin/ruby -r ./siteconf20180712-7-7chxou.rb extconf.rb
checking for load library path... 
  LD_LIBRARY_PATH is not set.
  checking ld.so.conf... no
checking for cc... ok
checking for gcc... yes
checking for LP64... yes
checking for sys/types.h... yes
checking for ruby header... ok
...
RuntimeError (RuntimeError)
from /usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8/oraconf.rb:728:in
`initialize'
    from /usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8/oraconf.rb:269:in `new'
    from /usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8/oraconf.rb:269:in `get'
    from extconf.rb:22:in `<main>'
---------------------------------------------------
Error Message:
  Set the environment variable ORACLE_HOME if Oracle Full Client.
Append the path of Oracle client libraries to LD_LIBRARY_PATH if Oracle
Instant Client.

Here are the comands I run when installing INstant Client in the Docker container:

RUN alien -i oracle-instantclient12.2-basiclite-12.2.0.1.0-1.x86_64.rpm
RUN alien -i oracle-instantclient12.2-devel-12.2.0.1.0-1.x86_64.rpm
RUN alien -i oracle-instantclient12.2-sqlplus-12.2.0.1.0-1.x86_64.rpm

RUN export LD_LIBRARY_PATH=/usr/lib/oracle/12.2/client64/lib:$LD_LIBRARY_PATH
RUN export PATH=/opt/oracle/instantclient_12_2:$PATH
RUN export PATH=/usr/lib/oracle/12.2/client64/bin:$PATH

And, as it can be seen from the stack trace, it seems to be OK:

Removing intermediate container 2f21739c2993
 ---> 239ea737eb81
Step 11/19 : RUN export LD_LIBRARY_PATH=/usr/lib/oracle/12.2/client64/lib:$LD_LIBRARY_PATH
 ---> Running in 78779fb15cdc
Removing intermediate container 78779fb15cdc
 ---> e40cd2d3f575
Step 12/19 : RUN export PATH=/opt/oracle/instantclient_12_2:$PATH
 ---> Running in 43eb9cae4e20
Removing intermediate container 43eb9cae4e20
 ---> ce12510f8ba4
Step 13/19 : RUN export PATH=/usr/lib/oracle/12.2/client64/bin:$PATH

What is the problem with ORACLE_HOME or smth else ?

kubo commented 6 years ago
checking for load library path... 
  LD_LIBRARY_PATH is not set.

I have not used Docker setting files. I have a question.

RUN export LD_LIBRARY_PATH=/usr/lib/oracle/12.2/client64/lib:$LD_LIBRARY_PATH

Does Docker execute all specified commands at RUN lines in one process? Otherwise, does it execute them in each processes?

If the latter, the export LD_LIBRARY_PATH=... at the RUN line doesn't affect succeeding commands, so ruby-oci8 cannot find LD_LIBRARY_PATH. If so, I guess that there is a keyword similar to RUN to set environment variables which affect succeeding commands.

What is the problem with ORACLE_HOME or smth else ?

Oracle instant client runs without ORACLE_HOME. Only LD_LIBRARY_PATH is mandatory in your case.

belgoros commented 6 years ago

I searched for the value I set for LD_LIBRARY_PATH:

LD_LIBRARY_PATH=/usr/lib/oracle/12.2/client64/lib:$LD_LIBRARY_PATH

and didn't find it, it does not even exist on the specified location, - i followed the steps indicated in Oracle installation instructions. I thin that is the problem. Nevertheless, the error message coming from ruby-oci8 gem seems to be not adequate:

Error Message:
  Set the environment variable ORACLE_HOME if Oracle Full Client.
Append the path of Oracle client libraries to LD_LIBRARY_PATH if Oracle
Instant Client.

Backtrace:
  /usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8/oraconf.rb:909:in `get_home'
/usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8/oraconf.rb:728:in
`initialize'
  /usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8/oraconf.rb:269:in `new'
  /usr/local/bundle/gems/ruby-oci8-2.2.5.1/ext/oci8/oraconf.rb:269:in `get'
  extconf.rb:22:in `<main>'

even if your docs say that setting ORACLE_HOME isn't necessary. I'll have to figure out where the needed files are installed t be able to set LD_LIBRARY_PATH correctly.

kubo commented 6 years ago
checking for load library path... 
  LD_LIBRARY_PATH is not set.

This message indicates that nothing is set to LD_LIBRARY_PATH. It doesn't mean that the value of LD_LIBRARY_PATH is incorrect.

In a command prompt:

export LD_LIBRARY_PATH=/usr/lib/oracle/12.2/client64/lib:$LD_LIBRARY_PATH
echo $LD_LIBRARY_PATH

The echo command prints the content of LD_LIBRARY_PATH including /usr/lib/oracle/12.2/client64/lib.

In the Docker container:

RUN export LD_LIBRARY_PATH=/usr/lib/oracle/12.2/client64/lib:$LD_LIBRARY_PATH
RUN echo $LD_LIBRARY_PATH

I guess that the echo command doesn't print /usr/lib/oracle/12.2/client64/lib because the first and second commands run under different processes. export LD_LIBRARY_PATH=... affects only the process itself and processes created from the process. It doesn't affect other processes.

i followed the steps indicated in Oracle installation instructions.

Following instructions in a command prompt is different from following instructions under different processes. The latter case are not expected usually. What you did in Docker is similar with: (1) open a command prompt, (2) follow the first instruction, (3) close the command prompt, (4) open another command prompt, (5) follow the second instruction, (6) close the command prompt, (7) open yet another command prompt, (8) follow the third instruction, (9) close the command prompt, ...

I'll have to figure out where the needed files are installed t be able to set LD_LIBRARY_PATH correctly.

You have to figure out how to set LD_LIBRARY_PATH in Docker firstly. What you say is the next step.

belgoros commented 6 years ago

Yep, the first thing (LD_LIBRARY_PATH) was fixed, - you were right about separate processes.

checking for load library path... 
  LD_LIBRARY_PATH... 
    checking /opt/oracle/instantclient_12_2... yes
  /opt/oracle/instantclient_12_2/libclntsh.so.12.1 looks like an instant client.

There is another error now, - with libclntsh.so:

Error Message:
  Could not compile with Oracle instant client.
  /opt/oracle/instantclient_12_2/libclntsh.so could not be found.
  You may need to make a symbolic link.
     cd /opt/oracle/instantclient_12_2
     ln -s libclntsh.so.12.1 libclntsh.so

After creating the symlink, the gem was installed with success. I created a GitHub repo to demonstrate it. Hope this helps to others. Thank you.