bitbucketのパイプラインでリモートホストにデプロイ

bitbucketのパイプラインでリモートホストにデプロイを行う。パイプライン初学者。

「リモートホストでgit pull相当のことをしてデプロイする」という作業をbitbucketにpushしたタイミングで行いたい。

bitbucketのパイプラインを使うと簡単に実現可能。dockerコンテナを自動作成してその中で処理を行ってくれる。月50分までの処理時間は無料。ふつうはテストにも使うが、ここではデプロイだけ考える。

bitbucketの準備

下の説明でbitbucketのURLを載せているが、一部URLが違うかもしれないのでbitbucketのレポジトリの画面からたどったほうが正確に目的のページに到達できる。

基本的に、ブラウザでbitbucketの対象レポジトリのページを開いて行う。

パイプラインの有効化

まずは、パイプラインを使用するレポジトリの設定で、パイプラインを有効化する。ymlファイルをそのまま作成できるが、ここではしない。(してもいい)

有効化するために、2段階認証が必要かもしれない。そのときはAuthyで認証できるので、bitbucketのユーザアカウントページから行う。AuthyでQRコードをスキャンして、ワンタイムパスワードを打ってメールを確認する。アカウントページの2段階認証のところに詳しいやり方が書いてある。

パイプラインで使う環境変数の設定

ワークスペースの設定:https://bitbucket.org/<account_name>/workspace/settings/addon/admin/pipelines/account-variablesもしくは、リポジトリの設定:https://bitbucket.org/<account_name>/<repository_name>/admin/addon/admin/pipelines/repository-variablesにて(アカウント名・リポジトリ名は置き換えて下さい)、環境変数を設定しておく。リポジトリの設定はワークスペースのものより優先される。

設定する環境変数は、次の3つ:

  • DEPLOY_SERVER_SSH_PORT: ssh接続で使うポート番号
  • DEPLOY_SERVER_USERNAME: リモートホストのssh接続で使うユーザ名
  • DEPLOY_SERVER_IP: リモートホストのIPアドレスもしくはドメイン名

うん、普通だ。ただの接続情報。

パイプラインで使うssh鍵の設定

レポジトリの設定のPIPELINESSSH Keysから、ssh接続で使う認証鍵を登録しておく必要がある。GUI上で生成するか、自前で用意したおいたのを使うか選べる。 自分の場合は、同じような使い方をする複数のレポジトリは同じ鍵でいいという方針で自前の鍵を用意した。

鍵を用意したら、接続先のリモートホストをknown_hostsに追加する。<ip_addr>:<ssh_port>の形でHost Addressのところに入力して、Fetchボタンを押して、Fetchが終わるとAddに変わるのでAddボタンを押して完了。

これでbitbucketのページから設定することは終わり。

ソース側ですること

パイプラインの定義ファイルを追加する。そしてデプロイ用のスクリプトを書き換えるか、これ専用に新しく作るかのいずれかはする必要がある。

必要なファイル

基本的には2つあればOK。

  • bitbucket-pipelines.yml
    • ルート直下に配置する。パイプラインを定義する。ファイル名はこれでないといけない。
  • deploy.sh
    • デプロイで実行するスクリプト。bitbucket上ではなく、デプロイするリモートホスト上で実行される。ファイル名はなんでもいい。

bitbucket-pipelines.ymlは、当然複数のパイプラインを登録できるので以下の2つの場合などでも同時に使える。

特定ブランチのpushをトリガーにする

特定のブランチのpushでパイプラインを動かすなら、以下のようになる:

# bitbucket-pipelines.yml
# デプロイのみ行う。

image: atlassian/default-image:2

pipelines:
  branches:
    master:
      - step:
          name: Deploy to production
          deployment: production
          script:
            - echo "Deploying to production environment"
            - ssh -p $DEPLOY_SERVER_SSH_PORT $DEPLOY_SERVER_USERNAME@$DEPLOY_SERVER_IP bash < deploy.sh

masterブランチがpushされたとき、stepの処理を(stepが複数あれば順に)行う。 上の例では、stepが1つだけなので、そのscript部分をファイル先頭のimageで指定したdockerコンテナが行ってくれる。(このscriptの実行時間で月大体50分まで無料)

sshでdeploy.shの内容を実行する。その内容は:

# deploy.sh
#!/bin/bash
APP_NAME=<appname>

# あらかじめ、cloneしておくのを忘れない
cd ~/${APP_NAME}

# pullでもいい
git fetch origin
git merge origin/master

... # デプロイの実行
echo "Success!"

gitコマンドあたりが肝。リポジトリから最新の情報を取ってきて(fetch)、作業用ディレクトリをリモートブランチと同じ状態にする(merge)。タグだと少し違う方法になる。

