GitLab Workflow內容包括,git 版本控制系統、CI/CD Pipeline,以及專案管理的功能,像 Wiki、Issue Tracking、Kanban、Burndown Chart等。GitLab 的 CI/CD Pipeline 會依據使用者存放在各專案內的 .gitlab-ci.yml 檔自動建立,且能順利整合從測試到部署的大多數常見工具或第三方服務。
Continuous Integration 持續整合
藉由頻繁的整合,來減輕版本之間差異過大時,會發生的合併困難甚或失敗。在此階段,通常還會加入自動化測試來確保待合併的分支,不會發生功能錯誤。
Continuous Delivery 持續佈署
在確定程式碼的功能性正常後,會自動因應不同的環境進行相對應的程式檔佈署。佈署完成後,可以進行手動測試驗證。
Continuous Deployment 持續交付
在已經有相對應的程式檔後,自然就要落地到機器上來正式運行,給客戶們使用啦,這就是這階段的目的。
CI/CD可以加快代碼發布速度,CI/CD使開發人員能夠更快地做更多的事情,確保可靠性和可用性,提高開發人員的效率,自動化,工具和可觀察性。Gitlab Pipeline 優點如下,
.gitlab-ci.yml 是定義一個流程稱為 pipeline,他是每次要建置、測試時應該要跑完的完整步驟流程,而 pipeline 裡面可以切割成數個「stage」(階段,例如 build、test 這樣算兩個 stage),每個「stage」則可以有多個「job」(工作)。
在執行的時候,他會按照 stage 的順序執行,前一個 stage 完成後、才會執行下一個 stage。當 stage 的所有 job 都順利完成後,他才會去執行下一個 stage,其中如果有某些 job 失敗了,那就不會執行下一個 stage,pipeline 就會此以失敗的狀態結束。
當執行 .gitlab-ci.yml 定義的 pipeline 的時候,GitLab Server 會去找合適的 runner,把這個 job 丟給 runner 執行。至於哪個 job 該用哪個 Runner 是使用 tag來做區分。針對 Runner 做設定,看是要全站共用、群組共用、或是專案共用。
當 Runner 收到 GitLab Server 指派工作的時候,他就會從 GitLab Server 上把程式碼複製過來(用 git),然後執行所交付的工作,並將紀錄、結果回報給 GitLab Server。
Run GitLab Runner in a container
$ docerk pull gitlab/gitlab-runner
$ docker volume create gitlab-runner-config
$ docker run -d --name gitlab-runner --restart always
-v /var/run/docker.sock:/var/run/docker.sock
-v gitlab-runner-config:/etc/gitlab-runner
gitlab/gitlab-runner:latest
$ docker run --rm -it -v gitlab-runner-config:/etc/gitlab-runner gitlab/gitlab-runner:latest register
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
Docker Image
在 CI/CD流程
中有很重要的角色,CI流程時環境指令是否正確運行與是否使用對的 Image
有很大的關係。
我的 Dockerhub
帳號 xenophon566
有已經配好的 Docker Image
方便在每個CI流程使用。
如果不是使用 Gitlab 的
share runner
,gitlab-ci.yml
檔中就要特別指定tag 欄位
,否則會找不到runner
。
package.json
"scripts": {
"start": "ng serve --port 4201",
"ng:ut-r": "ng test --watch=false --browsers=ChromeHeadlessCI",
"cy:ci-r": "npx cypress run --config-file cy-ci.json",
"ng": "ng",
"build": "ng build"
}
karma.conf.js
module.exports = function (config) {
config.set({
...
customLaunchers: {
ChromeHeadlessCI: {
base: "ChromeHeadless",
flags: ["--no-sandbox", "--disable-setuid-sandbox"],
},
},
});
};
Dockerfile
# Stage 1: Compile and Build angular codebase
# Use official node image as the base image
FROM xenophon566/node:latest as build
# Set the working directory
WORKDIR /usr/local/app
# Add the source code to app
COPY ./ /usr/local/app/
# Install all the dependencies
RUN npm ci --include=dev
# Generate the build of the application
RUN npm run build
# Stage 2: Serve app with nginx server
# Use official nginx image as the base image
FROM xenophon566/ng-deploy:latest
# Copy the build output to replace the default nginx contents.
COPY --from=build /usr/local/app/dist/cypress-playground /usr/share/nginx/html
# Expose port 80
EXPOSE 80
.gitlab-ci.yml
的檔案,並根據該檔案所定義的內容自動建立 CI/CD Pipeline。.gitlab-ci.yml
// 表示目前規劃有4個 stages
stages:
- build
- test:unit
- test:e2e
- deploy:uat
build:
// 建立階段 - build stage
stage: build
// 使用我的 node image
image: xenophon566/node
// 只觸發於 main 分支
only:
- main
// 腳本開始前
before_script:
// 安裝依賴包
- npm ci --include=dev --cache-folder node_modules
script:
// 打包專案
- npm run build
// 專案建好後放到 Gitlab Page
- mkdir .public
- rm -rf public/.public
- cp -r dist/* .public
- mv .public public
when: on_success
cache:
untracked: true
key:
files:
- package-lock.json
paths:
- node_modules/
policy: pull-push
artifacts:
paths:
- public
expire_in: 1 week
test:unit:
// 單元測試階段 - unit test stage
stage: test:unit
image: xenophon566/node
only:
- main
dependencies:
- build
before_script:
- npm ci --include=dev --cache node_modules --prefer-offline
script:
// 執行 Angular 內建的 Karma 進行單元測試
- npm run ng:ut-r
- echo "Unit Test DONE..."
test:e2e:
// E2E測試階段 - e2e test stage
stage: test:e2e
// 使用 cypress image 進行 E2E 測試
image: cypress/browsers:node16.14.2-slim-chrome103-ff102
only:
- main
dependencies:
- build
before_script:
- npm ci --include=dev --cache-folder node_modules
script:
// 執行 Cypress 進行 E2E 測試位於 Gitlab Page 的頁面
- npm run cy:ci-r
- echo "E2E Test DONE..."
deploy:uat:
// 佈署階段 - ng-deploy image
stage: deploy:uat
// 佈署 UAT 階段 - 使用我的 dind image
image: xenophon566/dind
services:
- docker:dind
only:
- main
dependencies:
- build
before_script:
- docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD"
script:
// 建立我的 xenophon566/ng-deploy image 並存到 Docker Hub
- docker build --cache-from $NG_DEPLOY_IMAGE:latest -t "$NG_DEPLOY_IMAGE:$CI_COMMIT_SHA" .
- docker push "$NG_DEPLOY_IMAGE:$CI_COMMIT_SHA"
// 手動 Pipeline 流程
when: manual
按照上述的流程佈署,最終在
UAT
階段會產生一個 Imagexenophon566/ng-deploy
然後在接其他自動流程或手動佈署到指定環境做使用。
deploy:uat
為手動執行階段play
按鍵後會製作 Docker Image
存到 Dockerhub
Karma
進行單元測試E2E
測試位於 Gitlab Page 的頁面ng-deploy image
推到 Dockerhub
ng-deploy
ImageUAT
環境,QA人員就可以進行人工測試了,例如佈署 ng-deploy
到本機 http://localhost/#/home
可見到畫面如下,前幾篇介紹了 Angular 的自動測試,有了 Gitlab Pipeline 的 CI/CD
工作流程,更讓自動測試功能如虎添翼,其他工具像是 CircleCI,Travis CI 等等數十種工作流程管理工具,有興趣可以自行去研究。
前幾篇也介紹了在 Gitlab 中被稱為 Merge requests 的功能,讓代碼最終被 push
時可以有機會被審查一次,能有效解決技術債的累積問題。
本文練習範例請參考 CypressPlayground
下一篇會總結一下,使用 Angular 開發專案還有哪些知識需要知道。