ゲーム感覚

自分にとってゲームとは集中して行うものであり、突き詰めるには多大な努力が必要と考えてるので、世間でのゲーム感覚という言葉の使われ方がイマイチしっくりこない。

と思ってググってみたら、はてなキーワードで似たような事が書いてあって笑った。 http://d.hatena.ne.jp/keywordtouch/%A5%B2%A1%BC%A5%E0%B4%B6%B3%D0

EC2上のログをtd-agent使ってCloudWatch Logsに投げようとしたらSSL認証エラーになった話

EC2上のログを、td-agentfluent-plugin-cloudwatch-logsを使ってCloudWatch Logsに送信しようとしたところ、SSL認証エラーが発生したので、エラーの解決方法を調べたのでまとめてみた。間違っている箇所があれば指摘ください!

before_shutdown failed error="SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed"

tl;dr

EC2でtd-agent使ってCloudWatch Logsにログを送信する場合は、/etc/sysconfig/td-agentに以下を追記すると上手くいくはず。

export SSL_CERT_FILE=/etc/pki/tls/cert.pem

バージョン情報

  • Amazon Linux AMI 2015.03
  • td-agent 2.2.0-0
  • fluent-plugin-cloudwatch-logs 0.0.7

エラー解消までの道のり

使用している証明書の確認してみる

td-agentに同梱されているrubyがどの証明書を使用しているかを確認。

$ /opt/td-agent/embedded/bin/ruby -r openssl -e 'p OpenSSL::X509::DEFAULT_CERT_FILE'
"/opt/td-agent/embedded/ssl/cert.pem"

td-agentに同梱されている証明書を使用しているようだ。

EC2組み込みの証明書を使用してみる

EC2の証明書は以下のパスにある。

/etc/pki/tls/cert.pem

OpenSSL::X509::DEFAULT_CERT_FILE_ENVで指定される文字列名で環境変数を指定すると、rubyが使用する証明書を変更できるのでそれを使う。

$ ruby -r openssl -e 'p OpenSSL::X509::DEFAULT_CERT_FILE_ENV'
"SSL_CERT_FILE"

td-agentはinitスクリプト内で/etc/sysconfig/td-agentを読み込むので、そこに以下の設定を書く

export SSL_CERT_FILE=/etc/pki/tls/cert.pem

td-agentを再起動して確認

service td-agent restart

td-agentを実行すると正常にログを送信することが出来た。

その他調べたこと

aws-sdk-rubyに証明書がバンドルされていないのか

aws-sdk-v1ではバンドルされていたが、aws-sdk-v2からバンドルしなくなった。

なぜaws-sdk-v2から証明書がバンドルされなくなったのか

証明書をバンドルすることで、SDKがセキュリティ上の懸念と責任を持つことになるので、望ましくないとのこと。(英語読み間違えてたらすみません)

なぜfluent-plugin-s3ではエラーにならないのか

fluent-plugin-s3はaws-sdk-v1を使用しているため。

fluent-plugin-cloudwatch-logsもaws-sdk-v1を使用すればよいのでは

aws-sdk-v2にしかCloudWatch Logsの実装は組み込まれてなくて、v1にバックポートもする予定ないらしい。

Amazon Linux以外のOSだとどうなの?

手元のMacでCentOS6.6の環境を作って試したけど、認証エラーが発生した。Amazon Linux以外では、aws-sdk-v1にバンドルされてる証明書を使わないとダメかもしれない。

CloudWatch Logs Agentはなんで大丈夫なの?

CloueWatch Logs AgentとはAWS公式のログ収集エージェント。内部的にはaws-cli(Python製)が使われている。aws-clibotocoreというAWS Interfaceライブラリを使用しており、それが証明書をバンドルしているので問題ない。

2014年振り返り

各月ざっくり

1月

  • AsakusaSatellite導入した
  • 各種通知をAsakusaSatelliteに流す対応をする

2月

3月

  • Perl 5.8.8から5.18.2への移行対応
  • CartonとかApp::FatPackerとか試す
  • Coroを使って非同期処理を書く
  • でんぱ組.incの曲に何故かハマる

4月

5月

6月

7月

  • Test::mysqldの素晴らしさを理解する
  • メインPCをMacBookAirに変える
  • スクフェスで初URを引いた
  • SQL::Translator::Diffを試したけどOracle対応してなかったので泣いた
  • 帰省した

8月

  • A Tour of Goを完走
  • beatmania IIDXを頻繁にプレイした
  • SlackにHubotを住まわせた
  • Travis CIを初めて使う
  • Herokuを初めて使う
  • MySQL5.1を5.6にアップグレードする対応してた
  • YAPC::Asia 2014に参加

9月

  • ゲーム実況やたらと見てた
  • 風来のシレンを一時期やってた
  • 引越し準備に追われる
  • ISUCON4に参加(予選敗退)
  • iPhone6に機種変更する
  • 第二子誕生

10月

  • 引っ越し
  • Data::Section::Simpleが便利なことに気づく
  • 古のサーバ移行に苦しむ
  • Chiba.pm#5に参加
  • Apache(httpd)と戯れる
  • BrainWarsにハマる
  • PerlCasual#6に参加
  • boot2docker入門

11月

  • DockerHubでAutomation Build
  • Net::POP3を使って一部のメールをHipChatに通知させた
  • VagrantとChef使って環境構築をコード化
  • Coverallsを初めて使う

