euphonictechnologies’s diary

Haskell超初心者の日記です。OCamlが好きです。

follow us in feedly

Haskell + OpenShiftでWarp + HaskellのウェブアプリケーションをPaaS上にデプロイするてはじめ

HaskellをサポートしているPaaSは少ないのだけど、OpenShiftが対応しているらしいのでいっちょ頑張ってHello, world.までやってみる。RedHadがやってるので、そんなに早く閉鎖することはないだろう。HaskellをサポートしているPaaSはWeb/Cloud - HaskellWikiによればOpenShiftとHeroku、あとはfluxflexが、あっ…

Fluxflexが6月30日に閉鎖、今後はRackhubに注力

今回参考にするURLは

Functional Programming in the Cloud: How to Run Haskell on OpenShift | Openshift Blog

Haskell - warpではじめる最小ウェブアプリケーション - Qiita

基本ここに沿いながら、次の違いに気をつけてみる

  • デプロイするのは単純なWai + Warpアプリケーション
  • ホットデプロイとかは全部無視。コミット次のビルドでいい

OpenShiftのアカウントを取る

まずは、アカウントを取得する。OpenShiftのトップページからできるよ。

OpenShift by Red Hat

f:id:euphonictechnologies:20140827213139p:plain

f:id:euphonictechnologies:20140827213149p:plain

登録を終えるとメールが来るのでVerifyしよう。

f:id:euphonictechnologies:20140827213220p:plain

Verifyしたら規約に同意して…

f:id:euphonictechnologies:20140827213231p:plain

できあがり!

RHCをインストールしてコマンドラインから作業できるようにする

Getting Started with OpenShift Online | OpenShift by Red Hatに従ってコマンドラインツールRHCをインストールしよう。

f:id:euphonictechnologies:20140827213414p:plain

やってみると:

$ sudo gem install rhc
assword:
Fetching: net-ssh-2.9.1.gem (100%)
Successfully installed net-ssh-2.9.1
<省略truncated...>
Fetching: rhc-1.28.5.gem (100%)
===========================================================================

If this is your first time installing the RHC tools, please run 'rhc setup'

===========================================================================
Successfully installed rhc-1.28.5
Parsing documentation for net-ssh-2.9.1
<省略truncated...>
Parsing documentation for rhc-1.28.5
Installing ri documentation for rhc-1.28.5
10 gems installed

途中省略してみたが、言われたとおりインストール後にrhc setupを実行してみる。

$ rhc setup
OpenShift Client Tools (RHC) Setup Wizard

This wizard will help you upload your SSH keys, set your application namespace, and check that other programs like Git are properly
installed.

If you have your own OpenShift server, you can specify it now. Just hit enter to use the server for OpenShift Online: openshift.redhat.com.
Enter the server hostname: |openshift.redhat.com|

ここはエンターでデフォルトを使う。

You can add more servers later using 'rhc server'.

Login to openshift.redhat.com: (登録時のメールアドレス)
Password: ***************

ここでは登録時のメールアドレスとパスワードを入力する。

OpenShift can create and store a token on disk which allows to you to access the server without using your password. The key is stored in
your home directory and should be kept secret.  You can delete the key at any time by running 'rhc logout'.
Generate a token now? (yes|no) yes
Generating an authorization token for this client ... lasts about 1 month

Saving configuration to /Users/username/.openshift/express.conf ... done

No SSH keys were found. We will generate a pair of keys for you.

    Created: /Users/username/.ssh/id_rsa.pub

Your public SSH key must be uploaded to the OpenShift server to access code.  Upload now? (yes|no) yes

Since you do not have any keys associated with your OpenShift account, your new key will be uploaded as the 'default' key.

Uploading key 'default' ... done

Checking for git ... found git version 1.8.5.2 (Apple Git-48)

Checking common problems .. done

Checking for a domain ... none

Applications are grouped into domains - each domain has a unique name (called a namespace) that becomes part of your public application
URL. You may create your first domain here or leave it blank and use 'rhc create-domain' later. You will not be able to create an
application without completing this step.

基本的には全部yesで構わない。gitのためにSSHキーをアップロードしますとかそういうやつ。懸念がある人はよく読んで対応してみてください。

Please enter a namespace (letters and numbers only) |<none>|: ndk
Namespace 'ndk' is already in use. Please choose another.
Please enter a namespace (letters and numbers only) |<none>|: euptech
Your domain 'euptech' has been successfully created

ここではアプリケーションに共通のドメインをつけることができるらしい。3文字は殆ど取られている模様なので少し長めにつけた。

Checking for applications ... none

