rails + sunspot なアプリケーションの本番環境をdocker-composeでつくる
Dockerやdocker-composeの話って結構「いいよ」と目にするんですが、いざ始めようと思うとハードルが高いですよね。
僕も今日は丸一日Docker(-compose)に吸われてしまいましたが、その成果をちょっとメモしておきます。
やりたいこと
やりたいのは以下のような構成。
- Railsが動くコンテナをDockerで作る
- Sunspotによる検索をしたいのでsolrをDockerで動かす
- DBはRDSを想定するのでコンテナでは作らず外部に繋ぐ
想定環境
- Mac OSX Sierra (10.12.4)
- Docker 17.06.1-ce
- docker-compose 1.14.0
DBをローカル宛にする方法
まず簡単な方から。
これは、単に docker.for.mac.localhost
というホスト名でホストOSが見えるようになっているので、以下のようにすればOK。
# .env.production (抜粋) DATABASE_URL=mysql2://root:@docker.for.mac.localhost:3306/my_app
# database.yml (抜粋) default: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 username: root password: '' socket: /tmp/mysql.sock production: <<: *default database: my_app # ↓ ここが重要。他はデフォルト。 url: <%= ENV['DATABASE_URL'] %>
この場合のDockerfile/docker-composeは後述のsolrを使う場合のから読み取って欲しい。
SolrをDockerベースで動かしつつsunspotと連携させる方法
こっちが難しかった。
先にコードを示す。
#Dockerfile FROM ruby:2.4.1 RUN apt-get update -qq && \ apt-get install -y build-essential libpq-dev nodejs RUN mkdir /app WORKDIR /app COPY Gemfile /app/Gemfile COPY Gemfile.lock /app/Gemfile.lock RUN bundle config build.nokogiri --use-system-libraries && \ bundle install -j3 --without test development --no-cache COPY . /app
こっちは割と普通の例だと思う。
bundle install
に --deployment
を付けるとrakeがないって怒られるようになってしまったので、つけるのやめた。
# docker-compose.yml version: '2' services: web: restart: always build: . env_file: .env.production command: "bundle exec rails s -p 3000 -b '0.0.0.0' -e production" volumes: - .:/app ports: - "3000:3000" depends_on: - solr solr: image: solr:6.6.0 volumes: - ./solr/configsets/sunspot/conf:/opt/solr/server/solr/production - solr:/opt/solr/server/solr/production/data entrypoint: - docker-entrypoint.sh - solr-precreate - production - /opt/solr/server/solr/configsets/sunspot volumes: solr:
何のことはなく、volumesでホストOSのディレクトリをゲストに使わせてるだけなんだけど、これが重要だった。
この状態で docker-compose build && docker-compose up -d
で立ち上げた後、solrの Core
というのを作るために次のコマンドを打つ
# このコマンドは打たなくてよくなった # docker-compose exec solr bin/solr create_core -c production
↑entrypointのセクションで不要に出来ました。
solrのwebコンソールとかにらめっこしながら、とにかく開発時にsunspotが生成する schema.xml
や solrconfig.yml
をdockerのsolrに認識してもらおうとしてたらこのようになった。
現状の課題
現状だと solr/configsets/sunspot/conf/core.properties
と solr/configsets/sunspot/conf/data/
にsolrのデータが生成されてしまう。
開発環境で邪魔になるという問題もあるし、本来これらはvolumeを定義してそこに保存されて欲しい。
しかし、solrのconfig類を渡す必要もあるので、いまひとつどうすればいいか分からなかった。
……solrについては元々あまり詳しくないので、誰か補足してくれたら凄く嬉しいです。是非コメントください。
参考
以上、調べるのに割と苦戦したのでメモでした。誰かの助けになれば幸い。
科学×中学生がテーマなノベルゲーム「EVERETT EFFECT」 開発途上版 "interpretation" 公開予定
Mac OSXでRPGツクール2000製のゲームを遊ぶ(EasyWine+IPAモナーフォント)
RPGツクール2000や2003の時代、名作フリーゲーム多いですよね。
久しぶりにやりたい作品があったので、手元のMacで動くようにしてみました。
ちなみに、クリアまでやった訳じゃないので、もしかしたらセーブデータの扱いとかでおかしくなることがあるかもしれないです!
2003とかでも似たような感じで動く気がします。まだやってないのですが、上手く行った/行かなかった人がいたらコメントください。
1. EasyWineのインストール
以下のページを参照。 NAVERまとめが公式配布先っていうちょっと変わり種ですね。
🍎 EasyWine.app 🍷 - 😃 mattintosh note 📝
2. RPGツクール2000RTPのインストール
2000時代はRTP同梱は稀ですよねー…ってことで。
RTPをダウンロードして、インストーラーのexeを開くだけです。
もしexeが他のソフトに関連付いてしまってる場合は、副ボタンクリック(二本指とかCtrl+クリックとか)からeasywineを選んで開く。
3. IPAモナーフォントのインストール
以下のサイトからIPAモナーフォントを持ってきてインストール。
各ファイルを開くとFontBookが開くので、流れに従えばインストールできるかと。
4. user.cfg の編集
レジストリ編集。しないと文字が汚くて遊べたもんじゃない。
参考サイトによると、IPAモナー明朝は下が途切れちゃうから明朝もゴシックにした方がいいとあり、 やってみたら確かに途切れちゃったので僕もゴシックにしてみました。
ここのやり方は、以下の通り。
- Finderで適当なウィンドウを開いて Cmd+Shift+G でフォルダ移動ダイアログを開く
~/Library/Caches/Wine/prefixes/default/
と入れて開く- user.cfg というファイルがあるので、CotEditorなどで開く
[Software\\Wine\\Fonts\\Replacements]
と書かれたエリアに以下の内容を書き足す
"MS Gothic"="IPA \x30e2\x30ca\x30fc \x30b4\x30b7\x30c3\x30af" "MS Mincho"="IPA \x30e2\x30ca\x30fc \x660e\x671d" "MS PGothic"="IPA \x30e2\x30ca\x30fc P\x30b4\x30b7\x30c3\x30af" "MS PMincho"="IPA \x30e2\x30ca\x30fc P\x660e\x671d" "MS UI Gothic"="\x30d2\x30e9\x30ae\x30ce\x4e38\x30b4 Pro W4" "\xff2d\xff33 \x30b4\x30b7\x30c3\x30af"="IPA \x30e2\x30ca\x30fc \x30b4\x30b7\x30c3\x30af" "\xff2d\xff33 \x660e\x671d"="IPA \x30e2\x30ca\x30fc \x30b4\x30b7\x30c3\x30af" "\xff2d\xff33 \xff30\x30b4\x30b7\x30c3\x30af"="IPA \x30e2\x30ca\x30fc P\x30b4\x30b7\x30c3\x30af" "\xff2d\xff33 \xff30\x660e\x671d"="IPA \x30e2\x30ca\x30fc P\x660e\x671d"
尚、念のためuser.cfgのバックアップを取っておいた方が安心です。
参考:
GAE/Goの基本的な設定の覚え書き
Go言語は昔(1.4まで?)はパッケージ管理の標準的な仕組みがなくて、1.7あたりでvendorディレクトリを必ず読むようになったらしい。 デファクトスタンダードは、今の所glideというものらしい。 godepsも良いみたいだけど、個人的に何となくglideの方が扱いやすく思えたので。
GOPATHを指定する必要があり、僕はautoenvを使う事にしたけど、何にせよこの後のプロセスを踏む前に必ず、作業ディレクトリがGOPATHに含まれてるようにする。
echo $GOPATH /Users/akn/go:/Users/akn/Documents/TimeCard/time-card-gae
普通の $PATH
と同様 :
で区切っていいらしい。
で、とにかくディレクトリ構造が肝心。僕はこんな風にした。(srcなしとかも試したけど、srcがないと上手く動作しなかった)
your-app-dir └── src ├── app.yaml ├── glide.lock ├── glide.yaml ├── main.go ├── server │ └── server.go └── vendor
主要なファイルの中身を晒しておく。
app.yaml
application: my-app version: 0 runtime: go api_version: go1 handlers: - url: /.* script: _go_app nobuild_files: - vendor skip_files: - vendor/.*$
main.go
package main import ( "server" ) func init() { server.Start() }
良く分かんないんだけど、main.goから直接vendor以下のを読みに行くと上手く行かなかったので、server packageを定義して、そっちから読むようにしてる。
あとは以下で開発
goapp serve
もしくはデプロイ
goapp deploy
これだと覚え書きすぎて分かりにくいので、丁寧めの記事へのリンクを貼っておきます。 ただし、僕は goenv を使って app/srcでディレクトリを分ける方法はCan’t findとか言われてライブラリが読まれず、上手く行かなかった。
Refile+S3のpresignにSwiftからダイレクトにアップロードする
画像等のファイルをS3(とかのクラウドストレージ)に置くのが当たり前になってきた昨今、クライアントから画像をアップロードするときにアプリケーションサーバーを経由するのは、そこからさらにS3に挙げるという点ではムダ。
この改善方法として、クライアントサイド(ブラウザやネイティブアプリ)からS3に直接アップロードして、アプリケーションサーバーには「ここに置いといたよ」とだけ伝える方法がある。 このアプローチは、特にherokuのようなアプリケーションサーバーに負荷をかけたくない環境では高い効果を発揮する。
で、このエントリの対象読者は、上の文で何が言いたいか分かってくれる人。
そうじゃない人は、諦めてアプリケーションサーバーに頼ってCarrierWaveかPaperclipの安定版を使う事を強くオススメする。
さて本題。
CarrierWaveの後継と噂される(同じ人が開発している)Rails向けの画像取り扱いgemのRefileというのがある。まだ安定バージョンではないし、Rails5系に組み込もうとするとSinatraとrakeのバージョンがぶつかってしまったり面倒が多いが、設計はCarrierWaveよりもさらに洗練されているっぽい。
GitHub - refile/refile: Ruby file uploads, take 3
Refileにはdirect uploadとPresigned uploadsという機能がある。(大文字小文字はREADMEに倣った)
direct uploadはフォームをsubmitしようとしたときにファイルを1個ずつRails側に送って、それが完了してからフォームをsubmitする方式。
Presigned uploadsは、上記で言ったS3に直接上げる方式。
Refileでは、Javascriptからのアップロードのみ実装されているので、これをSwift側で実装する。
ざっくり言えば refile/refile.js at master · refile/refile · GitHub の移植。
// まずはpresign情報を取得する request("https://example.com/attachments/cache/presign").validate().responseSwiftyJSON { (presignResponse) in // ※エラー処理は自分で書いて下さいね。 switchで .Success / .Failure 分岐するのが個人的には好き。 let url = presignResponse.value!["url"].stringValue let fields = presignResponse.value!["fields"].dictionaryValue let asName = presignResponse.value!["as"].stringValue Alamofire.upload(multipartFormData: { (multipartFormData) in for (name, value) in fields { multipartFormData.append(value.stringValue.data(using: .utf8)!, withName: name) } // 以下のNSDataを用意する部分もお好みで。 UIImagePNGRepresentation を使っても良いし、拡張子などで分岐しても良い。 let image = UIImage(named: "image1.jpg")! let imageData = UIImageJPEGRepresentation(image, 1.0)! multipartFormData.append(imageData, withName: asName) }, to: url, encodingCompletion: { (encodingResult) in // ここにもAlamofireのドキュメントを参照してエラー分岐等を書く必要があると思います。 print("uploaded") }) }
ここで得たデータをPOSTやPUTしてruby側でActiveRecordに渡してやる必要があるけれど、そこはまだやってないので追記するつもり。
ちなみに現状のGemfileの中身はこんな感じ。
tagすら切られてない中途半端なバージョンなので、不用意にバージョンが上がってバグらないように一応refを固定。
gem 'rails', '~> 5.0.1' # Refile (最新版, unstableなので依存解決のために無理して入れてます) gem "refile", require: "refile/rails", github: 'refile/refile', ref: 'd7a42dcd7c' gem "refile-mini_magick" gem "refile-s3" # Refileのために以下が必要っぽい gem "sinatra", github: "sinatra/sinatra", tag: "v2.0.0.beta2"
そういえば、全然関係ないんですが、最近Skyrimにハマってます。めっちゃ面白いですね。
JWTで認証するGem「Knock」でRSA認証する
Knockのデフォルトは secret_key_base を使ったHMAC using SHA-256らしい。
つまり、公開鍵暗号じゃないので、クライアントサイドで自由に中身を見れるというJWTの利点を半分失ってる(安全性については問題ないと思うけど…)
(追記)…と適当な事を書いてたら補足を頂きました。その通りですね! @koniyan ありがとう。
@AknEp HSとRSの違いはクライアント側で見れるかではなく、クライアント側で公開鍵を使ってverifyできるかどうかが違いじゃないかな。
— Kyoji Konishi (@koniyan) 2017年2月16日
※この辺とても難しいし、僕は暗号の専門家じゃないので、重要なプロジェクトで使う場合は、鵜呑みにしないで裏を取ってくださいね。
で、このメモで書いておきたいのは、KnockでRSA認証する方法。ただそれだけ。
まず、g knock:install で生成される knock.rb の各項目に以下のような感じで書く。 File.readにしてるけど、ENVに設定すればENVから引っ張り出しても良いと思う。(ENVに改行入れる手段とかは知らない…)
# knock.rb config.token_signature_algorithm = 'RS256' config.token_secret_signature_key = OpenSSL::PKey.read(File.read(Rails.root.join('keys','jwt-private.pem'))) config.token_public_key = OpenSSL::PKey.read(File.read(Rails.root.join('keys','jwt-public.pem')))
で、以下のコマンドで鍵ペアを生成する。
openssl genrsa 2048 > jwt-private.pem openssl rsa -in jwt-private.pem -pubout -out jwt-public.pem
あとは所定の位置にpemファイルを置いておくだけ。 クライアントサイドで複合したい時は、jwt-public.pem を誰でも見れるところに置いておくなりして、複合すればOK。お手軽。
特に分かりやすい利点としては、複合したトークンのexpをチェックするだけで期限がチェックできるので、トークンの延長をすべきか否かの判断とかが手軽にできる。とか。そのへん。
ClipMenu, Clippy がハングアップするので Pastebot に乗り換えたら神だった
クリップボード管理アプリで ClipMenu や、その思想を受け継ぐClippyがありますが、僕の環境だと度々CPUが100%に張り付きます。
何かないかなーと思っていたら、Tweetbotなどで有名なチームTapbotsが、Pastebotというアプリを出してました。 かなり使いやすいのでオススメ。