LoginSignup
6
2

More than 3 years have passed since last update.

Ruby on RailsをOracle Autonomous Databaseに接続する

Posted at

はじめに

いまじわじわと話題になってる?Autonomous DatabaseをRailsから使うための設定方法です。

こちらのスクリプトは、Docker環境でOracle Autonomous Database(Autonomous Transaction Processing)を利用したRailsの設定となります。

「Oracle Code TokyoでRailsのハンズオンやろうぜ」と誘われ、「いいよ」とノリで答えてしまってからGKBRしておりました。

実は一年ほど前に、Oracleとの接続をためしたのですがそのときはあえなく撃沈。先にお断りしておきますが、MacOSだと事情があってこの手順そのままでは動きません。今回はOracle LinuxのDockerを利用することで比較的すんなりと接続することができました。

5/17にOracle Code Tokyoのハンズオンセッションで実施する内容とほぼ同じです。どこかのRubyの勉強会で呼んでもらえたら実演しにいきます。

Docker作成と実行

ざくっとDockerfileを書きました。これをコピペしてDockerfileという名前にしてください。

# LICENSE UPL 1.0
#
# Copyright (c) 2014-2018 Oracle and/or its affiliates. All rights reserved.
#
# ORACLE DOCKERFILES PROJECT
# --------------------------
#
# Dockerfile template for Oracle Instant Client
#
# HOW TO BUILD THIS IMAGE
# -----------------------
#
# Run:
#      $ docker build -t oracle/instantclient:18.3.0 .
#
FROM oraclelinux:7-slim

# # docker login container-registry.oracle.com
# FROM oracle/serverjre:8


RUN  curl -o /etc/yum.repos.d/public-yum-ol7.repo https://yum.oracle.com/public-yum-ol7.repo && \
     yum-config-manager --enable ol7_oracle_instantclient && \
     yum -y install oracle-instantclient18.3-basic oracle-instantclient18.3-devel oracle-instantclient18.3-sqlplus && \
     rm -rf /var/cache/yum && \
     echo /usr/lib/oracle/18.3/client64/lib > /etc/ld.so.conf.d/oracle-instantclient18.3.conf && \
     ldconfig

RUN echo 'export LD_LIBRARY_PATH="/usr/lib/oracle/18.3/client64/lib"' >> ~/.bash_profile
RUN echo 'export TNS_ADMIN="/usr/local/etc"' >> ~/.bash_profile
RUN echo 'export NLS_LANG="Japanese_Japan.AL32UTF8"' >> ~/.bash_profile
RUN yum install -y git unzip vim gcc openssl-devel readline-devel zlib-devel sqlite-devel nodejs bzip2 make
RUN git clone https://github.com/sstephenson/rbenv.git /usr/local/rbenv
RUN mkdir /usr/local/rbenv/shims /usr/local/rbenv/versions /usr/local/rbenv/plugins
RUN groupadd rbenv
RUN chgrp -R rbenv /usr/local/rbenv
RUN chmod -R g+rwxXs /usr/local/rbenv
RUN git clone https://github.com/sstephenson/ruby-build.git /usr/local/rbenv/plugins/ruby-build
RUN chgrp -R rbenv /usr/local/rbenv/plugins/ruby-build
RUN chmod -R g+rwxs /usr/local/rbenv/plugins/ruby-build
RUN /usr/local/rbenv/plugins/ruby-build/install.sh
RUN git clone https://github.com/sstephenson/rbenv-default-gems.git /usr/local/rbenv/plugins/rbenv-default-gems
RUN chgrp -R rbenv /usr/local/rbenv/plugins/rbenv-default-gems
RUN chmod -R g+rwxs /usr/local/rbenv/plugins/rbenv-default-gems
RUN echo 'export RBENV_ROOT="/usr/local/rbenv"' >> /etc/profile.d/rbenv.sh
RUN echo 'export PATH="/usr/local/rbenv/bin:$PATH"' >> /etc/profile.d/rbenv.sh
RUN echo 'eval "$(rbenv init -)"' >> /etc/profile.d/rbenv.sh
RUN echo '%rbenv ALL=(ALL) ALL' >> /etc/sudoers
RUN su -l root -c '/usr/local/rbenv/bin/rbenv install 2.6.3 -v'
RUN su -l root -c '/usr/local/rbenv/bin/rbenv rehash'
RUN su -l root -c '/usr/local/rbenv/bin/rbenv global 2.6.3'
RUN su -l root -c 'gem install -N rails ruby-oci8'
RUN su -l root -c 'mkdir /usr/local/app && cd /usr/local/app'
RUN su -l root -c 'rails new dummy && cd dummy && bundle package --all'

