VagrantとChefでサーバーサイドSwiftの実行環境を構築する


仕事ではSwiftでiOSアプリを開発しているエンジニアです。

最近Swift製のWebアプリケーションフレームワークが続々出てきているので、
いつでもサーバーサイドでSwiftが実行できるように環境の準備をしてみます。

今回はVagrant+ChefでUbuntu15.10の仮想環境にSwiftの実行環境を構築します。


# Swiftが実行できる環境
[公式サイト](https://swift.org/download/#linux)によると現在（2016.2）Swiftをサーバーサイドで動かすことができる環境は以下のようです。

> Ubuntu 14.04 or 15.10 (64-bit)

# 仮想環境の構築
早速環境構築の準備を始めます

## 最終的に
以下のコマンドを実行するだけでSwiftの動くサーバーを構築できるようになります

```sh
$ vagrant halt # 停止
$ vagrant destroy # 破棄

$ vagrant up # 起動
$ bundle exec knife zero bootstrap server_name -N node_name --sudo
$ bundle exec knife node run_list add node_name swift
$ bundle exec knife zero converge 'name:node_name' -a knife_zero.host
```

## Vagrantの初期化
[こちら](https://cloud-images.ubuntu.com/vagrant/wily/current/)からUbuntu15.10のBox(Vagrant用OSイメージ）を取得できるので、vagrantコマンドで追加&初期化をします。

```sh
$ vagrant box add ubuntu_15.10 https://cloud-images.ubuntu.com/vagrant/wily/current/wily-server-cloudimg-amd64-vagrant-disk1.box
$ vagrant init ubuntu_15.10
$ vagrant up
```

vagrant upで起動に成功したら、vagrant sshで仮想環境にログインできるようになります。

※ VirtualBoxとVagrantがインストールされていなければ以下からインストールができます。
> VirtualBoxDL: https://www.virtualbox.org/wiki/Downloads
> VagrantDL: https://www.vagrantup.com/downloads.html

## SSHの設定
swifty_serverという名前でSSHできるようにしておきます

```sh
$ vagrant ssh-config --host swifty_server >> ~/.ssh/config
$ ssh swifty_server
welcome to Ubuntu 15.10 (GNU/Linux 4.2.0-27-generic x86_64)

 * Documentation:  https://help.ubuntu.com/

  Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

0 packages can be updated.
0 updates are security updates.
```

ログインに成功しました！

# Swift実行環境の構築
続いてSwiftを実行できる状態にするための作業に移ります。

## Chefのインストール
Chef Zeroを利用するので、knife-zeroも合わせてインストールします

```sh
$ bundle init
$ vim Gemfile
Gemfile
-------
gem ‘chef'
gem ‘knife-zero'

$ bundle install --path vendor/bundle
```

## Chef Zero Local Modeの設定

```sh
$ knife configure
$ vim ~/.chef/knife.rb
local_mode true # この一行を加える
```

## ChefリポジトリとSwiftクックブックの作成

```sh
$ chef generate repo chef-repo
$ cd chef-repo
$ bundle exec knife cookbook create swift
```

## ノードの初期化

```sh
$ bundle exec knife zero bootstrap swifty_server -N swifty_node --sudo
$ bundle exec knife node run_list add swifty_node swift
```

## 必要なライブラリのインストール
`/chef-repo/cookbooks/swift/recipes/default.rb`

```ruby
# $ apt-get update
execute "apt-get-update" do
  command "apt-get update"
end

# $ apt-get install clang libicu-dev
libraries = ["clang", "libicu-dev"]
libraries.each do |lib|
  package lib do
    action :install
  end
end
```

## Swiftを入手
[こちら](https://swift.org/download/#latest-development-snapshots)から入手できます。

Swiftのファイルは時間が経つと新しいものに置き換わってリソースがなくなっている可能性があるので、cookbooks/swift/files/default下にファイルをダウンロードしておき、サーバーには展開だけします

```sh
$ wget https://swift.org/builds/swift-2.2-branch/ubuntu1510/swift-2.2-SNAPSHOT-2016-02-08-a/swift-2.2-SNAPSHOT-2016-02-08-a-ubuntu15.10.tar.gz -P cookbooks/swift/files/default
$ wget https://swift.org/builds/swift-2.2-branch/ubuntu1510/swift-2.2-SNAPSHOT-2016-02-08-a/swift-2.2-SNAPSHOT-2016-02-08-a-ubuntu15.10.tar.gz.sig -P cookbooks/swift/files/default
```

`/chef-repo/cookbooks/swift/recipes/default.rb`

```ruby
swift_snapshot = "swift-2.2-SNAPSHOT-2016-02-08-a-ubuntu15.10"
filenames = [
  "#{swift_snapshot}.tar.gz",
  "#{swift_snapshot}.tar.gz.sig"
]

filenames.each do |filename|
  cookbook_file filename do
    source filename
    path "/usr/local/src/#{filename}"
  end
end
```

## 署名とSwiftの展開を行う
必要な署名を行った後、Swiftを解凍してPATHが通るように準備しておきます

```ruby
bash "setup" do
  code <<-EOH
    wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
    gpg --keyserver hkp://pool.sks-keyservers.net --refresh-keys Swift
    gpg --verify /usr/local/src/#{swift_snapshot}.tar.gz.sig
    tar xzf /usr/local/src/#{swift_snapshot}.tar.gz -C /usr/local/src
    echo 'PATH=$PATH:/usr/local/src/#{swift_snapshot}/usr/bin' >> ~/.profile
  EOH
end

```

## レシピの適用
最後に、作成したレシピをknifeコマンドで仮想環境に適用します

```sh
$ bundle exec knife zero converge 'name:swifty_node' -a knife_zero.host
```

少し時間がかかりますが、待つこと数分…

```sh
swifty_server Running handlers:
swifty_server Running handlers complete
swifty_server Chef Client finished, 6/6 resources updated in 339.485214707 seconds
```

実行が完了しました！

サーバーにログインしてSwiftが実行できるか確認してみます。

```sh
$ ssh swifty_server
$ swift
Welcome to Swift version 2.2-dev (LLVM ee6c2618e5, Clang 9b95f4af98, Swift d45cca1dc1). Type :help for assistance.
  1> print("hello, world!!!")
hello, world!!!
  2>  
```

Swiftが実行できました！！

今回はSwift2.2のスナップショットを利用しましたが、フレームワークによっては「Latest Development Snapshots」を利用しないと動かないものもあるみたいです。
その場合は適宜cookbooks/swift/files/default下に置いておくファイルと、swift_snapshotのファイル名を置き換えて実行すればOKです。

### GitHub
ソースはこちらに置いてあります
https://github.com/chocoyama/SwiftyChefRepository

```ruby
#
# Cookbook Name:: swift
# Recipe:: default
#
# Copyright 2016, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#
execute "apt-get-update" do
  command "apt-get update"
end

libraries = ["clang", "libicu-dev"]
libraries.each do |lib|
  package lib do
    action :install
  end
end

swift_snapshot = "swift-2.2-SNAPSHOT-2016-02-08-a-ubuntu15.10"
filenames = [
  "#{swift_snapshot}.tar.gz",
  "#{swift_snapshot}.tar.gz.sig"
]

filenames.each do |filename|
  cookbook_file filename do
    source filename
    path "/usr/local/src/#{filename}"
  end
end

bash "setup" do
  code <<-EOH
    wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
    gpg --keyserver hkp://pool.sks-keyservers.net --refresh-keys Swift
    gpg --verify /usr/local/src/#{swift_snapshot}.tar.gz
    tar xzf /usr/local/src/#{swift_snapshot}.tar.gz -C /usr/local/src
    echo 'PATH=$PATH:/usr/local/src/#{swift_snapshot}/usr/bin' >> ~/.profile
  EOH
end
```