euphonictechnologies’s diary


follow us in feedly

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

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



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

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


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



OpenShift by Red Hat









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



$ sudo gem install rhc
Fetching: net-ssh-2.9.1.gem (100%)
Successfully installed net-ssh-2.9.1
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
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

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


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

Login to (登録時のメールアドレス)
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/

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 (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.


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


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.アプリを動かすところまで行ってみよう。


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

$ rhc app create hello



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

rhc git-clone hello

cabal 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)



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




cabal install --only-dependencies


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 3000


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

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






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@<つくったドメイン>
   2ed7af2..3b19052  master -> master






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