ENV PATH=$PATH:/usr/lib/oracle/18.3/client64/bin
ENV LD_LIBRARY_PATH="/usr/lib/oracle/18.3/client64/lib"
ENV TNS_ADMIN="/usr/local/etc"


CMD ["/bin/bash", "--login"]

DockerfileができたらDocker buildします。

docker build -t oracle-code-tokyo2019/rails-atp:1.0 .

docker run -it -p 3000:3000 --name oracle-ruby-atp oracle-code-tokyo/rails-atp:1.0 /bin/bash --login

OracleLinuxインスタンスで試す場合の手動構成スクリプト ここから下の構成はDockerfileでは自動化済み。実験したインスタンスに入ってたinstantclientが18.5だったのでDocker版とは微妙に異なります。


echo 'export ORACLE_HOME="/usr/lib/oracle/18.5/client64"' >> ~/.bash_profile
echo 'export LD_LIBRARY_PATH="/usr/lib/oracle/18.5/client64/lib"' >> ~/.bash_profile
echo 'export TNS_ADMIN="/usr/local/etc"' >> ~/.bash_profile
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'export NLS_LANG="Japanese_Japan.AL32UTF8"' >> ~/.bash_profile

cd; yum -y install git
git clone git://github.com/sstephenson/rbenv.git .rbenv
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
exec $SHELL
git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build

一度抜ける

localpc$ docker start oracle-ruby-atp
localpc $ docker exec -it oracle-ruby-atp /bin/bash —login


sudo yum install -y gcc openssl-devel readline-devel zlib-devel sqlite-devel nodejs bzip2 make
rbenv install 2.6.3
rbenv global 2.6.3
mkdir /usr/local/app
cd /usr/local/app
gem install -N rails

Oracle Autonomous DB(ATP)接続設定

インスタンスの場合

ローカルPCからWalletのコピー

scp -i ~/.ssh/id_rsa Wallet_atp.zip opc@<innstance_ipaddr>:

ターゲットインスタンスで以下実行。sqlnnet.oraで環境変数TNS_ADMINと一致させる部分を書き換えます。

localpc#  ssh opc@<innstance_ipaddr> -i ~/.ssh/id_rsa
sudo cp Wallet_atp.zip /usr/local/etc/
cd /usr/local/etc/
sudo unzip Wallet_atp.zip
sudo cp sqlnet.ora sqlnet.ora.org && cat sqlnet.ora.org | sudo sh -c "sed -e 'N;s/\?\/network\/admin/\/usr\/local\/etc/g' > sqlnet.ora"

Dockerの場合

別ターミナルから、docker container idを確認

例 00407e328a55

docker ps |grep oracle-code-tokyo/rails-atp | awk '{ print $1 }'
docker cp Wallet_atp.zip 00407e328a55:/usr/local/etc

docker ps |grep oracle-code-tokyo/rails-atp | awk '{ print $1 }'
docker cp Wallet_atp.zip 00407e328a55:/usr/local/etc

複合スクリプト

docker cp Wallet_atp.zip `docker ps |grep oracle-code-tokyo/rails-atp | awk '{ print $1 }'`:/usr/local/etc

dockerにもどりWalletの解凍 sqlnet.oraの修正


cd /usr/local/etc/
unzip Wallet_atp.zip

