stackのテンプレートを使って Dockerを使ってHaskellアプリをHerokuにデプロイする と同じことをやってみます.
stackに警告を出されないように,~/.stack/config.yml に以下のような情報を追加しておくといいかも.
templates:
params:
author-email: EMAIL
author-name: NAME
stackのテンプレート servant-docker
を使ってプロジェクトの雛形を作らせます.
stack new PROJECT [--bare] servant-docker [--solver SOLVER]
雛形なのでこれでデプロイまでできるはずなのですが,いくつか問題があるので修正します.
まず,herokuの環境でlistenすべきポート番号は環境変数で取得しないといけないのでそれを反映させます:
diff --git a/src/Lib.hs b/src/Lib.hs
index 46ba8bc..c800dc5 100644
--- a/src/Lib.hs
+++ b/src/Lib.hs
@@ -10,6 +10,7 @@ import Data.Aeson.TH
import Network.Wai
import Network.Wai.Handler.Warp
import Servant
+import System.ReadEnvVar (readEnvDef)
data User = User
{ userId :: Int
@@ -22,7 +23,10 @@ $(deriveJSON defaultOptions ''User)
type API = "users" :> Get '[JSON] [User]
startApp :: IO ()
-startApp = run 1234 app
+startApp = do
+ port <- readEnvDef "PORT" 8080
+ putStrLn $ ";;; start server at " ++ show port
+ run port app
app :: Application
app = serve api server
ReadEnvVarパッケージを追加したのでcabalファイルにも追加:
diff --git a/appname.cabal b/appname.cabal
index b977aa5..e654f60 100644
--- a/PROJECT.cabal
+++ b/PROJECT.cabal
@@ -18,6 +18,7 @@ library
exposed-modules: Lib
build-depends: base >= 4.7 && < 5
, aeson
+ , read-env-var
, servant-server
, wai
, warp
ここでコンパイルしてエラーがないことを確認します.
$ stack build
動作確認は
$ export PORT=8080; APP &
$ wget http://localhost:8080/
まずdockerのイメージでプログラムが自動で実行されるようにDockerfile(ついでにstack.yml)を変更します. .
--- a/Dockerfile
+++ b/Dockerfile
@@ -9,3 +9,4 @@
COPY . /app/user
RUN stack install
+CMD APP.EXE
modified stack.yaml
@@ -66,6 +66,15 @@ allow-newer: true
# Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor
+image:
+ containers:
+ -
+ base: "haskell:8.4.3"
+ executables:
+ - APP.EXE
+ entrypoints:
+ - APP.EXE
以下を実行してイメージを作ります:
docker build -t APPNAME .
動作確認は
$ docker run -p 8080:8080 --publish-all APPNAME
$ wget http://localhost:8080/
heroku login
heroku apps:create APPNAME
$ heroku container:login
$ heroku container:push web [--app APPNAME]
$ heroku container:release web [--app APPNAME]
うまく行ったなら自動化させます.当然gitlab用に .gitlab-ci.yml
を作成:
build:
stage: build
script:
- docker build -t APPNAME .
deploy heroku:
stage: deploy
script:
- heroku container:login
- heroku container:push web --app APPNAME
- heroku container:release web --app APPNAME
(さらにherokuへのデプロイ用のキーを登録する必要があるかも)
That's it.
ということで以上の変更をしたテンプレート https://gitlab.com/snippets/1728485/raw を作りました. テンプレートはurl指定で使えるので,以下のようにするのが一番速いでしょう.
stack new projectname https://gitlab.com/snippets/1728485/raw
ということで結論
stack new PROJECT https://gitlab.com/snippets/1728485/raw
docker build -t PROJECT .
heroku container:login
heroku container:push web --app PROJECT
heroku container:release web --app PROJECT
このプログラムはPostgreSQLを使うために外部プログラムを呼び出していません。 対応するのは簡単で以下の通り:
nixos:2.0.4
に変更あとはherokuでpostgreSQLを有効にすればOK。 Dockerfileはこのようになりました。
FROM nixos/nix:2.0.4
ENV LANG C.UTF-8
RUN nix-channel --update
RUN nix-env -u
RUN nix-env -f "<nixpkgs>" -iA haskell.compiler.ghc843
RUN nix-env -i stack
WORKDIR /opt/PROJECT/src
ENV PATH "/opt/PROJECT/bin:$PATH"
# Build and install application binaries to /opt/PROJECT/bin.
COPY *.yaml /opt/PROJECT/src/
RUN stack --no-terminal build --only-dependencies
COPY . /opt/PROJECT/src
RUN stack --no-terminal --local-bin-path /opt/PROJECT/bin install
# clean up and run
RUN rm -rf /opt/PROJECT/src
CMD /opt/PROJECT/bin/PROJECT