はじめに
いまじわじわと話題になってる?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がエラーを吐く気がします。