Home

Shin x blog

AWS で請求金額にビックリしないようにやっておくべきこと

  • 2015-03-13 (金)
  • AWS
この記事の所要時間: 315

AWS は、従量課金なので、他者からの不正利用(本来無いことですが)や想定外の利用で、翌月の請求が来て、ビックリということがあります。

logo_aws

私自身も関わっているプロジェクトで、ある月に平時の数倍の請求が来て、原因調査を行ったという経験がありました。

転ばぬ先の杖ということで、先にやっておくべきことについてまとめておきます。

1. AWSアカウントの不正利用を防ぐ

まず、考えられるのが、アカウントを乗っ取られての不正利用です。もちろん、不正利用は、請求だけでなく、システムやリソースを守るという点でも防ぐべきことです。

そこで、AWS アカウントは、2要素認証(2段階認証 / 2 Factor authentication / 2FA)を設定しておきます。

手順は、下記のエントリがまとまっています。

AWSアカウント作ったらこれだけはやっとけ!IAMユーザーとAuthyを使ったMFAで2段階認証 – Qiita

私は、以前は、Google Authenticator を使っていたのですが、Authy に変えました。単純に見やすいですし、バックアップ機能もあり、スマートフォン買い替えなどで別デバイスへ移行する際も便利なので、おすすめです。

2. アクセスキーを適切に管理する

AWS アカウントの不正利用を防いだところで、アクセスキーの管理がずさんだと、結局は不正利用されてしまいます。

そこで、アクセスキーを適切に管理する方法を知っておきます。

これについては、AWS のドキュメントに、良い資料があるので、こちらを参考にすると良いでしょう。

AWS アクセスキーを管理するためのベストプラクティス – アマゾン ウェブ サービス

3. 請求金額を監視する

これで、不正利用は防げて安心、というなるところなのですが、正規な利用を行っていても、驚きの請求が来ることがあります。

私が、遭遇したケースは、まさにこれでした。

某Webサイトでの出来事だったのですが、アクセス数はそれほど変わらないのに、転送量が平時の月より大幅に増えて、それにより予想外の請求が来ていました。よくよく調べてみると、このサイトでは動画ファイルを公開していたのですが、動画ファイルの容量が大きく、これが原因で転送量が増加していました。確認してみると、動画ファイルを更新した時期と、請求額が大きく増えた月が一致していました。

このように、不正利用では無くとも、通常の運用でも、請求額が大きく増える可能性は十分にあります。

運用を気をつけるというのはもちろんなのですが、Billing Alerts で、請求額を監視しておくと安心です。

CloudWatch_Management_Console

アラートと通知で請求額を監視 – AWS 請求情報とコスト管理

Billing Alerts は、月ごとの請求額を監視して、設定した値を超えれば、アラートを送るというものです。

私の場合、下記の 2 パターンでアラートが来る用意設定しています。

  • $10 を超えたら、アラート通知
  • 平時請求額 * 3 を超えたら、アラート通知

前者は、ちゃんとアラートが飛んでくるか確認するためです。監視にありがちな「頼りがないのは良い知らせ」と思って、安心してたら、実はちゃんと監視できていない( or アラート設定が間違っていた)を防ぐためです。

後者が、想定外の請求を監視するもので、これが飛んできたら、請求内容を確認して、想定外のリソースが使われていないかを確認します。

さいごに

AWS は、従量課金でかつプログラマブルにリソースを操作できるので、想定外なリソース利用によって、請求額が増加する可能性があります。ただ、請求金額すら、リソースと同じように監視して、アラートが出せるというのが AWS らしくて良いですね。

突然の請求に驚かないように、今一度、確認しておきましょう。

  • コメント (Close): 0
  • トラックバック (Close): 0

「Azure Websites で作るスケーラブルな PHP アプリケーション」を GoAzure 2015 で発表してきました

この記事の所要時間: 430

Azure コミュニティの一大イベント GoAzure 2015 にて、「Azure Websites で作るスケーラブルな PHP アプリケーション」という発表を行ってきました。

Azure Websites

セッションでもお話したのですが、テーマは、もう一つあり、それは「LAMP(LAPP) ユーザが使う Azure Websites」でした。

Azure は、マイクロソフトのサービスなので、どうしても Windows に最適化されているイメージがあったのですが、普段 Mac で開発して、Linux にデプロイして、運用している人間でも、興味深いサービスであることを伝えようと考えました。

発表資料

発表資料は、こちらです。

発表冒頭で、Azure Websites を使っている方に挙手頂いたのですが、6-7 割の方から手が上がりました。Azure のイベントなので、当然といえば、そうなのですが、利用されているのが多いのだなと実感しました。

PHP で PaaS を使う

以前から、PHP を公式にサポートする PaaS はいくつかあったのですが、海外のサービスが多く、ドキュメントも英語版のみで、日本ではあまり使われていない印象でした。

PaaS の雄である Heroku が、2014 年に正式に PHP に対応したことで、今後、PHP でも PaaS を使うことが広がっていくでしょう。(Heroku も公式サイトは、英語ですが、日本語のブログ記事や書籍があります。)Heroku は、PaaS として非常によく出来ているのですが、残念ながら、日本国内にサーバがありません(2015/01/19現在)。

その点、Azure Websites は、日本国内(東日本と西日本)にサーバがあり、日本語のドキュメントもあるので、PHP で PaaS を使うなら、まずは試してみる価値はあります。

Azure Websites + PHP + New relic が利用できない

発表では、入れ忘れたのですが、困ったことを一つ。

Azure Websites は、Windows Server なので、Windows 版 PHP 用の DLL が無い拡張は利用することができません。主要な拡張は問題無いと思うのですが、私が触った範囲では、一つだけこの問題に当たりました。

それが、New Relic の PHP 拡張です。

Azure 自体は、New Relic と連携ができ、.NET 環境では利用できるようなのですが、New Relic の PHP 拡張は、Windows 版が無いため、利用することができませんでした。

New Relic for PHP の FAQ でも現在は対応されていないことが明示されています。New Relic は便利なので、ぜひ対応してもらいたいところです。

https://docs.newrelic.com/docs/agents/php-agent/getting-started/new-relic-php-faqs#windows

アーキテクチャを明示して欲しい

発表資料には入れていますが、一つの Websites 内にある各インスタンスでは、ストレージ(D ドライブ)が共有されているようです。

検証した結果では、おそらくそうであろうということは分かっていましたし、そうであるという情報も見聞きすることができました。

ただ、最後の裏取りとして、公式のドキュメントで、このことが明示されている箇所を探したのですが、残念ながら、見つけることができませんでした。

PaaS だから、裏側を知らなくても良いだろう、という考え方なのかもしれませんが、アプリケーションを作る上でも、構成を組むにしても重要な部分なので、はっきりと公式サイトで明示して欲しいと思いました。

実際、私自身も検証の段階で、このことを知らずに、想定したような結果が出ずに首を傾げるということを経験しました。

せっかく、共有ストレージのおかげで、スケールアウトが容易という特徴があるのですから、ちゃんと明示した方が双方にメリットがあるのではないでしょうか。

追記:2015/01/24
こちらの記事で共有ストレージであることが記載されているようです。https://msdn.microsoft.com/ja-jp/magazine/dn786914.aspx

さいごに

冒頭でも触れましたが、Azure は、以前は「Windows Azure」という名称だったため、どうしても「Windows ユーザのためのもの」という印象がありました。ただ、今回 Azure Websites を検証してみたところ、あくまでマイクロソフト社が運営しているというだけで、クラウドサービスの一つであるという認識に変わりました。