Run 'rhc create-app' to create your first application.

  Do-It-Yourself 0.1                      rhc create-app <app name> diy-0.1
  JBoss Application Server 7              rhc create-app <app name> jbossas-7
  JBoss Data Virtualization 6             rhc create-app <app name> jboss-dv-6.0.0
  JBoss Enterprise Application Platform 6 rhc create-app <app name> jbosseap-6
  Jenkins Server                          rhc create-app <app name> jenkins-1
  Node.js 0.10                            rhc create-app <app name> nodejs-0.10
  PHP 5.3                                 rhc create-app <app name> php-5.3
  PHP 5.4                                 rhc create-app <app name> php-5.4
  PHP 5.4 with Zend Server 6.1            rhc create-app <app name> zend-6.1
  Perl 5.10                               rhc create-app <app name> perl-5.10
  Python 2.6                              rhc create-app <app name> python-2.6
  Python 2.7                              rhc create-app <app name> python-2.7
  Python 3.3                              rhc create-app <app name> python-3.3
  Ruby 1.8                                rhc create-app <app name> ruby-1.8
  Ruby 1.9                                rhc create-app <app name> ruby-1.9
  Ruby 2.0                                rhc create-app <app name> ruby-2.0
  Tomcat 6 (JBoss EWS 1.0)                rhc create-app <app name> jbossews-1.0
  Tomcat 7 (JBoss EWS 2.0)                rhc create-app <app name> jbossews-2.0
  Vert.x 2.1                              rhc create-app <app name> jboss-vertx-2.1

  You are using 0 of 3 total gears
  The following gear sizes are available to you: small

Your client tools are now configured.

これで完成。なのでHello, world.アプリを動かすところまで行ってみよう。

cartridgeを使ってHaskellのアプリケーションを作る

今回はほんとにプレーンバニラのウェブアプリケーションを作るのでWai + Warpなんだけど、networkのcartridgeだとなんかうまくライブラリが入らないのでWai + WarpフレームワークであるScottyのcartridgeを使うことにする。Web/Cloud - HaskellWikiからScottyのcartridge manifestを指定して、以下のコマンドでアプリケーションを作る。コードのチェックアウトも同時に行われると思うので、コードをチェックアウトしたい場所で以下を叩こう:

$ rhc app create hello http://www.accursoft.com/cartridges/scotty.yml

作成したアプリケーションはhttps://openshift.redhat.com/app/console/applicationsに表示されるはず。

コードをチェックアウトして書く

おそらくapp createだけでチェックアウトもされているはず。チェックアウトされていなければ以下のコマンドでcloneできる。

rhc git-clone hello

cabal sandboxをつくる

これはお決まりのsandbox。さっきチェックアウトしたディレクトリの中で:

cd hello
cabal sandbox init

コードを書く

以下の様な簡単なWai + Warpアプリケーションを書いてみた。Main.hsという名前で保存しよう。

