身處在講求效率的時代,完整的開發流程當然少不了 CI/CD。什麼是 CI/CD 呢?CI ( Continuous Integration ) 中文為「持續性整合」,目的是讓專案能夠在每一次的變動中都能通過一些檢驗來確保專案品質。CD ( Continuous Deployment ) 中文則為「自動化佈署」,讓專案能夠自動在每次變動後能以最新版本呈現。
由於想要體會 CI/CD 到底有多方便,於是想要藉由實做一個簡單的 Node.js 專案來實際體驗看看。
內容架構
1.寫簡易的 Node.js Server
2.使用 CircleCI 整合 eslint/jest(CI)
3.使用 CircleCI deploy 到 GCP App Engine(CD)
NodejS Hello CICD demo
這是專案最終架構:
1 | ├── app.yaml |
哇!看起來很複雜?別急,下面會一一帶你做一遍!
Step by Step
建立資料夾
1 | mkdir demo-server |
初始化專案
1 | yarn init |
這時會出現問題問你,若沒有特殊設定可以一路按 Enter 就好,回答完後就會出現 package.json
。
這樣就能產生出 package.json 囉!
開發專案少不了版本控制,這樣就能開始使用 git 了 🥳
1 | git init |
而不必要的檔案記得寫進 .gitignore 讓 git 忽略。
新增 .gitignore
1 | node_modules |
安裝 express 及 babel
express 是一個 Node.js 的後端框架,這次 demo 會用來處理 server。 由於 Node.js 處理檔案引入和匯出方法為 require 及 module.export , 而 es6 出現了 import 及 export,如要使用就要使用 babel 來 transpile。
1 | yarn add express |
babel 只有在開發會用到,注意後面要加 — dev。
建立 src/server.js
1 | import express from 'express'; |
本機跑起來
1 | yarn babel-node src/server.js |
babel-node 會在 node runtime 即時使用 babel transpile javascript。
這樣就能在 localhost 跑起來了 😌
使用 nodemon 快速開發
nodemon 是一個無人不知無人不曉的開發 Node.js 專案的工具,nodemon 會隨時隨地監測程式,程式一發生變動就會自動重跑,重整網頁就能夠看到變化。
安裝 nodemon
1 | yarn add nodemon --dev |
新增 nodemon.json
1 | { |
在 package.json 新增 script
1 | "scripts": { |
新增 test/server.test.js
1 | import supertest from 'supertest'; |
這個結果就表示 test 通過囉 🙃
安裝 eslint 及 prettier
eslint 是 javascript linter 之一,可以用來預防語法錯誤,其實最大的好處是可以維持團隊的 coding style(ex. airbnb),但因為這次是個人專案這個優點就沒有被顯現出來了 XD
prettier 是要維持程式碼的整齊性,可以設定在存檔時程式碼格式化,統整團隊的規範。例如:要加雙引號還是單引號。
值得注意的是在同時引用 prettier 及 eslint 時,兩者會一些功能相衝突,而可以使用 eslint-plugin-prettier 解決這個問題。
設定 eslint + prettier + babel
開始著手寫設定檔 .eslint.js,這次 babel parser 會用到 babel-eslint,而在 extends 會用到 eslint-config-airbnb-base/ eslint-plugin-jest / eslint-plugin-prettier, eslint-plugin-import 是用來 lint es6 的 import 及 export。
1 | yarn add eslint-plugin-prettier eslint prettier babel-eslint eslint-config-airbnb-base eslint-plugin-jest eslint-plugin-prettier eslint-plugin-import --dev |
.eslint.js
下面有寫到常用的 rules,大家可以參考看看。
1 | module.exports = { |
.prettierrc
1 | { |
這裡可以看到相當多的 error,若想要一鍵把所有 error 解決掉,可以加上 --fix
。
在 package.json 新增 script
1 | "scripts": { |
就可以一鍵跑 eslint 啦 🤪
避免糟糕的 commit
忘記先跑 eslint 及 test 就 commit 情形難免會有,這時候在 commit 之前先做檢查就變得非常重要。這專案使用的是 git hooks husky
及 lint-staged
。
安裝 husky 及 lint-staged
1 | yarn add husky lint-staged --dev |
.huskyrc.js
使用 husky 跑 eslint 及 test。
1 | module.exports = { |
lint-staged.config.js
在 commit 之前會做到 eslint
及 git add
。
1 | module.exports = { |
這邊可以看到 husky 幫我們先跑了 lint 後再跑 test 🤠
app build
最後一步是進行 build 的動作,build 在 Node.js 專案通常是拿來做 bundle 或是 transpile,讓 node 能夠認識我們寫的 code 。
1 | "scripts": { |
p.s. --copy-files
會複製除了 js 以外的檔案,例如 .json
接下來就可以下指令了:
1 | yarn run build |
跑完後就發現多了 build 的檔案夾,
1 | ├── build |
裡面有 transpile 過後的 server.js,點進去後會發現有一堆紅線等著你。
這紅線也太討厭了吧 (O
別慌,這時候新增 .eslintignore
1 | /build/** |
讓 eslint 別去檢查 build 出來的東西,紅線就會消失了!build/server.js
等等會拿來做 deploy 。
到這邊就完成了基本的 Node.js App 囉 🥳
CircleCI
circ因為是要透過 GitHub 進行 CI/CD,所以是以 GitHub 帳號登入 CircleCI。首先會先進到 CircleCI 介面,選擇你要 CI/CD 的專案。
OS 我選擇 Linux (相較於其他二個最輕量),跑得比較快。因為是寫 Node.js,language 選 Node。
接下來設定在專案裡新增 circleci/config.yml,相關教學可以參考: https://circleci.com/docs/2.0/language-javascript/
1 | version: 2.1 # use CircleCI 2.1 |
把 commit push 到 repo,CircleCI 就開始幫你跑 lint / test 並 build 喔!這時候 CI 就完成了!
可以看到 lint 及 test CircleCI 都幫我們跑了!
成功囉!
我們將使用功能十分強大的 Google App Engine(GAE)進行部署,GAE 在處理大流量(load)時,例如訂票系統或是物流系統時非常適合。不但不用自己管理 load balance 的問題。Google 還會幫你自動開關 instances,使用者付費原則,用多少就付多少。
因為 GAE 是 Google Cloud Platform(GCP)下的一個服務所以若還沒有 GCP 先註冊註起來!新註冊的人可以享有一年 300 美金的試用,注意註冊時需要輸入一張信用卡才能開始使用,在試用階段 Google 並不會為向你收費,除非你主動跟他說要訂閱方案才會開啟收費流程。
註冊完後我們就能夠開始使用 GCP 了,進到 Google App Engine(GAE) 畫面,接下來點擊 建立應用程式。
這裡可以選擇你用的機房在哪裡,雖然 Google 近年有在彰化新增機房,但是因為是免費用戶的關係,不能選擇,所以我選擇最近的機房 asia-northeast2(日本大阪),ping 較低,延遲會比較少。
選擇你的專案是使用何種語言,環境若沒有特殊需求選擇標準即可。到這邊已經成功建立 App Engine 應用程式了!
但是要操作自如還要搭配 Google Cloud SDK,可以透過指令列工具來對 GCP 服務進行操作。這邊可以進行下載以及初始化的動作:
點擊下載 SDK 後選擇查看快速入門導覽課程後選擇 macOS 快速入門。
選擇 macOS 64 位元下載檔:
進到下載檔下 ./install.sh
,會跳出 Welcome to the Google Cloud SDK!就表示安裝完成了。
可以使用 gcloud -v
來確認是否真的安裝成功,正常的話,沒意外接下來就可以使用 gcloud 指令來進行操作了。
接下來照著說明文件開始 初始化並登入 gcloud SDK ,
就完成基本設定啦!
是時候來設定 App Engine 了,要設定 App Engine 需要有 app.yaml
檔。
這邊有簡易的設定教學可以參考: https://cloud.google.com/appengine/docs/flexible/nodejs/configuring-your-app-with-app-yaml?hl=zh-tw
若要更為詳細的可以看看這篇: https://cloud.google.com/appengine/docs/flexible/nodejs/reference/app-yaml?hl=zh-tw#general
這是我的 app.yaml
設定:
1 | runtime: nodejs # Name of the App Engine language runtime used by this application |
接下來,我們就可以手動 deploy 啦!
1 | gcloud app deploy |
在 CircleCI deploy
要透過 CircleCI 部署到 GCP,需要授權 Google Cloud SDK。在 circleci/config.yml
再加上
1 | deploy: |
記得到 CircleCI 填入需要的 key, project_id
, region
。
用到的 key 金鑰需要到 Cloud IAM 申請:
都填妥後,再 depoy 一次會出現下面這個 error:
會產生這個錯誤是因為是用 GCP 的 service account 部署,而這會需要用到 App Engine Admin API,這個 API 預設會是 disable 的,這時把選項 enable 再 rerun CircleCI 就好。
這樣就 deploy 完成囉 🥳
前人種樹後人乘涼
透過簡易的 Node.js server 完整跑一次 CI/CD 流程,發現設定好 CI/CD 能夠大大節省開發專案的時間,化繁為簡、提升效率,也能夠讓工程師專心在開發上,是個非常賺的投資啊 XD 減少 murmur 的時間(X)。 別等了!趕快在自己的專案加入 CI/CD 吧!
此篇同步發表於 👉 五倍紅寶石。
GitHub repo 👉 https://github.com/MindyTai/demo-nodejs-server