OSX や Linux 上でも動くコマンドラインツール(npm でインストール)があり、Azure Websites では、Git でデプロイができます。デプロイ時に任意のスクリプト(Bash)を実行することができるので、Composer やフレームワークでのマイグレーションなども自動化できます。

上手くやれば、わりと活用できるシーンはあると思うので、今後も使ってみたいと思います。

無料枠もあるので、まだの方は、ぜひ一度試してみてください。

  • コメント (Close): 0
  • トラックバック (Close): 0

2015年は「問題解決」

この記事の所要時間: 58

sheep

新年、あけましておめでとうございます。旧年中は、お世話になり、誠にありがとうございました。

2015 年に入って、最初のエントリということで、2014 年のふりかえりと 2015 年の抱負などを書いてみたいと思います。

2014 年ふりかえり

2014 年の抱負は、「ちゃんと稼いで、食べていく」でした。

社会人である以上、当たり前の目標なのですが、その当たり前を今一度、目標として、足場を固めていく一年になりました。おかげさまで、無事に、1 年を乗り切ることができました。ありがとうございます。

事業としては、「受託開発」「技術サポート」をメインに行いました。新規開発の案件では、Laravel と AngularJS を組み合わせて、サーバーサイドは API を提供して、UI 等は、クライアントサイドで開発するというスタイルで構築を行いました。今後もこうした形は、増えていくでしょう。

技術サポートについては、後述します。

また、ロクナナワークショップにて不定期ながら講師を務めることになり、2014 年中には、2 回講義を行いました。2015 年も開催予定なので、参加お待ちしています。

コミュニティ活動では、勉強会などのイベントへの参加と発表を行いました。1×1を会場とした勉強会が多かったので、それ以外では、発表のお誘いを受けて参加する機会が多かったです。発表資料などは、こちらで公開しています。

技術サポート

技術サポートというのは、開発プロジェクトにおける技術的な課題を一緒に解決する役割です。呼び名としては「技術コンサルティング」や「技術顧問」なども考えられますが、今のところ「技術サポート」という名前で呼んでいます。

2014 年は、この形で、いくつかのプロジェクトやチームに参加することが増えました。

これまでも、単発での依頼であったり、別のロール(開発やインフラ構築等)で参加しつつ、兼任でこの役割を担うことはあったのですが、継続的に参加するということが多くなりました。

以前から、こうした関わり方に興味があり、また、お役に立てる場面があるのではと感じていたので、2013 年の終わり頃には、直接会う機会があった方には、こういったことをやろうと思う、という話をしていました。そのおかげかどうかは分かりませんが、いくつか、技術サポートの依頼を頂くことができました。

お話した方からの依頼もあるのですが、言霊といいますか、直接この話を聞いてはいない方からも依頼があり、何事も表明するというのは大事だなと実感しているところです。

具体的にどのようなことを行っているかは、案件により様々ですが、下記のようなことを行っています。

  • リモートでの技術的質問の回答、調査(Redmine / Chatwork / Slack 等)
  • インフラ移行に関する移行計画のレビュー
  • 開発業務での困り事相談
  • 開発案件への Vagrant 導入サポート
  • AWS / Heroku などのクラウドサービス導入支援
  • コードレビュー(アプリケーションコード、プロビジョンコード)
  • サンプルコードの作成
  • パフォーマンスチューニング
  • 定例ミーティング参加
  • 訪問による技術相談会

基本は、リモートで、技術に関する質問を頂いて、その回答を行うというスタイルです。ただ、案件によっては、訪問して対面でお話を伺う場面もありますし、コードレビューやサンプルコードの作成、パフォーマンス改善など、アプリケーションコードを書く以外の周辺タスクをサポートするという場合もありました。

ご依頼頂いた内容を振り返ってみると、コードを書いたり、アプリケーションを構築することは自分たちで可能だが、新しくチャレンジする領域に関する知識やノウハウを知りたいという要望が多かったように思います。また、第三者の視点からのレビューが欲しいという要望もありました。

契約については、月額固定での契約で、お互いに齟齬があれば、都度ご相談というスタイルが多かったです。

2015 年は、この「技術サポート」をより進めていきたいと考えています。ご興味がある方は、下記のお問い合わせフォームなり、メッセージなりでご連絡くださいませ。

お問い合わせフォーム

2015 年は

2015 年は、まず事務所の移転を行います。(といっても同じビルで階が変わるだけですが)すでに移転先の契約も済ませており、2月早々には移転が完了する予定です。

事業の方は、「技術サポート」を中心に進めていき、さらに開発現場をサポートできるようなツールやサービスの構築なども行っていきたいと考えています。もちろん、従来の受託開発についても、引き続き行っていきます。

これまでは、アプリケーション開発やインフラ構築など、システムを作り上げて、何かの問題を解決してきました。この「技術サポート」も、目的は同じく「問題解決」なのですが、その手段が異なります。開発現場における技術的な問題を、システム構築ではなく、対話やアドバイスなどで解決するのが役割です。

技術情報は、書籍やインターネットを見れば、豊富にあります。しかし、そういった膨大な情報から、自分たちの問題を解決する手段を見つけ出し、その解決策を落としこむのは、意外に手間や時間がかかります(もちろん、問題自体の発見も必要です)。こうした問題を円滑に対処する方法としてお役に立てれば嬉しいです。

2015 年は、開発現場での問題解決屋となるべく、「問題解決」を抱負としたいと思います。

さいごに

実は、元旦から食中毒でダウンして、三ヶ日を布団の中で過ごすという散々なスタートになりました。。。昨年の後半から熱が出たり、蕁麻疹が出たりと不調が続いているので、体調管理が大事だと痛感しています。(この「問題」も解決しないと。)

年初から、GoAzure での発表準備や原稿執筆があり、また本業の方も立て込んでおり、さらに引っ越しの手配などもあるので、体調を整えて、アクセル全開でスタートします!

2014 年は、Shin x blog をご覧頂きありがとうございました。2015年も、よろしくお願いします!

  • コメント (Close): 0
  • トラックバック (Close): 0

2014 年に発表したセッションと資料まとめ

この記事の所要時間: 648

2014 年も残すは、あと 1 週間になりました。今年も様々なイベントで登壇しましたので、発表したセッションと資料をまとめてみます。

phpcon_kansai_2014
写真提供:久岡写真事務所

登壇イベント

2014/04/04 「わかってるフレームワーク Laravel」Laravel勉強会福岡

「わかってるフレームワーク Laravel」とうタイトルで発表しました。

Laravel で、とあるプロジェクトの開発が終わった後だったので、Laravel への良さを主観たっぷりでお話しました。

翌日の Laravel Meetup Tokyo と合わせて、一人 Laravel Japan ツアーでした:D

2014/04/05 「知っておくべき Auth オートログイン」 Laravel Meetup Tokyo vol.3

Laravel 4.1.25 以前にあった Auth フィルタ利用時のオートログインの問題点についてお話しました。

いくつかの前提条件は必要ですが、影響度が大きいので、「これはやばい」というのが伝わっていました。

なお、この問題は、4.1.26 にて修正されたので、現在は問題ありません。

Laravel ユーザなら知っておくべきAuthオートログインのこと

2014/04/12 「Vagrant ユーザのための Docker 入門」 第3回コンテナ型仮想化の情報交換会@大阪

Docker が盛り上がってきた時だったので、Vagrant ユーザを対象に Docker 入門をお話しました。

セッション途中でも活発に質問が飛び込んできたり、デモでコンテナ起動の速さに驚きの声があがったりで、盛り上がったのを覚えています。

「VagrantユーザのためのDocker入門」を発表してきました

