Link-U＋fabistrano（デプロイツール）の紹介

# ご挨拶

[Link-U](https://www.link-u.co.jp)の技術開発部の部長をやっております土屋と申します。
サーバーサイド担当でAPIや管理画面の開発を主に行っています。

Link-Uでは今年から技術開発部のメンバーでアドベントカレンダーをやることにしました。
今回やろうと決めた理由としては１人１記事書けるだけのメンバーが揃ってきたというのと、
今まで特にアウトプットをしていないのもあり弊社を知って頂く一つのきっかけになれば良いなと思って企画しました。

技術開発部は

* クライアント班（スマホネイティブアプリやWebフロント）
* インフラ班（サーバー機器、ネットワークなど）
* サーバー班（API、管理画面など）

の３つに分かれており今回参加してくれるメンバーも各班からお願いしました。
皆がどういうことを書いてくれるのか楽しみにしています。

とりあえず先頭バッターとして私の方では内製ツールの紹介をしていきます。

# fabistranoの紹介

Fabric + Capistrano から名前を取っておりそれらの機能を元に開発したデプロイツールです。
なぜPythonを選んだかと言うと

* Ubuntuで標準インストールされている
* ansibleを使うためやっぱりインストールされている
* プラグインが書きやすい
* インストールが簡単
* PHPのサービスが多いのでデプロイ時に差分やブランチを確認したい

特に最後のは重要でした。
今でこそデプロイも自動化されつつありますが、複数人で開発していると誰がどのブランチをデプロイしているのか、どこまでデプロイしているのかわからないことが多々ありました。下の方でもう少し詳しく書きます。

## インストール方法

fabistranoはpipでインストール出来ます（privateリポジトリなので関係者じゃないとDLできませんが）

```
$ pip install git+ssh://git@github.com/link-u/fabistrano.git
```

## 依存ライブラリ

### colorful

[https://github.com/timofurrer/colorful](https://github.com/timofurrer/colorful)

CLIの表示をわかりやすくするために利用しています。

### PyYAML

[https://github.com/yaml/pyyaml](https://github.com/yaml/pyyaml)

各サーバーへの接続情報はYAML形式で設定しています。

### click

[https://click.palletsprojects.com/en/7.x/](https://click.palletsprojects.com/en/7.x/)

コマンドのオプションの管理やサブコマンド化をするのが楽なので利用しています。


## 機能紹介

### デプロイ先どういう状態問題

例えばdev環境を一時的に別のブランチに切り替えたいとか問題解決のため一瞬だけ何か修正を入れたいとかそういうケースがあると思います。
PHPの場合はスクリプト言語なので設置されているファイルの通りに動きます。そのためサーバーにログインし、直接編集することもあると思います。

複数人による作業や様々な環境依存による問題が発生する開発現場において、fabistranoでは極力事故を無くす為の機能が備わっています。

### デプロイ先が環境別に記載されているconfig

IPやポートを間違えると他のサービスに影響を出してしまう可能性があります。プロジェクトで共有が出来る形になっており、デプロイ時はaliasを指定するだけです。
![スクリーンショット 2020-11-30 23.11.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11796/12078b7e-5c07-fe44-7f60-134308edcea2.png)

### git status確認機能

gitのコミット漏れやpush忘れがあった場合に、警告を出してくれます。
![スクリーンショット 2020-11-30 23.17.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11796/ded91bcf-52c1-546b-9fc2-5d8d1f45beb8.png)


### branch確認機能

既にデプロイされているリモートホストのbranchとこれからデプロイしようとしているbranchが違う時に警告を出します。
![スクリーンショット 2020-11-30 23.12.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11796/8f79b97e-0f3e-4b15-8310-5fe225bb8046.png)

### 差分確認機能

削除されたファイルや変更のあったファイルの一覧が色付きで表示されます。
![スクリーンショット 2020-11-30 23.13.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11796/8732faaf-ad52-1fb2-adc4-c652c203cf80.png)

### 差分詳細確認機能

実際の変更内容を見れます。
![スクリーンショット 2020-11-30 23.38.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11796/3d745df7-ed7e-b815-3fe5-9f4b3f2b2de0.png)

### デプロイした日時や人（git configの情報）を記録

よくわからない差分を見つけた時に誰に聞けば良いのかすぐにわかります。

### プラグインによる機能拡張

管理画面などはwebpackでJSをビルドしないといけなかったりします。
それらをデプロイコマンドにインクルードすることが出来ます。
そうすることで必ず必要なビルド作業を強制させることが出来ます。

#### デプロイコマンドを上書きする例

```python:deploy.py
# -*- coding: utf-8 -*-
import click
import invoke

import fabistrano
from fabistrano.commands.deploy import deploy as orig_deploy


@click.command(help=u'APPデプロイを行う')
@fabistrano.deploy_options
@click.option('--skip-build', help=u'yarn build をスキップします', is_flag=True, default=False)
@click.option('--skip-composer', help=u'composer installをスキップします', is_flag=True, default=False)
@click.pass_context
def deploy(ctx, config, ignore_git, ignore_diff, force, apply_force, skip_composer, skip_build):
    """
    通常のデプロイ操作に加えてcomposer install, buildを行う
    """

    if not skip_build:
        c = invoke.Context()
        with c.cd(config.env.local_root_dir + '/front-end'):
            c.run('yarn build', pty=True)

    # --no-devオプションを付与しない環境名のリスト
    dev_envs = []

    if not skip_composer:
        c = invoke.Context()
        if config.env.env_name in dev_envs:
            with c.cd(config.env.local_root_dir):
                c.run('COMPOSER_VENDOR_DIR=vendor ./composer.phar install', pty=True)
        else:
            with c.cd(config.env.local_root_dir):
                c.run('COMPOSER_VENDOR_DIR=vendor-no-dev ./composer.phar install --no-dev', pty=True)

    kwargs = {
        'config': config,
        'ignore_git': ignore_git,
        'ignore_diff': ignore_diff,
        'force': force,
        'apply_force': apply_force,
    }
    ctx.invoke(orig_deploy, **kwargs)

```

所定のディレクトリに `[コマンド名].py` と言うファイルを配置すると自動的にコマンド化してくれます。
既存のコマンドを上書き出来たり新規コマンドを簡単に追加することが出来たりします。
ただしこの機能はあまり使われておらず開発者である自分も使っていません:innocent:


## まとめ

ざっくりですがfabistranoの紹介をさせて頂きました。
いつかローカライズ対応してオープンソース化出来たら良いなと思っております。

Link-Uではサービスはもとより、内製ツールも作れる人を募集しています。
興味を持って頂けた方は弊社の採用ページよりご応募下さい！
[https://www.link-u.co.jp/recruit/](https://www.link-u.co.jp/recruit/)