
持續整合&持續交付. Docker、CircleCI、AWS、NodeJS (一)
前言
傳統開發流程中,常常出現程式在我的電腦可以跑,但是換到你的電腦或正式環境就無法運作的狀況,因此發展出Docker 容器技術,可以使用統一的Dockerfile 來制定開發環境,並設定正式環境,解決常見環境設定問題。
解決了環境設定問題後,每次更新程式碼,都需要手動重新從Git上拉最新的程式碼下來部署,也是一件非常消耗時間成本的事情,因此便有了持續整合&持續交付(Continuous Integration & Continous Delivery),簡稱 CI&CD。CI&CD可以自動化測試,自動化部署,減少開發時的人工消耗。
網路上已有許多文章,但都已過時,因此參考其他文章並重新彙整
使用到的工具:
Git: 版本控制工具 Github: 程式碼託管 CircleCI: 自動化建置、測試、部署 Docker: 輕量級容器 AWS Elastic Beanstalk: 雲端平台
完整的部署流程圖如下
Node.js
使用Node.js作為範例,安裝Node文章請參考: Linux作業系統如何安裝最新或是指定版本的Node.js?
創建一個專案目錄
$ mkdir hello-ci-workflow $ cd hello-ci-workflow
在本地端執行 Node.js
初始化專案
$ npm init
此步驟會在hello-ci-workflow專案目錄下初始化一個Nodejs的執行環境,包含package.json
等檔案。
在這邊我們用express框架作為測試,所以先安裝express
$ npm install express --save
此命令會將express框架儲存在專案目錄內,並寫入package.json
內
// package.json { "name": "hello-ci-workflow", "main": "index.js", "dependencies": { "express": "^4.17.0" }, "scripts": { "start": "node index.js" } }
接著我們在index.js
寫入一段程式碼
// index.js var express = require('express') //把express引用進來 var app = express() //設置Router app.get('/', (req, res) => { res.send('Hello World!') }) //把輸出port設置為3000 app.listen(3000, () => { console.log('Example app listening on port 3000!'); }) module.exports = app;
執行 npm start
或 node index.js
做第一次運作
$ npm start
打開瀏覽器,輸入網址 http://localhost:3000
,看到結果
在本地端測試 Node.js
我們以Jest、supertest
為測試套件,先進行安裝
Jest
為測試軟體,supertest
為模擬各種http request行為套件
$ npm install jest supertest --save-dev // --save-dev: 寫入 package.json 的 devDependencies,正式上線環境不會被安裝
編寫測試程式 index.test.js
// index.test.js const index = require('./index'); //把index.js import進來 const supertest = require('supertest'); // 把supertest import進來 test('HelloWorld', () => { // 對index.js打一個get('/')的request,觀察他的respond supertest(index).get('/').then((res) => { expect(res.statusCode).toBe(200) expect(res.body).toEqual(expect.any(Object)) expect(res.body).toEqual(expect.objectContaining({ result: expect.any(String) })) expect(res.body.result).toBe('Hello World!'); done(); }); })
簡單說明這個測試程式,為透過supertest打一個get request,並檢查他的respond是否有如你預期般地執行
檢查respond的Statue Code 是否為 200 (檢查是否正確的連線及回傳)
檢查respond的Body是否為一個物件
檢查respond的Body是否含有字串
檢查respond的Body是否回傳 Hello World!
在進行測試之前,修改package.json
// package.json "scripts": { "test": "jest --coverage --forceExit", "start": "node index.js" }
完成後的package.json
// package.json { "name": "hello-ci-workflow", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "node index.js", "test": "jest --coverage --forceExit" }, "author": "", "license": "ISC", "dependencies": { "express": "^4.17.0" }, "devDependencies": { "jest": "^24.9.0", "supertest": "^4.0.2" } }
說明test部分為使用Jest作為測試框架,–coverage為顯示測試程式碼的涵蓋範圍,– forceExit的部分,則為當你測試完後強制結束測試。
進行測試
$ npm test
看到測試結果為
執行完測試程式後,會看到「PASS」,但也會看到紅字「Uncoverd Lines」,代表在index.js裡面,第6, 10行的程式碼沒測到。 接著回到專案目錄下,會發現多了一個coverage資料夾, 點進去看會發現,它提供給你的覆蓋率參考檔案。
設定Git
$ git init $ vi .gitignore
修改 .gitignore
,加入以下兩行,代表忽略以下資料夾更動內容
coverage node_modules
接著就可以送出第一次commit了
$ git add . $ git commit -m "initial commit"
Docker 設定
當你在本機開發好,要上正式環境時,還需要額外安裝web server、node.js 、database等,而Docker就是一次設定就可以通用的一個設定檔,詳細內容可以參考:Docker 實戰系列(一):一步一步帶你 dockerize 你的應用
看完Docker介紹後,了解到設定Docker都必須有一個dockerfile
的設定檔,Dockerfile範例如下
# Dockerfile # 從 [Docker Hub](https://hub.docker.com/) 安裝 Node.js image。 FROM node:12.2.0-alpine # 設定 container 的預設目錄位置 WORKDIR /hello-ci-workflow # 將專案根目錄的檔案加入至 container 中 # 安裝 npm package ADD . /hello-ci-workflow RUN npm install && npm cache clean --force # 開放 container 的 3000 port EXPOSE 3000 CMD npm start
上述的dockerfile 會將本地程式碼包進docker容器內,接著安裝npm 相關的packages,最後運行一個nodejs的環境。
接著來建立這個容器
$ docker build -t hello-ci-workflow . //建立一個名為hello-ci-workflow的映像檔
$ docker run hello-ci-workflow // 運行
使用Docker-compose
寫好dockerfile後,為了針對不同環境會有不同的設定值,所以我們額外寫一個docker-compose來快速啟動docker
$ vi docker-compose.yml
// docker-compose.yml version: '3.3' services: hello-ci-workflow: image: hello-ci-workflow build: .
首先指定docker-compose版本,接著幫這個service取名(取為hello-ci-workflow
),並且設置 image名稱(設為 hello-ci-workflow
),再來 build : .
的意思為,將現有資料夾裡的內容,build 成一個image打包起來。
測試docker-compose
$ docker-compose -f docker-compose.yml run hello-ci-workflow
會得到跟上面直接運行docker一樣的結果
修改docker-compose-test.yml
再來為了以後CI的需要,我們為了測試也寫一個docker-compose,來設置不同環境
$ vi docker-compose-test.yml
// docker-compose-test.yml version: '3.3' services: hello-ci-workflow: image: hello-ci-workflow command: npm test // 只增加了這行 build: .
為了測試所以增加了一行 npm test
,運行這個容器時,會直接進到測試環境。
docker-compose -f docker-compose-test.yml run hello-ci-workflow
會跟上述直接運行 npm test
時,會有一樣的結果,代表正常運作
到這邊Docker部分告一段落
Github設定
在Github上創建完一個名為hello-ci-workflow
的repository後,可以使用以下指令將本地端的程式碼push到github上進行程式碼託管
$ git remote add origin https://github.com/<Your_user_name>/hello-ci-workflow.git $ git add . // 追蹤本機的修改檔案 $ git commit -m "add docker" // 加上此次的註解 $ git push -u origin master // 推送到github上
<Your_user_name> 改為你的github帳號
以上做完後,前往 https://github.com/<Your_user_name>/hello-ci-workflow
就可以看到你的程式碼
CircleCI
下一集內容會講到與CricleCI關聯部分,敬請期待下一集
參考資料:
DevOps Handbook中文版|打造世界級技術組織的實踐指南
DevOps:持續整合&持續交付(Docker、CircleCI、AWS)
超新手的一日CI/CD初體驗,使用CircleCi、Github-Flow自動部署Node.JS於AWS Elastic Beanstalk