2014/04/19 「最近なんだか、はてブがおかしい」俺聞け8 in Tokyo

資料未公開

当初は「Webエンジンアとしてご飯を食べていく」という内容を考えていたのですが、事前に、主催の @msng さんから「ブログに関する発表が多くて嬉しい」というコメントがあったので、ブロブに寄せようと内容を変えました:)

会場には、著名なブロガーの方が多く、みなさん同じようなことを感じているようで、発表後の情報交換が捗りました。

2014/04/24 「Vagrant 体験入門」DevLove関西

これから Vagrant を学ぶ方向けに、Vagrant 概要についての発表と体験ハンズオンを行いました。

Vagrant ハンズオンでは、みんなで同一拠点から一斉にプロビジョンを行うので、遅延やエラーが起こったり、環境の違い(Vagrant + VirtualBox が起動するまでの)でトラブルが発生したりで、毎回発見があります。

ハンズオンの資料は Qiita に公開しています。

Vagrant体験入門ハンズオン手順 – 2014/04/24 DevLove関西

Vagrant体験入門ハンズオンの資料を公開します

2014/06/19 「Heroku で作るスケーラブルな PHP アプリケーション」第16回関西PHP勉強会

Heroku で PHP が正式サポートされたので、スケーラブルな構成をどう組むかという内容でお話しました。

その後、いくつかのプロジェクトで Heroku + PHP を使っているのですが、やはり PaaS として良くできていますね。まだ掴みきれていない部分もあるので、引き続き追いかけていきます。

Heroku で作るスケーラブルな PHP アプリケーション

2014/06/28 「PHPコードではなく PHPコードの「書き方」を知る」PHPカンファレンス関西2014

PHPカンファレンス関西の初心者向けセッションということで、FizzBuzz を題材に、関数化、クラス化、そして自動テストを書くという流れをお話しました。

「PHPコードではなくPHPコードの「書き方」を知る」を発表してきました

2014/07/05 「開発現場で活用する Vagrant」夏の JAWS-UG 三都物語 2014

関西での JAWS-UG イベント、三都物語でのセッションでした。JAWS-UG では久しぶりの発表になりました。

Vagrant を実際に使う例として、デモで実演しながらセッションを進めました。

会場がフランクな雰囲気で、話しやすかったのが印象的でした。あと Yo を使って、バーチャル拍手というかうなずきを送ってもらったりもしましたね。

「開発現場で活用するVagrant」を発表しました

2014/08/23 「Vagrant 心得 5 ヶ条」DevLove 甲子園 2014 西日本大会

資料未公開

DevLove 甲子園にて、Vagrant についてお話しました。ここでは、Vagrant を活用する上で、気をつけておくと良いことを 5 つにまとめました。

内容は、いずれ blog に書きたいと思います。

2014/10/11 「Ansible ではじめるサーバ作業の自動化」PHPカンファレンス 2014

PHP カンファレンスで、Ansible についてお話しました。発表を聴いた方からは、好意的なフィードバックが多く、「Chef を使っていましたが、Ansible 使ってみます!」という意見もあり、良かったです。

準備している時は、話したいことをどう上手くおさめるかを苦心したので、普段スピーカーをしているコミュニティの仲間から「うまくまとまっていましたね」と言ってもらえ、やはり見ている人には分かるんだなあと感じたりもしました。

このセッションを見た方から、別のイベントでの登壇についてお誘いがあったり、次につながったセッションでもありました。

「Ansibleではじめるサーバ作業の自動化」を発表してきました

2014/12/19 「ビルドサーバで使う Docker」DevLove 関西

年内最後の発表は、やはり Docker でした。今年は、ほんと Docker が躍進した一年でしたね。

Jenkins サーバでの活用例から、導入のポイントや設定方法などをお話しました。

「Jenkinsサーバで使う Docker」を発表してきました

ロクナナワークショップ 「Laravel で学ぶモダン PHP 開発講座」

11 月から、ロクナナワークショップさんにて「Laravel で学ぶモダン PHP 開発講座」という講座を行っています。

みっちり 1 日で、Vagrant や Composer の使い方、Laravel を使った REST API の実装、そして、その自動テストを書くという内容です。

すでに 2 回開催しているのですが、参加された方は熱心に課題に取り組まれていて、講師としても勉強になることが多いです。まとまった時間でじっくり課題をこなしていくので、これから学んでいこうという方にはおすすめです。

次回は 2015/02/17 に開催予定ですので、もし興味がある方は、ご参加下さい。

新原雅司のLaravel で学ぶモダン PHP 開発講座

さいごに

今年を振り返ってみると、自分で名乗り出るよりも、お声がけ頂いて、登壇するという機会が増えました。お声がけ頂けるのは嬉しく、スケジュールやタイミングが許せば、できるだけお引き受けしたいです。

人前で話すというのは、準備も大変ですし、いつも緊張しますが、毎回色々な発見があり、また、終わった後は何ともいえない解放感というか充実感を感じることができます。聴いて頂いた方からのフィードバックも嬉しいものです。

今年も、セッションに参加して頂いた方、イベントにお声がけ頂いた方、本当にありがとうございました。

2015 年は、年始の 1/16 に GoAzure 2015 で登壇する予定です。Websites でスケーラブルな PHP アプリケーションを作るという内容ですので、ご参加お待ちしています!

  • コメント (Close): 0
  • トラックバック (Close): 0

「Jenkinsサーバで使う Docker」を発表してきました

この記事の所要時間: 142

すっかり年の瀬ですが、今年最後の発表を DevLove 関西にて行いました。

docker

Docker 実践編ということで、CI の一環でビルドサーバに使っている Docker についてお話してきました。

発表資料

Jenkins サーバに Docker を入れており、ビルドの環境として利用しています。構成や使い方は、わりとベーシックな内容です。

プロビジョンには Ansible を使っており、ローカルコネクションで ansible-playbook を実行しています。

使い捨てできる環境なら実用的

勉強会の最後に、発表者への QA の時間があったのですが、多数の質問があり、Docker に対する関心が高いのをあらためて実感しました。

今回、参加された方は、これから Docker を使ってみようという方が多いようで、導入に関することや、安定性などに対する質問が多かったです。(安定性に関しては、私のセッションでトラブルの話をしたせいもありますが。)

セッションでも触れましたが、現状は、開発環境やビルドやジョブワーカーのように、作って、使って、捨てるという環境では、Docker は実用的です。

一方、Web システムのように、常に動き続ける環境では、Docker デーモン自体の運用やイメージリポジトリなど、Docker コンテナをデプロイ、運用していく上で考慮すべきことがあり、まだ様子を見ているというのが率直なところです。

とはいえ、この時期だからこそ、果敢にチャレンジして、ノウハウを貯めるというのも一つの戦略で、トラブルシュート込みで実践してみるというのもアリです。(今回、自前でビルドサーバを構築したのは、こういった意味合いもありますし。)

個人的には、Docker コンテナが動く環境は AWS や GCE などのクラウドサービスに任せて、こちらでは Docker コンテナをビルドして、然るべきところへ送信すれば、後はよしなにやってくれるようになると嬉しいです。

  • コメント (Close): 0
  • トラックバック (Close): 0

Docker Hub 公式 PHP イメージで、複数バージョンの PHP コンテナを起動する

この記事の所要時間: 422

Docker Hub の 公式 PHP イメージで、PHP 5.4, 5.5, 5.6 のコンテナを起動します。

docker

PHP Advent Calendar 2014 の 12 日目です。昨日は、PHPで簡単に華麗にDIとAOPをキメる でした。

