Smalltalk Web開発編（Seasideアプリ公開）

Seasideでアプリ開発をしたら世の中に公開をしましょう。今回はSeasideを公開する際に必要な情報を紹介していきます。

# css、jsについて
Seasideでは、image内にcss、jsをインポートして参照する機能ありますが、imageのサイズが大きくなってしまうことや修正の度にインポートする必要が出てくるため、image外部に配置して、アプリケーションから外部url参照にするとよいでしょう。


# Seasideのツールバーの非表示
開発時には便利なツールですが、アプリケーションを公開する前には非表示にします。非表示の方法は以下のコードを実行するだけです。

```smalltalk
WAAdmin applicationDefaults removeParent: WADevelopmentConfiguration instance.
```

# セッションのCookie化
Seasideのデフォルト設定だとセッションキーがURLに埋め込まれてしまいます。URLにセッションキーを埋め込むのは危険ですので、セッションキーのCookie化の方法を紹介します。Seasideのバージョンによって異なりますので、いくつかご紹介します。
*そろそろデフォルトでCookieでいいと思うんですけどね・・・。*

```smalltalk:Seaside3.0
| app |
app := WAAdmin register: MyCounter asApplicationAt:'mycounter'.
app preferenceAt: #useCookies put: true.
app cache expiryPolicy configuration at: #cacheTimeout put: 3600. 
```

```smalltalk:Seaside3.1
| app |
app := WAAdmin register: MyCounter asApplicationAt:'mycounter'.		
app preferenceAt: #trackingStrategy put: WACookieOnlySessionTrackingStrategy new.
app cache expiryPolicy configuration at: #cacheTimeout put: 3600. 
```

# SSLの運用について
SeasideをSSLで運用する際には、ApacheやNginxのSSLプロキシを利用することをおすすめします。Smalltalk側でもSSL通信ができますが、少しパフォーマンスが心配なところがあります。また、SSLの運用で気をつけることはセッションのCookie化した際にSecure属性を付けることです。SSL運用をしても、Secure属性がないとセッションの盗聴の恐れがあります。

Secure属性は以下のコードで設定できます。

```smalltalk
| app |
app := (WAAdmin register: self asApplicationAt:'app')
	preferenceAt: #sessionClass put: MSession;
	yourself.
app preferenceAt: #trackingStrategy put: WACookieOnlySessionTrackingStrategy new.		
app preferenceAt: #serverProtocol put: 'https'.
```

Chromeのデベロッパーツール > Resources > Cookies > Secure でクッキーのSecure属性にチェックが付いていれば、Secure属性になっています。HTTP, HTTPSの両方で動くようなアプリケーションの場合は少し工夫がいりますが、最近では常時SSL運用も一般的になりつつあるので、常時SSL運用にしてしまうとよいでしょう。