{-# LANGUAGE OverloadedStrings #-}

import Data.String (fromString)

import System.Environment (getArgs)

import qualified Network.Wai as Wai
import qualified Network.Wai.Handler.Warp as Warp
import qualified Network.HTTP.Types.Status as Status
import qualified Data.ByteString.Lazy.UTF8 as BSLU
import qualified Data.List as List

helloApp :: Wai.Application
helloApp req = do
    putStrLn . show . Wai.pathInfo $ req
    putStrLn "Processing request."
    return $ Wai.responseLBS Status.status200 [("Content-Type", "text/html")] contents

contents :: BSLU.ByteString
contents = BSLU.fromString $ List.intercalate "\n"
  [ "<html>"
  , "<head>"
  , "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">"
  , "</head>"
  , "<body>"
  , "<h1>Test</h1>This is test page. Running Warp 2 with Haskell."
  , "</body>"
  , "</html>"
  ]

main :: IO ()
main = do
    (ip, port) <- commandLineOptions
    let setting = Warp.setPort port . Warp.setHost (fromString ip) $ Warp.defaultSettings
    putStrLn $ "start server port = " ++ show port
    Warp.runSettings setting helloApp

commandLineOptions :: IO (String, Int)
commandLineOptions = do
    (ip:port:_) <- getArgs
    return (ip, read port :: Int)

このMain.hsにあわせてcabalファイルを書いてみる。

server.cabalファイルを書く

server.cabalにはbaseやwai, warp, http-types,utf8-stringが必要なはずなので、テンプレートを参考に以下を書く:

name:          server
version:       0.0
cabal-version: >= 1.2
build-type:    Simple

executable server
  other-extensions:   OverloadedStrings
  main-is:            Main.hs
  build-depends:      base,http-types,warp,wai,utf8-string

ここで名前がserverになっていることを確認しよう。

ライブラリをインストールする

早速

cabal install --only-dependencies

とやりたいところだけど2014年8月27日現在、古いバージョンのWarpしか動かないようなので、バージョン指定でライブラリをsandboxにインストールする必要があるみたい。面倒だね…。

cabal install http-types-0.8.3
cabal install wai-2.1.0
cabal install warp-2.1.3
cabal install utf8-string

ビルドしてみる

cabal configure
cabal build
$ cabal configure
Resolving dependencies...
Configuring server-0.0...
$ cabal build
Building server-0.0...
Preprocessing executable 'server' for server-0.0...
[1 of 1] Compiling Main             ( Main.hs, dist/build/server/server-tmp/Main.o )
Linking dist/build/server/server ...

できたようだ。ローカルで実行してみよう。

テストしてみる

Haskell cartridgeに対応したアプリケーションは引数にhostのipとportを指定する約束になっているので、localhostの3000番で走らせるには

cabal run 127.0.0.1 3000

とすればよい。

$ cabal run 127.0.0.1 3000
Preprocessing executable 'server' for server-0.0...
start server port = 3000

で実行中。http://localhost:3000にアクセスしてみよう。 もしMacならファイアウォールのダイアログが出るので許可してあげよう。

f:id:euphonictechnologies:20140827215617p:plain

うまくビルドされていれば以下の様なページにアクセスできるはず:

f:id:euphonictechnologies:20140827215647p:plain

変更をコミットしてプッシュする

必要なファイルはMain.hsとserver.cabalだけでとりあえず。

git add Main.hs
git add server.cabal
git commit -m "Initial check-in"
git push

するとpush時にcabal buildが走って、ビルドの様子が見られるはず。注意としては他のファイルとかsandboxのファイルとかをアップロードするとビルドできなくなるので、必要なファイルだけをアップロードしよう。

$ git push
Counting objects: 7, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 1.01 KiB | 0 bytes/s, done.
Total 4 (delta 1), reused 0 (delta 0)
remote: Building git ref 'master', commit 3b19052
remote: Resolving dependencies...
remote: Downloading utf8-string-0.3.8...
remote: Configuring utf8-string-0.3.8...
remote: Building utf8-string-0.3.8...
remote: Preprocessing library utf8-string-0.3.8...
remote: [1 of 7] Compiling Codec.Binary.UTF8.String ( Codec/Binary/UTF8/String.hs, dist/build/Codec/Binary/UTF8/String.o )
remote: [2 of 7] Compiling Codec.Binary.UTF8.Generic ( Codec/Binary/UTF8/Generic.hs, dist/build/Codec/Binary/UTF8/Generic.o )
remote: [3 of 7] Compiling Data.String.UTF8 ( Data/String/UTF8.hs, dist/build/Data/String/UTF8.o )
remote: [4 of 7] Compiling System.IO.UTF8   ( System/IO/UTF8.hs, dist/build/System/IO/UTF8.o )
remote: [5 of 7] Compiling System.Environment.UTF8 ( System/Environment/UTF8.hs, dist/build/System/Environment/UTF8.o )
remote: [6 of 7] Compiling Data.ByteString.UTF8 ( Data/ByteString/UTF8.hs, dist/build/Data/ByteString/UTF8.o )
remote: [7 of 7] Compiling Data.ByteString.Lazy.UTF8 ( Data/ByteString/Lazy/UTF8.hs, dist/build/Data/ByteString/Lazy/UTF8.o )
remote: In-place registering utf8-string-0.3.8...
remote: Creating package registration file: /tmp/pkgConf-utf8-string-0.3337181.8
remote: Installing library in
remote: /var/lib/openshift/53fdd0bc5004461e980000cd/app-root/runtime/build-dependencies//lib/utf8-string-0.3.8/ghc-7.6.3
remote: Registering utf8-string-0.3.8...
remote: Installed utf8-string-0.3.8
remote: Configuring server-0.0...
remote: Building server-0.0...
remote: Preprocessing executable 'server' for server-0.0...
remote: [1 of 1] Compiling Main             ( Main.hs, dist/build/server/server-tmp/Main.o )
remote: Linking dist/build/server/server ...
remote: Installing executable(s) in
remote: /var/lib/openshift/53fdd0bc5004461e980000cd/app-root/runtime/dependencies/
remote: Installed server-0.0
remote: stripping libraries ...
remote: Preparing build for deployment
remote: Deployment id is 870f9d0e
remote: Activating deployment
remote: -------------------------
remote: Git Post-Receive Result: success
remote: Activation status: success
remote: Deployment completed with status: success
To ssh://53fdd0bc5004461e980000cd@<つくったドメイン>.rhcloud.com/~/git/hello.git/
   2ed7af2..3b19052  master -> master

完了したらOpenShiftの自分のページの"Applications"からデプロイしたhelloアプリケーションを選んでウェブにアクセスしてみよう。

f:id:euphonictechnologies:20140827215955p:plain

やったね!

その他に

IntelliJとのインテグレーションが可能なようだけど、私の環境では"Clouds"の設定項目がIntelliJにないんだよね。。。

Getting Started with OpenShift in IntelliJ IDEA - YouTube Getting Started with OpenShift in IntelliJ IDEA - YouTube

そのうち調べてみます。とりあえずデプロイまで。次はScottyかYesodできちんとURLパラメータ処理できるような例を示しつつ、スペル修正プログラムを組み込んでいってみようと思う。