Docker Hub には、公式でミドルウェアや言語のイメージがで公開されています。PHP もその一つで、現在は、5.4, 5.5, 5.6 が公開されています。また、バージョン毎に複数のタグが存在し、cli / fpm / apache(mod_php) といた構成違いのものが存在します。

https://registry.hub.docker.com/_/php/

ここでは、5.x-apache タグのイメージを使って、複数バージョンのコンテナを起動して、ブラウザから、同一コンテンツを異なる PHP バージョンで確認できるようにします。

boot2docker のインストールと起動

Docker の実行環境として、boot2docker を使いました。

pkg ファイルが公開されているので、これをダウンロードして、インストールすると良いです。

http://docs.docker.com/installation/mac/

インストールできたら、boot2docker を起動しておきます。

$ boot2docker init
$ boot2docker up

boot2docker の VM が起動したら、IP アドレスを確認しておきます。

$ boot2docker ip

The VM's Host only interface IP address is: 192.168.59.xxx

公式 PHP イメージでコンテナを起動

Docker Hub 公式の PHP イメージを使って、5.4, 5.5, 5.6 の Docker コンテナを起動します。5.4-apache / 5.5-apache / 5.6-apache のイメージは、Apache + mod_php の構成になっており、手軽に Web アプリケーションを実行できます。

実行するコンテンツは、OSX 上にあるファイルを利用します。boot2docker では、1.3 から shared_folder で、OSX の /Users のディレクトリを、VM から /Users として参照することができます。これにより、VM の docker コンテナからシームレスに OSX のディレクトリをマウントすることができます。

コンテンツは、単純に PHP バージョンを出力するだけです。

$ cat /Users/path/to/index.php
<?php
echo 'PHP ' . phpversion();

バージョン毎にポートを分けて、以下のようにコンテナを実行します。初回は、各イメージをダウンロードするので時間がかかります。次回以降は、即座に起動します。

$ docker run -v /Users/path/to:/var/www/html -p 8084:80 -d php:5.4-apache
$ docker run -v /Users/path/to:/var/www/html -p 8085:80 -d php:5.5-apache
$ docker run -v /Users/path/to:/var/www/html -p 8086:80 -d php:5.6-apache

ブラウザから確認

では、ブラウザから起動した Docker コンテナにアクセスします。ポートを変えて、アクセスすると、それぞれの PHP バージョンが出力されます。

  • http://boot2docker-vm:8054/
PHP 5.4.35
  • http://boot2docker-vm:8055/
PHP 5.5.19
  • http://boot2docker-vm:8056/
PHP 5.6.3

さいごに

Docker Hub 公式の PHP イメージを使って、複数バージョンの PHP を起動しました。

このイメージは、使ってみると分かるのですが、拡張は必要最低限となっており(mbstring も pdo_mysql / pdo_pgsql もありません)、実際のアプリケーションを動かすには、拡張を追加して、ビルドする必要があります。

もちろん、こうした状況は考慮されており、イメージには docker-php-ext-install という拡張を追加するコマンドが用意されています。

実用する場合は、公式イメージをそのまま使うのではなく、これをベースに Dockerfile を書き、独自に拡張を追加したイメージを使うという方法になりますね。

明日の PHP Advent Calendar 2014は、ngyuki さんです。お楽しみに!

  • コメント (Close): 0
  • トラックバック (Close): 0

自分流 Laravel 4 アプリケーションアーキテクチャ

この記事の所要時間: 2130

Laravel Advent Calendar 2014 の 9 日目です。

laravel

今年の Advent Calendar では、Laravel 5 リリース目前ということで、Laravel 5 の話題が多いのですが、それは他の方にお任せして、ここでは、Laravel 4 でのアプリケーション実装について書いてみます。

Laravel は自由度の高いフレームワークですので、アプリケーションも自由な構成にすることができます。ただ、この「自由さ」が故に、どういう構成が良いのかというのが悩ましい点でもあります。

このエントリでは、私が実際に構築したプロダクトをベースに構成例をご紹介します。Laravel アプリケーションを構築する上での参考になれば嬉しいです。

1. ディレクトリ構成

まずは、大枠のディレクトリ構成から。アプリケーションや開発環境用の Vagrantfile やプロビジョンファイルなどは、Git リポジトリで管理しています。

ディレクトリ構成としては以下になります。

Dockerfile は、CI サーバで Docker を使って、自動テストを行っているので、そのためです。

Vagrantfile は、開発環境用の VM を管理するためのものです。アプリケーションディレクトリにルートに Vagrantfile を置いておくと、アプリケーション内のどのディレクトリからでも vagrant コマンドできるので便利です。

provision/ は、開発環境、上記 CI サーバでの実行環境、ステージング環境用のプロビジョンファイルが入っています。プロビジョンには、Ansible を使っています。本番環境は、構成管理はこちらでは行わないので、デプロイ用の playbook が格納されています。

src/ が、Laravel アプリケーションのコードが入っているディレクトリになります。以下では、この src/ について見ていきます。

.
├── Dockerfile
├── README.md
├── Vagrantfile
├── docker/
├── provision/
└── src/

1-1. src/ ディレクトリ

src/ の構成は以下です。

このアプリケーションは、Laravel で REST API を実装して、AngularJS で実装したクライアント側と連携して動作するアーキテクチャになっています。また、クライアント側のコンポーネントの管理に、bower を使っており、そのためのファイルやディレクトリがあります。

Laravel 自体は、ベーシックな構成ですが、アプリケーション独自のコンポーネントを格納するために、package というディレクトリを作っています。これについては、後述します。

.
├── CONTRIBUTING.md
├── Gruntfile.js
├── _ide_helper.php
├── app/
├── artisan
├── bootstrap/
├── bower.json
├── bower_components/
├── composer.json
├── composer.lock
├── karma.conf.js
├── package/
├── package.json
├── phpunit.xml
├── public/
├── readme.md
├── server.php
├── spec/
└── vendor/

2. Laravel アプリケーション の役割

Laravel アプリケーションでは、主に以下の役割を担っています。

  • HTML の生成、出力
  • JavaScript(AngularJS アプリケーション) / CSS などの生成、出力
  • REST API の提供(AngularJS アプリケーションと連携)

初期のビューは、Laravel で生成、出力して、あとは、AngularJS + REST API で連携して動作する SPA(Single Page Application) の形です。このアプリケーションでは、特定ユーザのみが利用するものなので、認証を行い、認可されたユーザのみがアプリケーションを利用できるように、ビューの出力も Laravel で行っています。

ほとんどの機能は、REST API にて提供されるので、以降はこの部分について書いていきます。

3. 処理フロー

REST API への HTTP リクエストは、概ね、以下のフローで処理されます。

laravel-4-application-flow

  • Routing – リクエストされた URI から、処理すべきハンドラを決定します。通常は、コントローラのメソッド、簡単な処理ならネイティヴクロージャに処理を委ねます。
  • Controller – 処理の起点となります。バリデーションを行い、正常値であれば、サービスクラスのメソッドに値を渡して、実行します。
  • Service – 実処理を行う部分です。ビジネスロジックを実行し、Model(Eloquent)を使って、データベースへの操作などを行います。
  • Model(Eloquent) – Eloquent を継承したクラスです。データベースへのアクセスを担うとともに、エンティティ固有の処理なども行います。

各フェーズ(レイヤ)では自身の責務に注力すればよく、上位のフェーズを関知する必要はありません。(必要な情報は受け渡されます。)

HTTP レスポンスボディは、JSON で返すので、blade などのビューテンプレートは、ここでは利用しません。

4. アプリケーションクラスの構成(namespace, autolaod)

