職業プログラマの休日出勤

職業プログラマによる日曜自宅プログラミングや思考実験の成果たち。リアル休日出勤が発生すると更新が滞りがちになる。記事の内容は個人の意見であり、所属している(いた)組織の意見ではない。

PostgreSQLカンファレンス2015 に参加してきた

PostgreSQLカンファレンスに参加してきたので、その感想文および備忘録を書いておく。

www.postgresql.jp
ハッシュタグ#pgcon15j

前回参加したのは、2011年のことだった。

なぜ参加しようと思ったのか?

  • 最近PostgreSQLを触る機会があんまり無くて焦ってたから
  • 近い将来、新規に導入する予定があるから意識を高めたかったから


以下、拝聴した講演のうちのいくつかを紹介したい。

基調講演その1: PostgreSQL 9.5

http://www.postgresql.jp/events/jpug-pgcon2015/detail#keynote_1

開発者のMichaelさんの、日本語での基調講演で、12月にリリースされるかもしれないPostgreSQL 9.5 の新機能などの話。

主な内容はこんな感じ。

  • Upsert : insert文の最後につける ON CONFLICT 句の使い方と用途事例
  • BRIN : 部分インデックス(と訳すのが正しいのかどうかは不明) Blockc Range INdex
  • RLS : Row Level Security
  • パフォーマンス改善
    • ソートの改善
    • マルチCPU(マルチコアじゃない)環境下での改善
  • Streaming Replication における WALアーカイブの取り扱いの改善(これは9.4までの挙動をあんまり知らないから、上手く飲み込めなかった)

性能、信頼性を大幅に向上した pgpool-II 最新バージョンについて

http://www.postgresql.jp/events/jpug-pgcon2015/detail#J1

自分が pgpool-II の導入を検討していろいろ調べてたのは、PostgreSQL8.x の時代。当時はPostgreSQL本体に Streaming Replication の機能が無くて pgpool-II が擬似(?)replicationの仕組みを提供してくれていた。しかしその方式は全てのPostgreSQLノードに対して同じ(だったっけ?)SQLを投げるというもので、ある種の「怖さ」があった。他にも単純に組めばSPOFになってしまうなどの問題もあった。あれから数年が経過し、Streaming Replication登場後の pgpool-II の変貌についてほとんど知らなかったので、参加した。

最新バージョン 3.5 (現在はalpha版がリリースされたところ)での様々な改善の中で最も興味深いのは Watchdog の改善。こういう運用に嬉しい機能が強化されていくのは嬉しい。

他にもいろいろ。
pgpool-II 3.5 development - pgpool Wiki

PostgreSQL セキュリティ総復習

http://www.postgresql.jp/events/jpug-pgcon2015/detail#M2

心に残ったものいくつか。

  • psql\dp コマンドの実行結果の見方
  • sql_firewall : SQL Injection から防御するための拡張(怪しいクエリはエラーにする)
  • 「抑止と予防には予算と労力を投じる割に、検知と回復ができてない」といった趣旨のお話:確かに。

何が違うのか?PostGIS と最新版 MySQLGIS 機能を徹底比較

http://www.postgresql.jp/events/jpug-pgcon2015/detail#K3

大雑把にはこんな感じの話だったように記憶している。

  • MySQLだと本体に built-in なので導入が超簡単で、高速な動作をする。だけど単純な処理しかできない。
  • PostGIS だと最初のセットアップに一手間かかって気をつけないと遅くなっちゃうけど、様々な機能が揃っている。
  • MySQL Workbench の地図プレビューは優秀!
  • PostGIS 開発のキッカケはDB技術者じゃなくて地形界隈の専門家の動きによるもの。
  • 2つのDBはデータ形式がまったく異なるので、数値や文字列だけからなるデータみたいに簡単にダンプをやりとりするようなことはできない。一工夫いる。
  • GeoJSON の取り込み:これはどちらか一方の取り込みが遅いから、早い方で取り込ませて、ダンプを一工夫させつつ他方に取り込ませる手法が良い、みたいな話だったが、どっちがどっちだったか忘れた。。

PGroonga の実装

http://www.postgresql.jp/events/jpug-pgcon2015/detail#M4

講師の方がユーモア溢れる方で良い雰囲気のセッションだったのだが、ここで会場挙手アンケートの結果をご覧頂きたい。

内容は、PostgreSQLとGroongaとをどうやって繋いでいるのか?というお話。
他の製品との機能や性能の比較などもあって面白かった。
全文検索の話になると「あっちは日本語サポートしてない」「こっちもだ」みたいになるので大変。
日本語全文検索やってる皆さんにはほんとに頭が上がらない。

