サーバーレスサーバーサイドSwiftとHexaville

## はじめに
こんにちは、tk1024です。
この前の金曜日に[Tokyo Server Side Swift Meetup #7](https://tokyo-ss-swift.connpass.com/event/56630/)が行われました。

その中でYuki Takei (noppoMan)さんが`Server Less Server Side Swift with Hexaville`という物を発表していたので今回も関連するMediumの記事を翻訳してみました。
元記事: [Serverless Server Side Swift with Hexaville](https://medium.com/@yukitakei/serverless-server-side-swift-with-hexaville-ef0e1788a20)

Google翻訳に毛が生えた程度なので誤字脱字・翻訳間違い等、コメントでも編集リクエストでも送っていただければ幸いです。

以下、翻訳
<hr>

# サーバーレスサーバーサイドSwiftとHexaville

Hello World.

自分で起こした会社でSwiftを使いサーバーサイド、クライアントサイドアプリケーションを書いています。この会社は自己資金を使い2人だけ(自分とco-founder/Engineer)で運営しています。充分な資金が無く潤沢なサーバーインスタンスも24時間サーバー立ち上げ続ける為に人を雇う余裕もありません。

ベンチャー企業をはじめるに当たり、このような状況でサーバーレスコンピューティングは１つの解決法だと期待しています。

## サーバーレスコンピューティング

>  <b>function as a service (FaaS)</b>として知られているサーバーレスコンピューティングはクラウド事業者がplatform as a service (PaaS)コンテナ内でリクエストに応じてコードを実行するモデルです。
 また仮想マシン毎ではなくリクエスト処理の実行時間で課金されるのでリソースにかかる支払額をより抽象的に測ることができます。

サーバーレスコンピューティングではコードが実行された場合のみ料金が発生します。(かなり安い)
これにより、サーバーインスタンスにかかる費用を気にする必要がなくなります。
そして多くの場合、クラウド事業者がサービスをフルマネージするので、スケーリングについて気にする必要もありません。

完璧に見えますが欠点もあります。
- クラウド事業者に縛られる
- クラウドサービスを使えなければならない
- クラウドサービスがダウンするとサービスもダウンする
- デプロイとルーティングを管理画面から操作する必要がある(Not programmatically)
- ミドルウェアとのコネクションを維持できない
- 同時並列実行にリミットがある(上限引き上げには申請が必要)

HexavilleはサーバーレスなSwift webアプリケーションを作るために作りました。同時に上に書いたいくつかの欠点も克服しています。

## Hexaville
Github: [noppoMan/Hexaville](https://github.com/noppoMan/Hexaville)

*Swiftの為のモダンなWebアプリケーションフレームワーク及びエンジン*

`Swiftで作られたwebアプリ`をlambdaとapi-gatewayで実行する事をコンセプトにしています。

これらは、Swiftのビルドとデプロイ、実際にlambdaのHexavilleフレームワーク上で実行するアプリケーション作る2つのレイヤーに分かれています。

## Hexavilleを使いサーバーレスアプリケーションの作成とクラウド上へのデプロイをする
これからHexavilleを使ってサーバーレスアプリケーションを実際にビルドしていきます。
インストールはすごく簡単です。クローンしてビルドする、それだけです。

以下に書くコマンドは全てMacで実行したものです。(El Capitan, Xcode 8.3.2)

### インストール

```bash
git clone https://github.com/noppoMan/Hexaville.git
cd Hexaville
swift build
```

### Hexavilleプロジェクトを生成する
まず、オプションなしでHexavilleを実行します。

```bash
./.build/debug/Hexaville
```

出力はこのようになります。

```
Available commands:

- generate            Generate initial project

- deploy              Deploy your application to the specified cloud provider

- routes              Show routes and endpoint for the API

- help                Prints this help information

- version             Prints the current version of this app
```

実行可能なコマンド(`Available commands`)を見てください。
そして、`generate`コマンドを実行して最初のHexavilleプロジェクトを初期化してください。

```
./.build/debug/Hexaville generate --dest /Users/name/Desktop/Hello
```

`generate`コマンド実行後には`Hello`ディレクトリが作られていると思います。中を覗いてみましょう！

```
/Users/name/Desktop
├── Hexavillefile.yml
├── Package.swift
└── Sources
    ├── RandomNumberGenerateMiddleware.swift
    └── main.swift

1 directory, 4 files
```

ディレクトリは一般的なSwift Package Managerプロジェクトの構成です。`swift package generate-xcodeproj`を実行する事で自動でxcodeprojを生成する事ができます。これはXcodeでHexavilleアプリケーションを開発できる事を意味します。

```bash

cd ~/Desktop/Hello
swift package generate-xcodeproj
open *.xcodeproj
```

このようにしてXcodeで開く事ができます。

### main.swift

![](https://cdn-images-1.medium.com/max/800/1*QM79dlh2WGWP-SFyc1BWGw.png)
`main.swift`の中にはHexavilleフレームワークのサンプルコードが書かれています。ExpressやSinatraと似ています。

編集しないでデプロイしてみます。

### Edit Hexavillefile.yml

Hexavillefile.ymlはHexavilleの設定ファイルです。

設定ファイルを開いて、credential, region, lambdaのroleを埋めてください。
(credential, region, passは環境変数として省略する事もできます)

```
name: test-app
service: aws
aws:
  credential:
    access_key_id: xxxxxxxxxxxxx
    secret_access_key: xxxxxxxxxxxxx
  region: us-east-1
  lambda:
    role: arn:aws:iam::xxxxx:role/xxxxxxxxxxxxx
    timout: 10
build:
  nocache: false
```

### Deploy
では、`deploy`コマンドでデプロイしましょう

```
/path/to/your/Hexaville/.build/debug/Hexaville deploy Hello
```

時間がかかるのでしばらく待ちます...

### ルーティング情報を取得する

次に、デプロイしたリソースを確認するためにルーティングを取得してみましょう。

```
/path/to/your/Hexaville/.build/debug/Hexaville routes
```

このように出力されます

```
Endpoint: https://{id}.execute-api.{region}/staging
Routes:
  GET    /hello
  GET    /random_img
  GET    /
  POST   /hello/{id}
  GET    /hello/{id}
```

### リソースにアクセス

curlでリソースのエンドポイントにアクセスします

```bash

curl https://{id}.execute-api.{region}/staging/

<html><head><title>Hexaville</title></head><body>Welcome to Hexaville!</body></html>
```

もしHTMLファイルをエンドポイントから取得できていれば、デプロイは成功です。

やったね！

## デプロイフローの詳細
実際にlambda上での動作を確認しましたが、lambdaは現在Swiftのランタイムをサポートしていません。では、どのようにしてlambda上でSwiftを実行してのか説明していきます。

はじめにデプロイフローの図をご覧ください。この図に従って何をしているのか説明していきます。

![](https://cdn-images-1.medium.com/max/800/1*mrU0YLdr9LFU9wG3SjDQOg.png)

`Build Swift on Docker`を見てください。
もし、SwiftをMac上でビルドしてバイナリをアップロードするとAmazon Linux上で実行するlambdaでは動きません。

なので、`Linux_x86`と互換性のあるバイナリをビルドするために`Docker for Mac`を使う必要があります。

そして、ビルドされたバイナリと関連するオブジェクトは`-v`オプションでdockerとホストマシンの共有ディレクトリにデプロイされます。

また、Linux上でSwiftのバイナリを実行するには以下の.soファイルが必要です。

```
/${SWIFTFILE}/usr/lib/swift/linux/*.so
/usr/lib/x86_64-linux-gnu/libicudata.so
/usr/lib/x86_64-linux-gnu/libicui18n.so
/usr/lib/x86_64-linux-gnu/libicuuc.so
/usr/lib/x86_64-linux-gnu/libbsd.so
```

これらをディレクトリにまとめて、zipファイルにした後にAWS S3にアップロードします。

また、Hexavilleアプリケーションのルーティングがapi-gatewayにそのまま反映されている事を不思議だと思いましたか？

Hexavilleフレームワークで作られたアプリケーションはコマンドラインアプリケーションとして実行できます。

```
Available commands:
- gen-routing-manif   Generate routing manifest file
- execute             Execute the specified resource. ex. execute GET /
- serve               Start Hexaville Builtin Server
- help                Prints this help information
- version             Prints the current version of this app
```

`gen-routing-manif`コマンドに注目してください。

このコマンドを一度、実行してみてください。
Hexavilleフレームワークアプリケーションからルーティング情報を抽出して`.routing-manifest.json`に出力します。

```..routing-manifest.json
{
  "routing" : [
    {
      "method" : "get",
      "path" : "\/"
    },
    {
      "method" : "get",
      "path" : "\/hello"
    },
    {
      "method" : "get",
      "path" : "\/hello\/{id}"
    },
    {
      "method" : "post",
      "path" : "\/hello\/{id}"
    },
    {
      "method" : "get",
      "path" : "\/random_img"
    }
  ]
}
```

.routing-manifest.json はapi-gatewayのRestAPIのパラメータをマップしたものです。

## Lambda上でどのようにしてSwiftを実行するのか
最後に、lambda上でどのようにしてSwiftのバイナリを実行するのか説明します。
![](https://cdn-images-1.medium.com/max/800/1*xxDMQUT2ERP2qoj_x5n9tA.png)
この図が示すようにNode.jsをlambdaのランタイムとして、Swiftバイナリをchild_processモジュールでプロセスとして生成しています。

生成後、オリジンプロトコルで子プロセスから親プロセスにパイプでメッセージを送っています。

## 追伸
どうでしたか？

Hexavilleはまだ幾つかの機能しかなくできることは多くありませんが、実際に動かしながらフィードバックを提供し続けていきたいと思います。

次は以下の機能を実装しようと考えています。
- ログ出力(Cloud watch logs -> Amazon Athena)
- VPCサポート
- カスタムドメインサポート
- バイナリメディアサポート

これらの機能があれば、実用的なWebアプリケーションを作成する選択肢の1つになると私は信じています。

## 訳者あとがき
Github: [noppoMan/Hexaville](https://github.com/noppoMan/Hexaville)
Twitter: [@noppoMan722](https://twitter.com/noppoMan722)
Connpass: [Tokyo Server Side Swift Meetup](https://tokyo-ss-swift.connpass.com/)