楽しめなかったという反省。15日目のエントリです。昨日はkokuyouさん、明日はsaitenさんです。要約Ansibleを使って、Chinachuがインストールされた録画サーバーを自動でセットアップするPlaybook作りました。安心してアニメが観たい。世の中の大抵の人は、安心してアニメが観たいはずです。世の中の大抵の人は、普通のテレビと普通のBDレコーダーを使い、安心してテレビを観たり録画しているはずです。変なテレビやレコーダーを買わない限り、普通にアニメを観てアニメを録画できる機能が備わっています。世の中には、宗教的な理由や金銭的な理由で、テレビやレコーダーを買うことを拒む人が居ます。このエントリでは、訳があってテレビやレコーダーを買えないけれど、クリスマスはどうせ暇だから一日中アニメを観たいという人のために、クリスマスまで安心してアニメを録画し続けることが出来る、録画サーバーの作り方を解説します。安心とは難しいテーマだ......安全とは一体なんなのか。冗長性......とかそういうのが安全な気がしますが、このエントリで言う安全とは、「壊れてもすぐに治せる」ことです。普通のテレビと普通のレコーダーは、仮に物理的に壊れても、同じものを買えばすぐに治ったと同じ状態です(HDDとかが壊れたら別ですが)。自分で作った録画サーバーはどうでしょう......?つらさこれまで、自宅サーバーやVPSを含めて、いくつものサーバー的なモノを運用してきましたが、大抵は「その場で対応した再現法のわからない謎のレシピの積み重ね」がさらに積み重なり、確実に再現できない上に、この設定を作った時の俺は何を考えていたのかすら理解できない。明日の他人は今日の自分、お前は俺で俺はお前状態のモノを大量に作ってきました。嫌いな言葉は環境依存です。再現可能な環境を作る環境に依存したつらい環境はなく、壊れてもすぐに同じ状態を再現するために、構成管理ツールを使いましょう。代表的なものは、ChefとかPuppetなどがありますが、あれらは何百台ものサーバーを常に管理し続けるためのツールです。一年に一回、壊れるかどうかもわからないような録画サーバーを管理するために存在しているわけではありません。そこでおすすめの構成管理ツールが、Ansibleです。Python製ですが、設定の記述にYAMLを使い、特定の言語に依存しない簡単な記述で構成管理が可能ということで、今年ブレイクした(多分)ツールです。テンプレートエンジンにはPythonのJinja2というライブラリを使っているため、ほんの少しだけPythonの記述に依存する場所がありますが、学習コストは非常に低いです。似たような哲学を共有する構成管理ツールとしてFabricというものもありますが、少なくとも国内ではFabricよりもAnsibleの方が流行っていると思います。年に一回壊れるかどうか、と言いましたが、サーバーを一回クリアにして再度セットアップしたくなる状況は、年に何度か出てくると思います。私の場合、録画サーバー上で複数の仮想サーバーを運用しているため、物理メモリを増やしたくなったとか、USB3.0のカードを追加したくなったなどという事態が年に数度起きます。そんな場合でも、構成管理を使えば、物理環境を変えた後にでも、以前と全く同じ設定を自動で作り出すことが可能です。やってみよう私が作った録画サーバーの環境を、そのまま紹介します。作りたかった録画サーバーの条件として、ファンレスゼロスピンドル多めのメモリ3番組以上の同時録画という要求が自分の中でありました。自室で24h動くサーバーなので、うるさいと気になって眠れないし、仮想マシンをいくつか動かすので、メモリは多めに欲しいという判断からです。3番組以上の録画に関しては、実際に今年の春頃に、3番組が重なって絶望感を覚えたからです。2ACアダプタのATX電源まず、ASRockのQ1900は、CeleronのJ1900をオンボードで載せたSoCで、ファンレスのボードです。クアッドコア搭載で、ePCIが3枚刺せ、何より同じJ1900の中でもメモリも最大16Gと十分な拡張性を持っているため、選択しました。PT3の二枚刺しは、3番組同時録画の要件を満たすためです。電源もファンレスのためにACアダプタタイプを選択しました。J1900のTDPは10Wで、PT3を二枚刺してもまだ電力的な余裕は十分です。残念ながら、テレビを録画するという事自体が非常に容量を食う問題であったため、サーバー自身にもある程度のストレージは欲しいと思い、SSDは一旦見送り2.5インチの静音HDDを選択しました。これらのパーツは、決して特殊なものではありません。物理的に壊れても、すぐに電気屋に買いに行くことで、構成管理を使い自動的に復帰が可能です。サーバーに何を選択するか録画サーバー機能そのものには、Chinachuというソフトを使います。Linux用の録画サーバーを構築するソフトとしては、メジャーなものにfolitaやEPGrecなどがあります。他のソフトと比較した時のChinachuの特徴は、インストールの容易さ、癖のあるUI、そしてWebAPIのエンドポイントが用意されており、ほぼすべてをAPI経由で操作できるなどの設計もさておき、「世界で一番キュートな録画システム」という可愛らしく魅力的な謳い文句です。他には、これはとても重要なことですが、作者の方が積極的にコミケでChinachuの設計方針や扱い方などを書いた同人誌を売っていたり、あとはDBなどのミドルウェアに依存が無くNode.jsだけ有ればいいなど、とにかく扱いやすく解決策を探しやすいという点が選択した理由です。記述されており、一回壊れると手作業での修復はほぼ不可能です。いえ、壊れたら再構成すればいいのです。録画サーバーを構成管理するAnsibleのPlaybookをGithubにあげてあります。すべてのコードはこっちを見てもらうとして、重要な部分を解説しますYasuhiroKinoshita/chinachu_ansibleディレクトリ構成ペストプラクティスを採っています。ロールは6つに分解してあり、それぞれ共通設定PT3のドライバと録画コマンドのインストールChinachuのインストール前確認ChinachuのインストールSambaのインストールVagrantとVirtualBoxのインストールに分かれています。Chinachuのサーバー構築に必要なのは1から4までで、5と6は自分が家のサーバーに欲しかった機能を入れているものです。1、5、6は、他のプロジェクトにも使えそうなので、Gitのサブモジュール化を行っています。このレポジトリを作った当初は、サブモジュール化を進めて色々応用させることに意欲を持っていたのでしょうが、これはこれで管理がつらいです。Chinachuのロールが前後に分解されているのは、ユーザーの切り替えが面倒だったからです。事前準備はrootで行い、インストールはchinachuユーザーで行うためです。chinachuを実行するユーザーのホームディレクトリを設定します。Twitterの通知を使用する場合に使うトークン。chinachuを実行するユーザーのホームディレクトリを設定します。Twitterの通知を使用する場合に使うトークン。</span>マシンの再起動PT3のドライバを入れた後など、どうしても物理的にマシンを再起動する必要が出てきますが、せっかく自動化しているので手動でやるのはアホらしいです。次のような記述でマシンを再起動し、再びsshで接続できるよう待機します。Calendarを参考にしました。delay=60ただし、この設定では、仮想環境での実行がうまくいきません。基本的に録画サーバーは物理サーバーだと思うので、特に配慮はしませんが、仮想環境でPlaybookの実行テストを行う場合には注意が必要です。chinachu_useruserモジュールのpasswordオプションは、SHAでハッシュ化した値を渡さなくてはなりません。上のコードでは、’chinachu’という文字列をハッシュ化しています。詳細は公式FAQのここを参照。cloneをしてきた後に、ディレクトリルートに居るchinachuコマンドを実行するだけで、自動的にインストールされます。そのコマンドが対話的で、引数を使った動作の制御が出来ないので、expectスクリプトを使って自動でインストールします。"1\n"interactこのファイルをリモートにコピーし、chinachuコマンドへのシンボリックリンク経由で実行します。chinachuは、シンボリックリンクからでも正しくパスを認識して実行することが可能です。chinachuPT3のドライバに関して怖いのであまり触れません実行するChinachuは、Debian上で動作させることを推奨されています。Wheezyをサーバーにインストールします。このとき、root以外にユーザーを作製することを求められますが、chinachuというユーザーは作らないでください。Ansibleによって、自動的に作成されます。このDebianのインストール自体も自動化したかったのですが、手順的に特に難しいものでも無いことと、メンテのコストを考えると、手動でもいいかと思い特に何もしていません。開発用の最小構成でインストールしてください。site.yml毎回タイプするのが面倒なので、作っただけです。Vagrantなどで作成したDebianのマシンで、試してみると何が起こるのか解ると思います。(ただし、VagrantやVirtualBoxでの起動では、PT3用のドライバ等をインストールしている最後のRoleで行う再起動のタスクがうまく行きません。このPlaybookは実機を前提としているので、そこの部分をコメントアウトして自分で再起動を試してください)録画サーバーとの通信さえ問題なければ、これであとは勝手にchinachuサーバーが作成されるはずです。指定した公開鍵を使って、chinachuユーザーとしての公開鍵を使ったログインも可能です。chinachuユーザーのデフォルトのパスワードはchinachuなので、sudoなどの際に必要であれば指定してください。まとめ以上の手順で、Ansibleを使った録画サーバーのプロビジョニングが完了します。あとは、Chinachuのドキュメントを参照して、初回の番組取得や起動スクリプトの作成など、自動化できないChinachuのオペレーションを開始してください。物理マシンへのOSのインストールと、セットアップ後のChinachuの運用を除いて、ほぼすべて自動化しました。これで仮にどこかで故障が起きても、すぐに同じ環境を再度作製することが出来ます。安心してアニメが見れます。このプロビジョニングで作成した録画サーバーを使って、私は2014年冬のアニメをほぼ無事にすべて録画しています。最近引っ越したので、正確なアップタイムは忘れましたが、少なくとも三ヶ月近くは無停止で稼働し続けました。いくつか観れていないものがあるので、クリスマスに安心して観ようと思っています。みんなで安心して、クリスマスはずっとアニメを観よう。このパーマリンクをブックマークする。楽しめなかったという反省。パフォーマンスのために命令的な記述を交えることがあります。つまるところ、「命令型プログラミング」「関数型プログラミング」とは書き方のスタイルの問題であって、言語はそのサポートに過ぎない、というわけです。いったわけで、もし「関数型言語で書けばそれは関数型プログラミングなんだ!」と思っている人がいたら、そうではなく「関数型プログラミングをどこで活かせるか」を考えてもらえると嬉しいです。関数型プログラミングのメリットさて、関数型プログラミングがなんぞや、の部分を分析しましたが、それで結局、関数型プログラミングで書くとなにが良くなるんでしょうか。「副作用のない関数」として問題を記述する、という特性についてだけ考えれば、メリットは以下のような点になりそうです。宣言的な記述のため、簡潔に書けることが多く関数の仕様を理解しやすい副作用がないため、形式的な証明がしやすい関数の評価結果がコンテキストに依存しないため、テストがしやすいコンテキストに影響を与えないため、関数を組み合わせて利用しても相互に影響しない関数が相互に影響しないため、並列・並行処理が書きやすい(?)並列・並行性に関しては、メリットとして取り沙汰されることが多いものの、関数型の利点かというと微妙なところがある気はします。この手の話題になると必ずErlangの話が出てきますが、それはErlang自体が並列処理を行うためのマイクロプロセスとメッセージパッシングの機構を持っているためであって、関数型の恩恵というのは語弊があるでしょう。Kayのいう意味での)オブジェクト指向の恩恵といえるかもしれません。Haskellでは並行・並列処理で一冊本が出るレベルなので、「関数型を採用すれば並列処理が簡単になる」というのはやや誇張表現と言わざるを得ないでしょう。Streamなど)の話も混じってきてしまうため、例えとしてあまり適切ではありませんでした。古典的な「複数のスレッドが共有リソースを書き換えながら動作するようなプログラミングスタイルと比べて」と解釈していただければと思います。関数型とセットで取り沙汰されることの多い高階関数のメリットは、「関数自体の表現力が上がる」の一点だと思います。いえ関数自体の表現力が上がるのは非常にわかりやすいメリットです。命令型のパラダイムと相反するわけではないため、高階関数の機能だけを独立して導入している言語も多く見られます。rubyのブロックを扱うメソッドやC#のLINQなどは実質的に高階関数になっています。(もっとも、オブジェクト指向でも処理のまとまりを渡すブロックという仕組みがSmalltalkにあるため、そちらから影響を受けている部分もあるでしょう)他に強力な静的型検査システム、型推論による型注釈の省略、などが挙げられることもありますが、この辺は関数型言語の中でも一部の言語(主にOCamlとHaskell)に特有のもので、関数型プログラミングのメリットかというと微妙な気がするため今回は外します。関数型プログラミングのデメリットデメリットは、一部のメリットの裏返しが多いです。宣言的な記述のため、知識がないと実際にどう動くのかを追いづらく、パフォーマンスチューニングが難しい状況に応じて別のことをさせる、という処理はやや書き難いコンパイルが重くなりがちIOなど、本質的に副作用のある処理の記述が難しいとはいえ、そもそも命令型がコンピュータがわかりやすいものであるのに対して、宣言型はより人間の考え方に近いもののはずなので、個人的には(少なくとも命令型と比べての)デメリットは少ないのではないかと思います。IOなどに関しては、無理に関数型プログラミングにこだわらず、そこだけ命令的に記述する、というのが最も簡単な解決策でしょう。個人的には、本質的なドメインロジックを副作用を排して書き、IOに関わる部分は多少の副作用を許容する、というのがバランスが良い気がします。関数型プログラミングと関係ないトピックメリットのところにも書きましたが、強力な静的型検査システム、型推論による型注釈の省略などは関数型プログラミング自体とは関連性が薄い気がします。そもそもErlang、Lispなどは動的型言語なので、「関数型プログラミングだから」という話ではなく、静的型付け言語だから、というべきでしょう。これは割と重要だと思うのですが、「どのような単位で処理を切り分けるのか」について、関数型プログラミングというパラダイムは特段示唆を与えていません。オブジェクト指向と関数型を比べて「関数型では処理を適切な単位に切り分ける基準がない」「設計論が確立されていない」みたいな論調を見たことがありますが、これについてはそもそも関数型プログラミングという枠で議論するべきではないでしょう。(オブジェクト指向設計レイヤーでの)クラスと同レイヤーで使われるだろう機能として、OCamlにはファンクターの機能が、Haskellには型クラスの機能があります。これらは言語特有の機能のため、個別に使われ方や設計論を分析したうえで比較する必要があるはずです。オブジェクト指向という言葉がモジュール分割的な使われ方も兼ねているため、この辺は大変分かりづらい状況になっています。(今回その辺も絡めて記事にしたかったのですが、時間的にも文字数的にもボリュームが多すぎるため断念しました...)まとめアドベントカレンダーなので日付が変わる頃には投稿したかったのですが、既に1時をがっつり回ってしまっています...というわけで、今回「関数型プログラミングとはなんぞや」というのを自分なりにまとめてみました。非常に長文になりましたが、これで少しでも関数型プログラミングに対する理解が広まればと思います。公開されたり共有されたりしません。最近の投稿APIがカオスってたプロダクトでOpenAPI対応やってみた技術書典7で、「ActiveRecord完全に理解した」という本を出します。Framework.。