特盛!heroku

41
2013/09/05 株式会社 FLECT 小西俊司

Upload: shunji-konishi

Post on 02-Nov-2014

27 views

Category:

Documents


7 download

DESCRIPTION

かなり重隅をつついた感じのHeroku技術資料。 2012年12月に書いた内容を全面的に改稿しました。

TRANSCRIPT

2013/09/05 株式会社 FLECT

小西俊司

Herokuで開発をする際に知っておいた方が良いことはだいたい書いたつもり ◦ 初版は2012年12月

◦ Herokuは機能アップデートが頻繁にあるし、自分の理解が進んだ部分もあるので全面改稿

◦ 古い情報を残してもしょうがないのでスライドは置き換え

基本Java(Play)での開発経験をベースに書いているが他の言語を使用する場合でもほとんど変わらない

Heroku内部のアーキテクチャについては半分想像だが中の人と話してもそんなに外してない

各種言語で構築したWebアプリケーションを実行するプラットフォーム

標準サポート言語 ◦ Ruby ◦ Node.js ◦ Clojure ◦ Python ◦ JVM(Java, Gradle, Grails, Scala, Play)

標準サポートではない言語もカスタムbuildpackを使用することで利用可能 ◦ PHPは標準サポートではないがFacebook連携のデフォルトとなっているため山ほど使われている

プラットフォーム全体がEC2上にある ◦ 現在はUS-EASTとEUリージョンがある ◦ Tokyoにはいつ来るんだー

Git ◦ ソースコードのやり取りはすべてgit経由

Dyno ◦ Herokuがユーザーアプリケーションを実行する環境のこと ◦ 役割によってWebDyno, WorkerDynoのように呼ばれることもある ◦ 課金の単位でもある

Slug ◦ Dynoに転送されるアプリケーションの塊(最大300MB) ◦ これが大きければ大きいほどDynoの起動に時間がかかる

Stack ◦ DynoのベースとなるOS環境 ◦ 過去にはStackの違いを意識する場面もあったが、Cedar(Ubuntu)がデフォルトになって以降、それ以外を使用することはまずない

Buildpack ◦ RubyやJavaなどの各種言語毎の実行環境を構築するモジュール

実際のところHeroku固有の用語や独自の技術はほとんどない。 トリッキーなことはせずに標準技術のみで実装されている。

http://www.heroku.com/ ◦ まずはアカウント作成

◦ 必要な情報はメールアドレスだけ

https://toolbelt.heroku.com/ ◦ herokuクライアントのインストール

◦ 現行のインストーラではgitも一緒にインストールしてくれるらしい。

