例えばディレクトリの作成にinstallコマンドを使う

こんなことしたいとしますよね。

mkdir -p /path/to/dir
chown 2gou /path/to/dir
chgrp oretachino /path/to/dir
chmod 700 /path/to/dir

chown 2gou.oretachino /path/to/dirでもいいけど行数稼ぐために分けた。

同じことをするには、意外と知られてないけどinstall使うと1コマンドでイナフ。

install -o 2gou -g oretachi -m 700 -d /path/to/dir

installのmanを見てみると

This install program copies files (often just compiled) into destination locations you choose. If you want to download and install a ready-to-use package on a GNU/Linux system, you should instead be using a package manager like yum(1) or apt-get(1).

とあります。このコマンドに気付いたのはrpmを作成しているときにspecファイルに書いてあったからで、specファイルを読むとinstallコマンドによるファイルコピー方法も分かります。

# Install systemd service files
mkdir -p $RPM_BUILD_ROOT%{_unitdir}
for s in httpd htcacheclean; do
  install -p -m 644 $RPM_SOURCE_DIR/${s}.service \
                    $RPM_BUILD_ROOT%{_unitdir}/${s}.service
done

例えばCentOS7のhttpdパッケージ内%installセクションですが、systemd用のファイルをコピーする時にはこんな感じで書いていたり。

コピーの部分に関しては以下の便利オプションがあるので

  • -p : コピー元のタイムスタンプはそのまま
  • -b : ファイル内容に差異があればコピー先のバックアップを取得してからコピー

別ディレクトリに取ってあるバックアップ元のファイルを元の場所に戻したりするときにも便利かなあと思ったのだけれども

  • -mを忘れるとデフォルトの755になってしまう
    • あらかじめコピー元のファイルのパーミッションを知ってないといけなくて面倒
  • 再起コピーがないのでバックアップ元が複数階層あってもと同じ階層を再現出来ない

ので、日常だと最初に書いた空ディレクトリの作成が一番重宝するかなと思います。リストアは普通にcp -aとかrsyncでやればよさそう。

CloudFront+S3の画像配信にリサイズ機能を追加する

CloudFront+S3の画像配信システムに、サムネイルとかに使う画像のリサイズ機能を追加してみる。

要するにオリジナル画像がこのURLだとすると、

http://xxx.cloudfront.net/sample.jpg

f:id:oretachino:20141220234355j:plain

こういうURLで100×100にリサイズできるようにする。

http://xxx.cloudfront.net/resize/100x100/sample.jpg

f:id:oretachino:20141220234512j:plain

システム構成

元の構成はこういうのを想定。
画像はS3に保存され、アクセスは全てCloudFront経由。

f:id:oretachino:20141220233902p:plain

これをパスが/resize/で始まる場合は、画像変換サーバを通してリサイズするようにする。

f:id:oretachino:20141220233919p:plain

画像変換サーバはEC2で、ちゃんとELBを使って冗長化もする。
既にELB+EC2でAPPサーバを運用しているなら、流用して追加コスト0で実現できるかも。

画像変換サーバの設定

今回はnginxのimage_filterモジュールを使う。
もちろんsmall_lightを使ってもいいし、自前で開発してもいい。

インストールはAmazonLinuxであれば、ただyum install nginxするだけ。
それ以外の場合ではたぶん、--with-http_image_filter_moduleをつけてnginxをコンパイルしないといけない。
※EPELのnginxは流石にバージョンが古すぎる。

image_filterもその1つなんだけど、AmazonLinuxの標準レポジトリのnginxは、公式rpmには含まれないいくつかのモジュールが追加されているので、確認してみると面白いかも。

# nginx -V
...
configure arguments: ... --with-http_image_filter_module ...

サイズを完全に自由指定できるようにするには、こんな感じで設定する。

server {
  listen 80 default_server;
  server_name _;

  root /var/nginx_root;

  location ~ ^/resize/(\d+)x(\d+)/(.*)$ {
    set $width $1;
    set $height $2;
    set $path $3;

    image_filter resize $width $height;
    image_filter_jpeg_quality 90;

    rewrite ^ /$path break;
  }
}

これでドキュメントルート配下の画像のリサイズが確認できるはず。
※画像が無い時に404にするには『error_page 415 =404 /404.html;』を追加する。

ただ開発環境はいいけど、本番環境にこの設定を入れるとDOS攻撃が怖い。
例えば幅を1ずつ増やしてDOS攻撃されると、

for i in {1..10000};do curl http://xxx.cloudfront.net/resize/${i}x1000/sample.jpg;done

