Ansistranoでデプロイしてみる

# Ansistranoとは
[Capistrano](https://capistranorb.com/)ライクにデプロイできるAnsibleロール。
yamlファイルにデプロイフローを書くことで簡単にデプロイができます。
Ansistranoは[Ansible Galaxy](https://galaxy.ansible.com)から入手可能です。

**※Ansible Galaxyとは**
[Ansible Galaxy](https://galaxy.ansible.com)とはAnsibleのロールを共有できるホスティングサービスのこと。

## 色々なデプロイ方法に対応
アプリケーションをデプロイする方法を色々提供しています。

- scp
- rsync
- git
- svn
- hg
- HTTPダウンロード
- S3 get

## バージョン管理を行える
アプリケーションのバージョンを指定した数まで保持することができます。これにより、過去のバージョンへの切り戻し（ロールバック）が簡単に行えます。
また、アプリケーションのバージョン数が指定した数を超えると、最古のバージョンのものが削除されていきます。これにより、サーバのディスクスペースを食い尽くしません。

## ロールバックが可能
コマンド一つで簡単にロールバック可能です。

## デプロイの各ステップ前後に処理を挟める
後述しますが、Ansistranoはデプロイフローが決められています。デプロイフローは5つのステップで構成されており、それぞれのステップの前後には任意の処理を挟むことができます。

# 使い方
## 使用したバージョン
以下のバージョンを前提に記載しています。

|ツール・ロールなど|バージョン|
|:-:|:-:|
|ansistrano.deploy|3.4.0|
|ansistrano.rollback|3.0.0|
|ansible-playbook|2.9.6|

## インストール
Ansible Galaxyからデプロイ用とロールバック用のAnsistranoロールをインストールします。

```shell
$ ansible-galaxy install ansistrano.deploy ansistrano.rollback
```

## デプロイplaybook作成
以下はgit cloneでアプリケーションを取得してそれを配置している例です。

```deploy.yml
---
- hosts: webserver
  remote_user: vagrant
  become: yes

  vars:
    ansistrano_deploy_to: /var/www/my-app
    ansistrano_keep_releases: 5
    ansistrano_deploy_via: git # ここをgitにする
    ansistrano_git_repo: git@github.com:kawakawaryuryu/my-app.git
    ansistrano_git_branch: master
    ansistrano_git_identity_key_path: ~/.ssh/id_rsa
  roles:
    - ansistrano.deploy # デプロイ用のAnsistranoロールを指定する
```

## 実行（デプロイ）

```shell
$ ansible-playbook -i dev.yml deploy.yml
```

これだけ！

# デプロイ後
デプロイ後のディレクトリ構造は以下のようになります。

```
-- /var/www/my-app.com
|-- current -> /var/www/my-app.com/releases/20100512131539
|-- releases
|   |-- 20100512131539
|   |-- 20100509150741
|   |-- 20100509145325
|-- shared
|-- repo
```
それぞれのディレクトリの意味合いは以下の通りです。

|ディレクトリ|内容|
|:-:|:-:|
|current|現在のアプリケーションコードを格納する<br>releasesディレクトリ配下の最新のバージョンに対してシンボリックリンクを貼っている|
|releases|リリース日時ごとにアプリケーションコードを格納する<br>アプリケーションコードの数は`ansistrano_keep_releases`で指定した数を上限とする|
|shared|releasesディレクトリの共通アセットを格納する|
|repo|gitで取得したソース(リポジトリ)を格納する|

# デプロイplaybook
基本的に書くことは以下の2つです。

- rolesに`ansistrano.deploy`を指定する
- varsに`ansistrano~`の変数を定義する

varsに定義する変数は[こちら](https://github.com/ansistrano/deploy#role-variables)を参照してください。

例1: デプロイ先でgit cloneしてアプリケーションを配置するplaybook

```deploy.yml
---
- hosts: webserver
  remote_user: vagrant
  become: yes

  vars:
    ansistrano_deploy_to: /var/www/sample-spring-boot
    ansistrano_keep_releases: 5
    ansistrano_deploy_via: git # ここをgitにする
    ansistrano_git_repo: git@github.com:kawakawaryuryu/sample-spring-boot.git
    ansistrano_git_branch: master
    ansistrano_git_identity_key_path: ~/.ssh/id_rsa # git pullするためのssh秘密鍵のあるローカルのパス
  roles:
    - carlosbuenosvinos.ansistrano-deploy
```

例2: rsyncでローカルからサーバーに対してデプロイするplaybook

```deploy.yml
---
- hosts: webserver
  remote_user: vagrant
  become: yes

  vars:
    ansistrano_deploy_from: tmp/target/sample-spring-boot-1.0-SNAPSHOT.jar
    ansistrano_deploy_to: /var/www/sample-spring-boot
    ansistrano_keep_releases: 5
    ansistrano_deploy_via: rsync
    ansistrano_before_update_code_tasks_file: create-jar.yml
    ansistrano_after_cleanup_tasks_file: cleanup.yml
  roles:
    - ansistrano.deploy
```

# デプロイフロー
Ansistranoはデプロイのフローが決められており、以下のようになっています。
![Main workflow](https://raw.githubusercontent.com/ansistrano/deploy/master/docs/ansistrano-flow.png)

|フェーズ|内容|
|:-:|:-:|
|Setup|releasesディレクトリ配下にリリース日時を名前としたディレクトリを作成する|
|Update Code|アプリケーションをreleasesディレクトリに配置する|
|Symlink Shared|releasesディレクトリ配下のファイルやディレクトリのシンボリックリンクをsharedディレクトリ配下のファイルやディレクトリに向ける|
|Symlink|デプロイ後currentディレクトリのシンボリックリンクを最新のreleasesディレクトリ配下のものに向ける|
|Clean Up|releasesディレクトリ以下の最古のものを削除する<br>これは`ansistrano_keep_releases`で指定した数を超えた場合に実行される|

またそれぞれのフェーズの前後にbefore〜とafter〜というフェーズがあり、任意のタスクを挿入することができます。
例えば先程の例2のデプロイplaybookではUpdate Codeの前に`create-jar.yml`、Clean Upの後に`cleanup.yml`内に書かれているタスクを実行しています。

```deploy.yml
---
- hosts: webserver
  remote_user: vagrant
  become: yes

  vars:
    ansistrano_deploy_from: tmp/target/sample-spring-boot-1.0-SNAPSHOT.jar
    ansistrano_deploy_to: /var/www/sample-spring-boot
    ansistrano_keep_releases: 5
    ansistrano_deploy_via: rsync
    ansistrano_before_update_code_tasks_file: create-jar.yml # Update Code前に処理を挟む
    ansistrano_after_cleanup_tasks_file: cleanup.yml # Clean Up後に処理を挟む
  roles:
    - ansistrano.deploy
```

**create-jar.yml:**
gitからリポジトリをcloneしてソースコードをビルドしてjarを生成する

```create-jar.yml
---
- block:
  - name: clone project
    git:
      repo: git@github.com:kawakawaryuryu/sample-spring-boot.git
      dest: tmp
  - name: build jar
    command: mvn clean package
    args:
      chdir: tmp
 
  delegate_to: localhost 
  run_once: true
  become_user: "{{ dev_user }}"
```

**cleanup.yml:**
`create-jar.yml`で生成したtmpディレクトリを削除する

```cleanup.yml
---
- name: delete tmp directory
  file:
    path: tmp
    state: absent
  delegate_to: localhost 
  become_user: "{{ dev_user }}"
```

# ロールバック
アプリケーションを一つ前にリリースした状態に戻すことができます。
最新のリリースバージョンは削除されます。

ロールバック前

```
-- /var/www/my-app.com
|-- current -> /var/www/my-app.com/releases/20100512131539
|-- releases
|   |-- 20100512131539
|   |-- 20100509150741
|   |-- 20100509145325
|-- shared
|-- repo
```
ロールバック後

```
-- /var/www/my-app.com
|-- current -> /var/www/my-app.com/releases/20100509150741
|-- releases
|   |-- 20100509150741
|   |-- 20100509145325
|-- shared
|-- repo
```
## ロールバックplaybook
デプロイと同様に基本的に書くことは以下の2つです。

- rolesに`ansistrano.rollback`を指定する
- varsに`ansistrano~`の変数を定義する


varsに定義する変数は[こちら](https://github.com/ansistrano/deploy#rolling-back)を参照。

```rollback.yml
---
- hosts: webserver
  remote_user: vagrant
  become: yes

  vars:
    ansistrano_deploy_to: /var/www/sample-spring-boot
  roles:
    - ansistrano.rollback # ロールバック用のAnsistranoロールを指定する
```

## 実行

```shell
$ ansible-playbook -i dev.yml rollback.yml
```

# サンプルソースコード
今回作成したPlaybookとアプリケーションのサンプルです。

- デプロイPlaybook
  - https://github.com/kawakawaryuryu/sample-spring-boot-infrastructure
- サンプルアプリケーション
  - https://github.com/kawakawaryuryu/sample-spring-boot

# 参考
- [ansistrano/deploy: Ansible role to deploy scripting applications like PHP, Python, Ruby, etc. in a capistrano style](https://github.com/ansistrano/deploy)
- [Ansistranoを利用して簡単にデプロイしよう(前編) – 株式会社 PIALab. (ピアラボ)](https://pialab.co.jp/technology/4901)
- [Ansistranoを利用して簡単にデプロイしよう(後編) – 株式会社 PIALab. (ピアラボ)](https://pialab.co.jp/technology/4915)
- [構成管理ツールで Ansible を使ってる人必見！デプロイするなら Ansistrano ロールを使おう！ - Qiita](https://qiita.com/kotarella1110/items/23ba0e1fb1eda974630c)
- [外部接続を絞られているあなたのための Ansistrano を使ったデプロイ環境構築 | GMOインターネット 次世代システム研究室](https://recruit.gmo.jp/engineer/jisedai/blog/ansistrano-in-enterprise-network/)