LoginSignup
15
12

More than 3 years have passed since last update.

F# SuaveをHerokuデプロイ

Last updated at Posted at 2019-11-01

最近F#を触り始め、HerokuにWebアプリをデプロイしてみた。
色々調べたので手順をまとめておく。

完成物

環境

OSX Mojave
.NET Core 3.0
Heroku CLI 7.33.3

.NET Coreのインストール

インストーラで簡単に導入できる。
dotnetコマンドも自動で入る。

ソリューション・プロジェクト作成

ソリューション作成

dotnet new sln -o heroku-suave-getting-started

プロジェクト作成

cd heroku-suave-getting-started
dotnet new console -lang F#
dotnet sln add heroku-suave-getting-started.fsproj

Hello World

dotnet run
Hello World from F#!

Suave導入

SuaveはF#における (たぶん) デファクトのWEBフレームワーク。
Expressのようなマイクロフレームワーク。

パッケージインストール

サードパーティのパッケージマネージャなど不要で、dotnetコマンドでパッケージインストールが行える。

dotnet add package Suave --version 2.5.6

サーバを起動してみる

先程のHello Worldの記述がされているProgram.fsというファイルがあるので下のように書き換える。

Program.fs
open Suave

[<EntryPoint>]
let main _argv =
    startWebServer defaultConfig (Successful.OK "Hello World!")
    0

dotnet run でビルドと実行を行える。

dotnet run
[20:00:56 INF] Smooth! Suave listener started in 45.809ms with binding 127.0.0.1:8080

この状態でブラウザを開き http://localhost:8080/ を見ると 「Hello World!」が確認できる。

Herokuで動作するコードに変更

Herokuの仕様でポートは環境変数 $PORT から読み取るようにしなければいけない。
そのため下記のように変更する。

Program.fs
open System
open Suave
open Suave.Sockets
open YoLo

[<EntryPoint>]
let main _argv =
    let portByEnv =
        match Env.var ("PORT") with
        | Some(x) -> x
        | None -> "8080"

    let ip : Net.IPAddress = Net.IPAddress.Parse("0.0.0.0")
    let port : Port = uint16 portByEnv

    let socketBinding : Sockets.SocketBinding =
        { ip = ip
          port = port }

    let httpBinding : Http.HttpBinding =
        { scheme = Protocol.HTTP
          socketBinding = socketBinding }

    let conf = { defaultConfig with bindings = [ httpBinding ] }
    startWebServer conf (Successful.OK "Hello World")
    0

ずらずら書いているが環境変数 $PORT を読み取ってそれを起動ポートとしているだけ。
$PORT 変数がない場合は8080となる。

実行ファイルを生成して実行 (Mac OSX)

.NET Core3.0にはスタンドアロンな実行ファイルを生成するという機能がある。

dotnet publish コマンドは、プラットフォーム固有の単一ファイルの実行可能ファイルにアプリをパッケージ化することをサポートします。 実行可能ファイルは自己展開型であり、アプリの実行に必要なすべての依存関係 (ネイティブを含む) が含まれます。

自己完結型アプリには、コードの実行に必要なものがすべて含まれるので、ホスト コンピューターに .NET をインストールする必要はありません。

スタンドアロンというだけあってデプロイ先の本番環境に.NETがなくても動作する。

ではまずはローカル (OSX) で試す。

ビルド時にどのOS向けかを指定する必要がある。

RIDカタログによるとOSXはosx-x64となるので -r オプションの引数に指定。

dotnet publish -c Release -r osx-x64 /p:PublishSingleFile=true /p:PublishTrimmed=true

少し待つとビルドが終わりbin/Release/netcoreapp3.0/osx-x64/publishの下にheroku-suave-getting-startedとheroku-suave-getting-started.pdbというファイルができる。
本番にはこの2つのファイルを設置しheroku-suave-getting-startedを実行すれば動作する。

実行してみる。

 ./bin/Release/netcoreapp3.0/osx-x64/publish/heroku-suave-getting-started
[20:09:07 INF] Smooth! Suave listener started in 52.388ms with binding 127.0.0.1:8080

このようにサーバ起動できた。

デプロイ準備

Herokuでは.NETの公式ビルドパックがないため、

  • サードパーティのビルドパックを使う
  • Dockerデプロイする

かのどちらかになる。
今回は後者でいく。

最も、上述のシングル実行ファイル生成機能のおかげで環境構築は非常に簡単。

デプロイ用バイナリを生成 (Alpine Linux)

RIDカタログを参照。
Alpineなので linux-musl-x64 を指定。

dotnet publish -c Release -r linux-musl-x64 /p:PublishSingleFile=true /p:PublishTrimmed=true

Dockerfile

ソリューション直下にDockerfileを用意する。
動かすのはスタンドアロンな実行ファイルなので、.NET入りのDockerイメージを用意する必要はなく、素のAlpineで構わない。
しかし多少の依存はあるらしく、最低限以下のパッケージを入れれば動くようだ。

apk add gcc libintl icu

Dockerfileの内容は下記。

Dockerfile
FROM alpine:3.10

RUN apk update && \
    apk add gcc libintl icu

ADD ./bin/Release/netcoreapp3.0/linux-musl-x64/publish /app

CMD /app/heroku-suave-getting-started

Herokuデプロイ

CLIインストール

brew tap heroku/brew && brew install heroku

で導入できる。

Herokuログイン

heroku login
heroku container:login

Herokuアプリ作成

heroku create heroku-suave-getting-started

heroku-suave-getting-startedは任意のアプリ名。

デプロイ

heroku container:push web -a heroku-suave-getting-started
heroku container:release web -a heroku-suave-getting-started

アプリをブラウザで開く

heroku open

「Hello World!」が出ていればOK。

参考

https://docs.microsoft.com/ja-jp/dotnet/core/tools/dotnet-new?tabs=netcore22
http://maxfie1d.hatenablog.com/entry/2018/01/23/141755
https://docs.microsoft.com/ja-jp/dotnet/core/rid-catalog
https://dev.to/pluralsight/creating-trimmed-self-contained-executables-in-net-core-4m08
https://hub.docker.com/_/microsoft-dotnet-core
https://docs.microsoft.com/en-us/dotnet/core/deploying/deploy-with-cli

15
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
12