史上最齊全最詳細的Drone自動化教學文件
===
###### tags: `drone` `agent` `devops` `runner` `CI/CD`
[TOC]
---
## 概述
Drone可以協助開發者commit code之後,自動將code佈署到主機,並且將佈署結果自動發布通知給相關人員,減少人為執行重複佈署的工作。
但在建立Drone之前,需要清楚該主機作為client或是server的角色,不然很容易搞混SSL/TLS Key的授權。
以下為簡單Drone流程圖

建立Drone自動化,關鍵步驟在於:
* 清楚知道現在設定的主機是流程圖的哪個角色
* 確認主機是Server or Client
* **建立SSH/TLS Key免密碼登入(最重要!!)**
---
## Drone主機資訊
Drone Server : xxxxx (Core OS)
外網開放IP/Port:xxxx:port
登入資訊: xxxx / xxxx
Drone資料夾(使用docker):/docker/drone
Drone Runner(Agent) : xxxxx
外網開放IP/Port:xxx:xxxx
登入資訊: xx / xxxxx
Drone資料夾(使用docker):/docker/dr-runner
---
## 透過SSH Key建立主機之間的連接
### Drone Server與Drone Runner
Drone Server需要將Trigger訊號送至Drone Runner,所以在SSL Key的角色為Client Side, 因此要將Drone Server的帳號(比如root)的SSL Key加到Drone Runner。

---
#### Drone Server
1. 切換成root身份
> sudo su
2. 確認SSL Key(Public Key)
> ls ~/.ssh/id_rsa.pub
如果不存在就自己建立一組公私鑰:
```
ssh-keygen -t rsa
```
不設phrasepassword,後面直接Enter確定。
3. Copy公鑰內容到Server端(Drone Runner)
> ssh-copy-id centos@1.2.3.4
接著輸入Runner主機的密碼,日後即可不透過輸入密碼就能登入。
(Drone運作過程中若需要輸入帳密,佈署流程就會被中斷)
4. 測試無密碼登入
測試登入,應該不會出現要求輸入密碼。如果有,則使用手動方式,將公鑰加入到Server主機的authorized_keys。
> ssh centos@1.2.3.4
==**!!注意!! 在進行SSH KEY配對之前,要確認你是用什麼使用者身份登入對方主機再做KEY配對**==
比如 ```Client: root, Server: centos```
就要在client side的主機,尋找root的Public Key,並且加到server side的centos使用者的~/.ssh/authorized_keys
如果沒有確認使用者身份,很容易混亂,加錯Key,造成無法登入的問題。
#### Drone Runner
5. 確認使用者是centos
6. 確認SSH Key(Public Key)
> vim ~/.ssh/authorized_keys
>
確認authorized_keys檔案有加入剛剛ssh-copy-id過來的Drone Server公鑰(id_rsa.pub)內容。
***若是ssh-copy-id失敗,也可以使用手動複製client side的id_rsa.pub將內容貼到Server side的authorized_keys內***
***注意!若server與agent為跨外網的兩台主機,drone server需要建立對外的http server,若該主機已經有其他http server,需要更改預設80 port,URL指定至主機對外的IP,並且在Firewall設定Port Forwarding到內部主機。***
### Runner與Production
Runner需要驅動佈署到正式區主機(Production Server),所以也要建立Runner與Production的SSL連結。

#### Drone Runner(Agents)
1. 切換成root身份
> sudo su
>
2. 確認SSH Key(Public Key)
> ls ~/.ssh/id_rsa.pub
如果不存在就自己建立一組公私鑰:
```
ssh-keygen -t rsa
```
不設phrasepassword,後面直接Enter確定。
3. Copy公鑰內容到Server端(Production Server)
> ssh-copy-id root@5.6.7.8
接著輸入Runner主機的密碼,日後即可不透過輸入密碼就能登入。
(Drone運作過程中若需要輸入帳密,佈署流程就會被中斷)
> ssh root@5.6.7.8
測試登入,應該不會出現要求輸入密碼。如果有,則使用手動方式,將公鑰加入到Server主機的authorized_keys。
#### Production Server
4. 切換成root
> sudo su
5. 確認SSL Key(Public Key)
> vim ~/.ssh/authorized_keys
>
確認authorized_keys檔案有加入剛剛ssh-copy-id過來的runner公鑰(id_rsa.pub)內容。
***若是ssh-copy-id失敗,也可以使用手動複製runner的id_rsa.pub將內容貼到Server side的authorized_keys內***
---
### Github(Bitbucket)與Production Server
Code佈署上去的Production Servers(以下簡稱PD)也需要與版控平台(Github, Bitbucket)建立佈署權限,相當於開發者將完成測試的codes從
Github Pull下來的動作,因此在自動佈署之前,需要完成從PD可自動從Github Pull下來的權限(不詢問密碼)。