トリガーの引き方は単純に対象のブランチをpushするだけ:

$ git push origin master

bitbucketのレポジトリのダッシュボードからパイプラインのページを開けば確認できる。

ブランチをトリガーにするケースは以上。

特定タグ形式のpushをトリガーにする

タグの場合はあまり例がなかったので自前の実装が多い。そのため穴があるかもしれない。

特定のタグの形式をトリガーにするときは、パイプラインは大きくは変わらない:

# bitbucket-pipelines.yml
image: atlassian/default-image:2

pipelines:
  tags:
    prod-*:
      - step:
          name: Deploy to production
          deployment: production
          script:
            - echo "Deploying to production environment"
            - ssh -p $DEPLOY_SERVER_SSH_PORT $DEPLOY_SERVER_USERNAME@$DEPLOY_SERVER_IP bash /dev/stdin $BITBUCKET_TAG < deploy.sh

branchmasterが、タグのものに変わる。タグは毎回同じ訳はないのでワイルドカードというかglobが使える。上の例では、prod-で始まるタグのpushがトリガーとなる。

scriptのsshの実行も少し変わる。後述のdeploy.shでタグを利用するので、タグを渡してやる必要がある。 ブランチの時のままでは、引数を追加しても渡せない。標準入力がスクリプトの中身となるから、それをbashの第一引数にする必要がある。なので/dev/stdinを指定しておけばいい。その次以降の文字列が引数として渡されるので、bitbucketのパイプラインで用意されるタグ用の変数BITBUCKET_TAGを使えば適切な引数を指定できる。

deploy.shの内容は下のように:

# deploy.sh
#!/bin/bash
APP_NAME=<appname>

# あらかじめ、cloneしておくのを忘れない
cd ~/${APP_NAME}

# fetchしてcheckoutでタグからbranchを作成。-B利用
# $1はパイプラインから渡されるタグ名
git fetch origin
git checkout -B release $1

... # デプロイの実行
echo "Success!"

fetchまではブランチトリガーの時と同じ。

タグがトリガーの場合は、ただマージしたのではタグの位置のコミットを利用できない。origin/masterの示す位置とタグの示す位置が異なる場合があるからだ。

そのため、git checkout -b|-B <new_branch> [<start_point>]の形式を使う。

start_pointとは、Git - git-branch Documentationによると、

<start-point>
The new branch head will point to this commit. It may be given as a branch name, a commit-id, or a tag. If this option is omitted, the current HEAD will be used instead.

ということなので、タグも使える。

-Bオプションは、ブランチを生成するが、すでに存在するならそれをリセットするというもの。2回目以降もこのコマンドで済ますためこれを使うことにした。-bオプションでは、ブランチが既存だとfatal: A branch named 'release' already exists.というメッセージが出る。

試していないが、おそらくreleaseブランチでなく、masterでも使えるのではないかと思う。ローカルのmasterブランチがリセットされるだけなので。

ブランチのpushだけでは、タグはpushされないので:

$ git commit -m "some commit"
$ git push origin master
$ git tag -a prod-v1 -m "version 1"
$ git push origin prod-v1

などでタグをpushする必要がある。タグをpushした時点でマッチするglobパターンならパイプラインが動作を開始する。

タグをまとめてpushしたとき

git push origin --tagsでまとめてタグをpushした時も調べてみた。

調べ方は、

  • ローカルにタグを2つ用意。タグv1v2の順に作成。コミットは1つずらした。
  • bitbucketをoriginとして、git push origin masterする
  • 続けて、git push origin --tagsする

でどうなるかチェックした。

結果として、gitの出力に

...
 * [new tag]         prod-v1 -> prod-v1
 * [new tag]         prod-v2 -> prod-v2

となっていると、v1が先にパイプラインで処理された。v2puasedとなっていた。順に処理されるようだ。

v2のパイプラインは、bitbucketのGUI上でResumeを押すと処理できた。

3つ以上の場合も最初の1つ以外はpauseされるのだと思う。

参考

おわり

タグとパイプラインについて書いておきたいと思ったら結構長くなってしまった。日本語に直しただけみたいになっているところもあるかもしれない。

deploy.shについては最後にechoしているので常に戻り値が0になっているのは余計だった。これがあると、デプロイが失敗していても、bitbucketのパイプラインの実行結果を見てもSuccessfulと表示されてしまう。 これは良くないので、deploy.shはもう少し考えて作ろう。

バージョンで分けたいという理由でタグをトリガーとしたパイプラインを作るのが最適かどうか不安が残る。 リモートにrelease用ブランチを作る方向でもいいとは思った。 でもバージョンは記録したい気もするから、やっぱりタグがいいかな。悩む。

以上です。


広告

Bitly
タイトルとURLをコピーしました