LT

こんな話を拝聴した。

さいごに

CakePHP3で簡易監査ログ

情報システムを組み上げるときは「誰がいつ何をした」といった情報を残していくことが非常によくあります。この情報のことを監査ログと呼びますが、他にも呼び方があるかもしれません。英語では audit trail と言ったりしてたと思います。たぶん。

そのシステムがRDB(関係データベース)を用いたものである場合、監査ログそのものもRDB上に残すことがあります。
きちんとした監査ログにするためには、監査ログを格納するための専用のテーブルを設けます。そのテーブルはシステム全体で1個であることもあれば、システムが管理しているデータごとに設けていくこともあります。専用のテーブルを設けずに、いわゆる「論理削除」を積み重ねていってそれを監査ログ代わりにすることもあるでしょう(望ましいとは思えませんが)。
これらの手法は、正確な監査ログが取れるようになる代わりに、かなり手間がかかります。構築する情報システムにかける予算が少なかったり期間が短かったりすると、省略されることもしばしばあります。
省略するとは言っても完全に何も記録を取らないのは精神衛生上よくありませんので、簡易的な監査ログをとることになります。
何が簡易なのかと言うと、保持する情報を以下のものに限るのです。

  • 当該データを最初に登録した日時
  • 当該データを最初に登録した人
  • 当該データを最後に更新した日時
  • 当該データを最後に更新した人

これだけの情報が残っていれば、本当に僅かなものではありますが、何か調査するときの手がかりにはなります。

さて、かなり長い前置きになりましたが、ここからはCakePHPの話です。
CakePHPでは昔から(少なくとも 2.x 系から)、日時だけではありますが、簡易の監査ログをRDBに保存する仕組みがあります。テーブルに「modified」「created」といったタイムスタンプ型の列を用意しておくと、そこに自動で登録日時や更新日時をセットしてくれるのです。

Saving Your Data — CakePHP Cookbook 2.x documentation

登録/更新した人については、 AuthComponent::user('id') によってModel内のコードからでも当該HTTPリクエストのセッションに紐付いたユーザIDを取ることができたので、beforeSaveコールバックあたりを実装すれば保存できていました。

ところが、CakePHP 3.x になってから、上記の方法ではユーザIDを取得することができなくなってしまいました。このことはGitHub上でも話題になり、こんなissueが立てられています。github.com
良い設計ではないものを誘発するという理由で速攻でcloseされてしまっています。これまでの手法がそのような性質を帯びたものであることには一切異論は無いのですが、簡易監査ログを取ることにそんなにコスト(時間)かけられないというのも事実です。

じゃあ、悪い設計であることは重々承知の上で簡単な実装を作っちゃえ! ということで、ModelのBehaviorを作りました。ソースはGistに置いてるのをこの記事に埋め込んでます。
gist.github.com

作った後に気付いたのですが、素晴らしい先人たちはもっと良い実装を既にされていました。github.com
これはPluginとしての実装なので、こちらの方が使い易いという人も多いでしょう。しかもstaticおじさんと呼ばれる危険性を摘み取ってくれていますし。


こういったものを活用して、気軽に簡易監査ログを取れるようにして、健全な情報システムを構築していきましょう。