#### Bitbucket
至Bitbucket專案資料夾,點擊Clone按鈕取得
> xxxxx@bitbucket.org:/xxxxplatform/xxxx.git
的專案連結
#### Production Server
在需要的佈署的程式資料夾執行以下指令:
```shell=
$ git init
$ git remote add origin master
$ git remote set-url origin abcdefg@bitbucket.org:/platform/xxxx.git
$ sudo ssh -T abcdefg@bitbucket.org
```
在最後一步輸入你的Bitbucket密碼就可完成權限開通,之後在Drone對此資料夾做Pull的動作都不用再人工輸入密碼。
### Github(Bitbucket)與Drone Server
Github(Bitbucket)的專案一旦收到更新,就會執行.drone.yml文件的內容,所以必須建立Runner與Github之間的金鑰連接,在執行過程才不會出錯。

#### Bitbucket
使用OAuth2.0與Bitbucket建立連結
1. 登入Bitbucket
2. 點擊你在Bitbucket的個人帳號選單 -- All workspaces
3. 選擇你個人的Workspaces

4. 點擊Settings

5. 點選OAuth consumers -- Add consumers

***參考設定***
注意,要預先設定給Drone Server使用的URL域名,如果只是要臨時測試用可使用ngrok 可以參考 [這裡](https://vagrantpi.github.io/2018/09/28/drone-101/)
6. 紀錄Key and Secret
7. 撰寫專案的.drone.yml
在你要佈署測試的專案內建立一個新檔案,檔名為.drone.yml,此檔案使用yaml格式撰寫如何將程式pull, test and deployment的流程。
##### 設定Yml文件
專案pipeline的yml文件可參考官方文件 [這裡](https://docs.drone.io/pipeline/overview/)
本案例以整合docker使用為主。並且使用appleboy/drone-ssh的Drone套件,將佈署流程寫在pipeline的yml檔內。
注意在yml文件內,ssh的登入使用key secret,避免密碼以明碼方式顯露。

***請注意:在主機之間盡量不要用明碼顯示登入密碼,透過後台 UI 介面將密碼或者是金鑰內容儲存在 Secret 設定頁面,就可以使Runner與被佈署主機之間的通訊不因帳密問題而中止***
##### 參考設定(以包網為例)
.drone.yml file:
```shell=yaml
kind: pipeline
name: Deploy_Bao
clone:
depth: 20
workspace:
path: /docker/drone-runner
steps:
- name: ssh-deploy-WebA
image: appleboy/drone-ssh
settings:
repo: /aaaplatform/xxxx
host:
- 1.2.3.4
username: root
key:
from_secret: ssh_key
port: 2201
timeout: 60s
command_timeout: 2m
script:
- cd /home/www/xxxx/
- git fetch --all
- git reset --hard origin/master
- git pull origin master
when:
branch:
- master
- name: ssh-deploy-WebB
image: appleboy/drone-ssh
settings:
host:
- 1.2.3.4
username: root
key:
from_secret: ssh_key
port: 2202
timeout: 60s
command_timeout: 2m
script:
- cd /home/www/xxxx
- git fetch --all
- git reset --hard origin/master
- git pull origin master
when:
branch:
- master
- name: ssh-deploy-WebC
image: appleboy/drone-ssh
settings:
host:
- 1.2.3.4
username: root
key:
from_secret: ssh_key
port: 2203
timeout: 60s
command_timeout: 2m
script:
- cd /home/www/xxxx
- git fetch --all
- git reset --hard origin/master
- git pull origin master
when:
branch:
- master
- name: ssh-deploy-AWS_Stage
image: appleboy/drone-ssh
settings:
host:
- 192.168.1.1
username: root
key:
from_secret: ssh-key-stage
port: 22
timeout: 60s
command_timeout: 2m
script:
- cd /var/www/html/xxxx
- git branch
- git checkout stage
- git fetch --all
- git reset --hard origin/stage
- git pull origin stage
when:
branch:
- stage
- name: telegram
image: appleboy/drone-telegram
pull: true
settings:
token:
from_secret: tele_token
to:
from_secret: tele_to
format: markdown
message: >
{{#success build.status}}
✅ Build #{{build.number}} of `{{repo.name}}` succeeded.
📝 Commit by {{commit.author}} on `{{commit.branch}}`:
```
{{commit.message}}
```
🌐 {{ build.link }}
{{else}}
❌ Build #{{build.number}} of `{{repo.name}}` failed.
📝 Commit by {{commit.author}} on `{{commit.branch}}`:
```
{{commit.message}}
```
🌐 {{ build.link }}
{{/success}}
when:
status:
- failure
- success
trigger:
event:
- push
- pull_request
- tag
```
#### Drone Server
1. 在docker container目錄建立.env文件
2. 將剛剛從Bitbucket紀錄的Key, Secret紀錄到.env file
***TIPS:${DRONE_RPC_SECRET} 值可以用以下指令來產生 Token :***
`openssl rand -hex 16`
之後把 .env 檔案放在與docker-compose.yml同一層的目錄即可。
#### 參考設定
##### .env file:
(記得要放在跟docker-compose同一層目錄下)
```shell=yaml
DRONE_SERVER_HOST=drone.domain:1234
DRONE_SERVER_PROTO=http
DRONE_RPC_SECRET=111111111111
DRONE_BITBUCKET_CLIENT_ID=oooooooooooooo
DRONE_BITBUCKET_CLIENT_SECRET=12345678qwertyuasfdghzxcv
```
##### 安裝Drone Server
在設定Drone Server之前必須先安裝,安裝部份請參閱下個章節。
---
## 建立Drone Server(Server)
Drone Server主機安裝好Linux OS(本案例使用Core OS),並且安裝好docker-compose環境。
### 安裝Docker-compose
* docker安裝過程請參考 [這裡](https://hackmd.io/d__Zwa5JQR2U_DlqCyQFWQ#%E5%AE%89%E8%A3%9DDocker-%E7%9B%B8%E9%97%9C%E5%A5%97%E4%BB%B6)
* docker-compose文件請參考 [這裡](https://docs.docker.com/compose/)
### 撰寫docker-compose.yml
本文件建立Drone Server以撰寫docker-compose.yml文件為啟動方式,yml文件內主要紀錄項目為:
* DRONE_SERVER_HOST:Drone Server的IP或URL
* DRONE_SERVER_PROTO:使用的協定,這裡使用http(亦可用https,但要開443 port)
* DRONE_RPC_SECRET:與runner溝通的key(可自訂)
* ==DRONE_BITBUCKET_CLIENT_ID:在Bitbucket,個人Setting的OAuth consumers顯示的Key值==
* ==DRONE_BITBUCKET_CLIENT_SECRET:在Bitbucket,個人Setting的OAuth consumers顯示的Secret值==

#### 參考設定
Docker Server yaml file:
```shell=yaml
version: '2'
services:
drone-server:
container_name: drone-server
image: drone/drone:1
ports:
- 80:80
volumes:
- ./:/data
restart: always
environment:
- TZ=Asia/Taipei
- DRONE_SERVER_HOST=${DRONE_SERVER_HOST}
- DRONE_SERVER_PROTO=${DRONE_SERVER_PROTO}
- DRONE_RPC_SECRET=${DRONE_RPC_SECRET}
- DRONE_BITBUCKET_CLIENT_ID=${DRONE_BITBUCKET_CLIENT_ID}
- DRONE_BITBUCKET_CLIENT_SECRET=${DRONE_BITBUCKET_CLIENT_SECRET}
- DRONE_LOGS_TRACE=true
- DRONE_LOGS_PRETTY=true
- DRONE_LOGS_COLOR=true
- DRONE_RUNNER_CAPACITY=10
```
.env file:
```shell=yaml
DRONE_RPC_SECRET=111111111111
DRONE_BITBUCKET_CLIENT_ID=oooooooooooooo
DRONE_BITBUCKET_CLIENT_SECRET=12345678qwertyuasfdghzxcv
```
### 啟動Docker-compose
```
docker-compose up -d #啟動Drone Server Container
docker-compose logs #檢查log是否有出現錯誤
docker ps -a #檢查container運作情況
```
### Drone Server的頁面設定
若前面設定都沒有出現錯誤,輸入 drone.domain.com:1234 應該可以見到Drone Server的UI頁面,同時頁面會跟Bitbucket網站連結,輸入你在Bitbucket的帳號就可見到你有權限的專案列表。

先點按Sync按鈕,讓Drone Server與Bitbucket同步。
#### 啟動專案
一開始所有專案都處於沒有Active狀態,可點進一個你需要使用Drone佈署的專案並且啟動它。

#### Drone YAML檔名
在專案內頁面,Setting - Configuration欄位填入.drone.yml檔案名稱,此名稱可更改,唯必須以.檔名開頭。

##### 寫入Drone Secrets
將key secret寫入至drone server
* **注意!這部份是Drone能否成功推送的關鍵,必須將.drone.yml檔內引用的Key值寫入此欄位。**
1. **將Runner的root key(Private私鑰 ~/.ssh/id_rsa)填入此欄位,並且Secret Name要符合.drone.yml檔內的名稱**

* Secret Name為 .drone.yml的from_secrets值
* Secret Value為 Runner Server的私鑰值
**是否使用root key取決於你在.drone.yml使用的container image,因為我使用的是appleboy/drone-ssh,預設使用者是root,所以必須使用root的私鑰而非其他使用者。**
2. 將tele_token 與 tele_to 的Key值寫入(.drone.yml的Telegram Token)
3. 如果寫入內容錯誤,就Delete再次重作Add A Secret
---
## 建立Drone Runner Server(Agent)
Runner Server主要負責處理codes佈署與測試,Drone Server與Github or Bitbucket連結並且Trigger,再將需求以Webhook方式丟給Runner處理。
同樣準備一台主機安裝好Linux OS(本案例使用AWS EC2),並且安裝好docker-compose環境,
### 安裝Docker-compose
[參考上方安裝過程](https://hackmd.io/EPZwS2N1SeStTaEwTglMUw?both#%E5%AE%89%E8%A3%9DDocker-compose)
### 設定Yml文件
***參考設定***
Docker Runner Server yaml file:
```shell=yaml
version: '2'
services:
drone-runner:
container_name: dr-runner
image: drone/drone-runner-docker:1
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DRONE_RPC_HOST=${DRONE_RPC_HOST}
- DRONE_RPC_PROTO=${DRONE_RPC_PROTO}
- DRONE_RPC_SECRET=${DRONE_RPC_SECRET}
- DRONE_RUNNER_CAPACITY=3
- DRONE_RUNNER_NETWORKS=drone-runner_default
- DRONE_RUNNER_NAME=runner_dev
```
.env file:
```shell=yaml
DRONE_RPC_HOST=drone.domain.com:1234
DRONE_RPC_PROTO=http
DRONE_RPC_SECRET=111111111111
```
* ${DRONE_RPC_HOST} 填入給Drone使用的URL
* ${DRONE_RPC_SECRET} 填入跟Drone Server一樣的值,Server與Agent靠這個Key認證溝通
### 啟動Drone Runner(Agent)
```
docker-compose up -d #啟動Drone Server Container
docker-compose logs #檢查log是否有出現錯誤
docker ps -a #檢查container運行狀態
```
---
## 測試自動化佈署
### 手動測試佈署
進入PD主機的專案資料夾,進行人工測試佈署:
```shell=
$ git fetch --all
$ git reset --hard origin master
$ git push origin master
```
確認可成功Pull之後,再更新程式Push到Bitbucket上,由版控端進行Drone自動化作業。
### 更新程式
1. 確認要更新的專案已在Drone Server被Activate
2. 更新專案的程式
3. Push到Bitbucket
4. 會發現Bitbucket的專案頁面多了Builds欄位,綠色打勾就代表build成功

### 觀察Drone Server
一旦Bitbucket程式庫有更新,便會立即執行專案pipeline,這時進入drone server的頁面會發現顯示圖示改變了
變成黃色(寶貝球?),代表該專案正在running(CI/CD Process)
點進頁面可看到專案正在依照.drone.yml文件執行

### 觀察佈署結果
一旦佈署成功,會全部顯示綠燈
如果佈署失敗,查看佈署過程的log,再去檢查相關的設定

**TIPS: 如果想要將佈署成功/失敗都發出通知,除了透過email以外也可以使用Telegram外掛,將通知發布到Telegram**
**TIPS: 如果是主機之間的ssh or SSL Key設定問題,可透過手動執行指令,模擬自動化,便比較有可能找出問題原因**
---
## 參考文件
[git push 免帳號密碼 | ssh key](https://aben20807.blogspot.com/2018/03/1070302-git-push-ssh-key.html)
[ssh-key添加之后依旧需要密码输入Bug的解决](https://www.cnblogs.com/marility/p/8400354.html)
[drone.yml參考官方文件](https://docs.drone.io/)
[Drone Secret 安全性管理](https://blog.wu-boy.com/2017/11/drone-secret-security/)
[三分鐘學會Drone ,CI/CD輕鬆上手!](https://www.tpisoftware.com/tpu/articleDetails/1884)