コンテンツへスキップ
GitHubリポジトリ フォーラム RSS-ニュースフィード

Heroku Buildpack

Brian J. Cardiff

2014年末に、Crystalのための最初のドラフトが作成されました。HerokuスタックでCrystalアプリを実行できるようになるのは素晴らしいアイデアでした。

言語、ツール、標準ライブラリの開発を続ける中で、Crystalを取り巻くコミュニティは成長しました。多くの人がHerokuでCrystalベースのウェブアプリを試すことに関心を持っていました。このBuildpackのGitHub上のネットワークグラフは、bashスクリプトの集まりにしては非常に大きいです!

しかし、アプローチにいくつかの欠陥があったため、BuildpackはCrystalの最新バージョンに追いつくことができませんでした。しかし、それは今解決されました!やった!

現在、ウェブフレームワークの開発努力が続けられていますが、追加の依存関係なしにHerokuにウェブアプリケーションをデプロイするためにCrystal Buildpackを使用する基本的な手順を共有したいと思います。

Crystalプロジェクトの作成

既にCrystalがインストールされていることを前提としています。

crystal init appを使用してアプリを作成します。

$ crystal init app heroku101
    create  heroku101/.gitignore
    create  heroku101/LICENSE
    create  heroku101/README.md
    create  heroku101/.travis.yml
    create  heroku101/shard.yml
    create  heroku101/src/heroku101.cr
    create  heroku101/src/heroku101/version.cr
    create  heroku101/spec/spec_helper.cr
    create  heroku101/spec/heroku101_spec.cr
Initialized empty Git repository in /Users/bcardiff/Work/Manas/crystal/heroku101/.git/

$ cd heroku101/

注記:投稿の残りの部分では、すべてのコマンドがheroku101/ディレクトリから実行されます。

shard.ymlファイルは、プロジェクト名をheroku101として宣言します。これは、Buildpackがコンパイルするメインソースファイル(./src/heroku101.cr)を決定するために使用されます。

$ cat shard.yml
name: heroku101
version: 0.1.0
...

シンプルなHTTPサーバーを作成するには、src/heroku101.crファイルを編集し、次の内容を追加します。

# file: src/heroku101.cr
require "http/server"

bind = "0.0.0.0"
port = 8080

server = HTTP::Server.new(bind, port) do |context|
  context.response.content_type = "text/plain"
  context.response << "Hello world, got #{context.request.path}"
end

puts "Listening on http://#{bind}:#{port}"
server.listen

プログラムのビルドと実行

$ crystal src/heroku101.cr
Listening on http://0.0.0.0:8080

http://0.0.0.0:8080でブラウザを開きます。

Ctrl+Cを押してプロセスを終了することで、サーバーを停止します。

Heroku対応にする

現時点では、プロジェクトはHerokuについて何も知りません。開始するには、まずHerokuアプリケーションを登録する必要があります。最も簡単な方法は、Heroku Toolbeltを使用することです。

$ heroku create --buildpack https://github.com/crystal-lang/heroku-buildpack-crystal.git
Creating app... done, ⬢ sleepy-thicket-16179
Setting buildpack to https://github.com/crystal-lang/heroku-buildpack-crystal.git... done
https://sleepy-thicket-16179.herokuapp.com/ | https://git.heroku.com/sleepy-thicket-16179.git

上記のコマンドは、ランダムなアプリ名を生成します。アプリ名最初から指定する方法については、ドキュメントを確認してください。

デプロイする前に、小さな変更を加える必要があります。Herokuは、アプリで使用されるポート番号をランダムに割り当てます。Buildpackのおかげで、アプリケーションの実行時に--portオプションでこれが通知されます。

そのため、src/heroku101.crの先頭にrequire "option_parser"を追加し、port変数のデフォルト値を次のようにオーバーライドします。

OptionParser.parse! do |opts|
  opts.on("-p PORT", "--port PORT", "define port to run server") do |opt|
    port = opt.to_i
  end
end

完全なsrc/heroku101.crは次のようになります。

# file: src/heroku101.cr
require "http/server"
require "option_parser"

bind = "0.0.0.0"
port = 8080

OptionParser.parse! do |opts|
  opts.on("-p PORT", "--port PORT", "define port to run server") do |opt|
    port = opt.to_i
  end
end

server = HTTP::Server.new(bind, port) do |context|
  context.response.content_type = "text/plain"
  context.response << "Hello world, got #{context.request.path}"
end

puts "Listening on http://#{bind}:#{port}"
server.listen

--portオプションを使用してビルドおよび実行するには

$ crystal src/heroku101.cr -- --port 9090
Listening on http://0.0.0.0:9090

または、ローカルで最適化されたリリースをビルドし、次のように実行します。

$ crystal build src/heroku101.cr --release
$ ./heroku101
Listening on http://0.0.0.0:8080
^C
$ ./heroku101 --port 9090
Listening on http://0.0.0.0:9090
^C

デプロイ!

アプリを公開する準備ができたら、通常の方法でgit push heroku masterを使用してデプロイします。

$ git push heroku master
Counting objects: 22, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (17/17), done.
Writing objects: 100% (22/22), 2.85 KiB | 0 bytes/s, done.
Total 22 (delta 3), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Fetching set buildpack https://github.com/crystal-lang/heroku-buildpack-crystal.git... done
remote: -----> Crystal app detected
remote: -----> Installing Crystal (0.17.3 due to latest release at https://github.com/crystal-lang/crystal)
remote: -----> Installing Dependencies
remote: -----> Compiling src/heroku101.cr (auto-detected from shard.yml)
remote:
remote: -----> Discovering process types
remote:        Procfile declares types     -> (none)
remote:        Default types for buildpack -> web
remote:
remote: -----> Compressing...
remote:        Done: 289.4K
remote: -----> Launching...
remote:        Released v3
remote:        https://sleepy-thicket-16179.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy.... done.
To https://git.heroku.com/sleepy-thicket-16179.git
 * [new branch]      master -> master

Buildpackは次の処理を行います。

  1. 最新のCrystalリリースをインストールします。
  2. Shardsを使用してプロジェクトの依存関係をインストールします。
  3. リリースモードでメインソースファイルをコンパイルします。
  4. --portオプションを使用してWebサーバープロセスを実行します。

Crystalバージョンの指定

異なるCrystalバージョンを使用する場合は、crenvの規則に従って、目的のバージョンを含む.crystal-versionファイルを作成します。

$ echo '0.17.1' > .crystal-version

.crystal-versionの変更をコミットしてデプロイします。

$ git push heroku master
Counting objects: 3, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 301 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Fetching set buildpack https://github.com/crystal-lang/heroku-buildpack-crystal.git... done
remote: -----> Crystal app detected
remote: -----> Installing Crystal (0.17.1 due to .crystal-version file)
remote: -----> Installing Dependencies
remote: -----> Compiling src/heroku101.cr (auto-detected from shard.yml)
...

これで、(0.17.1 due to .crystal-version file)という説明が表示されます。

最新のCrystalバージョンにアップグレードする準備ができたら、ファイルの内容を更新するか、削除して再度デプロイします。

コードを見せてください!

使用されているサンプルソースコードはすべてhttps://github.com/bcardiff/sample-crystal-heroku101にあります。

Crystal Buildpackに貢献するには、フォークしてください。貢献は大歓迎です!