2018-02-02

RubyのCGIをGoogle Cloud Platformの無料枠で動かしたい ~(1)セットアップ

RubyのCGIをGCPで(無料で)動かしたい

自分で使う用のこまごまとしたWebアプリを動かすために手頃なレンタルサーバーを借りていたのですが、年契約の更新時期が来ました。
ふと思い出したのが昨春Google Cloud Platform(GCP)の無料枠拡大の話。2年目以降も無料で使えるのはかなり限られた構成になりますが、自分しか使わないサーバーなのでスペックは足りそう。乗り換えてみることにしました。

GCP(の無料枠)でPHPやRuby on Railsを動かすための情報はいくつか見つかったのですが、CGIの話は見当たらなかったので、作業記録やひっかかりポイントを書き残しておきます。

無料トライアルに申し込む

無料枠内しか使わないつもりでも、クレジットカードの登録は必要です。

申込みから初期セットアップまでの手順はいろんな方がまとめてくれているので、ここでは改めて書きません。たとえば下記などを参考に。

OSはCentOS 7にしました。個人的にはDebianのほうが慣れていますが仕事だとCentOSが多いので、これを機に馴染んでおこうかと。

他、ポイントとしては:
  • ゾーンはus-westを選びます。usしか無料にならないので、せめて日本から一番近い西海岸を
  • ディスクサイズはせっかくなので無料枠の上限である30GBに上げます
  • 固定(静的な外部)IPアドレスを割り当てます(1つなら無料)

最低限の初期設定

GCE(Google Compute Engine)のVMインスタンスが起ち上がったら、Web上の管理画面からブラウザ上で動くSSHクライアントを起動できます。
最終的には手元のPC等のネイティブSSHクライアントから入ったほうが快適なのですが、とりあえずの作業はブラウザからでも事足ります。ちょっとレスポンスが遅いのが難点ですが。

ブラウザSSHだとbash上でCtrl+Wを叩くと、1語消えるかわりにブラウザが「このサイトを離れてもよろしいですか?」と訊いてくる問題もありますが、ChromeならSSH for Google Cloud Platform 拡張機能をインストールすればCtrl+WもCtrl+NもCtrl+Tも叩き放題です。

最低限、次のあたりを設定しておきます。
  • 22番ポートをファイアウォールで遮断。セキュリティ対策
  • 代わりに適当なポートでSSHで入れるように
  • タイムゾーンを日本に
    $ sudo timedatectl set-timezone Asia/Tokyo

ほかはお好みで。

Apacheをインストール

$ sudo yum install httpd
/etc/httpd/conf/httpd.conf などを適宜編集したら、
$ sudo systemctl enable httpd

DNSやSSLの設定は後回しにして、いったん手元のPC等から http://IPアドレス/ でwelcomeページを表示できることを確認します。
表示できない場合は、Apacheやファイアウォールなどの設定を見直します。

ところで CentOS 7 ではサービスの制御は systemctl を使いますが、httpd.conf を編集した後に反映させるのは graceful ではなく reload です。
$ sudo systemctl graceful httpd
Unknown operation 'graceful'.
$ sudo systemctl reload httpd
$ (反映された)

/usr/lib/systemd/system/httpd.service には次のように定義されており、ちゃんと graceful してくれます。
(略)
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
(略)



yumのRubyは古い

Rubyもyumで…と思いきや、バージョンがずいぶん古いのでした。
$ yum info ruby
(略)
Available Packages
Name        : ruby
Arch        : x86_64
Version     : 2.0.0.648
Release     : 30.el7
(略)
仕方ないのでrbenvを入れて自分でビルドします。
ちょっと重い作業になりますが、レンタルサーバーと違って新しいバージョンが使えるというのはうれしいものです。いまだに1.8しか使えないレンタルサーバーとかありますし……。

Rubyビルドの事前準備(パッケージ導入・スワップファイル作成)

ビルドに必要なパッケージを入れます。
$ sudo yum -y install git gcc openssl-devel readline-devel
(他にも何か入れたかも。ビルド中にエラーが出たら適宜yum installしてください)

最初、このままビルドに進んだら途中でメモリ不足になってしまいました。
無料枠のf1-microインスタンスのメモリは0.6GB。国民機PC-9801の1000倍ですが、それでも足りないようです。

スワップファイルを作ります。
$ sudo su -
# dd if=/dev/zero of=/swapfile bs=1M count=1024
# chmod 600 /swapfile
# mkswap /swapfile
# swapon /swapfile
# free -m
           total       used       free     shared buff/cache  available
Mem:         588        148        319          4        119        323
Swap:       1023          0       1023

1GBにしたのにはキリがいいからですが、推奨値はRAMの2倍なので1.2GBのがよかったのかもしれません。ただ、1GBでもRuby 2.5.0のビルドには問題ありませんでした。

今後もスワップファイルを常用したければ /etc/fstab に書きます。
/swapfile       swap    swap    defaults        0 0

rbenvをシステム全体で使えるようにインストール

rbenvの基本的な導入方法は https://github.com/rbenv/rbenv に書かれているとおりですが、~/.rbenv/ にインストールしてしまうとCGIで使うにはちょっと不便です。システム全体で使えるよう /opt/rbenv に導入することにします。

rbenvを /usr/local 以下に導入した話をよく見かけますが、FHS(Filesystem Hierarchy Standard)では /usr/local には任意のディレクトリを作ってはならないと規定されています。パッケージ名でディレクトリを作りたければ /opt を使うそうです。

.bash_profile に書く設定は代わりに /etc/profile.d/ 以下に置けば、自動的に全員にロードされます。
# git clone https://github.com/rbenv/rbenv.git /opt/rbenv
# echo 'export RBENV_ROOT="/opt/rbenv"' >> /etc/profile.d/rbenv.sh
# echo 'export PATH="${RBENV_ROOT}/bin:${PATH}"' >> /etc/profile.d/rbenv.sh
# echo 'eval "$(rbenv init -)"' >> /etc/profile.d/rbenv.sh
# . /etc/profile.d/rbenv.sh

Rubyをビルド・symlink作成

Rubyのバージョンは事情に応じて選びます。
特に事情もないなら最新版(現時点では2.5.0)でよいかと。
# mkdir -p "$(rbenv root)"/plugins
# git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
# rbenv install 2.5.0
(20分くらいかかりました)
# rbenv global 2.5.0
# ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]

このままでもRubyは実行できますが、CGIスクリプトのファイル1行目を次のように書くことになります。
#!/opt/rbenv/shims/ruby
ちょっと見慣れなすぎて覚えられなさそうなので、見知ったパスにシンボリックリンクをはってしまいます。
# ln -s /opt/rbenv/shims/ruby /usr/local/bin/ruby

SELinuxの設定変更

この状態でももうCGIスクリプトは動作するのですが、cgi-bin ディレクトリ以外に置くと 500 Internal Server Error になってしまいます。
/var/www/html 以下でもCGIスクリプトは動かしたい場合、SELinuxの設定変更が必要です。

長くなってきたので次回の記事で。

0 件のコメント:

コメントを投稿