# 使用Bitbucket Pipelines 來實做Continuous Delivery / Deployment

# Date: 2019/March/18

環境 & 背景介紹: 
Bitbucket, AWS EC2 (Ubuntu), Laravel project (with dotenv file)

我們的程式佈署在EC2上, 可是每次做完pull request, 還要自己手動連進機器裡面佈署最新的程式碼.

手動佈署的工作實在太過無趣, 是不是能用什麼工具來節省寶貴的時間呢?


# 60 seconds

# 簡單暴力解 (bitbucket pipelines & ssh command)

我們需要某種方法, 能讓Bitbucket接收到push的時候, 命令AWS EC2 server自動去執行git pull
(在這個範例是git fetch + git reset), 這樣子便達到了最簡單的自動佈署了!
(保留dot env檔案不進版控, 套件/需要編譯的檔案做最低限度的安裝/更新)


Step 1. Set SSH keys & Known hosts

Step 1. Set SSH keys & Known hosts

設定SSH 鑰匙資訊 - Settings > SSH keys > 將公鑰私鑰填入適當的位置, 並把server address加進
Known hosts裡面.


Step 2.

Step 2. Set AWS security group

通常AWS EC2上會設定security group, 我們會需要將Bitbucket IP list加入清單當中(用以辨認來自Bitbucket的SSH請求)


Step 3. 在**bitbucket-pipelines.yml**裡, 要執行CD的地方加上這行
$ ssh user@your_host "cd /your/project/path && git fetch - all && git reset - hard origin/your_branch"
1

它會自動到你要佈署的資料夾裡做類似 git force pull 的動作, 這樣便達到了自動佈署的目的.

當然, 如果有安裝/更新相依性套件的需求, 也能直接加在上面ssh的指令裡, 或是透過 git hook 觸發



# 不使用第三方版控工具 (git bare repository & worktree on deployment server)


如果是要直接將最新的程式推上目標伺服器的話, 也可以使用 **git bare repository**,

配合git hook一樣能達到簡單的自動佈署 (原文請參照這篇)

首先我們先在要佈署的伺服器建立兩個資料夾, 一個是deploy-folder, 另一個則是bare-repository-folder

$ mkdir ~/deploy-folder
$ git init --bare ~/project.git
1
2

再來是設定git hook, 這裡我們使用的是post-receive

#!/bin/bash
TARGET="/home/webuser/deploy-folder"
GIT_DIR="/home/webuser/project.git"
BRANCH="master"

while read oldrev newrev ref
do
    # only checking out the master (or whatever branch you would like to deploy)
    if [ $ref = refs/heads/$BRANCH ];  # 這邊在我們的機器上用雙[]會報錯, 因此在這裡改為單[]
    then
        echo "Ref $ref received. Deploying ${BRANCH} branch to production..."
        git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f
    else
        echo "Ref $ref received. Doing nothing: only the ${BRANCH} branch may be deployed on this server."
    fi
done
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

(記得要把執行的權限打開! git hook會使用git這個使用者)

接著在你自己的本地端加上要佈署目標的資訊

$ cd ~/path/to/working-copy/
$ git remote add production demo@yourserver.com:project.git
1
2

最後, push讓伺服器觸發deploy的git hook即可.


這個方法是建立一個裸倉庫(bare repository), 並指定它的worktree.

當本地端的使用者推送資料到伺服器的時候,
git hook會將這個裸倉庫worktree的資料夾內的程式, 強制指到最新的版本.

所以如果有編譯/安裝相依套件的需求時, 記得要加上執行相關動作的指令.


# 60 minutes

# 開發Bitbucket pipelines 遇到的問題

  • Branch workflow

Bitbucket branch workflow

pipelines裡, 可以針對各個commit / branch設定不同的工作.

需要注意的是, 此處的default/branch是類似if-else條件, 也就是說符合branch條件以後是不會去執行default的內容的.


  • Parallel steps

Pipelines可以並行處理腳本, 不過有最多同時執行10筆的上限.

另外, 產生檔案發生衝突時會以最後一個parallel step為準.

詳細資訊


# CD with git bare repository and git hook

洛桑扎巴 - 使用 Git Hooks 实现自动项目部署 (http://notes.11ten.net/apps-auto-deploy-with-git.html)

gist - icyleaf/post-receive.sh


其實一開始我的作法如下圖所示

original flow

透過pipeline, git push到server上的裸倉庫後, 再觸發post-receive,
讓deployment資料夾去抓取最新的程式.

不過會遇到git hook沒辦法認得deployment資料夾git 狀態的問題.

這一篇文章的作法有提到使用:

env -i git pull
1

來替代原本的指令

git pulll
1

或許可以解決這個問題.


參考: Why is it better to use “#!/usr/bin/env NAME” instead of “#!/path/to/NAME” as my shebang?


# References

# 其他參考資料

Bitbucket Support - Build, test, and deploy with Pipelines

Bitbucket Support - Bitbucket Deployments

Bitbucket Support - Run pipelines manually

Last Updated: 4/7/2019, 6:55:59 AM