12月

  • Time::Piece::Iteratorというモジュール書いた
  • Advent Calendarに初参加
  • Serverspecを導入
  • Circle CIとDocker使って自動テスト

ブログ

17記事を投稿。前年に比べると倍に増えてるけど、まだまだアウトプットが足りない。
Perlの記事が比較的多かったかな〜。

読書

f:id:waniji:20150103104612p:plain

http://booklog.jp/users/waniji/chart/2014/total

技術書1冊、ラノベ3冊、その他1冊。壊滅的。どげんかせんといかん。

Pocket

f:id:waniji:20150103104549p:plain

年末時点でPocketの残り記事数は70。追加した記事が2,655件、読んだ記事が2,721件だった。
積み記事は消化出来てるのでいい調子だけど、もうちょっと減らしたい。

まとめ

2014年は育児の年だったなぁ。第2子も生まれて更に賑やかになった。
技術に関して下半期はそこそこ頑張れてる印象。ISUCONに参加したり、仲間内でもくもく会したり。まさか業務でDocker使うことになるとは思わなかったけど、趣味で触っててよかったと思えた。
自分の自由時間が少なくなったことに慣れてきたので、来年は有効活用したい。

2015年

業務でRubyを使用することが決まったので、2015年はRubyかな〜。Golangは入門しかしてないので本格的に使いたい。
後は基礎を固めたい。何するにも基礎が固まってると飲み込みが早い気がするので。
それと英語......。

ある範囲内の日付時刻を、指定間隔で反復するTime::Piece::Iteratorというモジュールを作った

この記事はPerl Advent Calendar 2014の18日目の記事です。

17日目の記事はid:kfly8さんの間接オブジェクト記法のアンチパターンでした。

Time::Piece::Iterator

Time::Piece::Iterator

指定した範囲内の日付時刻を、指定した間隔で反復するモジュールが欲しかったのですが、見つからなかったので作成しました。(他にあれば教えて下さい!)
日付とか年月を引数に取るバッチを、特定の期間分(半年とか)実行したい時に使ってます。

使い方

Time::Pieceオブジェクトを2つ渡すと、その範囲内の日付時刻を返してくれます。

use Time::Piece;
use Time::Piece::Iterator;

my $iterator = day_iterator(
    localtime->strptime('2014/01/01', '%Y/%m/%d'),
    localtime->strptime('2014/01/03', '%Y/%m/%d'),
);

while( my $t = $iterator->next ) {
    print $t->ymd, "\n";
}
2014-01-01
2014-01-02
2014-01-03

間隔はdayだけではなくsecond/minute/hour/week/month/yearを用意しています。
例えば、今年の各月最初の平日を知りたい場合はこんなかんじです。

use Time::Piece;
use Time::Piece::Iterator;
use Time::Seconds;
use Calendar::Japanese::Holiday;

sub is_weekday {
    my $t = shift;
    my $is_holiday = isHoliday( $t->year, $t->mon, $t->mday, 1 );
    if( $is_holiday || $t->wday == 1 || $t->wday == 7 ) {
        return 0;
    }
    return 1;
}

my $from = localtime->strptime('2014-01-01', '%Y-%m-%d');
my $to = $from->add_years(1) - ONE_DAY;

my $iterator = month_iterator( $from, $to );
while( my $t = $iterator->next ) {
    while( !is_weekday($t) ) {
        $t += ONE_DAY;
    }
    print $t->ymd, "\n";
}

用意されている間隔では要件が満たせない場合は、自分で設定することが出来ます。
以下の例は、間隔が3週間の場合です。

my $iterator = custom_iterator(
    $from, $to,
    sub {
        my ($t, $sign) = @_;
        return $t + ( $sign * 3 * ONE_WEEK );
    }
);

第1引数が現在の日付時刻、第2引数が符号(plus or minus)です。過去に遡ることも出来るので、符号を受け取れるようにしています。

注意点

month_iteratorとyear_iteratorはTime::Pieceのadd_monthsとadd_yearsを使っているので、月末の扱いに注意する必要があります。

今後

無限iteratorを可能にする、Time::Piece::Plusも扱えるようにする、などを考えています。

あと、CPANには上げていないのですが、使っていただける方がいれば上げたいなと思っています。

明日

19日目はid:y_uukiさんです!

Chefでdirectoryをrecursive trueで作成するときの注意点

階層の深いディレクトリを作成するとき、mkdir -pのように一気に作ろうとrecipeを作った。

directory '/home/user/foo/bar' do
    owner 'user'
    group 'user'
    mode '0755'
    recursive true
end

しかし、これだとownergroupmodeの指定が、一番深い階層のディレクトリ(bar)のみに適用され、中間のディレクトリ(foo)には適用されないので、以下のように書く必要がある。

%w[
    /home/user/foo
    /home/user/foo/bar
].each do |path|
    directory path do
        owner 'user'
        group 'user'
        mode '0755'
    end
end

公式ドキュメントにも書いてた。
http://docs.getchef.com/chef/resources.html#recursive-directories

過程を伝える

調査依頼された時、結果だけ伝えるのではなく、過程もある程度伝えたほうが良い。あれやこれはやったか?という確認をする手間も省けるし、過程に誤りがあった場合に指摘がしやすいので効率的。