ルーティング以外のクラスは、app/ 以下ではなく、package/以下に配置しています。また、namespace で、独立したパッケージとして分離しています。

アプリケーションをフレームワークの構成から独立したパッケージとすることで、フレームワークの一部としてアプリケーションを構成するのではなく、アプリケーションの一部としてフレームワークを利用することをイメージしています。

package/
└── Foo/
    ├── DomainA
    │   ├── Command/    <--- CLI Command
    │   ├── Controller/ <--- Controller
    │   ├── Model/      <--- Model(Eloquent)
    │   ├── Service/    <--- Serivice
    │   ├── Test/       <--- Test
    │   └── Validation/ <--- Validation
    ├── DomainB
    │   ├── Command/
    │   ├── Controller/
    │   ├── Model/
    │   ├── Service/
    │   ├── Test/
    │   └── Validation/
    OneByOne/
    └── Laravel
        ├── Controller/
        ├── Exception/
        ├── Service/
        └── Test/

namespace のトップレベルには、アプリケーション名(Foo)を、次に、ドメインパッケージ名(DomainA / DomainB)が続きます。アプリケーション内でも業務などのドメイン毎にパッケージを分けています。さらに、それぞれのドメインごとに、Controller や Model など役割に応じた namespace を割り当てています。

例えば、Foo システムの DomainA の Controller にある SampleController であれば、Foo\DomainA\Controller\SampleController となります。

ここでは、Foo システムの他に、汎用コンポーネントを集積した OnebyOne システムも同梱しています。

アプリケーションクラスは、composer.json にて、PSR-4 を使って、オートロードで読み込めるようにしています。Laravel におけるアプリケーションは、オートローダで読めれば、どこに配置しても良いので、こうした柔軟な構成が可能です。

  • composer.json
{
    "autoload": {
        "psr-4": {
            "Foo\\": "package/Foo"
            "OneByOne\\": "package/OneByOne"
        }
    },

}

5. Routing

ルーティングでは、URI と処理を行うコントローラのメソッドを Route::verbs() で連結するだけです。
一部、単純にデータベースから値を読み込んで、JSON として返す程度のものは、ネイティヴクロージャで実装しています。

認証が必要な API については、認証用のフィルタを実装しておいて、それを、Route::group() で指定します。Route::group() のネイティヴクロージャ内に認証が必要な API の定義を記載します。

Route::when() では、POST, PUT, DELETE リクエスト場合は、csrf フィルタを適用するようにしています。

Route::pattern() では、/foo/{id}{id}を受け入れるパターンを定義していまます。こうしておけば、各ルーティングで、正規表現を定義する必要がなく、便利です。

  • app/config/routes.php
<?php
use Foo\DomainA\HogeController;

$apiPrefix = '/api/v1';

// csrf filter
Route::when('*', 'csrf', ['POST', 'PUT', 'DELETE']);

// patterns
Route::pattern('id', '[0-9]+');

Route::group(
    ['before' => 'auth'],
    function () use ($apiPrefix) {
        $controller = HogeController::class;
        Route::get($apiPrefix . '/foo', $controller . '@read');
        Route::post($apiPrefix . '/foo', $controller . '@create');
        Route::put($apiPrefix . '/foo/{id}', $controller . '@update');
        Route::delete($apiPrefix . '/foo/{id}', $controller . '@delete');
    }
);

6. Controller

コントローラでは、入力値のバリデーション、サービスクラスの実行、そして、HTTP レスポンスを構築します。

下記は、典型的なコントローラの例です。

コントローラクラスでは、フレームワークの Contoller クラスを継承しています。あと、API 共通処理(JSON レスポンス等)を ApiControllerTrait というトレイトに実装しているので、これを use しています。

  • package/Foo/DomainA/Controller/SampleController.php
<?php
namespace Foo\DomainA\Controller;

use Foo\DomainA\Service\SampleService;
use Foo\DomainA\Validation\SampleValidatorBuilder;
use OneByOne\Laravel\Controller\ApiControllerTrait;

class SampleController extends Controller
{
    use ApiControllerTrait

    /**
     * @var SampleService
     */
    protected $service;

    /**
     * @param SampleService $serivice
     */
    public function __contruct(SampleService $service)
    {
        $this->service = $service;
    }

    public function create()
    {
        // validation
        $validator = (new SampleValidatorBuilder())->create(Input::all());
        if ($validator->fails()) {
            return $this->validationError($validator->messages());
        }

        $this->service->create(Input::all());

        return $this->created();
    }
}

下記が、ApiControllerTrait の一部です。ここでは、JSON レスポンスを返すメソッドをまとめています。

  • package/OneByOne/Laravel/Controller/ApiControllerTrait.php
<?php
namespace OneByOne\Laravel\Controller;

use Response;
use Symfony\Component\HttpFoundation\Response as Res;

trait ApiControllerTrait
{
    /**
     * ok
     *
     * @param mixed $message
     * @return Illuminate\Http\JsonResponse
     */
    public function ok($message = '')
    {
        return Response::json($message);
    }

    /**
     * validationError
     *
     * @param mixed $messages
     * @return Illuminate\Http\JsonResponse
     */
    public function validationError($messages = [])
    {
        return $this->badRequest('validation', $messages);
    }

    /**
     * BadRequest
     *
     * @param string $error
     * @param array $messages
     * @return Illuminate\Http\JsonResponse
     */
    public function badRequest($error = null, $messages = [])
    {
        $response = [
            'error' => $error,
            'messages' => $messages,
        ];
        return Response::json($response, Res::HTTP_BAD_REQUEST);
    }
(snip)
}

6-1. サービスクラスのインジェクト

SampleController に戻ります。コンストラクタでは、処理を担うサービスクラスを引数に取ります。コントローラは、フレームワークによって、インスタンス化されるので、Laravel の IoC コンテナにより、SampleService クラスのインスタンスが自動でインジェクトされます。

もちろん、テストなどの際は、自らインスタンス化して、モックオブジェクトを差し込むことも可能です。

6-2. バリデーション

ルーティングによりリクエスト URI に合致したメソッドが実行されます。

ここでは create メソッドが実行されるとします。コントローラのメソッドでは、まず、入力値のバリデーションを行います。

SampleValidatorBuilder クラスにて、バリデーションクラスのインスタンスを生成します。

SampleValidatorBuilder の実装例は下記です。バリデーションクラスの生成(ルールの設定)をクラス化しておくことで、コントローラからバリデーションルールの設定を逃がすことができ、同じルールを異なる箇所で共有できます。当然、テストからも、バリデーションクラスが生成できるので、バリデーションのテストが書くのが容易です。

このバリデーションビルダのインターフェースとテスト用のトレイとをまとめて、packagist に公開しています。

shin1x1/laravel-validator-builder

  • package/Foo/DomainA/Validation/SampleValidatorBuilder.php
<?php
namespace Foo\DomainA\Validation;

use Shin1x1\ValidatorBuilder\ValidatorBuilder;
use Validator;

/**
 * Class SampleValidatorBuilder
 * @package Foo\DomainA\Validation
 */
class SampleValidatorBuilder implements ValidatorBuilder
{
    /**
     * @param array $inputs
     * @return IlluminateValidationValidator
     */
    public function create(array $inputs)
    {
        return Validator::make(
            $inputs,
            [
                'name' => 'required',
                'email' => 'required|email',
            ]
        );
    }
}

6-3. サービスクラスの実行

入力値が妥当なものであれば、サービスクラスのメソッドを実行します。

サービスクラスのインスタンスは、コントローラのコンストラクタでセットされているので、これを利用します。

