ポンコツ.log

ひよっこエンジニアのちょっとしたメモ。主に備忘録。たまに雑記。

capistranoでデプロイしたときにunicornが再起動しない対応

capコマンドを使ってデプロイしたあと、unicornが再起動していないことが頻発します。

$ ps -ef | grep unicorn | grep -v grep
user  1234     1  0 19:08 ?        00:00:03 unicorn master -E staging -c <PRJ_ROOT>/current/config/unicorn/staging.rb -D
user  5678  1234  0 19:08 ?        00:00:00 unicorn worker[0] -E staging -c <PRJ_ROOT>/current/config/unicorn/staging.rb -D
user  9102  1234  0 19:08 ?        00:00:00 unicorn worker[1] -E staging -c <PRJ_ROOT>/current/config/unicorn/staging.rb -D

プロセスの起動時間がデプロイ時間より古ければ明らかにおかしいので、ひとまずログを確認。
すると、下記のようなログがあります。

I, [2016-06-06T16:01:57.399854 #26684]  INFO -- : forked child re-executing...
<HOME_DIRECTORY>/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/bundler-1.12.5/lib/bundler/definition.rb:23:in `build': <PRJ_ROOT>/releases/20160603064119/Gemfile not found (Bundler::GemfileNotFound)

Bundler::GemfileNotFound なんて言われているけれど、確認するとちゃんとGemfileはあるのでオカシイ。
よく見ると、Gemfileを読み出そうとしている/releases以下のディレクトリ、この時点では既に過去のバージョンのものなので、ディレクトリ自体なかったりします。
なぜか古いGemfileを読み出そうとして、GemfileNotFoundを引き起こしている模様。

調べてみると、ENV['BUNDLE_GEMFILE']の値に古いGemfileのパスが入っていて、その値を利用してプロセスを起動するため「Gemfileないよ!」と言われているらしい。
対応として、before_execで明示的にパスを指定してあげれば、新しいGemfileを読みだすようになる。

# config/unicorn/staging.rb
current_dir = "<PRJ_ROOT>/current"
before_exec do |server|
  ENV['BUNDLE_GEMFILE'] = File.expand_path('Gemfile', current_dir)
end

なんで起きるんだろう。

参考:
Capstarano3でデプロイ時にUnicornが再起動しているようで失敗している時の対処法 - Qiita

S3上にあるファイルがうまく参照できないときのCORS設定

RailsでassetsファイルをS3に上げて、そこにある画像を参照しようとすることはよくあると思うのですが、その際にCORSではまったので対応メモ

Font-Awesomeを使おうとしてエラー

Font-Awesomeを使って表示しているところが、いわゆる豆腐状態(本来フォントが表示されて欲しいところが、□しか表示されない残念な状態)になっていたので開発者ツールのConsoleを確認。
すると、下記のようなエラーが表示されていました。

Font from origin 'https://hoge-bucket.s3.amazonaws.com' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://hogehuga.com' is therefore not allowed access.

※ URLはダミーのものです

エラー対応

おとなしくググってみると、S3上でAccess-Control-Allow-Originを設定しなければないけない、とのこと。

S3のバケット一覧へアクセスし、該当のバケットのプロパティを表示。
プロパティを表示すると画像のような表示が見えるので、アクセス許可のメニューを展開し、CORS設定の編集を選択。 f:id:mr_96:20160601235329p:plain

すると、CORS 構成エディターなるモーダルが表示されるので、テキストフォームにCORSルールを記述します。 <サンプル>

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

f:id:mr_96:20160602000020p:plain

S3側での設定は終わったので、Web上で確認すると、期待した通りに表示されています。
一件落着。

参考:
Cross-Origin Resource Sharing (CORS) - Amazon Simple Storage Service

CORSについて:
CORSまとめ - Qiita

【Rails】sitemap_generatorでsitemapを生成して、S3AdapterでS3にアップロードする

sitemap_generatorを使って生成したsitemapをS3にアップロードする方法で、S3Adapterを使った方法の実装メモ github.com

sitemap生成準備
Gemfileにsitemap_generatorを追加してbundle install

# Gemfile
gem 'sitemap_generator' 

sitemapをインストールして設定ファイルを生成する

$ bundle exec rake sitemap:install
#=> config/sitemap.rbが生成される

設定
生成された設定ファイルにsitemapに出力するパスなどを記述する
ここでSitemapGenerator::Sitemap.adapterS3Adapterを指定するとCarrierwaveを使わずに指定S3へアップロードできる

# config/sitemap.rb
# 自分のサイトURL
SitemapGenerator::Sitemap.default_host = "http://hoge.com"
# アップロード先になるS3のURL
SitemapGenerator::Sitemap.sitemaps_host = "https://BUCKETNAME.s3.amazonaws.com/"
# アプリケーション内のsitemap生成先ディレクトリ
SitemapGenerator::Sitemap.public_path = 'public/'
# sitemap配置ディレクトリ
SitemapGenerator::Sitemap.sitemaps_path = 'sitemaps/'

# S3Adapterを利用してS3へアップロードする
SitemapGenerator::Sitemap.adapter = SitemapGenerator::S3Adapter.new({
  fog_provider: 'AWS',
  fog_directory: BUCKETNAME,
  fog_region: REGION,
  aws_access_key_id: ACCESS_KEY_ID,
  aws_secret_access_key: SECRET_ACCESS_KEY
})

SitemapGenerator::Sitemap.create do
  Article.find_each do |article|
    add article_path(article), lastmod: article.updated_at, changefreq: 'daily'
  end
end

参考:ECサイトの開発運用に必要になった技術メモ: Railsでsitemap_generator使ってS3にサイトマップを作成する方法

確認
sitemapの生成はrake sitemap:refresh
rake sitemap:refresh:no_pingのようにするとGoogleなどの検索エンジンに更新通知せずに、sitemapだけ更新できる

$ bundle exec rake sitemap:refresh:no_ping
#=> public/sitemaps/sitemap.xml.gzが生成される(public_path + sitemaps_path + sitemapファイル)

周辺設定
/sitemap.xml.gzにアクセスされたら、S3上のsitemapにリダイレクトさせる設定を追加

# config/routes.rb
get 'sitemap.xml.gz', to: redirect('https://BUCKETNAME.s3.amazonaws.com/sitemaps/sitemap.xml.gz')

public/robots.txtファイルにsitemapの場所を指定することで、検索エンジンにsitemapの参照場所を伝えることができる

# robots.txt
Sitemap: https://BUCKETNAME.s3.amazonaws.com/sitemaps/sitemap.xml.gz

参考:robots.txt ファイルについて - Search Console ヘルプ
参考:robots.txtファイルでサイトマップの場所を指定 - Google Search Consoleの使い方(旧ウェブマスターツール)

【gem】ec2sshが便利だったのでメモ

sshログインするとき、ssh_configにHostを設定して便利な使い方をしますが、EC2インスタンスのIPが変わる度に修正しないといけなかったりして、ちょいと手間が発生したりします。
ec2sshはその手間を解消してくれる便利Gemでした。

READMEの記述通りに作業して、さくっとインストール&初期化

$ gem install ec2ssh
$ rbenv rehash
$ ec2ssh init

何故か忘れやすいrehash
rbenvを使っていたのですが、rehashを忘れたままec2sshコマンドを叩いて怒られました。
rbenv-gem-rehashを使ってしまえば解消されるんですけどね…。
参考:Ruby - rbenv を使っているなら rbenv-gem-rehash を使おう - Qiita

initした段階で.ec2sshというファイルが作成されます。
この中でAWSのキーなどを指定しています。
デフォルトでは環境変数として指定されているので、環境変数に必要なものをexportします。
ここまで出来ればあとはコマンド1つ叩くだけ。

$ ec2ssh update

これで.sshディレクトリ配下のconfigファイルの中に、EC2上にあるインスタンスのHostを設定してくれます。
IPが変わった場合もec2ssh updateを叩くだけで更新してくれるので、書き換える手間もなし。便利。

GitHub - mirakui/ec2ssh: A ssh_config manager for AWS EC2

【イベント】Android祭に遊びに行きました

f:id:mr_96:20150622230827p:plain
昨日、祭 with Androidへ遊びに行ってきました。
ドロイド君かわいかったです。

初めてAndroidWearを身につけたのですが、予想以上に時計っぽくて驚きました。
遊び過ぎてフリーズさせてしまいましたが…。
AppleWatchはベルトも専用のベルト以外をつけると動かない仕様と聞きましたが、AndroidWearはそうでもなさそう。
スマホケースのようにデザイン性を持たせたサービスが出てきそうな気もします。
日本人的な感覚なのかもしれませんが、やっぱり時計に向かって話しかけるのは抵抗あるなあと思いました。
GoogleMapの利用シーンに入っていそうな駅付近だとそれなりに声も出さないと騒音に負けてしまうわけで。
うーん、慣れれば気にならなくなるのでしょうか。

密かに嬉しかったこととしては、太鼓のゲームでフルコンを叩き出したことでした。
太鼓の達人で爆笑される身としては思ってもいない出来事です。
f:id:mr_96:20150622231738j:plain

それにしても、こういったイベントの収支関係はどうなっているのだろう…。

【Ruby】EC2のインスタンスが取得できなくてはまったお話

AWS SDKを使ってAWSのEC2のインスタンス名を取得しようとしたものの、そもそもEC2のインスタンス一覧を取得すること自体できていなくてはまったお話。
下記ドキュメントを参考にコンソール上でお試し。
Class: AWS::EC2 — AWS SDK for Ruby - Amazon.com

S3の場合

> s3 = AWS::S3.new( : access_key_id => ACCESS_KEY_ID,
           : secret_access_key => SECRET_ACCESS_KEY)
=> <AWS::S3>
> s3.buckets.to_a
=> [#<AWS::S3::Bucket:BUCKET1>, #<AWS::S3::Bucket:BUCKET2>, …]

とするとS3上にあるバケット一覧が取得できる。(to_aメソッドで配列表示)
「いける…!」と思ったので、EC2でも同じようにしてインスタンス一覧を取得。
しようとしたものの、to_aメソッドを付けて見てみると、返ってくるのは空の配列でした。残念。

> ec2 = AWS::EC2.new( : access_key_id => ACCESS_KEY_ID,
             : secret_access_key => SECRET_ACCESS_KEY)
=> <AWS::EC2>
> ec2.instances.to_a
=> [ ]

ここではまりにはまって途方にくれていたところ、こんな記事を見つけました。
Rubyからaws-sdkを使ってEC2のインスタンスとEBSのボリューム一覧を取得する
よくよく見るとアクセスキーIDとシークレットキーID以外にリージョンも指定している…?
ということで、早速追加してみたところ、ちゃんとインスタンス一覧が取得できました。

> ec2 = AWS::EC2.new( : access_key_id => ACCESS_KEY_ID,
             : secret_access_key => SECRET_ACCESS_KEY,
                : region => REGION )
=> <AWS::EC2>
> ec2.instances.to_a
=> [ <AWS::EC2::Instance id:INSTANCE-ID1>, <AWS::EC2::Instance id:INSTANCE-ID2>,… ]