-
Notifications
You must be signed in to change notification settings - Fork 9
How heroku works
これはHerokuの仕組みに関する高度で、技術的な説明です。Herokuプラットフォームでアプリを書いたり、構成したり、デプロイしたり、そして実行したりする際に遭遇するであろう多くの概念をまとめています。
callout Getting Startedのチュートリアルの中に出てくる説明は、 このドキュメントにかかれている概念をより具体化したものになっています。
このドキュメントは続けて呼んでください。: 論理的に話を伝えるために、プラットフォームについての概念を徐々に明らかにするように書いています。
最後のセクションでは、Herokuのデプロイまでと実行中という形で、全ての定義を一緒にまとめています。
HerokuではRuby, Node.js, Java, Python, Clojure, Scalaでかかれたアプリケーションをデプロイと実行、そして管理することができます。
アプリケーションとは、これらの言語のうちのどれかでかかれたソースコードの集まり、おそらくフレームワーク、またアプリケーションを構築したり実行するために必要な依存ファイル群に関するビルドシステムの指示につかういくつかの依存ファイルに関する記述からなっています。
note 用語 (仮): アプリケーションとは、ソースコードと依存ファイルに関する記述から成っています。
依存ファイルの仕組みは言語によって変わってきます。: RubyではGemfile
, Javaではpom.xml
, Pythonではrequirements.txt
... と言った感じです。
依存ファイルと一緒になったあなたのアプリケーションのソースコードは、Herokuのプラットフォームがあなたのアプリケーションを実行したり、実行できるようにするためのものを生成するために必要十分な情報を提供しなければなりません。
Herokuで実行するために、アプリケーションを大きく変更する必要はありません。一つだけ、プラットフォームにあなたプラットフォームのどの部分が実行するのに必要かを通知する事が必要です。
もし何らかの確立されたフレームワークを使っていた場合は、Herokuはそれも検知することができます。例えば、Ruby on Railsの場合は普通rails server
、Djangoの場合はpython <app>/manage.py runserver
、Node.jsの場合はpackage.json
、などです。
note 用語: Procfiles はプロセスタイプ(実行したいと思われるコマンド)の一覧です。
他のアプリケーションに関しては、なにが実行に必要なのかを明示的に宣言する必要があるでしょう。ソースコードと一緒に、これをテキストファイルの中で行います。これがProcfileです。それぞれの行にプロセスタイプ(作ったアプリケーションに対して実行したいコマンド)を宣言します。例えば、Procfileはこのような見た目になります :
web: java -jar lib/foobar.jar $PORT
queuty: java -jar lib/queue-processor.jar
このファイルはweb
プロセスタイプと、実行するために叩く必要のあるコマンド(この場合は、java -jar lib/foobar.jar $PORT
)を宣言しています。また同様にqueuty
プロセスタイプと、これに一致するコマンドを宣言しています。
始めのアプリケーションの定義にこのProcfileを追加して、改めたいと思います。
note 用語: アプリケーションとは、ソースコードと依存ファイルに関する記述、そしてProcfileから成っています。
Herokuは依存ファイルとProcfileを使って、あらゆる言語で使えるプラットフォームを実現しています。全ての言語を通して、似たような決まりやマナーでアプリケーションを構築、実行、拡張することを可能としています。Procfileはあなたの構造的な側面を露にします。(上記の例では、アプリケーションに2つのエントリーポイントがあります)。そしてこの構造は、例えば独立して各部分の拡張を行うこともできます。Herokuで実行するアプリケーション向けに、良く動くための構造に関する原理の素晴らしいガイドがThe Twelve-Factor Appにあります。
Gitは、多くの開発者がソースコードのバージョン付けや管理をするために使っている、強力な分散バージョンコントロールシステムです。Herokuではアプリケーションのデプロイのための主な手段としてGitを使っています。
Herokuでアプリケーションを作るとき、あなたのアプリケーション用のローカルのgitリポジトリと一緒に、新しいgitリモートが付いてきます。これは通常heroku
という名前になっています。
結果として、デプロイのためのコードはgit push
にとても似ており、heroku
リモートに差し替えるだけです :
$ git push heroku master
note 用語: アプリケーションのデプロイとは、gitを使ってHerokuへアプリケーションを送る事で行います。
デプロイはこの時、ローカルからHerokuへアプリケーションを移すためにgitを転送の仕組みとして利用します。
Herokuがgitのプッシュを受信した時、アプリケーションのビルドを初期化します。ビルドのメカニズムは一般的に言語によって具体的なところは異なりますが、同じパターンをなぞっており、典型的には特定の依存ファイルを回収し、必要なアセットを作ります。(スタイルシートの処理の様に簡単か、もしくはコードのコンパイルの様に複雑かどちらかです)
callout 一歩踏み込んで: BuildpacksはSlugの統合処理の後ろに存在します。オープンソースなので、Herokuが他の言語やフレームワークを扱えるように拡張することも可能です。Buildpacksはアプリケーションとその依存ファイル郡、そして言語の実行系を取得して、Slugを生成します。
例えば、ビルドシステムがRailsのアプリケーションを受信した場合、Gemfileの中に指定されている依存ファイルの全てを取得し、同様にアセットパイプラインに基づいてファイルを生成するでしょう。Javaのアプリケーションならば、Mavenを使っているバイナリベースのライブラリファイルを集め、それらのライブラリと共にソースコードをコンパイルし、そして実行用のJARファイルを生成します。
生成されたアセットやコンパイルされたコードのような収集されたビルド段階の生成物と依存ファイル、また同様に言語とフレームワークと一緒になっているアプリケーションのソースコードは、Slugとして組み立てられます。
note 用語: Slug はあなたのソース、収集された依存ファイル、言語の実行系、生成/コンパイルされたビルドシステムの出力のまとまりです。 - 実行ができる準備ができている状態です。
これらのSlugはアプリケーションの実行中に起こる事の基本的な様相を示しています。これらはコンパイルされ、組み立てられたアプリケーションを含み、実行したい指示(Procfileのこと)と共に実行する準備が出来ています。
Herokuは用意されたSlug(実際はRelease; Slugとまだ定義してない設定用変数やアドオンと併せたもの)と共にあらかじめ読み込まれているDynoの上で、あなたがProcfileに指定したコマンドを叩く事でアプリケーションを実行します。
Dynoでの実行は、あなたのアプリケーションのSlugをファイルシステムに含んでいる、軽量で安全で仮想化されたUnixのコンテナだと考えてください。
note 用語: Dynoは独立した、仮想化されたUnixのコンテナで、アプリケーションが実行されるのに必要な環境を提供します。
通常、初めてのアプリケーションをデプロイする場合、Herokuは自動で1個のWeb Dynoを使用します。言い換えると、Dynoを起動し、Slugを読み込んで、そしてProcfileの中のwebプロセスタイプとして指定されたコマンドを実行します。
どんなときでも、いくつのDynoを実行するかをコントロールすることができます。先のProcfileの例を前提に考えると、3個をWebプロセスタイプ、2個のQueutyプロセスタイプ、合計で5個のDynoを使用した場合は以下のようになります :
$ heroku ps:scale web=3 queuty=2
アプリケーションの新しいバージョンをデプロイするときは、現在実行している全てのDynoは一旦終了され、そして新しいもの(新しいReleaseと共に)が入れ替わりに実行されます。現存するDyno構成は維持されます。
note 用語: アプリケーションのDyno構成とは現在実行中のDynoの合計の数であり、あなたが拡張するのに併せて様々なプロセスタイプの間で分配されます。
何が実行されているかを理解するために、何のDynoがどのプロセスタイプを実行しているのかを知る必要があります :
$ heroku ps
== web: 'java lib/foobar.jar $PORT'
web.1: up 2013/02/07 18:59:17 (~ 13m ago)
web.1: up 2013/02/07 18:52:08 (~ 20m ago)
web.2: up 2013/02/07 18:31:14 (~ 41m ago)
== queuty: `java lib/queue-processor.jar`
queuty.1: up 2013/02/07 18:40:48 (~ 32m ago)
queuty.2: up 2013/02/07 18:40:48 (~ 32m ago)
Dynoはあなたのアプリケーションを拡張する重要な方法になります。この例だと、アプリケーションはWebとキューのワーカー用Dynoを独立してスケールさせることができる良い設計になっています。
アプリケーションの設定は、デプロイ(ステージング、プロダクション、開発環境、その他...)によって異なってくるすべての物を指します。これはデータベース、認証、もしくはあなたのアプリケーションに関わる文脈的な情報を提供する環境変数のような、裏で提供されるリソース管理を含んでいます。
Herokuはカスタマイズ可能な設定をした上でアプリケーションを実行することができます。設定はアプリケーションのコードの外に存在し、独立して変更することができます。
アプリケーションの設定はconfig varsに保持されています。例として、どのようにあなたのアプリケーション用の暗号化キーを設定するのかを示します :
$ heroku config:add ENCRYPTION_KEY= my_secret_launch_codes
Adding config vars and restarting demoapp... done, v14
ENCRYPTION_KEY: my_secret_launch_codes
note 用語: 設定変数 はカスタマイズ可能な設定用のデータを含んでいます。これはあなたのアプリケーションのコードとは独立して変更可能です。設定は環境変数を通して実行中のアプリケーションに適応されます。
実行系では、すべて全ての設定変数が環境変数として扱われます。つまりは、これらはプログラムで簡単に抽出することが可能です。上記のような設定変数とともにデプロイされたRubyのアプリケーションは、ENV["ENCRYPTION_KEY"]
を使ってこれにアクセスすることができます。
全てのアプリケーション内のDynoは、実行系で確実に同じ設定変数を使用します。
これまで、この記事では、Dynoにあるアプリケーションを実行するために、HerokuはDynoと共に最新のSlugを読み込むと述べました。しかし、これは改める必要があります。実際には、Slugと共にあなたがアプリケーションに割り当てた環境変数を読み込んでいます。Slugと設定の組み合わせはReleaseと呼ばれます。
note 用語 (仮): Releases はSlugと設定変数の、書き込み専用の台帳です.
すべてのReleaseは自動的に書き込み専用の台帳に書き込まれ、アプリケーションと他のReleaseを管理しています。heroku releases
コマンドを使って、Releaseのデプロイの軌跡を見てみましょう :
$ heroku releases
== demoapp Releases
v103 Deploy 582fc95 [email protected] 2013/01/31 12:15:35
v102 Deploy 990d916 [email protected] 2013/01/31 12:01:12
callout デプロイのメッセージの横にある数字、例えば
582fc95
、はHerokuにデプロイしているリポジトリのコミットハッシュと一致します。
あなたがアプリケーションの新しいバージョンをデプロイするたびに毎回、新しいSlugが作られ、Releaseが生成されます。
Herokuはアプリケーションの過去のReleaseを含んでいるため、ロールバックや過去のReleaseをデプロイし直す事はとても簡単です。
$ heroku releases:rollback v102
Rolling back demoapp... done, v102
$ heroku releases
== demoapp Releases
v104 Rollback to v102 [email protected] 2013/01/31 14:11:33 (~15s ago)
v103 Deploy 582fc95 [email protected] 2013/01/31 12:15:35
v102 Deploy 990d916 [email protected] 2013/01/31 12:01:12
アプリケーションを、ソースか設定のどちらか部分的に変更することは、結果として新しいReleaseを作ります。
Releaseとは、Herokuがアプリケーションのソース(Slugの中に保持されている)の中のアプリケーションの設定(設定変数)を独立して変更できるようにしている背景の仕組みです。Releaseはこの仕組みと共に存在してます。アプリケーションに関連する設定変数を変更するときはいつでも、新しいReleaseが生成されます。
Herokuプラットフォームの一部、DynoマネージャーはDynoの実行中状態を維持する事が仕事です。例えば、Dynoは最低でも1日に一回は回転し、Dynoマネージャーはいつでも実行中のアプリケーションの問題(アウトオブメモリなど)、またはDynoを物理的に新しい場所へ移す必要があるようなハードウェアに潜む問題を発見します。
note 用語: HerokuプラットフォームのDynoマネージャー はHerokuで実行中のすべてのアプリケーションを渡って使われるDynoを管理することが仕事です。
このDynoのサイクルは通常時として自動で、そして可視性を持って行われ、ログが取られています。
note 用語: 1個のDynoで稼働しているアプリケーションは非アクティブな状態から1時間経つとスリープします. HTTPのトラフィックをスリープ中のアプリケーションが受信した場合、数秒の遅延を引き起こしながら立ち上がります。 拡張されたWeb Dynoはスリープしません。
Herokuがアプリケーションを実行、管理するため、OSや他の内部システムの設定の管理をする必要はありません。One-off Dynoはローカルのターミナルに与えられた入出力を実行できます。これらはまた、共有資源の状態を変更するような管理用のタスクを実行するためにも使われます。たとえばデータベースの設定です。おそらくschedulerを通して定期的に行われます。
note 用語: One-off Dyno はローカルのターミナルに与えられた入出力を実行できる一時的なDynoです。最新のReleaseを使って行います。
ここにOne-off Dynoを生成し、コマンドを送るもっとも単純な方法を示します :
$ heroku run bash
Running `bash` attached to terminal... up, run.8963
~ $ ls
これは新しいDynoを立ち上げ、あなたのReleaseを読み込み、そしてbash
コマンドを実行しています。Unixのシェルの様に使えます(Dynoは効率的に独立させた仮想化Unixコンテナということを忘れないでください)。一度セッションを切ると、もしくは一定時間非アクティブになると、Dynoは削除されます。
1つのDynoのファイルシステムに対する変更は、他のDynoへ伝搬したり、デプロイを通して書き込まれたりせず、Dynoが再起動します。より良い、拡張性のある方法として、データベースやキューなどの共有リソースを使う事があります。
note 用語: それぞれのDynoは自分の刹那的ファイルシステムを持っており、最新のReleaseのコピーが含まれています。一時的な簡易メモのような使われかたをされ、ファイルシステムに対する変更は他のDynoに反映されません。
Dynoの中の刹那的な環境は、上記のコマンドを使って確認することができます。DynoのUnixシェルでheroku run bash
を実行してOne-off Dynoを作り、そのあとにそのDynoの上にファイルを作成し、セッションを切った場合、変更は失われます。同じアプリケーション内であっても、全てのDynoは独立しています。そしてセッションが切れるとDynoは終了し、削除されます。新しいDynoはいつもSlugから作られ、他のDynoの状態から作られる事は決してありません。
アプリケーションは通常、データベースやキューイング、キャッシュシステム、ストレージ、メールサービスなどのバックサービスを提供するために、アドオンを利用します。アドオンはHerokuやサードパーティからサービスとして提供されます。ここにアドオンを選ぶ事が出来る大きなマーケットプレイスがあります。
Herokuはこれらのアドオンを追加されたリソースとして扱います。アドオンの準備は、アドオンのマーケットプレイスから一つ選び、アプリケーションに追加する事で行えます。
例えば、これはアプリケーションにRedisの後ろで動くストアアドオン(RedisToGo)の追加方法です :
$ heroku addons:add redistogo:nano
アドオンの提供者はそのサービスに責任を持っています。そして、アプリケーションとのインターフェースはしばしば設定変数を通して提供されます。たとえばこの例の場合、アドオンが準備されたときにアプリケーションにREDISTOGO_URL
が自動的に追加されます。これでURLを通してサービスとつなぐコードを書く事が出来ます。例えばこのようになります :
uri = URI.parse(ENV["REDISTOGO_URL"])
REDIS = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
note 用語: アドオン はサードパーティの、ある部分に特化した、価値を付加してくれるクラウドサービスです。機能を拡張しながらも、簡単にアプリケーションに追加する事が出来ます。
アドオンはアプリケーションと、多くの場合設定変数を使って連携されます。そのため、Releaseの既出の定義を改める必要ががあります。あなたのアプリケーションのReleaseはSlugと設定変数だけではありません。Slugと設定変数の他に、備え付けられたアドオンも含みます。
note 用語 (仮): Releases はSlugと設定変数、そしてアドオンの書き込み専用の台帳です. Herokuはあなたが作ったリリースの書き込み専用台帳を管理保持します。
設定変数の様に、アドオンを追加、削除、変更した時は、いかなる場合でも新しいReleaseが作られます。
Herokuはログを時系列のイベントの出力として扱います。そして、全てのDynoとHerokuプラットフォームの構成物の中で実行されているすべでの処理から生成されたログの出力を順に、Logplexの中に並べます。これはログ提供のための高パフォーマンスでリアルタイムなシステムです。
プラットフォームの構成物とDynoの全てを横断するログを確認するのは簡単な事です :
$ heroku logs
2013-02-11T15:19:10+00:00 heroku[router]: at=info method=GET path=/articles/custom-domains host=mydemoapp.heroku.com fwd=74.58.173.188 dyno=web.1 queue=0 wait=0ms connect=0ms service=1452ms status=200 bytes=5783
2013-02-11T15:19:10+00:00 app[web.2]: Started GET "/" for 1.169.38.175 at 2013-02-11 15:19:10 +0000
2013-02-11T15:19:10+00:00 app[web.1]: Started GET "/" for 2.161.132.15 at 2013-02-11 15:20:10 +0000
3個のタイムスタンプが付いているログの行がここで確認できます。始めはHerokuのルータから、最後の2行はWebプロセスタイプを実行している2個のDynoからです。
note Terminology: Logplex は自動的にあなたのアプリケーションの実行中のすべてのDyno、また同様にルータのような構成物からのログのエントリを順にならべ、アクティビティの一元化された情報源として提供しています。
更に、ただ一つのDynoを選択して、チャンネルを開けっ放しにしながら、さらなるイベントを確認することができます。
$ heroku logs --ps web.1 --tail
2013-02-11T15:19:10+00:00 app[web.2]: Started GET "/" for 1.169.38.175 at 2013-02-11 15:19:10 +0000
Logplexはパフォーマンス的な理由により、限られた量のバッファのみ保持します。これらを保存したり、例外時にEメールで通知をするようなイベントを起こすためには、Logging Add-onを使ってください。Logplexからの出力を受信するAPIで、ログの流出に対して効果的です。
あなたのDyno構成によりますが、いくつかのDynoはWebプロセスタイプに関連づいたコマンドを実行し、そしていくつかは別のプロセスタイプに関連づいたコマンドを実行する状態になります。
Webプロセスタイプを実行するDynoは他のすべてのDynoと比べて1点大きく違う所があります。それは、彼らがHTTPのトラフィックを受信するということです。HerokuのHTTP routersはアプリケーションの実行中のWeb Dynoの間で、到着しようとしているリクエストを分配します。
そのため、アプリケーションのWebトラフィックに対する許容量を拡張するために、Web Dynoの数を増やす事は有効に働きます。
$ heroku ps:scale web+5
ランダムな選択アルゴリズムがDyno間でのHTTPリクエストのロードバランシングでは使われています。そしてこのルーティングはHTTPとHTTPSのトラフィック両方を制御します。タイムアウトの制御と、複数同時接続もサポートされています。
ここで説明してきた概念は、2つの領域に分ける事ができます。アプリケーションの開発とデプロイに関するもの。そしてHerokuとデプロイされたあとのアプリケーションへの実行時の指示に関するものです。
下記の2つのリストは、プラットフォームの主な構成物を要約し、2つの領域に分けたものになっています。
- アプリケーションはあなたのソースコード、あらゆる依存ファイルへの記述、そしてProcfileから構成されます。
- Procfilesはプロセスタイプ(実行してもらいたいコマンド)の一覧です。
- アプリケーションのデプロイに、Gitを使ってHerokuにアプリケーションを送ることがあります。
- BuildpacksはSlugの収集処理の後ろに存在しています。BuildPacksはアプリケーション、その依存ファイル、そして言語の実行系を取得し、Slugを生成します。
- Slug はあなたのソース、収集された依存ファイル、言語の実行系、生成/コンパイルされたビルドシステムの出力のまとまりです。 - 実行ができる準備ができている状態です。
- 設定変数 はカスタマイズ可能な設定用のデータを含んでいます。これはあなたのアプリケーションのコードとは独立して変更可能です。設定は環境変数を通して実行中のアプリケーションに適応されます。
- アドオンはサードパーティの、ある部分に特化した、価値を付加してくれるクラウドサービスです。機能を拡張しながらも、簡単にアプリケーションに追加する事が出来ます。
- Releases はSlugと設定変数、そしてアドオンの書き込み専用の台帳です. Herokuはあなたが作ったリリースの書き込み専用台帳を管理保持します。
- Dynoは独立した、仮想化されたUnixのコンテナで、アプリケーションが実行されるのに必要な環境を提供します。
- アプリケーションのDyno構成とは現在実行中のDynoの合計の数であり、あなたが拡張するのに併せて様々なプロセスタイプの間で分配されます。
- Dynoマネージャー はHerokuで実行中のすべてのアプリケーションを渡って使われるDynoを管理することが仕事です。
- 1個のDynoで稼働しているアプリケーションは非アクティブな状態から1時間経つと、Dynoマネージャーによってスリープ状態にされます。複数個のWeb Dynoに拡張された場合はスリープしません。
- One-off Dyno はローカルのターミナルに与えられた入出力を実行できる一時的なDynoです。最新のReleaseを使って行います。
- それぞれのDynoは自分の刹那的ファイルシステムを持っており、最新のReleaseのコピーが含まれています。一時的な簡易メモのような使われかたをされ、ファイルシステムに対する変更は他のDynoに反映されません。
- Logplex は自動的にあなたのアプリケーションの実行中のすべてのDyno、また同様にルータのような構成物からのログのエントリを順にならべ、アクティビティの一元化された情報源として提供しています。
- アプリケーションの拡張(スケーリング)には、それぞれのプロセスタイプのDynoの数を変更することがあります。