Vagrant仮想環境に Yesod-MySQL をインストール

HaskellのwebフレームワークYesodを使いこなすべく、気軽にいじれる環境が欲しかったので、
vagrant up一発で立ち上がることを目標に、仮想環境を作ってみました。

Yesodは、お世辞にもメジャーとは言えないですが、
この記事が敷居を下げる一助になれば幸いです。

daemon化するにあたっては、nginxやketerが必要なのですが、
今回はsshログイン後、フォアグラウンドでコマンドを叩いてのサーバー起動までを行います。

公式の[yesodチュートリアル](https://www.yesodweb.com/page/quickstart)では、関連する手順をシンプルに説明するためにsqliteを使っていましたが、
あえてMySQLを使ってみます。

vagrantfileとprovision.shですぐに環境を手に入れたい方は[こちら](https://qiita.com/rs06042/items/5424538a5769c51fab3c#vagrantfile--provisionsh%E3%81%AB%E3%82%88%E3%82%8B%E8%87%AA%E5%8B%95%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA)

# 前提条件
Vagrant と VirtualBoxがインストールされていること

# 手順

### 1. 準備
適当な場所に仮想環境用のディレクトリを作ります。

```
$ mkdir yesod-demo
$ cd yesod-demo
```

### 2. Vagrantfile

ベースとなるVagrantfileを生成します。

```bash
$ vagrant init
```


```ruby:Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://vagrantcloud.com/search.
  config.vm.box = "bento/centos-7.3"

  # ~ 中略 ~

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  config.vm.network "private_network", ip: "192.168.33.10"

  # ~ 中略 ~

  # config.vm.provision "shell", inline: <<-SHELL
  #   apt-get update
  #   apt-get install -y apache2
  # SHELL
end
```

上記設定で、
config.vm.boxで仮想環境のOSを CentOS7.3に、
ホストOSからアクセスできるIPアドレスを 192.168.33.10 に設定したら、

```bash
$ vagrant up
```

を実行し、Vagrant環境を起動します。
起動完了後、以下を実行して、仮想環境にログインします。

```bash
$ vagrant ssh
```

### 3. MySQLインストール
仮想環境にログインしてから行う作業は、大きく分けると以下の4つになります。
1. MySQLインストール
2. Stack（Haskellのビルドツール）インストール
3. Yesod（Haskellのwebフレームワーク）インストール
4. ビルド実行＆サーバーの起動

まず、 MySQLをインストールします。

```bash
$ sudo yum install http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm
$ sudo yum install mysql mysql-devel mysql-server
```

インストールが完了したら、デーモンを起動します。

```bash
$ sudo service mysqld start
```

初期パスワードをインストールログから取得し、
いったんrootユーザーのパスワードを期限なしの指定文字列に変更しています。

```bash
$ DB_PASSWORD=$(grep "A temporary password is generated" /var/log/mysqld.log | sed -s 's/.*root@localhost: //')
$ mysql -uroot -p${DB_PASSWORD} --connect-expired-password -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'rsYesodServer_2019'; flush privileges;"
```

webサーバからアクセスするためのDBを作成し、ユーザーと権限を設定します。

```bash
$ mysql -uroot -prsYesodServer_2019 -e "CREATE DATABASE yesod_db CHARACTER SET utf8mb4;"
$ mysql -uroot -prsYesodServer_2019 -e "GRANT ALL PRIVILEGES ON yesod_db.* TO 'rsyesodserver'@'%' IDENTIFIED BY 'UgwD9_hwn3'"
```

これでひとまず、DBの設定は完了になります。



### 4. Stack & Yesod のインストール

[Stack](https://docs.haskellstack.org/en/stable/README/)のインストールは、下記コマンド1発で終わります。

```bash
$ curl -sSL https://get.haskellstack.org/ | sh
```

Yesod の前に、依存ライブラリをインストールします。

```bash
$ sudo yum install zlib-devel pcre-devel
```

入れ終わったら、下記コマンドで、Yesodをダウンロードします。

```bash
$ stack new rsyesodserver yesod-mysql 
$ cd rsyesodserver
$ stack install yesod-bin --install-ghc
```
15分近くかかるので、気長に待ちましょう。

### 5. ビルド & サーバ起動

DB接続のための環境変数を設定します。

```bash
$ export YESOD_MYSQL_USER='rsyesodserver'
$ export YESOD_MYSQL_PASSWORD='UgwD9_hwn3'
$ export YESOD_MYSQL_HOST='localhost'
$ export YESOD_MYSQL_DATABASE='yesod_db'
```

入力が面倒であれば、上記コマンドを ~/.bashrc などに記述するか、

~/rsyesodserver/config/settings.ymlを開き、以下の箇所を設定してください。

```yaml:~/rsyesodserver/config/settings.yml
database:
  user:     "_env:YESOD_MYSQL_USER:reyesodserver"
  password: "_env:YESOD_MYSQL_PASSWORD:UgwD9_hwn3"
  host:     "_env:YESOD_MYSQL_HOST:localhost"
  port:     "_env:YESOD_MYSQL_PORT:3000"
  # See config/test-settings.yml for an override during tests
  database: "_env:YESOD_MYSQL_DATABASE:yesod_db"
  poolsize: "_env:YESOD_MYSQL_POOLSIZE:10"

```




```bash
$ stack build
```

で、ビルドしたら、以下を実行します。



```bash
$ stack exec -- yesod devel
```

これで、無事サーバを起動することが出来ました！
好きなブラウザから、 http://192.168.33.10:3000 にアクセスすると、ページが開きます。

# Vagrantfile / provision.shによる自動セットアップリポジトリ

おもに自分用ですが、Vagrantfile と provision.shを使って、サーバー起動以外の部分を自動化したものを用意しました。
適当なところで以下のコマンドを叩き、リポジトリからソースをダウンロードしてください。

```bash
$ git clone https://github.com/rs0604/yesod-demo.git
$ cd yesod-demo
$ vagrant up
```

20分くらいかけて、MySQL, stack, yesod のインストールが自動で行われます。
その後、

```bash
$ vagrant ssh
```
でログインし、[こちら](https://qiita.com/rs06042/items/5424538a5769c51fab3c#5-%E3%83%93%E3%83%AB%E3%83%89--%E3%82%B5%E3%83%BC%E3%83%90%E8%B5%B7%E5%8B%95)の方法でDB接続設定を行い、

```bash
$ cd rsyesodserver
$ stack exec -- yesod devel
```
を実行すると、サーバが立ち上がります。


### vagrant up 時に "/sbin/mount.vboxsf: mounting failed with the error: No such device"と表示されて失敗する場合

参考：https://qiita.com/chubura/items/4166585cf3f44e33271d

ホスト-ゲスト間のフォルダ共有の仕組み（Guest Addition）のバージョン不一致によるエラーです。
自動でバージョンアップを行うプラグインvagrant-vbguestをインストールするために以下コマンドを試みてください。

```bash
$ vagrant plugin install vagrant-vbguest && vagrant vbguest && vagrant up
```

### TODO
* 共有フォルダなどの設定
* keter による daemon 化
* SSL通信など、「まともなサーバが当たり前にやっていること」を一通り設定する