処理が正常であれば、created メソッド(ApiControllerTrait に実装)を呼び出して、201 Created を返します。

現在は、コンストラクタインジェクションでサービスクラスをインジェクトしているので、1コントローラ=1サービスの形が多いです。(App::make() などで、メソッド内で、サービスクラスのインスタンスを取得する場合もあります。)

6-4. Laravel 5 でのメソッドインジェクション

今後の話ですが、Laravel 5 では、コントローラのメソッドについても、IoC コンテナによる DI が可能になります。これにより、各アクションメソッド毎にサービスやバリデーションビルダがインジェクトできるので、より使いやすくなります。

7. Service

サービスクラスでは、ビジネスロジックなどのドメイン固有の処理を実行します。フレームワークのクラスは継承せず、単なる POPO として実装しています。

ユースケースに対応して実装することが多いので、名称から内容が想起できるもにしています。例えば、予約を扱うアプリケーションなら、ReservationService をクラス名とし、各メソッド名は、予約業務のユースケースである「予約する(book)」「予約を更新する(update)」「予約を取り消す(cancel)」としています。

下記では、Bar クラスのインスタンスを作って、入力値をデータベースに保存しています。

入力値のバリデーションは、コントローラで終わっているので、このクラスで処理する場合は、引数は正当な値であるとみなします。ただ、値の整合性(一意制約などのアプリケーション制約)など、事前条件のチェックはここで行います。もし事前条件に違反している場合は例外を投げて処理を中断します。

  • package/Foo/DomainA/Service/SampleService.php
<?php
namespace Foo\DomainA\Service;

use Foo\DomainA\Model\Bar;

class SampleService
{
    /**
     * @param array $inputs
     */
    public function create(array $inputs)
    {
        $bar = new Bar();
        $bar->name = array_get($inputs, 'name');       
        $bar->email = array_get($inputs, 'email');       
        $bar->save();
    }
}

8. Model(Eloquent)

モデルは、フレームワークの Eloquent クラスを継承しており(正確には、Eloqent を継承した AppModel クラスを継承)、通常の Laravel アプリケーションで利用するものと同じです。

エンティティ固有の処理などは、こちらに実装します。

  • package/Foo/DomainA/Model/Bar.php
<?php
namespace Foo\DomainA\Model;

use OneByOne\Laravel\Model;

class Bar extends AppModel
{
}

さいごに

Laravel 4 で構築したアプリケーションの構成について見てきました。

考え方の基本は、本文でも書いたとおり、アプリケーションが主で、フレームワークはそれを実現するためのものツールに過ぎないということです。そのため、アプリケーションはフレームワークとは、独立したパッケージとして構成しています。

この考え方をより進めるなら、package/ 以下のクラスについては、フレームワーククラスを利用する箇所はより抽象化していく(例えばリポジトリパターンを利用して、Eloquent と分離するなど)方法もあるのですが、抽象化を進めすぎて、かえって複雑になるのを避けるために、現在の状態に留めています。

構築するアプリケーションにもよるとは思いますが、これまでは、この形がしっくり来ています。(もちろん、今後変わる可能性もあります。)

こうしたアプリケーションを主体にした構成にしておけば、フレームワークのバージョンが変わっても、柔軟に対応できそうです。Laravel 5 では、アプリケーションディレクトリの構成が変わりますが、そもそも別構成にしているので、オートローダで読み込めれば問題ありません。

まだまだ改良していく余地はありますが、こうした柔軟な構成が取れるのも Laravel の面白さですね。

Laravel Advent Calendar 2014、明日は neronplex さんです。お楽しみに!

  • コメント (Close): 0
  • トラックバック (Close): 0

Composer を倍速にした、たった 1 行のコード

  • 2014-12-04 (木)
  • PHP
この記事の所要時間: 426

まだ 12 月早々ですが、PHP ユーザに素敵なクリスマスプレゼントが届きました。

Composer

いまや使うのが当たり前となった Composer ですが、複雑な依存解決に実行時間がかかるのがネックでした。

これは日本国内だけでなく、海外のユーザも同じで、皆がしょうがないと思いつつも、小さな不満を持ちながら使っていました。

そんな、ある日、わずか 1 行のコードが追加されたことで、実行時間が、わずか半分になるという現象が起こりました。

Composer を倍速にするには?

composer self-update を実行して、最新版にするだけです。

$ composer self-update

実際の効果

このコードの効果を見てみましょう。composer コマンドの --profile オプションを使って、実行時間と使用メモリ量を出力します。

$ composer update --dry-run --profile

まずは、比較のために、変更される前の composer で実行します。3 回続けて実行した結果が以下です。

# composer = 1.0.0-alpha8
Memory usage: 199.44MB (peak: 854.47MB), time: 397.92s
Memory usage: 199.44MB (peak: 854.68MB), time: 353.29s
Memory usage: 200.05MB (peak: 855.5MB), time: 338.84s

続いて、変更後の composer で実行します。

# composer = 1.0-dev (37ec0bde9dd6826591308e7a1ad55cb5e38ef117)
Memory usage: 122.17MB (peak: 209.3MB), time: 67.82s
Memory usage: 122.17MB (peak: 209.29MB), time: 16.34s
Memory usage: 122.17MB (peak: 209.3MB), time: 16.77s

なんと、メモリピークは 1/4 、そして実行時間は、6-20 倍ほど早くなっています!!

Github のコメントなどで見ると、効果のほどは、定義されている依存関係や環境によっても異なり、メモリ使用量の変化は小さい場合もあるようですが、実行時間に関しては概ね半分程度にはなるようです。

たった 1 行のコード

では、どんな魔法を使って、この改善を行ったのでしょうか。

その答えが、下記の commit です。

https://github.com/composer/composer/commit/ac676f47f7bbc619678a29deae097b6b0710b799

変更したコードは、わずか 1 行です。(実際には、空行の追加があるので、2 行)