re:Invent 2015(の報告会 #jawsug )に行ってきた

JAWS UG 大阪さんのイベント、re:Invent 2015 報告会 に参加してきた。もちろん聴衆として。jawsugosaka.doorkeeper.jp

個人的に気になった話をいくつか書き留めておきたい。

最近AWSから出るサービスは、運用系に近いものが多い

筆者のように、AWSを活用して全く別のものを作っている人間は喜ぶ話であるが、見方を変えると、EC2やら何やらを組み合わせて色々作って他のAWSユーザ向けに商売してても、競合するものがAWS本体から登場してメシが食えなくなることがあるよ、という話である。iOSで流行ったアプリの機能がOSそのものに取り込まれてしまうという現象にも似ている。
自分達がやっている商売がどんな特性を帯びているのか、そして今後どのような領域の需要が出てくるのかは絶えず注意を払っておかなければならない。そしてそのヒントは re:Invent に行けばゴロゴロ転がってる(らしい)。

Lambdaが世界を変える

みんな大好きLambda。re:Inventで発表された新機能はどれも魅力的でスグに使えるものばかり。
ただ一つ、VPC対応はまだリリースされていない。

Mobile Hub

今回のイベントでの実演を見て、あれだけの操作でiOSアプリのソースが吐き出されるのは凄いなあと改めて思った。

kintoneとAWSの補完関係

サイボウズさんのkintoneはビジネスアプリのUIを作る部分で強い代わりにデータ加工などの いわゆるサーバサイドの処理 で弱い。一方でAWSは逆。
という話を聞いてなるほど〜、と思った。

参加するにあたって

  • 「情報は生中継やTwitterなどを介してスグに手に入る」
  • 「クラスメソッドさん仕事速過ぎ」

という背景があるので、現地参加するにあたっては「現地でしかできないことに集中する」のが良いとのこと。この辺の現象はWWDCとかも同じかと。

あと、旅行代理店のHISさんが、こんなツアーを企画されていたらしい。
AWS re:Invent 2015 ツアー|H.I.S.海外視察旅行セクション
コースによってはAWS本社訪問というイベントがあったりして、かなり魅力的。

さいごに

2016年こそは行きたい。

スクラム本を読んだ

スクラム 仕事が4倍速くなる“世界標準”のチーム戦術」を読んだ。「スクラム本」と言うと以前は別の本のことを指していた気がするが、具体的にどれだったか忘れた。

紙バージョン

スクラム 仕事が4倍速くなる“世界標準”のチーム戦術

スクラム 仕事が4倍速くなる“世界標準”のチーム戦術

Kindle


なぜ読もうと思ったのか?

ここ数ヶ月というか数年というか、身の回りの組織が適切に運用されていないと感じることが多々あった。トップが無能であることもあれば、歴史的な経緯で意思決定が異常に遅い組織体制になっているということもある。もちろん、構成するメンバーが非協力的であることによって上手く行っていない組織もある。
5年ほど前にスクラム(と言うよりはアジャイル型開発)の本を読んで、それの影響を受けて可能な事項から少しずつ、身の回りの組織を実験台(良い意味で!)にして実践を進めてきた。
ここ最近、自分の手に負えないほど酷い事例をいくつか目の当たりにしてきたのだが、矯正しようにも自分から微妙に距離があったり、自分のあやふやな知識では組織体制を変えるほどの説得力を帯び得ないと感じてきた。そんな折、書店を彷徨っているとこの本が視界に飛び込んできたので買った。やはり、ある程度まとまった知識を得るには書籍が一番である。
今まであまり見たことない表紙だな、と思って確認してみると2015年6月の初版発行だった。(6月頃から9月頃まであまり書店に足を運んでいなかったのがバレる発言)

何が書いてあるのか?

  • スクラムの各構成要素が有効に作用する事例
  • (2個目書こうとしたけど良いのが思い浮かばない)

という訳で、基本的には事例集である。他のスクラムの本とは少し異なり、紹介されている事例がソフトウェア開発の分野が主体なのではなく、教育、軍隊、結婚式、医薬品業界など多くの場所から集められている。表紙にも「ソフトウェア」や「開発」といった語が見られないことからも、ソフトウェア開発業界以外に売りに出そうとしていることがわかる。
もちろん、我々ソフトウェア開発業界の人間が読んでもすんなり読める。

感想

もっと実践しよう。

EC2にRedmine(Apache|Passenger|HTTPS)

人に頼まれてRedmineAWSのEC2上に構築することになった。この記事はその作業記録である。

要件

  • ランニングコストは最低限に抑えたい:業務時間中しか使わないし
  • オレオレ証明書で良いから、平文のHTTPは一切禁止、HTTPSのみでの運用にしたい
  • OSはAmazon Linuxがいい
  • ネットワーク的にはいろんな場所からアクセスする

らしい。

報酬

肉。心は踊るが財布は踊らない。

インフラの用意

ドメイン

既にRoute53で運用しているドメインが存在していたので、それのサブドメインを使った。
Aレコードを、後述のElasticIPのものに設定する。

EC2仮想マシン

運用はt2.microを使うのだが、メモリが1GBしかないときは後述のPassengerのビルド時に「メモリ足らねえぞゴルァ、swapの設定しやがれ」と怒られていろいろ面倒臭かった記憶があったので、そんなのは金で解決する。構築中はt2.smallインスタンスを使い、構築が終わったらt2.microに切り替える。
「業務時間中しか使わない」ということであったが、予算の都合でELB使えないし複雑なことはしたくない(報酬が少ない!)ので、EC2インスタンス起動する度にPublicIPアドレスをRoute53に登録するような構成は取らず、ElasticIPを使う。

やったこと

  • ElasticIP 1個取得
  • t2.small インスタンス
    • Amazon Linux
    • Security Groupは、sshを制限付きで許可、HTTPSをどこからでも許可、という感じのを用意。
    • IAM Role は、例えばバックアップをS3に置いたりってことが考えられるけど今はそこまで設計するの面倒くさいので、一応空っぽのものを付けとく。起動した後にRole設定することは非常に面倒臭いけど、既存のRoleに権限追加するのは簡単なので。
    • ストレージはデフォルトの8GBで構築。こういう小さい容量だとGP-SSDよりはMagneticの方が良い気がしてるのでMagneticで構築。(容量少ないときのGP-SSDのベンチ、誰か取ってないかなー?)
  • root ユーザになる: $ sudo su -
  • # yum update
  • /etc/sysconfig/network をいじってホスト名を設定
  • 気になるならOS再起動

MySQLの用意

MySQL 5.6 は、Amazon Linuxがデフォルトで提供しているリポジトリの中では最新版。世の中は5.7の話題で持ちきりだけど、ここは5.6を使う。(5.7は落とし穴も一杯あるし…)

# yum install mysql56-server

そして起動。

# service mysqld start

初回起動時はいろいろ設定するらしく、ログがたくさんでる。その中に「特権ユーザのパスワードを設定しろよ!」というメッセージが居るので見逃さずに設定する。

# /usr/libexec/mysql56/mysqladmin -u root password 'new-password'

Apacheの用意

# yum install httpd24 mod24_ssl
オレオレ証明書

という戦略を取る。完全に予算の都合である。

# cd /etc/httpd
# mkdir ssl
# cd ssl
# openssl genrsa 2048 > server.key
# openssl req -new -key server.key > server.csr
※ここで、署名要求に記載する事項の入力を対話型で求められる。CN(Common Name)は、事前に用意しておいたドメインを指すようにする。
# openssl x509 -days 36500 -req -signkey server.key < server.csr > server.crt
# chmod 400 server.key

最後の秘密鍵の権限設定は、気軽な鯖だったらやんなくても良いかという気がするが、手が勝手に打ち込む。

証明書の用意ができたら、Apacheにそれを食わせる。
秘密鍵絶対パス/etc/httpd/ssl/server.key になっていて、証明書の絶対パス/etc/httpd/ssl/server.crt になっているはずなので、これらの情報を /etc/httpd/conf.d/ssl.conf に書き込む。このファイル内のどこに書いたら良いのかってのはこのファイルの中身を見ればわかるはずだ。

ここまでできれば、 # service httpd startApacheを起動してHTTPSの動作確認ができるはずだ。

OS起動設定

OSが起動したときに、MySQLApacheが起動するようにしておく。

# chkconfig --level 345 mysqld on
# chkconfig --level 345 httpd on

Redmineの用意

さて、ここからが本番である。基本的には公式のマニュアル http://www.redmine.org/projects/redmine/wiki/RedmineInstall に沿うことになる。
個人的にrubyを取り扱うときにいつも悩むのが、gemをどのユーザのところにインストールさせるのかというところ。今回はRedmineの専用鯖になるのでrootユーザに仕込もうかとも考えたが、マサカリが大量に飛んでくる可能性もある訳で、やはり redmine という名の専用のユーザを用意する。

以下、# はroot権限、$redmine権限でのコマンド実行である。

ユーザの用意
# useradd redmine

以後の操作は基本的に redmine ユーザで実施する。 # su - redmine で成りきれる。

バージョンの選定と入手:公式マニュアルのStep1に相当

個人的なポリシーとして「構築時の最新の stable リリースのものを使う」ことにしている。この記事の執筆時点では Redmine 3.1.1 がそれに該当する。この記事の執筆時点でのAmazonLinuxデフォルトのRubyのバージョンは動作できる Ruby のバージョンは2.0.0であるが、これは Redmine 3.1.1が動作可能なバージョンであるようだ。このまま3.1.1使う。ダウンロードページ http://www.redmine.org/projects/redmine/wiki/Download から必要なアーカイブのリンクをコピって、wgetとかでダウンロード!

$ cd ~
$ wget http://www.redmine.org/releases/redmine-3.1.1.tar.gz
$ md5sum redmine-3.1.1.tar.gz
(一応確認しとく)
$ tar -zxf redmine-3.1.1.tar.gz

この結果、redmineユーザの ~/redmine-3.1.1 にディレクトリができてるので、そこに入っておく。

DBの用意:公式マニュアルのStep2に相当

面倒臭いから、MySQLのrootユーザで接続させる。だからユーザは作らない。

$ mysql -h localhost -u root -p

で接続して、

CREATE DATABASE redmine CHARACTER SET utf8;

でDB作成。終わったら quit

DB接続設定:公式マニュアルのStep3に相当

config/database.yml.exampleconfig/database.yml にコピって使えと公式マニュアルが言っておられるので、素直にそれに従う。設定内容もマニュアルに従う。ここまで作ってきたDBの環境のことを思い出しながら。

必要なgemのインストール:公式マニュアルのStep4に相当

どうやら、これらのコマンドを実行するときの作業ディレクトリは大事であるようだ。Gemfileが見えている場所でってのが大事なんだろう、きっと。

$ gem install bundler
$ bundle install --without development test

この2個目の bundle コマンドを動かすと「◯◯がありません」みたいなエラーが出て止まる。Redmineインストールの難関その1である。
エラーメッセージに従って必要なものをインストールする。ここで何が必要なのか?を調べるのが、Redmine(というかruby)のツラいところだと思ってる。まあruby初心者の戯言ではあるが。

# yum install ruby-devel rubygem20-io-console gcc zlib zlib-devel patch mysql56-devel ImageMagick ImageMagick-devel

このyumのあと、また redmine ユーザに戻って、ディレクトリを間違えずに bundle install すれば良い。

パスワード生成:公式マニュアルのStep5に相当

Redmineのバージョンによって流すべきコマンドが異なる。1.4.x と 2.x には案内があるが、3.x の案内は無い。ここでは 2.x のガイドに従う。

$ bundle exec rake generate_secret_token
テーブル構築:公式マニュアルのStep6に相当

これで一発。前述のDB接続設定をミスってると死ぬ。

$ RAILS_ENV=production bundle exec rake db:migrate
初期値投入:公式マニュアルのStep7に相当

テーブル構築が成功してたらうまく行く。

$ RAILS_ENV=production bundle exec rake redmine:load_default_data

どの言語?って聞かれるので、英語がよければそのままreturn, 日本語が良ければ ja 指定だ。

ファイル権限設定:公式マニュアルのStep8に相当

ここで語ることは何もない。公式マニュアル通り。

chmod 777 files
chmod 777 log
chmod 777 tmp
chmod 777 tmp/pdf
chmod 777 public/plugin_assets

で終わりと行きたいところであるが、ここまでの手順に沿うと redmine ユーザのホームディレクトリ内に置いてあるredmineのファイル群にApacheのプロセスが辿り着けない。もういっちょ chmod 755 ~ を流す必要が有る。
※本当なら /var/ の下だったり /usr/local/ の下だったりに置くのが理想的なんだろう。でも専用鯖なので大目に見る。

Webrickでの動作確認:公式マニュアルのStep9に相当

SecurityGroupでHTTPのポート開けるの面倒臭いし、パス。初期パスワードをインターネット上に平文で流すのも嫌だし。


Passengerの用意

まずはgemのインストール。

$ gem install passenger

これはすんなり行く。
次に、Apacheモジュールのインストール。

$ passenger-install-apache2-module

で、また足りないものをインストールする必要に迫られる。

# yum install gcc-c++ libcurl-devel httpd24-devel apr-devel apr-util-devel

再度モジュールのインストールを試みると、ビルドが始まる。メモリ足らないマシン使ってるとここで怒られる。
数分待つと、Apacheの設定ファイル書き換えろよっていうメッセージが出てくるので、それに従う。これがちょっと面倒で、もう一つのセッションでsshつなぐ必要がある。接続できたらroot権限で /etc/httpd/conf.d/redmine.conf とか言って書き込む。別セッションの方はこれで任務完了であるが、接続を残しておくのも良い。

DocumentRoot の設定

もしもRedmineのインストールディレクトリが /home/redmine/redmine-3.1.1/ であるならば、設定すべきDocumentRootは /home/redmine/redmine-3.1.1/public になる。
これはApacheの設定ファイル /etc/httpd/conf/httpd.conf に直接書き込む。一緒にディレクトリの設定もしてしまう。

DocumentRoot "/home/redmine/redmine-3.1.1/public"
<Directory "/home/redmine/redmine-3.1.1/public">
        AllowOverride None
        Require all granted
</Directory>

ここまでできたら、 # service httpd restart すればRedmineを使えるようになっているはずだ。初期パスワードなどは公式のマニュアルに書いているので、あとは好きにしたら良いだろう。

定期的バックアップは、また暇なときにやる(たぶん記事にはしない)。設定したIAM Roleがきっと役に立つはずだ。

インスタンスタイプ

もともとt2.smallを使ってた理由はPassengerのApacheモジュールのビルドにメモリが必要だったから、である。稼動確認できたらもうt2.smallである必要はなくて、t2.microに切り替えて良い。