◦ Gettinng Started(https://devcenter.heroku.com/articles/quickstart)

を見るとSSHの鍵の生成とherokuへのアップロードまで半自動でやってくれるっぽい

Playアプリケーションを新規作成してHeroku上で動作確認するまでの全コマンド

$ play new test $ cd test $ git init $ git add . $ git commit -m "Initial put" $ heroku create $ git push heroku master $ heroku open

たったこれだけでまたひとつインターネットにゴミが増える。。。(-- (実際のところHeroku上で動いているアプリの半分はこんなんだと思う)

あとはコードを書いてはgit pushの繰り返し

• Gitでソースコードを管理する上では「.gitignore」は常に作成した方が良いがここでは省略

• PlayのbuildpackではProcfileが存在しない場合は自動生成されるのでなくても良い

Buildpackはpushされたファイルの種別から選択される ◦ pom.xmlがあればJavaプロジェクトなど ◦ またはアプリ毎に明示的にGitHubにあるカスタムbuildpackを指定することもできる

SlugCompilerがpushされたソースをコンパイルしてSlugを作成 Slugサイズが大きいほどコピーは遅い

Http(s)リクエストはHerokuRouterが受けてDynoにhttpで転送 Dynoの数を増やすことで負荷分散が可能 Dynoが複数ある場合単純なラウンドロビンでリクエストは割り振られる

◦ セッションは考慮されないので単一マシンからのリクエストがばらばらのDynoに割り振られる

◦ Dyno間で情報を共有するためにはMemcache, RDB, Cookieなどを使用する必要がある

Dynoが30秒間レスポンスを返さない場合はHerokuRouterがClientに503を返す

Dyno起動時に実行するコマンドが定義されたファイル

web: play run --%web --http.port=$PORT $PLAY_OPTS hoge: play run --%hoge --http.port=$PORT $PLAY_OPTS fuga: play run --%fuga --http.port=$PORT $PLAY_OPTS

[名前]: に続けて実行コマンドを記述 上の例では引数だけ変えてすべてPlayを起動している $PORTはHttpRequestを受け付けるポートを定義した環境変数(web以外ではここにリクエストが来ることはない)

名前が「web」の定義だけは特別扱いされており、これだけがRouterからのhttpリクエスト転送を受ける(WebDyno)

それ以外の定義行はすべてWorkerDynoと呼ばれバックエンドでの処理を構築する際に使用する メールやキューをポーリングして処理を実行する、など

Procfileに設定した各行がそれぞれWebDyno、WorkerDynoとなり個別に起動する台数を指定できる ◦ 一般的にはWebDynoは負荷によって台数を増減させ、WorkerDynoは1台のみ起動させることが多い

◦ いずれのDynoもオートスケールはしない

WebDyno1台のみ、WorkerDynoなしという構成の場合料金は無料(厳密な説明は次ページ) ◦ ただし、WebDynoが1台だけの場合は1時間程度リクエストがない状態が続いた際にDynoがシャットダウンする(次のリクエストが来た時にDynoをまた起動するので初回リクエストのレスポンスが遅くなる) WebDynoが2台以上の場合はアイドル状態によるシャットダウンはない WorkerDynoは1台でもアイドル状態によるシャットダウンはない

WebDynoとWorkerDynoはコードベースとしては同じもので、ただWebDynoはHerokuRouterからのHttpRequestの転送を受けるという点だけが異なる。

デフォルトでDynoでの使用可能メモリは512MB ◦ Javaアプリを動かすことを考えるとかなり少ない

WebコンソールでDyno種別ごとにメモリを512MBで使用するか倍の1GBで使用するかを選択できる

今のところ1GB以上のメモリを使用することはできない

ちなみにメモリを倍にすると価格も倍

Dynoが起動している時間をDyno時間と呼ぶ ◦ 1Dyno時間は1台のDynoが1時間起動していたことを表す

1Dyno時間の料金=0.05$

ただし750Dyno時間までは無料 ◦ つまりWebDyno1台をまる一ヶ月動かしたとしても

1 × 24 × 31 = 744Dyno時間にしかならないため料金はかからない

WebDynoがアイドル状態であったとしてもDyno時間を消費する

スケジューラやheroku runコマンドの実行もDyno時間を消費する

2XDynoは1時間の起動で2Dyno時間を消費すると考える

これ以外にアドオンの料金がかかる

heroku domainsコマンドで使用するドメイン名を追加

DNSをCNAMEで「xxx.herokuapp.com」を指すように設定すればOK

ただしSSLを使用する場合はホスト名が変わるので要注意

$ heroku domains:add www.xxx.com

SSLのアドオンを追加(20$/month) heroku certsコマンドで証明書と秘密鍵を追加 ◦ 中間証明書がある場合は証明書に追加しておく

証明書がインストールされると新しいホスト名「xxx.herokussl.com」が生成されるのでDNSでそのホストを設定 ◦ ちなみにxxx.herokussl.comの実体はELB ◦ なのでSSLではhttpの転送が1段増えていると思う

herokuapp.comには「*.herokuapp.com」の証明書が入っているのでSSLアドオンを使用しなくてもSSL通信自体は可能

$ heroku addons:add ssl:endpoint $ heroku certs:add <PEM> <KEY>

例えば開発環境をコピーしてステージング環境を作成したい場合は開発環境のディレクトリで。。。

heroku createで新しいアプリを作成

作成後にgitのURIが表示されるので適当な名前でgit remoteに登録

その名前でgit push

$ heroku create staging-xxxx $ git remote add staging [email protected]:staging-xxxx.git $ git push staging master

heroku createコマンドはそこにあるリポジトリに「heroku」というremote名が登録されていない場合は自動的に登録する。 そのため、最初にアプリを作成した直後はgit remote addを実行する必要はない

heroku forkというアプリをコピーするコマンドもあるが 課金アドオンが元と同じプランで作成されるためあまり使わない

herokuコマンドはgit remoteに登録されたエイリアスからアプリを判断する ◦ 「[email protected]」で始まるリモートリポジトリの「:」以降が

Herokuアプリケーション名

◦ Herokuのリモートリポジトリが一つだけの場合はherokuコマンド実行時にアプリケーション名を省略可

◦ 複数ある場合はコマンド実行時に「-a <アプリケーション名>」を明示的に指定する必要がある

$ git remote –v heroku [email protected]:prod-myapp.git (fetch) heroku [email protected]:prod-myapp.git (push) stg [email protected]:staging-myapp.git (fetch) stg [email protected]:staging-myapp.git (push) $ heroku logs –a staging-myapp

環境によってアプリの動作を変えたい場合には環境変数を利用する

環境変数を変更した場合WebDyno、WorkerDynoともにすべて再起動する

heroku config heroku config:add hoge=fuga aaa=bbb

HerokuのGit上にmaster以外のブランチを作成しても無視される ◦ masterへのpushをフックしてビルドプロセスが実行される

◦ ブランチ自体は普通に使えるがブランチのソースでSlugコンパイルを行うことはできない

チーム開発を行う場合、GitHub等の外部リポジトリはほぼ必須 ◦ Herokuのgitはアプリのリリース専用と割り切るべき。

◦ 開発環境では検証のために「push -f」で強制上書きが必要になることもあるかもしれない

あんまり気が進まないので実際にはやったことはないがアリだとは思っている

Slugサイズが大きいとDynoへのデータ転送が遅くなり結果として起動に時間がかかることになる ◦ JavaアプリはJDKがSlugサイズに含まれるためサイズ的には不利

◦ Play2などは最初から100MB超

サイズの大きなファイルはgit pushしない ◦ PDFや大量の画像ファイルなどはS3などの外部ストレージに置く

「.slugignore」ファイルを使用する ◦ ここで指定したファイルはslugに含まれない

◦ 書式は「.gitignore」とほぼ同じ(「!」など一部書式未サポート)

◦ テストでしか使用しないクラスなどSlugに必要ない物はできるだけ指定した方が良い。

Dynoは以下のタイミングで再起動する ◦ Git push

◦ heroku configの変更 ◦ おおむね1日1度の頻度で自動的に再起動

ここで再起動と言っているのは実際にはインスタンスが切り替わる ◦ Herokuはマルチテナントなので一つのEC2インスタンス上に複数のDynoが同居

◦ このためHerokuのIPはころころ変わる

WebDynoはともかくWorkerDynoが毎日再起動するのは とても困る(--

最初にルーティングを止めて、 全てのDynoをシャットダウン

◦ シャットダウンの前に実行中のリクエストのレスポンスを待っている?

その後再起動 ◦ つまりコードや環境変数の異なるDynoが同時に起動しているという状態はない

その後ルーティングを再開 ◦ その間のリクエストはRouterのキューに入ると思われる 再起動中にブラウザでF5を連打した場合レスポンスは遅いがエラーとはならない もちろんリクエストが多くてキューがあふれた場合はエラーになると思われる

Preboot(現在ベータ 扱い)を使用すると DownTimeも短くなる

Down Time

WorkerDynoは外部から現在仕事中かどうかを知るすべがない ◦ 例えば5分おきにメールポーリングしているDynoのステータスは外からはわからない

◦ これに対してWebDynoはRouterから回されている仕事がなければアイドル中と判断できる。(もちろん作りによるけど)

にも関わらず1日に1度容赦なく再起動がかかる Herokuのドキュメントには「SIGTERMを受け取ったら

10秒以内に安全にシャットダウンしろ」とか書かれているが、現実には実行中のタスクのどのタイミングで再起動が来るかわからないので対応不能。。。。(--

HerokuAPIとは ◦ herokuコマンド相当のことをプログラムから実行するための

WebAPI

24時間未満で自動再起動がかかることはない(多分)のでその前でWorkerプロセスの中から自力で再起動してしまう

HerokuAPI api = new HerokuAPI(“xxxx”);//引数のAPIKeyはWebConsoleで取得 api.restartProcessByType(“yyyy”,”worker”);//heroku ps:restart worker

api.scaleProcess(“yyyy”, “worker”, 0);//heroku ps:scale worker=0

Workerが常時動いている必要がない場合はscaleProcessメソッドでWorkerを停止するのもアリ ◦ この場合どうやってWorkerを起動するかは別途検討が必要

https://devcenter.heroku.com/articles/labs-preboot

Heroku labsは正規リリース前の機能を実験的にユーザーに使用できるようにしたもの

Prebootを使用すると再起動時の動作が 新Dyno起動 > ルーティングスイッチ > 旧Dyno停止 の順になり、ダウンタイムを短縮できる ◦ WebDynoにのみ適用 ◦ WebDynoが2台以上起動している場合のみ適用

Prebootを使用するとSlugサイズやアプリの起動時の重たい処理のダウンタイムへの影響もなくなる

Dynoの再起動問題/Prebootについて別スライドあり http://www.slideshare.net/shunjikonishi/heroku-dyno

指定時間間隔でコマンドを実行するアドオン ◦ 間隔としては24時間毎、1時間毎、10分毎が選択できる

実行時にはWebDynoでもWorkerDynoでもない新しいDynoが作成され、そこでコマンドが実行される ◦ つまり自分で作ったアプリが実行できる

スケジューラでのコマンド実行はDyno時間を消費する

標準ではスケジューラでherokuコマンドは実行できない ◦ 後述のheroku-buildpack-toolbeltをいれることで実行可能になる

Dyno上で任意のコマンドを実行するHerokuコマンド ◦ viがないなどコマンドはかなり制限されている ◦ アプリのルートに「.profile」を作成しておくと起動時にそれが実行される(WebDynoやWorkerDynoでも実行される)

heroku runコマンドでも新しいDynoが作成される ◦ 既存のWebDynoやWorkerDynoに接続できるわけではない ◦ もちろんDyno時間を消費する

「heroku run bash」とたたくと。。。 ◦ telnet的な操作が可能

◦ スケジューラでどういうコマンドが実行できるかを確認するのに便利

◦ つなぎっぱなしで放置してはいけない(Dyno時間を消費する)

Herokuはgit pushや環境変数の変更毎にそのリビジョンを保存している

$ heroku releases v35 Add hoge config [email protected] 2013/09/03 13:28:53 v34 Deploy 8740ef9 [email protected] 2013/08/29 12:27:29 v33 Deploy 2469798 [email protected] 2013/08/23 20:25:13

「heroku releases:rollback <リビジョン番号>」を叩くことで、任意のバージョンにロールバックすることが可能 ロールバックはS3に保存されている各リビジョンのコンパイル済みSlugと差し替えることで実現

ロールバック後に再度git pushするとpushされた再度最新のソースからSlugが作成される。(git内でrevert等のロールバック操作は一切行われてない)

2013年9月現在、US-EASTとEUの2つのリージョンが利用可能

リージョンはアプリ作成時に指定する(デフォルトはUS-EAST) ◦ コードベースが同じでもリージョンが違えば別アプリになる。

データベースやMemcacheなどのAddonは自動的にHerokuアプリ本体のリージョンと同じになる ◦ ただし、EUリージョンに対応していないAddonもあるらしい

◦ DBを統一したいなどの理由でEUからUS-EASTのAddonを利用することはできるがネットワークレイテンシ―が問題となる

Tokyoにはいつ来るんだー

クラウド上にあるというだけでごく普通のPostgreSQL

制限事項 ◦ パラメータを変更できない

◦ Userを作れない

◦ 接続を制限できない(URLを知っていればどこからでもアクセス可能)

複数のHerokuアプリから同じDBを使用しても良い ◦ この場合heroku configのDATABSE_URLをコピーする

◦ Heroku以外からも使用できるがUS-EASTなので日本からの接続は遅い

価格毎に土台となるEC2のインスタンスが異なる ◦ メモリ(キャッシュサイズ)の差異よりもCPUパワーの差が大きい

pgbackups ◦ アドオンの一つ ◦ 毎日自動でバックアップを取ってくれる ◦ 無料なので必ず使うべき ◦ ただしバックアップを取る時間帯は指定できない(アクセスの少ない夜間に、という設定はできない)

◦ heroku pgbackupsコマンドで手動でのバックアップ/リストア/ダウンロードが可能

Fork ◦ 既存のDBをコピーして新しいDBを作成

Follow ◦ 既存のDBのレプリケーションDBを作成 ◦ 本番DBの障害時に切り替えて使用することが可能(手動)

https://dataclips.heroku.com/ SELECT文を登録しておいてその結果をいつでも参照できる ◦ ExcelやCSV形式でダウンロード ◦ GoogleDocsへのExport GoogleSpreadsheetのURLが生成されてそこにアクセスするといつでも最新のデータを参照できる

グラフもそこで作れたりする

色々と惜しい ◦ セキュリティのデフォルト設定が「URLを知っている人は誰でも使える」のは危険

◦ パラメータが使えない ◦ 登録したSELECT文を整理できない

不便なので代替ツールを自分で作ってみた https://github.com/shunjikonishi/sqltool http://www.slideshare.net/shunjikonishi/furoku-sqltool

Localeが「en_US.UTF-8」固定 ◦ このためCREATE TABLE時に「COLLATE “C”」を設定しないと日本語列のソートがおかしくなる

◦ 何故か日本語Localeは指定できない

実行に2秒以上かかる遅いSQLはデータ込みでログ出力される ◦ データがログに残ることが一切NGな場合は注意が必要。

◦ 原則はそんな遅いSQLは実行しないこと(だがデータ量や負荷によってはいかんともしがたい場合もあるので。。。(--)

◦ 別アプリでDBを作ってDATABASE_URLをコピーする運用にしたこともある。(Papertrailにログを流さないようにするため)

Herokuのログはデフォルトで1500行しか保存されないのでなんらかのログAddonは必須

ログAddonは複数あるがこれが一番使いやすかった ◦ 1年位前の評価だが他のに変える動機が無い

機能 ◦ ブラウザ上でのログ表示 ◦ DailyでのS3へのログアーカイブ ◦ 監視文字列を設定してメール通知

料金体系 ◦ 1日当たりのログ出力量によって課金 ◦ 10MB/日まで無料、有償版は50MB/日で月間$7から ◦ Limitに到達するとそれ以降のログは無視される

パフォーマンス監視

Herokuで一番使われているAddonらしい ◦ 1年半くらい前の情報

有償版は高いので使ったことが無い ◦ Dyno数に応じた従量課金

◦ しかし無償版でも十分高機能

Memcacheサーバー

WebDynoを複数使用する場合はほぼ必須

料金体系 ◦ キャッシュサイズによって課金

◦ 25MBまで – 無料

◦ 100MBまで - $15

◦ …

◦ 10GBまで - $550

Papertrail, NewRelic, Memcachierの3つは はほとんど毎回利用する鉄板Addon

メール送信Addon

機能 ◦ SMTP/WebAPIでのメール送信 ◦ Webコンソールでの送信/不達メール確認 ◦ メール中のURLのクリック数カウント メール中のURLをSendGridが自動的にリダイレクトURLに書き換えて、そのリクエスト数を数える

◦ メールの開封確認 HTMLメールのみ(メール中に非表示の画像URLを埋め込むことでその画像URLのリクエスト数を数える)

価格体系 ◦ 200通/日まで無料 ◦ 有償版は40000通/月で9.95$から

https://github.com/gregburek/heroku-buildpack-toolbelt

Dyno上からherokuコマンドを実行するためのbuildpack

heroku-buildpack-multiと組み合わせて使用する

これを利用することでスケジューラからherokuコマンドを発行できるようになるので便利 アクセスの少ない夜間にheroku ps:scaleでDyno数を減らしたりとか

各アプリに個別にこのbuildpackを組み込む必要はなく、管理用のアプリを一つ建てておくと良い。

HerokuAPI ◦ herokuコマンドが裏で実行しているREST API

◦ Heroku APIのJavaラッパー https://github.com/heroku/heroku.jar

認証にはHEROKU_API_KEYを使用

PlatformAPI ◦ Oauth経由でHerokuを操作するREST API

◦ 現在ベータ版のため、APIの変更はあと数ヶ月はかなりある見込み

◦ APIのJavaラッパーは今のところない

Heroku社内で優先して作っているのはRubyとNode.jsらしい

Herokuアプリの作成はコマンドでしかできないので、課金アカウントが個人アカウントと別な場合ちょっと面倒 ◦ いつのまにかWebコンソールからアプリ作成ができるようになっていたのでほとんどアカウントを切り替える機会はなくなった。

https://github.com/ddollar/heroku-accounts ◦ 複数のHerokuアカウントを切り替えるプラグイン

またはこれだけでもOK $ set HEROKU_API_KEY=xxxxx

この場合SSHのkeyは入れ替わらないのでgitへのアクセスはできないがそれ以外のherokuコマンドは普通に使える

gitも切り替える場合は「.ssh/config」で鍵の切り替えを設定する

Tokyoにはいつ来るんだー