public function run()
{
+    gc_disable();

これは、PHP 5.3 にて、循環参照によるメモリ・リークを解消するために導入されたガベージコレクションを無効にする関数です。デフォルトでは有効になっているのですが、今回は、これを無効にしたことで、パフォーマンスが大幅に改善されました。

このガベージコレクションについては、PHP マニュアルに記述があります。

http://php.net/manual/ja/features.gc.php

また、今回の事象を踏まえて、さらに詳細な内容がまとまっていますので、こちらもどうぞ。

ircmaxell’s blog: What About Garbage?

PHP ユーザの熱狂

この、あまりの効果に PHP ユーザが熱狂しました。Twitter でも多くのコメントがありますが、最も分かりやすいのが、Github です。

この修正を行った commit のページには、数多くの賞賛コメントが付いており、祭りの様相を呈しています:D

Gif アニメーションが多数貼られており、ブラウザで開き切るのも時間がかかる状況です。もはや、悪ノリ感もありますが、いかに多くの PHP ユーザがこの改善を喜んでいるかが分かりますね。

https://github.com/composer/composer/commit/ac676f47f7bbc619678a29deae097b6b0710b799

さいごに

わずか、1 行のコードで、問題が大幅に改善される。

特にパフォーマンスの問題に関しては、こうした体験をした人は多いのではないでしょうか。その 1 行が生まれるまでには、多くの時間が必要なのです。Github 上でもディスカッションが行われていました。

そして、結果として書いたコードは、たったの 1 行でした。

早くなった composer を動かしつつ、やはり大事なのはコードを書いた量ではなく、問題を解決することなんだな、としみじみ感じた出来事でした。

なお、速くなるのは、依存解決の部分なので、ダウンロードの時間は変わりません。あしからず。

  • コメント (Close): 0
  • トラックバック (Close): 0

CakePHP2 アプリケーションを Heroku で動かす設定

この記事の所要時間: 163

CakePHP2 アプリケーションを Heroku 上で動かす設定についてです。

cakephp_logo_250_trans

以前のエントリにも書きましたが、Heroku で Web アプリケーションを動かす際に重要なのは、Web サーバ自体(Heroku では、Dyno)に、アプリケーションの状態(データ、セッション情報、ログ等)を保持させないということです。

Heroku の Dyno は、デプロイの際や、定常的な再起動により、破棄されるため、記録されたファイルは消えてしまいます。よって、こうしたデータファイルは、アドオンなど外部に記録する必要があります。

Heroku では、アドオンを活用するのがポイントですので、ここでは、主に CakePHP アプリケーションからこうしたアドオンと連携する方法を見ていきます。

Environments Library as a plugin

まず、開発環境と Heroku 環境で設定値を切り替えるために Environments Library as a plugin を使います。

https://github.com/josegonzalez/cakephp-environments

これは、CAKE_ENV という環境変数の値で、環境に応じて、データベースやキャッシュなどの設定を切り替えるものです。昨今のフレームワークではお馴染みの機能ですね。

ここでは、下記の設定について切り替えを行います。

  • ログ
  • データベース
  • キャッシュ / セッション

このプラグインでは、まず Config/bootstrap/environments.php を作成します。このファイルで、環境毎の設定ファイルの読み込みを行います。下記では、Heroku 環境用の heroku.php と、開発環境用の development.php を読み込んでいます。

  • Config/bootstrap/environments.php
<?php
CakePlugin::load('Environments');
App::uses('Environment', 'Environments.Lib');

include dirname(__FILE__) . DS . 'environments' . DS . 'heroku.php';
include dirname(__FILE__) . DS . 'environments' . DS . 'development.php';

Environment::start();

次に、Heroku 環境用の Config/bootstrap/environments/heroku.php です。

環境の設定は、Environment::configure() で行います。第一引数に環境名(CAKE_ENVで指定するもの)、第二引数は適用条件(true なら、CAKE_ENV に合致しなければデフォルトとして適用)、第三引数に設定値の連想配列(Configure::write() する)、第四引数にコールバックを指定します。

第三引数で設定する方法もあるのですが、より柔軟な設定を行うために、ここでは、第四引数のコールバックを指定します。実際の設定は、以降で順に指定していきます。

  • Config/bootstrap/environments/heroku.php
<?php
Environment::configure('heroku', false, [
], function () {
    // Heroku 用設定
});

開発環境用の Config/bootstrap/environments/development です。コールバックで、デフォルトの設定を記述しています。

  • Config/bootstrap/environments/development.php
<?php
Environment::configure('development', true, [
], function () {
    // Log settings
    App::uses('CakeLog', 'Log');
    CakeLog::config('debug', array(
        'engine' => 'File',
        'types' => array('notice', 'info', 'debug'),
        'file' => 'debug',
    ));
    CakeLog::config('error', array(
        'engine' => 'File',
        'types' => array('warning', 'error', 'critical', 'alert', 'emergency'),
        'file' => 'error',
    ));

    // Database settings
    Configure::write('DATABASE_OPTIONS', [
        'datasource' => 'Database/Postgres',
        'persistent' => false,
        'host' => 'localhost',
        'login' => 'shin',
        'password' => '',
        'database' => 'app',
    ]);

    Configure::write('TEST_DATABASE_OPTIONS', [
        'datasource' => 'Database/Postgres',
        'persistent' => false,
        'host' => 'localhost',
        'login' => 'shin',
        'password' => '',
        'database' => 'app_test',
    ]);

    // Cache settings
    Cache::config('default', array('engine' => 'File'));
});

次に、database.php での接続情報を、環境ごとに設定できるように下記のようにします。各環境ファイルで Configure::write()
した値を、DATABASE_CONFIG クラスに設定します。

  • Config/database.php
class DATABASE_CONFIG {
    public $default = [];
    public $test = [];

    public function __construct() {
        $this->default = Configure::read('DATABASE_OPTIONS');
        $this->test = Configure::read('TEST_DATABASE_OPTIONS');
    }
}

このプラグインを有効にするために、bootstrap.phpを以下のように変更します。コメント部分は削除しています。

  • Config/bootstrap.php
<?php
require_once __DIR__ . '/../vendor/autoload.php';

include __DIR__ . '/bootstrap/environments.php';

Configure::write('Dispatcher.filters', array(
    'AssetDispatcher',
    'CacheDispatcher'
));

Heroku で環境変数 CAKE_ENV をセット

このアプリケーションが、Heroku にデプロイした際に、heroku.php を利用するように、環境変数CAKE_ENVherokuをセットします。これで、デプロイしたアプリケーションは、heroku 設定で動作するようになります。

$ heroku config:set CAKE_ENV=heroku

ログ

Heroku 環境でのログの設定です。ログは、ファイルではなく、標準出力もしくは標準エラー出力に出力します。

こうしておくと、heroku logs コマンドでログが確認できます。また、Papertail や FlyData のようにログを各サービスへ転送するアドオンを使うと、出力されたログを閲覧したり、S3 などに転送することができます。

ログは、まずは標準出力もしくは標準エラー出力にして、あとそれをどう活用するかは、アドオンに任せるという考え方です。

下記では、アプリケーションログを標準出力へ、エラー出力を標準エラー出力へ出力しています。

  • Config/bootstrap/environments/heroku.php
<?php
Environment::configure('heroku', false, [
], function () {
    // Log settings
    App::uses('CakeLog', 'Log');
    App::uses('ConsoleOutput', 'Console');
    CakeLog::config('debug', [
        'engine' => 'ConsoleLog',
        'stream' => new ConsoleOutput(),
    ]);
    CakeLog::config('error', [
        'engine' => 'ConsoleLog',
        'stream' => new ConsoleOutput('php://stderr'),
    ]);
});

あとは、アドオンと追加すれば、出力されたログがアドオンで利用できます。例えば、Papertrailを以下のコマンドで追加して、アプリケーションを動作させると、Papertrail の画面でログが確認できます。

$ heroku addons:add papertrail

データベース

Heroku のデータベースといえば、PostgreSQL なので、Heroku Postgres を使います。(もちろん、MySQL が良ければ、ClearDB なり、RDS なり使えます。)

$ heroku addons:add heroku-postgresql

Heroku 内では接続情報が環境変数で渡されるので、これをパースします。パースされた情報を、heroku.php で、Configure::write() で、セットしていきます。

  • Config/bootstrap/environments/heroku.php
<?php
Environment::configure('heroku', false, [
], function () {
    // Log settings
    (snip)

    // Database settings
    if (empty(getenv('DATABASE_URL'))) {
        throw new CakeException('no DATABASE_URL environment variable');
    }
    $url = parse_url(getenv('DATABASE_URL'));
    Configure::write('DATABASE_OPTIONS', [
        'datasource' => 'Database/Postgres',
        'persistent' => false,
        'host' => $url['host'],
        'login' => $url['user'],
        'password' => $url['pass'],
        'database' => substr($url['path'], 1),
    ]);
});

キャッシュ / セッション

キャッシュ / セッションのデータストアには、Redis を使います。

ここでは、Redis サービスのアドオンとして、Redis To Go を利用します。

$ heroku addons:add redistogo

データベースと同じく、接続情報が環境変数で渡されるので、それをパース(ホスト、ポート、パスワード)して、セットするだけです。セッションハンドラには、Cache を使いたいので、その指定も行います。

これで、キャッシュもセッションも、Redis To Go に保存されます。

  • Config/bootstrap/environments/heroku.php
<?php
Environment::configure('heroku', false, [
], function () {
    // Log settings
    (snip)

    // Database settings
    (snip)

    // Cache settings
    if (empty(getenv('REDISTOGO_URL'))) {
        throw new CakeException('no REDISTOGO_URL environment variable');
    }
    $url = parse_url(getenv('REDISTOGO_URL'));
    Cache::config('default', [
        'engine' => 'Redis',
        'server' => $url['host'],
        'port' => $url['port'],
        'compress' => false,
        'password' => $url['pass'],
        'serialize' => 'php'
    ]);

    // Session Settings
    Configure::write('Session', [
        'defaults' => 'cache',
    ]);
});

さいごに

ベーシックな部分だけですが、Heroku で CakePHP アプリケーションを動かす設定を見てきました。

ここで紹介した以外では、メールやデータファイル(画像等)など、他にもアプリケーションでは必要なものがありますが、ほとんどのものは、ここで見てきたようにアドオンを活用することで実現できます。

こうした構成にしておけば、Dyno が再起動したり、インスタンス数を増減しても、アプリケーションデータはアドオンに保持されているので、動作に支障はありません。こうしたスケーラブルナ構成にしておくのが、Heroku のような PaaS を活用する肝ですね。

このエントリは、CakePHP Advent Calendar 2014 の 3 日目でした。まだ少し空き枠があるので、CakePHP な何かを書いてみてはどうでしょうか。

  • コメント (Close): 0
  • トラックバック (Close): 0

Retina 5k iMac(Late 2014) が届いたので、環境構築メモ

  • 2014-11-28 (金)
  • mac
この記事の所要時間: 61

10 月末に発注した Retina 5k iMac(Late 2014)が、約一ヶ月待って、到着しました。

retina-5k-imac

早速、日頃の開発に使えるようにセットアップしましたので、そのメモです。

0. セットアップ

セットアップは、旧 iMac からの移行は行わず、クリーンインストールの状態から行っていきます。

1. OSX 環境設定

セキュリティとプライバシー

  • FileVault で暗号化
  • ファイアウォールを入にする

Dock

  • 画面上の位置を「左」に
  • 「Dock を自動的に隠す/表示」にチェック

Spotlight

  • 「21. Bing Web 検索」のチェックを外す

キーボード

「キーボード」タブ

  • 「キーのリピート」を右端(速い)に
  • 「リピート入力認識」までの時間を右端(短い)に
  • 「F1, F2 などのすべてのキーを標準のファンクションキーとして使用」にチェック

「修飾キー」をクリック

  • Caps Lock キーを「Control」に
  • Control キーを「Caps Lock」に

「ショートカットキー」タブ

  • 「フルキーボードアクセス」を「すべてのコントロール」に

「入力ソース」タブ

  • 日本語を追加
  • [日本語] 入力ソースは、ひらがなのみ
  • [日本語] 「Windows 風のキー操作」にチェック
  • [日本語] “/”キーで入力する文字を「/(スラッシュ)」に
  • [日本語] “¥”キーで入力する文字を「\(バックスラッシュ)」に
  • [日本語] 「数字を全角入力」のチェックを外す

トラックパッド

「ポイントとクリック」タブ

  • 「タップでクリック」にチェック
  • 「軌跡の速さ」を右端(速い)に

「その他のジェスチャ」タブ

  • 「アプリケーション Expose」にチェック

アクセシビリティ

「ズーム機能」

  • 「スクロールジェスチャと修飾キーを使ってズーム」にチェック。修飾キーは「Control」

「マウスとトラックパッド」

  • 「トラックパッドオプション」をクリック
  • [トラックパッドオプション] スクロールの速さを右端(速い)に

2. Homebrew インストール

アプリケーション類は、Homebrew / Homebrew cask で一気に入れたいので、まずは Homebrea 自体をインストールします。

$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

途中で、コマンドラインツールをインストールするかダイアログが出るので、インストールします。インストールが完了したら、brew コマンドが実行できるか確認しておきます。

$ brew -v
Homebrew 0.9.5

3. Homebrew / Homebrew cask でアプリケーションをインストール

Homebrew / Homebrew cask でアプリケーションを一括でインストールします。

以前は、brew bundle コマンドで、Brewfile に記述したアプリケーションを一括インストールする方法があったのですが、もうこのコマンドは存在しません。

ただ、Brewfile の各行の先頭に brew を追加すれば、単なるコマンドとして使えるので、シェルスクリプトにして、これを実行しました。(単に brew installbrew cask install を順に実行するだけ。)

今回利用したファイルは、以下のリポジトリに公開しています。

https://github.com/shin1x1/Brewfile

このリポジトリを展開して、Brewfile コマンドを実行します。

$ git clone https://github.com/shin1x1/Brewfile
$ cd Brewfile
$ ./Brewfile

あとは実行が終わるまで待つだけです。時折、インストールに root 権限が必要なパッケージがあるので、その際は順次パスワードを入力します。

4. Dropbox, Evernote の同期

Dropbox と Evernote を起動して、同期を行います。

とくに Dropbox の同期は時間がかかるので、早めに実行しておきます。

5. ライセンスの登録

有償ライセンスを購入しているアプリケーションがあるので、ライセンスキーを設定していきます。

  • PhpStorm
  • Dash
  • Bartender
  • iStat Menus

5. シェルの設定

設定ファイル類は、Dropbox にあるので、同期が完了したら、シンボリックリンクを張るスクリプトを実行します。

同期している設定ファイルは以下です。

  • .gitconfig
  • .gitignore_global
  • .vim
  • .vimrc
  • .zlogin
  • .zlogout
  • .zprezto
  • .zpreztorc
  • .zprofile
  • .zsh
  • .zshenv
  • .zshrc

また、「ユーザとグループ」を開いて、ログインユーザの「詳細オプション」(ユーザを右クリック)にある「ログインシェル」を /usr/local/bin/zsh (Homebrew でインストールした zsh)に変更します。   

6. アプリケーションの設定

アプリケーション群は必要に応じて設定していきます。

  • PhpStorm まずは、IdeaVim プラグイン。あとはその都度
  • iTerm フォントの変更と起動時ウィンドウサイズの変更
  • Chrome Google アカウントでログインすれば、同期されるので楽
  • Firefox 検索エンジンを DuckDuckGo に変更
  • Firefox about:config で、browser.newtab.urlabout:blank に変更

7. 秘密鍵の設定

あちらこちらに登録している公開鍵用の秘密鍵をインストールしておきます。もしくは新規の鍵ペアを作って、サーバやサービスに公開鍵を登録します。

さいごに

前回 も同じような作業を行いましたが、一番面倒なアプリケーション群のインストールが自動化できているので、楽ですね。

ソースコードは VCS リポジトリで管理して、開発環境は Vagrant、ドキュメント類もクラウド上や社内サーバにあるので、PC は、アプリケーションとその設定群があればセットアップは完了です。データ移行を考えなくてもいいので、良い時代になりましたね。

Retina iMac を1日触った感想としては、ブラウザやエディタなどのテキストがほんと綺麗です。あと、どのアプリケーションを使ってもキビキビ動いて快調です。(旧 iMac がじわじわと遅くなっていたので、余計にそう感じます。)ひとつ気になるのは、Mission Control や Expose でウィンドウを並べる時に、少しひっかかるというか、もっさりします。

レビューなどは、またしばらく使ってみた後に書いてみたいと思います。

  • コメント (Close): 0
  • トラックバック (Close): 0

Home

検索
フィード
メタ情報

Return to page top