画像変換サーバのCPUや、前段にキャッシュ用Proxyがある場合はそのメモリを使いきってしまうかもしれない。

これを防ぐ方法の1つは、cookpadのtofuのようにURLに予測不可能なハッシュ値を含めること。

http://img.cpcdn.com/cms_articles/3453/100x100c/cdcf6aff4c78c6619b67372f129bdef2.jpg?u=9769263&p=1418093860

しかしその場合はハッシュ関数とSEEDが漏れたらURLを変更しないといけなくなるかもしれない。まぁ直リン禁止なら問題ないけど。

もう1つの方法は、本番系は特定のサイズ指定のみ許可すること。
今回はこっち。

server {
  listen 80 default_server;
  server_name _;

  root /var/nginx_root;

  location ~ ^/resize/(100x100|200x200)/(.*)$ {
    set $type $1;
    set $path $2;

    if ($type = 100x100) {
      set $width 100;
      set $height 100;
    }

    if ($type = 200x200) {
      set $width 200;
      set $height 200;
    }

    image_filter resize $width $height;
    image_filter_jpeg_quality 90;

    rewrite ^ /$path break;
  }

  location ~ ^/resize/ {
    return 404;
  }
}

運用がちょっと面倒で応用も効きづらいけど、そのぶん実装は簡単。
設定が冗長になるのはchefとかで動的に作ればそんなに面倒じゃないはず。

CloudFront設定&画像変換サーバのProxy設定

事前にELBを作成して画像変換サーバをその配下に入れておく。

