-
程式碼的下載構建及編譯
-
執行單元測試,生成單元測試報告及改寫率報告等
-
在測試環境對當前版本進行測試
-
為待釋出的程式碼打上版本號
-
編寫 ChangeLog 說明當前版本所涉及的修改
-
構建 Docker 映象
-
將 Docker 映象推送到映象倉庫
-
在預釋出環境測試當前版本
-
正式釋出到生產環境
-
Clone 專案到本地, 修改專案程式碼, 如將 Hello World 改為 Hello World V2。
-
git add .,然後書寫符合約定的 Commit 並提交程式碼, git commit -m “feature: hello world v2”。
-
推送程式碼到程式碼庫git push,等待數分鐘後,開發人員會看到單元測試結果,GitHub 倉庫會產生一次新版本的 Release,Release 內容為當前版本的 ChangeLog, 同時線上已經完成了新功能的釋出。
-
Clone 專案到本地,建立一個分支來完成新功能的開發, git checkout -b feature/hello-world-v3。在這個分支修改一些程式碼,比如將Hello World V2修改為Hello World V3
-
git add .,書寫符合規範的 Commit 並提交程式碼, git commit -m “feature: hello world v3”
-
將程式碼推送到程式碼庫的對應分支, git push origin feature/hello-world
-
如果功能已經開發完畢,可以向 Master 分支發起一個 Pull Request,並讓專案的負責人 Code Review
-
Review 透過後,專案負責人將分支合併入主幹,GitHub 倉庫會產生一次新版本的 Release,同時線上已經完成了新功能的釋出。
-
以 dev 為主開發分支,Master 為釋出分支
-
開發人員始終從 dev 建立自己的分支,如 feature-a
-
feature-a 開發完畢後建立 PR 到 dev 分支,併進行 code review
-
review 後 feature-a 的新功能被合併入 dev,如有多個並行功能亦然
-
待當前開發週期內所有功能都合併入 dev 後,從 dev 建立 PR 到 master
-
dev 合併入 Master,並建立一個新的 Release
-
Clone 專案到本地,git checkout dev。從 dev 建立一個分支來完成新功能的開發, git checkout -b feature/feature-a。在這個分支修改一些程式碼,比如將Hello World V3修改為Hello World Feature A
-
git add .,書寫符合規範的 Commit 並提交程式碼, git commit -m “feature: hello world feature A”
-
將程式碼推送到程式碼庫的對應分支, git push origin feature/feature-a:feature/feature-a
-
由於分支是以 feature/ 命名的,因此 CI 會執行單元測試,並自動構建一個當前分支的映象,釋出到測試環境,並自動配置一個當前分支的域名如 test-featue-a.avnpc.com
-
聯絡產品及測試同學在測試環境驗證並完善新功能
-
功能透過驗收後發起 PR 到 dev 分支,由 Leader 進行 code review
-
Code Review 透過後,Leader 合併當前 PR,此時 CI 會執行單元測試,構建映象,併發布到測試環境
-
此時 dev 分支有可能已經積累了若干個功能,可以訪問測試環境對應 dev 分支的域名,如 test.avnpc.com,進行整合測試。
-
整合測試完成後,由運維同學從 Dev 發起一個 PR 到 Master 分支,此時會 CI 會執行單元測試,構建映象,併發布到預釋出環境
-
測試人員在預釋出環境下再次驗證功能,團隊做上線前的其他準備工作
運維同學合併 PR,CI 將為本次釋出的程式碼及映象自動打上版本號並書寫 ChangeLog,同時釋出到生產環境。
-
由此就完成了上文中 Checklist 所需的所有工作。雖然描述起來看似冗長,但不難發現實際作為開發人員,並沒有任何複雜的操作,流程化的部分全部由 CI 完成,開發人員只需要關註自己的核心任務:按照工作流規範,寫好程式碼,寫好 Commit,提交程式碼即可。
kubectl apply -f drone-pvc.yaml
-
drone/kubernetes-secrets 加密資料服務,用於讀取 Kubernetes 的 secrets
-
drone/drone:1.0.0-rc.6 就是 Drone 的 server 端,由於在 Kubernetes 下 Drone 利用了 Job 機制,因此不需要部署 Agent。
-
Drone/kubernetes-secrets 映象中
-
-
SECRET_KEY:資料加密傳輸所用的 key,可以使用 openssl rand -hex 16 生成一個
-
-
Drone/Drone映象中
-
-
DRONEKUBERNETESENABLED:開啟 Kubernetes 樣式
-
DRONEKUBERNETESNAMESPACE:Drone 所使用的 Namespace, 這裡使用 default
-
DRONEGITHUBSERVER:GitHub 伺服器地址,一般為 https://github.com
-
DRONEGITHUBCLIENT_ID:上文建立 GitHub Auth App 得到的 Client ID
-
DRONEGITHUBCLIENT_SECRET:上文建立 GitHub Auth App 得到的 Client Secret
-
DRONESERVERHOST:Drone 服務所使用的域名
-
DRONESERVERPROTO:http 或 https
-
DRONEDATABASEDRIVER:Drone 使用的資料庫型別,這裡為 SQLite3
-
DRONEDATABASEDATASOURCE:這裡為 SQLite 資料庫的存放路徑
-
DRONESECRETSECRET:對應上文的 SECRET_KEY
-
DRONESECRETENDPOINT:加密資料服務的地址,這裡透過 Kubernetes Service 暴露,無需修改
-
kubectl apply -f drone.yaml
kind: pipeline
name: deploy
steps:
- name: hello-world
image: docker
commands:
- echo "hello world"
-
程式碼部分:https://github.com/AlloVince/drone-ci-demo/tree/hello-world
-
Drone 構建記錄:https://cloud.drone.io/AlloVince/drone-ci-demo/1
-
Docker 映象:無
-
當 Master 分支接收到 push 後,執行單元測試
-
當 GitHub 釋出一次 Release, 構建 Docker 映象,並推送到映象倉庫
kind: pipeline
name: deploy
steps:
- name: unit-test
image: node:10
commands:
- node test/index.js
when:
branch: master
event: push
- name: build-image
image: plugins/docker
settings:
repo: allovince/drone-ci-demo
username: allovince
password:
from_secret: DOCKER_PASSWORD
auto_tag: true
when:
event: tag
-
透過 Drone UI 介面中, repo -> Settings -> Secrets 新增,所新增的加密資料將儲存在 Drone 的資料庫中,僅能在當前 repo 中使用。
-
透過 Drone cli 加密後儲存在 .drone.yml 檔案中, 使用範圍僅限 yaml 檔案內
-
透過 Kubernetes 儲存為 Kubernetes Secret,稱為 External Secrets,所有的 repo 都可以共享。如果是團隊使用的話,這種儲存方式顯然是最方便的,但也要註意安全問題,因此 External Secrets 還支援 repo 級別的許可權管理, 可以只讓有當前 repo 寫入許可權的人才能使用對應 secret。
-
程式碼倉庫:https://github.com/AlloVince/drone-ci-demo/tree/single-person
-
push 時觸發的 Drone CI:https://cloud.drone.io/AlloVince/drone-ci-demo/4
-
Release 時觸發的 Drone CI:https://cloud.drone.io/AlloVince/drone-ci-demo/5
-
Release 後 CI 構建的 Docker 映象:allovince/drone-ci-demo:latest
- name: unit-test
image: node:10
commands:
- node test/index.js
when:
branch:
include:
- feature/*
- master
- dev
event:
include:
- push
- pull_request
- name: build-branch-image
image: plugins/docker
settings:
repo: allovince/drone-ci-demo
username: allovince
password:
from_secret: DOCKER_PASSWORD
tag:
- ${DRONE_BRANCH##feature/}
when:
branch: feature/*
event: push
-
團隊成員從 dev 分支 checkout 自己的分支 feature/readme
-
向feature/readme提交程式碼並 push, CI 執行單元測試,構建映象allovince/drone-ci-demo:readme
-
功能開發完成後,團隊成員向 dev 分支 發起 pull request , CI 執行單元測試
-
團隊其他成員 merge pull request, CI 執行單元測試,構建映象allovince/drone-ci-demo:test
-
運維人員從 dev 向 master 發起 pull request,CI 執行單元測試,並構建映象allovince/drone-ci-demo:latest
-
運維人員 merge pull request, 並 Release 新版本 pre-0.0.2, CI 構建映象allovince/drone-ci-demo:pre-0.0.2
-
主版本號:當你做了不相容的 API 修改
-
次版本號:當你做了向下相容的功能性新增
-
修訂號:當你做了向下相容的問題修正
-
feat:新功能
-
fix:BUG 修複
-
docs:檔案變更
-
style:文字格式修改
-
refactor:程式碼重構
-
perf:效能改進
-
test:測試程式碼
-
chore:工具自動生成
feat:增加重置密碼功能
fix(郵件模組):修複郵件傳送延遲BUG
feat(API):API重構
BREAKING CHANGE:API v3上線,API v1停止支援
Commit 版本號變更
BREAKING CHANGE 主版本號
feat 次版本號
fix / perf 修訂號
- name: semantic-release
image: gtramontina/semantic-release:15.13.3
environment:
GITHUB_TOKEN:
from_secret: GITHUB_TOKEN
entrypoint:
- semantic-release
when:
branch: master
event: push
-
從 dev 向 master 發起 pull request,CI 執行單元測試,並構建映象allovince/drone-ci-demo:latest
-
merge pull request,CI 會執行單元測試並執行 semantic-release , 執行成功的話能看到 GitHub 新增 Release v1.0.0
-
GitHub Release 再次觸發CI 構建生產環境用 Docker 映象allovince/drone-ci-demo:1.0.0
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: ci-demo-deployment
namespace: default
spec:
replicas: 1
template:
spec:
containers:
- image: allovince/drone-ci-demo
name: ci-demo
restartPolicy: Always
- name: k8s-deploy
image: quay.io/honestbee/drone-kubernetes
settings:
kubernetes_server:
from_secret: KUBERNETES_SERVER
kubernetes_cert:
from_secret: KUBERNETES_CERT
kubernetes_token:
from_secret: KUBERNETES_TOKEN
namespace: default
deployment: ci-demo-deployment
repo: allovince/drone-ci-demo
container: ci-demo
tag:
- ${DRONE_TAG}
when:
event: tag
kubectl -n default set image deployment/ci-demo-deployment ci-demo=allovince/drone-ci-demo:v1.0.2
-
一個好的 Commit,代表著開發人員對當前改動之於整個系統的影響,有非常清楚的認識,程式碼的修改到底算 feat 還是 fix ,什麼時候用 BREAKING CHANGE 等都是要仔細斟酌的,每個 Commit 都會在 ChangeLog 裡“留底”,從而約束團隊不隨意提交未經思考的程式碼,提高程式碼質量。
-
一個好的 Commit 也代表開發人員有能力對所實現功能進行精細的劃分,一個分支做的事情不宜過多,一個提交也應該專註於只解決一個問題,每次提交(至少是每次 push)都應該保持系統可構建、可執行、可測試,如果能堅持做到這些,對於合併程式碼時的衝突解決,以及整合測試都有很大幫助。
-
由於每次釋出能清楚的看到所有關聯的 Commit 以及 Commit 的重要程度,那麼線上事故的回滾也會非常輕鬆,回滾到哪個版本,回滾後哪些功能會受到影響,只要看 CI 自動生成的 Release 記錄就一目瞭然。如果沒有這些,回滾誤傷到預期外的功能從而引發連鎖反應的慘痛教訓,可能很多運維都有過類似經歷吧。
-
Jenkins
-
JetBrains TeamCity
-
CircleCI
A:還是要結合自己團隊的實際情況做選擇。從成熟度來說,肯定是 Jenkins 使用者最多,成熟度最高,缺點是側重 Java,配置相對繁瑣。GitLab 自帶的 CI 相對簡單,可以用 yaml,和 GitLab 結合的最好,但功能肯定沒有 Jenkins 全面。如果是小團隊新專案,GitLab CI 又已經可以滿足需求的話,並不需要上 Jenkins,如果是較大的團隊,又是偏 Java 的,個人更偏向 Jenkins。
A:從 CI 的流程來說,CI 應用是不是跑在 Kubernetes 的並不重要,CI 只要能訪問程式碼庫,有許可權在生產環境釋出,是不是跑在容器裡從效果來說其實沒有區別,只是用 Kubernetes 部署 Jenkins 的話,運維的一致性比較好,運維團隊不用額外花時間維護一套物理機的部署方案。
A:程式碼一定是打包到映象裡的,映象的版本就是程式碼的版本,所以一定是切映象。至於回滾操作本身,Kubernetes 已經內建了很多滾動釋出(Rolling update)的策略,無論是發新版本還是回滾版本,都可以做到使用者無感知。
A:幾個要點:
-
映象倉庫部署在內網,映象推拉走內網,幾個 G 的映象傳輸起來也只是秒級別的
-
映象構建時將不經常變動的部分劃分到 1 層,因為 Docker 映象是分層的,這樣每次拉映象可以利用到 Docker 的快取傳輸的只有映象發生變化的部分
-
選擇 alpine 這樣儘量小的映象
A:可以調整一下思路,直接把需要的功能做成映象在 Drone 裡呼叫就好了。
A:Drone serve r用 Kubernetes 部署的話本身只起到了一個任務排程的作用,很難會遇到效能瓶頸。真的有效能問題可以嘗試水平擴充套件 Drone server,共享同一資料庫。
-
https://avnpc.com/pages/android-auto-deploy-workflow-on-travis-ci
-
https://github.com/AlloVince/drone-ci-demo
-
https://github.com/AlloVince/drone-ci-demo/blob/master/kubernetes/drone.yaml
-
https://docs.drone.io/user-guide/pipeline/conditions/
-
http://plugins.drone.io/drone-plugins/drone-docker/