Bitbucket Pipelinesで継続的デプロイ

ソースコードの管理やテスト、デプロイがBitbucket内で閉じるのはミニマルで素敵なので、
サーバーにsshしてデプロイする作業を Pipelines にやらせます。

環境は linux(debian9)上に **Django(python) + nginx + uwsgi** です。

正確には、staging環境へのデプロイになっているので、継続的デリバリーの方が正しい気がしますが、
デプロイの方がイメージしやすそうなので、この記事タイトルにしています。
あと、以降のデプロイサーバーという記述は各自、リモートホストやstagingサーバー、productionサーバーに読み変えてください。


## 事前準備

デプロイサーバーはリポジトリのクローン、nginxやuwsgiの起動は済ませた状態です。


## プロジェクトのディレクトリ構造

**※以降の説明に出てくるものだけを記載**

```sh
project
├── bin
│   ├── manage.py
├── bitbucket-pipelines.yml
├── deploy.sh
├── requirements.txt
├── tests
├── tmp
├
├
```


## bitbucket-pipelines.yml

bitbucket-pipelinesの処理を記述したyamlファイル。
[bitbucket-pipelines.ymlの記法詳細](https://ja.confluence.atlassian.com/bitbucket/configure-bitbucket-pipelines-yml-792298910.html)

今回はdevelopブランチでデプロイするので、
developブランチにテストとデプロイの2ステップ。  
もちろん、デプロイだけならテストのステップは不要です。

```python:bitbucket-pipelines.yml
image: python:latest

pipelines:
  branches:
    develop:
      - step:
          name: Test in develop
          caches:
            - pip
          script:
            - pip install -r requirements.txt
            - python bin/manage.py test -- tests/
          services:
            - postgres
      - step:
          name: Deploy to staging
          script:
            - ssh -p $DEPLOY_SERVER_PORT $BITBUCKET_BRANCH@$DEPLOY_SERVER_IP bash < deploy.sh
definitions:
    services:
      postgres:
        image: postgres
```

`$BITBUCKET_BRANCH`のところは、適宜、デプロイサーバーのsshログインユーザー名に置き変えてください。
私はデプロイサーバー上にブランチ名でユーザーを切っているので、このようにしてます。

ちなみに、`BITBUCKET_BRANCH` はデフォルトで定義されている *Enviroment variables* です。  
その他の *Enviroment variables* については → [Environment variables - Atlassian Documentation](https://confluence.atlassian.com/bitbucket/environment-variables-794502608.html)


## deploy.sh

デプロイサーバーでのデプロイ作業を記述したシェルスクリプト。
Bitbucketのリポジトリから`git pull`して、uwsgiのpidファイルをリロードしてます。

```sh:deploy.sh
#!/bin/bash

PROJECT=project

cd ~/$PROJECT
git pull
source /opt/$PROJECT/bin/activate && uwsgi --reload tmp/uwsgi.pid
echo "Deployed!"
```


## bitbucket側の設定

やることはドキュメント通りです。
[Use SSH keys in Bitbucket Pipelines - Atlassian Documentation](https://confluence.atlassian.com/bitbucket/use-ssh-keys-in-bitbucket-pipelines-847452940.html)

ですが、ドキュメントと違っている箇所や躓きやすい箇所を以下に書きます。

まず、Bitbucketのリポジトリ側でいじるのは、以下の3つ

![bitbucket1.jpg](https://qiita-image-store.s3.amazonaws.com/0/110426/1282f0c1-c0e5-4062-3268-693a0d7ddda6.jpeg)


+ *Settings > PIPELINES > Settings* → `有効`になっていなければ`有効`にする
+ *Settings > PIPELINES > Enviroment variables* → 以下に記述
+ *Settings > PIPELINES > SSH keys* → 以下に記述


### Enviroment variables

bitbucket-pipelines.yml 内で使用する

+ DEPLOY_SERVER_IP
+ DEPLOY_SERVER_PORT

はここで定義します。

![bitbucket2.jpg](https://qiita-image-store.s3.amazonaws.com/0/110426/39591605-13e6-6f5f-c291-aa6f172e460d.jpeg)

もちろん、ここでこれらの値を定義せずに bitbucket-pipelines.yml に値を直書きでも大丈夫です。


### SSH keys

デプロイサーバーへsshする為の鍵はここで生成、設定します。

勘違いしやすいですが、Bitbucketリポジトリへsshする為の鍵は、*Settings > GENERAL > Access keys* に登録しておく必要があります。
おそらく、事前準備の段階でBitbucketリポジトリをクローンするときに登録しているはずです。

+ Bitbucketリポジトリ(Pipelines) → デプロイサーバーへのssh設定は *Settings > PIPELINES > SSH keys*
+ デプロイサーバー → Bitbucketリポジトリへのssh設定は *Settings > GENERAL > Access keys*

![bitbucket3.jpg](https://qiita-image-store.s3.amazonaws.com/0/110426/2e2e3e2e-88c7-2954-c336-6960ced4fd5f.jpeg)

1. ここで *SSH Key* のペアを生成します。
2. デプロイサーバーの `~/.ssh/authorized_keys` に Public Key を追記します。
3. *Host address* にデプロイサーバーのアドレスを入れて、*Fetch* を押します。
    sshで使用するPortがデフォルトの`22`でなければ、`127.0.0.1:22222`のようにPortを指定したアドレスにします。
4. *Fetch* が上手くいったら、*Figerprint*ができるので、*add host* します。
   すると、入力欄の下のリストに *Host address* と *Fingerprint* が追加されます。

## BitbucketリポジトリにpushしてPipelinesを動かす

ここまで設定ができると、push時にPipelinesが動いてデプロイまでしてくれます。

![bitbucket4.jpg](https://qiita-image-store.s3.amazonaws.com/0/110426/338b1151-af18-753e-33f0-3dda14726ca9.jpeg)


## その他の環境でのデプロイ

AWSやHerokuへのデプロイはもっとお手軽です。

[Deployment guides - Atlassian Documentation](https://confluence.atlassian.com/bitbucket/deployment-guides-872011233.html)


## 最後に

Pipelinesからのsshは、1年前くらいの記事を見ると、base64エンコードしたsshキーを*Enviroment variables*に登録する方法がよく引っかかるので、そちらにハマってしまうと面倒です。
Atlassianもそのあたりが面倒なのが分かっていて、今年の3月くらいにBitbucketリポジトリからsshする際のキーを生成できるようにしたみたいです。

[Generate SSH keys for Bitbucket Pipelines | Bitbucket Blog](https://blog.bitbucket.org/2017/03/21/generate-ssh-keys-bitbucket-pipelines/)