![スクリーンショット 2014-12-17 13.50.54.jpg](https://qiita-image-store.s3.amazonaws.com/0/18287/595671d4-d629-99f2-42bb-73d8ae2edbcb.jpeg)


# マルチイメージでの運用
Pharo SmalltalkのVM開発は進んでいるため処理自体は速いのですが、中規模、大規模サービスになると１イメージでの運用は心配です。そこで、ポートを変えて複数のイメージを起動し、高負荷にも耐えれる運用を実現します。以下にApacheとNginxの設定について紹介しておきます。

![m-server.jpg](https://qiita-image-store.s3.amazonaws.com/0/18287/1d9f0711-c83c-498f-0f37-0c876a2107e6.jpeg)

ポイントとしてはSeasideはセッションの共有ができないため、ロードバランサーで運用する際には、同じサーバー（アプリ）で処理必要があります。sticky sessionをすることで実現します。

```apache:Apache
<VirtualHost *:80>
    ProxyPreserveHost On
    ProxyRequests Off
    ProxyStatus On
    ServerName exmaple.com
    ServerAlias exmaple.com
    DocumentRoot /home/ec2-user/public_html
    Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
    <Proxy balancer://mycluster>
      BalancerMember http://localhost:8080 route=first loadfactor=10
      BalancerMember http://localhost:8081 route=second loadfactor=10
      ProxySet stickysession=ROUTEID
    </Proxy>
    RewriteEngine On
    # applicationNameはSeasideのApplication Nameを指定すること
    RewriteRule ^/(applicationName.*)$ balancer://mycluster/$1 [P,L]
</VirtualHost>
```

Nginxはsticky sessionの機能が標準にないため、モジュールを追加する必要があります。

```nginx:Nginx
upstream app {
    sticky;
    server localhost:8080;
    server localhost:8081;
}

server {
    client_max_body_size 25M;
    client_body_buffer_size 128k;
    listen       80;
    server_name  example.com;

    location / {
        root   /home/ec2-user/public_html;
        index  index.html index.htm;
    }

    # applicationNameはSeasideのApplication Nameを指定すること
    location /applecationName {
        proxy_intercept_errors on;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_host;
        proxy_redirect   off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass_header 'Access-Control-Allow-Origin';
        proxy_pass http://app;
    }

}
```

# ELBでの運用
Pharo SmalltalkとSeasideでクラウドサービスを立ち上げる人もいるかもしれませんので、Amazon Web ServiceのELB(Elastic Load Balancing)を用いた運用も紹介します。

![elb.jpg](https://qiita-image-store.s3.amazonaws.com/0/18287/f8dfd7ce-7c6f-c3a0-8e72-7b5605409103.jpeg)

マルチイメージ運用と同じですが、負荷分散する際に同じサーバー（アプリサーバー）が処理するように設定をします。
AWS Management ConsoleのEC2 DashBoardのLoad Balancersを選択。Port ConfigurationのEditをクリック。「Enable Application Generated Cookie Stickiness」を選択して、Cookie Nameを_sとしましょう。これでアプリケーションのCookieを用いてセッション維持することが可能です。

![elb2.png](https://qiita-image-store.s3.amazonaws.com/0/18287/1ec88133-7c2d-f124-221e-1fdae4d8d4ed.png)

# GUIなしの起動方法

サーバーでウェブアプリとしてPharoを起動する場合、GUIをオフして起動するケースが多いため紹介します。サーバーがLinuxで公式サイトのVM（ http://pharo.org/download ）を利用している場合、起動シェル内の`-vm-display-X11`を`-vm-display-null`に変更します（以下は変更後のシェル）。

```bash:pharo3.0/pharo
#!/bin/bash

# path
DIR=`readlink -f $0` #resolve symlink
ROOT=`dirname $DIR` #obtain dir of the resolved path
LINUX="$ROOT/bin"
RESOURCES="$ROOT/shared"
ICONS="$ROOT/icons"

# icon (note: gvfs-set-attribute is found in gvfs-bin on Ubuntu
# systems and it seems to require an absolute filename)
gvfs-set-attribute \
	"$0" \
	"metadata::custom-icon" \
	"file://$ICONS/Pharo.png" \
		2> /dev/null

# zenity is part of GNOME
image_count=`ls "$RESOURCES"/*.image 2>/dev/null |wc -l`
if [ "$1" == "" ]; then 
	if which zenity &>/dev/null && [ "$image_count"  -ne 1 ]; then
		image=`zenity --title 'Select an image' --file-selection --filename "$RESOURCES/" --file-filter '*.image' --file-filter '*'`
	else
		image="$RESOURCES/Pharo3.0.image"		
	fi
else
	image=$*
fi


# execute
exec "$LINUX/pharo" \
	--plugins "$LINUX" \
	--encoding utf8 \
	-vm-display-null \
	$image
```

起動するには以下のコマンドを実行します。
*Pharo3.0よりコマンドラインでも実行できるようになったため、起動時にオプションの設定が必要になりました。*

```bash:Pharo3.0
./pharo3.0/pharo ./Pharo3.0.app/Contents/Resources/Pharo3.0.image --no-quit
```


# まとめ
Seasideの一般的な公開方法について説明してきました。セッションのCookie化、SSLの方法、マルチイメージ運用による負荷分散、クラウドサービスを用いた負荷分散などを知っていれば、Seasideを使ったサービスも可能なはずです。SeasideはSmalltalkらしいWeb Frameworkだと思っております。可能な限りSmalltalkで作るを徹底したところが、個人的には気に入っているところでもあります。ただ、Seaside自体はどんどん巨大なフレームワークなりつつありますし、今時のWebサービスを作る際には少し物足りなさも感じるところもあったりします。Smalltalk開発者の中には新しいWeb Frameworkの開発もしていたりしておりますので、注目しておくとよいでしょう。

#参考

HTTPSを使ってもCookieの改変は防げないことを実験で試してみた - 徳丸浩の日記
http://blog.tokumaru.org/2013/09/cookie-manipulation-is-possible-even-on-ssl.html

Sticky Sessions - Elastic Load Balancing 
http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/US_StickySessions.html

第68回Smalltalk勉強会
http://www.smalltalk-users.jp/Home/gao-zhi/dai68kaismalltalkbenkyoukai