cp sqlnet.ora sqlnet.ora.org && cat sqlnet.ora.org | sed -e 'N;s/\?\/network\/admin/\/usr\/local\/etc/g' > sqlnet.ora

Oracleへのコマンドからの接続確認

sqlplus admin/Oracle123456@atp_tp

Password: HogeHoge123456

つながるはずです。

Rails動作確認

まず、この状態でsqlite3を使って動作確認します。

rails new toy_app && cd toy_app/ && rails s -b 0.0.0.0
curl localhost:3000

Rails をOracle Autonomous DBで動かす

Oracle Driver のインストール

Oracleで使う場合は、activerecord-oracle_enhanced-adapter と ruby-oci8のgemをGemfileに追加してください。

# Use oracle as the database for Active Record
gem 'activerecord-oracle_enhanced-adapter', '~> 5.2.0'
gem 'ruby-oci8' # only for CRuby users

Oracle Driver追記スクリプト。めんどくさいのでコピペ一発のスクリプト化しました。

cd /usr/local/app/toy_app/
# sed -i -e "s/gem 'sqlite3'/\# gem 'sqlite3'/g" Gemfile

cat << 'EOS' | sed -i '9r /dev/stdin' Gemfile
# Oracle drivers
gem 'activerecord-oracle_enhanced-adapter', '~> 5.2.0'
gem 'ruby-oci8' # only for CRuby users
EOS


# Use oracle as the database for Active Record

Oracle Tips 10,000から始まるidを1から始まるように変更

ここで一旦うごいたのですが、idが10000から始まるという現象にノックアウト気味でした。どうやら設定が必要です。

Oracleのデフォルトではidが10000から始まるので、1から始まるように設定変更


cat <<EOS > config/initializers/oracle.rb
# It is recommended to set time zone in TZ environment variable so that the same timezone will be used by Ruby and by Oracle session
ENV['TZ'] = 'UTC'

ActiveSupport.on_load(:active_record) do
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
    # true and false will be stored as 'Y' and 'N'
    self.emulate_booleans_from_strings = true

    # start primary key sequences from 1 (and not 10000) and take just one next value in each session
    self.default_sequence_start_value = "1 NOCACHE INCREMENT BY 1"

    # Use old visitor for Oracle 12c database
    # self.use_old_oracle_visitor = true

    # other settings ...
  end
end
EOS

gemを有効化

bundle install

database.ymlを修正 tnsname.oraのtp設定を記入します。改行がはいってしまっているのは、ブロック単位で切り出して一行にnつなげてあげなければいけません。

DBユーザー名は、ここではadminにしています。実運用時にはちゃんとappユーザーを作るべきですね。
enncodingはutf-8を指定しないとひどい目に遭った気がします。

mv config/database.yml config/database.yml.org

cat <<EOS > config/database.yml
default: &default
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  adapter: oracle_enhanced
  username: admin
  password: HogeHoge123456
  timeout: 5000
  encoding: utf8

development:
  <<: *default
  database: (description=(address=(protocol=tcps)(port=1522)(host=adb.ap-tokyo-1.oraclecloud.com))(connect_data=(service_name=hogehogehogehoge_atp_tp.atp.oraclecloud.com))(security=(ssl_server_cert_dn="CN=adb.ap-tokyo-1.oraclecloud.com,OU=Oracle ADB TOKYO,O=Oracle Corporation,L=Redwood City,ST=California,C=US")))

test:
  adapter: sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000
  database: db/test.sqlite3

production:
  adapter: sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000
  database: db/production.sqlite3
EOS

Rails + ATPで実際にアプリを動かす

ここまで来たら、あとは普通に使うことができます。

rails generate scaffold User name:string email:string
rails db:migrate

rails s -b 0.0.0.0

お疲れ様です!

Tips

  • 順序が自動生成されているので、DB作り直しのときにSQL Developerから削除が必要でした
  • rails db:migrate:resetがエラーを吐く気がします。
6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2