そしてManagementConsoleのCloudFront設定で、/resize/で始まる場合はS3でなくELBに渡すよう設定する。

  • 『Origins』でELBをOriginとして追加
  • 『Behaviors』でPath Patternを『resize/*』、OriginをELBにしたBehaviorを追加

あとはnginxでCloudFrontにProxyするように設定する。
ここで1つ注意があって、CloudFrontから来たアクセスを同じCloudFrontにProxyする場合、1回目通った時にループ検出のために付与されるViaヘッダをクリアしないとアクセスが拒否されてしまう。

というわけでnginxのlocationに追加する設定は以下の2行。

proxy_set_header Via "";
proxy_pass http://d2sloa042uzrzo.cloudfront.net;

これで作業は完了。

http://d2sloa042uzrzo.cloudfront.net/kuma.jpg http://d2sloa042uzrzo.cloudfront.net/resize/100x100/kuma.jpg

まとめ

いろいろめんどくさいから、CloudFront自体に画像のリサイズ機能つかないかな。

Macでお手軽にリモートマシンからのコマンド終了通知

実行時間の長いコマンドの終了を通知できるようにGrowlや通知センターを使って工夫している人はそれなりにいらっしゃると思います。

ただ、これを ssh でログインしたリモートサーバでやろうと思うとけっこうめんどい。

ということで、自分がやっているお手軽な方法の紹介

必要なもの

iTerm2

設定方法

iTerm > Preferences > Profilers > Advanced > Triggers Edit

f:id:oretachino:20141219030540p:plain

  • ボタンを押して Trigger を作る。Finale, Show Alert, Finale としてみた。

f:id:oretachino:20141219032409p:plain

使い方

これで

$ echo Finale

とするとポップアップが表示されるようになる。

f:id:oretachino:20141219032451p:plain

あとは、

$ 重い処理; echo Finale

とかすれば良い。リモートサーバで実行しても iTerm2 上にその文字が出てくれば反応するので関係ない。

ちなみに、なぜ Finish じゃなくて Finale (フィナーレ) にしているのかというと、Finish だと普通にコマンド実行結果に含まれていることがあって、ノイズになることがあったため。

Travis CIでMongoDB 2.6系を使う設定

あるクエリがローカルやサーバでは動くのにTravisCIのテストでコケる現象があって、よくよく見ると2.4系では無い機能を使っていた。 で、TravisCI側をどうすれば良いのかなーとググっていたら

Using MongoDB 2.6 with TravisCI Builds

というズバリのブログを見つけてそのコピペです。

before_install:  
  - "sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10"
  - "echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list"
  - "sudo apt-get update"
  - "sudo apt-get install mongodb-org-server”

を.travis.yamlに書きましょうという話ですね。いつ頃2.6系対応されるかは対応自体は検討されているようなので、

MongoDB 2.6.x · Issue #2246 · travis-ci/travis-ci · GitHub

そのうち寝ていたら来ることでしょう。

おしまい。

Ruby の Object Data Dumper

プリントデバッグが大好きだ!!!何はなくともとりあえず標準出力に吐いてデバグ!!!!!!!!!っていうようなことはみなさんにおかれましても少なからずあるのではないでしょうか。

プリントデバッグを行う場合、単純に変数に何が入っているかというよりも、オブジェクトの状態とかを見たいことが多いかと思う。
そういうときのためのライブラリとして、Ruby だと、p, pp は組み込み、ap はもう定番化しててみんな使ってると思う。
で、ddp ってのもある。http://hisaichi5518.hatenablog.jp/entry/2014/11/05/154949

適当なクラスをでっち上げてそれぞれに食わせてみる

こんなクラスがあったとする。
インスタンスを作って、インスタンス自体、インスタンス変数、インスタンスメソッドをそれぞれのライブラリに食わせてみて、どんな感じに表示されるか見てみませう。

class Ore
end

class Oretachi < Ore
  attr_accessor :data
  def initialize
    @data = [
      { name: '1号', entry_count: 4, bookmark_count: 26 },
      { name: '2号', entry_count: 3, bookmark_count: 7 },
      { name: '3号', entry_count: 3, bookmark_count: 16 },
      { name: '4号', entry_count: 2, bookmark_count: 24 },
      { name: '5号', entry_count: 2, bookmark_count: 21 },
      { name: '6号', entry_count: 2, bookmark_count: 182 },
      { name: '7号', entry_count: 2, bookmark_count: 218 },
    ]
  end

  def [](name)
    @data.select { |ore| ore[:name] == name }.first
  end
end

インスタンス自体

内包するインスタンス変数をキレイに見たい場合だと pp に軍配が上がる感じがします。でもなんかインデントとか微妙だしイマイチ。
で、ddp はインスタンスのクラスの継承関係と、include されているモジュールの一覧まで見られるのでそういう用途においては他のライブラリの出番がなさそう。

require 'pp'
require 'ap'
require 'ddp'

oretachi = Oretachi.new

#### p
p oretachi
#=> #<Oretachi:0x007fef240a13b8 @data=[{:name=>"1号", :entry_count=>4, :bookmark_count=>26}, {:name=>"2号", :entry_count=>3, :bookmark_count=>7}, {:name=>"3号", :entry_count=>3, :bookmark_count=>16}, {:name=>"4号", :entry_count=>2, :bookmark_count=>24}, {:name=>"5号", :entry_count=>2, :bookmark_count=>21}, {:name=>"6号", :entry_count=>2, :bookmark_count=>182}, {:name=>"7号", :entry_count=>2, :bookmark_count=>218}]>

#### pp
pp oretachi
#=> #<Oretachi:0x007fef240a13b8
 @data=
  [{:name=>"1号", :entry_count=>4, :bookmark_count=>26},
   {:name=>"2号", :entry_count=>3, :bookmark_count=>7},
   {:name=>"3号", :entry_count=>3, :bookmark_count=>16},
   {:name=>"4号", :entry_count=>2, :bookmark_count=>24},
   {:name=>"5号", :entry_count=>2, :bookmark_count=>21},
   {:name=>"6号", :entry_count=>2, :bookmark_count=>182},
   {:name=>"7号", :entry_count=>2, :bookmark_count=>218}]>

#### ap
ap oretachi
#=> #<Oretachi:0x007fef240a13b8 @data=[{:name=>"1号", :entry_count=>4, :bookmark_count=>26}, {:name=>"2号", :entry_count=>3, :bookmark_count=>7}, {:name=>"3号", :entry_count=>3, :bookmark_count=>16}, {:name=>"4号", :entry_count=>2, :bookmark_count=>24}, {:name=>"5号", :entry_count=>2, :bookmark_count=>21}, {:name=>"6号", :entry_count=>2, :bookmark_count=>182}, {:name=>"7号", :entry_count=>2, :bookmark_count=>218}]>

#### ddp
Ddp.p oretachi
#=> Oretachi < Ore < Object < BasicObject {
  included_modules:
    PP::ObjectMixin
    Kernel
  inspect:
    #<Oretachi:0x007fef240a13b8 @data=[{:name=>"1号", :entry_count=>4, :bookmark_count=>26}, {:name=>"2号", :entry_count=>3, :bookmark_count=>7}, {:name=>"3号", :entry_count=>3, :bookmark_count=>16}, {:name=>"4号", :entry_count=>2, :bookmark_count=>24}, {:name=>"5号", :entry_count=>2, :bookmark_count=>21}, {:name=>"6号", :entry_count=>2, :bookmark_count=>182}, {:name=>"7号", :entry_count=>2, :bookmark_count=>218}]>
}

インスタンス変数

オブジェクトの構造を確認したい場合においては、優勝 ap, 次点 pp という感じでしょうか。
でもなんか ap もインデントとかキレイじゃなくてちょっと微妙な気がしてます。もうすこし階層の深いオブジェクトだとちょい見づらいことがあるのだよなー。

require 'pp'
require 'ap'
require 'ddp'

oretachi = Oretachi.new

#### p
p oretachi.data
#=> [{:name=>"1号", :entry_count=>4, :bookmark_count=>26}, {:name=>"2号", :entry_count=>3, :bookmark_count=>7}, {:name=>"3号", :entry_count=>3, :bookmark_count=>16}, {:name=>"4号", :entry_count=>2, :bookmark_count=>24}, {:name=>"5号", :entry_count=>2, :bookmark_count=>21}, {:name=>"6号", :entry_count=>2, :bookmark_count=>182}, {:name=>"7号", :entry_count=>2, :bookmark_count=>218}]

#### pp
pp oretachi.data
#=> [{:name=>"1号", :entry_count=>4, :bookmark_count=>26},
 {:name=>"2号", :entry_count=>3, :bookmark_count=>7},
 {:name=>"3号", :entry_count=>3, :bookmark_count=>16},
 {:name=>"4号", :entry_count=>2, :bookmark_count=>24},
 {:name=>"5号", :entry_count=>2, :bookmark_count=>21},
 {:name=>"6号", :entry_count=>2, :bookmark_count=>182},
 {:name=>"7号", :entry_count=>2, :bookmark_count=>218}]

#### ap
ap oretachi.data
#=> [
    [0] {
                  :name => "1号",
           :entry_count => 4,
        :bookmark_count => 26
    },
    [1] {
                  :name => "2号",
           :entry_count => 3,
        :bookmark_count => 7
    },
    [2] {
                  :name => "3号",
           :entry_count => 3,
        :bookmark_count => 16
    },
    [3] {
                  :name => "4号",
           :entry_count => 2,
        :bookmark_count => 24
    },
    [4] {
                  :name => "5号",
           :entry_count => 2,
        :bookmark_count => 21
    },
    [5] {
                  :name => "6号",
           :entry_count => 2,
        :bookmark_count => 182
    },
    [6] {
                  :name => "7号",
           :entry_count => 2,
        :bookmark_count => 218
    }
]

#### ddp
Ddp.p oretachi.data
#=> Array < Object < BasicObject {
  included_modules:
    Enumerable
    PP::ObjectMixin
    Kernel
  inspect:
    [{:name=>"1号", :entry_count=>4, :bookmark_count=>26}, {:name=>"2号", :entry_count=>3, :bookmark_count=>7}, {:name=>"3号", :entry_count=>3, :bookmark_count=>16}, {:name=>"4号", :entry_count=>2, :bookmark_count=>24}, {:name=>"5号", :entry_count=>2, :bookmark_count=>21}, {:name=>"6号", :entry_count=>2, :bookmark_count=>182}, {:name=>"7号", :entry_count=>2, :bookmark_count=>218}]
}

インスタンスメソッド

ddp すごい。source_location という項目で、そのメソッドがどこの何行目に定義されているかわかる。これはクソ便利だ。

require 'pp'
require 'ap'
require 'ddp'

oretachi = Oretachi.new

#### p
p oretachi.method(:[])
#=> #<Method: Oretachi#[]>

#### pp
pp oretachi.method(:[])
#=> #<Method: Oretachi#[]>

#### ap
ap oretachi.method(:[])
#=> Oretachi#[](name)

#### ddp
Ddp.p oretachi.method(:[])
#=> Method < Object < BasicObject {
  included_modules:
    PP::ObjectMixin
    Kernel
  inspect:
    #<Method: Oretachi#[]>
  source_location: ["-", 19]
}

まとめとか

構造をいい感じに表示 継承関係がわかる include されているモジュールがわかる メソッドの定義場所がわかる 組み込み require
p × × × × 不要
pp × × ×
ap × × × ×
ddp × ×
  • ddp がすごく便利
  • ddp がオブジェクトの構造をもっといい感じに表示してくれたら最高
  • Ddp.p って書くのダルい

  • ap, ddp は組み込みではないのでインストールが必要

    • bundle exec でどうこうしたい場合には一時的にでも Gemfile に書いておくなどしなければならずダルい
  • ap は Hash とか Array を直接食わせたらいい感じなのに、インスタンス自体を食わせたときには内包するインスタンス変数の内容の表示が残念なのでもうちっとなんとかならんか