當咱們修改一個需求完成後,將最新的代碼push到github的時候,咱們線上的版本會自動化完成拉取代碼,打包構建,重啓服務等流程。html
經過這種技術咱們能夠將本地代碼一秒完成線上項目的部署與重啓。再也不須要大量的人力去作上線部署重複的工做。前端
衆所周知,前端的需求常常發生變動及微小的調整,每一次上線須要經歷複雜的固定化的流程:修改代碼—代碼檢測—功能實現測試—構建項目—上傳構建完成的項目包—線上測試。vue
稍微大一點的項目更是涉及龐大的用戶人羣,稍有不慎,就將釀成上線慘案。一到上線日,忙得雞飛狗跳最後上線的代碼還有可能有着種種出乎本身意料的bug。給團隊和項目帶來不可估量的損失。node
自動化服務端持續集成部署就是將以自動化的方式將之前須要人工一步一步實現的上線流程,經過代碼自動化來實現,達到項目上線精準無偏差的地步。linux
已有項目:vue前端項目(font);後端項目:(back)nginx
#升級系統內全部的軟件與內核
#若是系統內已經有項目在跑的就不要使用這句命令,很高的風險會影響以前的項目環境
yum update
#安裝git
yum install git -y
#建立本地git項目下載存放的目錄
mkdir /usr/projects
#使用github的ssh 生成ssh免密用戶公鑰--後面兩步直接回車設置爲默認空
# -t指定加密算法爲rsa -b指定大小爲4096字節 -c指定github帳號郵箱地址
ssh-keygen -t rsa -b 4096 -C "1403029829@qq.com"
#查看已經生成的公鑰地址
cat /root/.ssh/id_rsa.pub
複製代碼
#找到項目根目錄
cd /usr/projects/
#克隆後端代碼
#注意:clone的時候會提醒是否確認克隆,必定要輸入yes
git clone git@github.com:cometang/back.git
#克隆前端代碼
git clone git@github.com:cometang/font.git
複製代碼
#安裝nvm node 版本管理工具
wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
#將nvm配置到服務器環境變量中
./root/.bashrc
#nvm安裝最新的node穩定版
nvm install stable
#nvm安裝node版本 11.11.0 【我本地開發所使用的node版本】
nvm install 11.11.0
#安裝nrm切換npm的安裝源,通常國內服務器切換爲淘寶鏡像
npm install nrm -g
#nvm 命令使用含義
#查看本地已經下載的全部node版本
nvm list
#切換node版本
nvm use 11.11.0
#查看node版本
node -v
#查看npm版本
npm -v
複製代碼
開放後端端口:'3000' 前端端口:'8080' webhook端口:'4000'
複製代碼
docker倉庫中有各類軟件的鏡像地址git
#安裝centos的yum-utils工具包
yum install yum-utils device-mapper-data lvm2
#設置docker的yum安裝源爲阿里雲的地址
yum-config-manager \
--add-repo \
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#安裝社區免費版docker
yum install -y docker-ce docker-ce-cli containerd.io
#查看docker版本
docker -v
#設置docker軟件源安裝地址爲阿里雲地址
#新建docker文件夾
mkdir -p /etc/docker
#設置安裝源地址爲阿里雲的地址[把下面的josn對象文本寫入到json文件中]
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors":["http://fwvjnv59.mirror.aliyuncs.com"]
}
EOF
#重置全部修改過的配置文件
systemctl daemon-reload
systemctl restart docker
#切換源爲淘寶鏡像地址
nrm use taobao
複製代碼
#進入back項目根目錄
cd back
npm install
#啓動服務
npm start
複製代碼
個人接口地址:http://47.99.192.199:3000/api/usersgithub
新創建一個鏈接,不要關閉後端服務,注意修改前端項目中的接口地址爲服務器公網ipweb
#進入font項目根目錄中
cd /usr/projects/font
npm install
npm run serve
複製代碼
在本地瀏覽器中訪問前端項目:IP地址:8080算法
先後端兩個項目保持一致
注意:鏈接密碼的配置必定要與webhook項目中的密碼保持一致
cd /usr/projects/
git clone git@github.com:cometang/webhook.git
cd webhook
npm install
node webhook
複製代碼
修改前端後端項目代碼後提交代碼到github 查看服務器是否會提醒代碼更新
//webhook.js //測試鏈接github是否可以檢測到代碼更新並向webhook服務發送請求並【非完整版代碼】 let http = require('http'); let server = http.createServer(function (req, res) { //判斷github發送的是否是post 是否是webhook發送的請求 console.log('檢測到前端後端代碼更新,github發來的請求信息以下:') console.log(req.method,req.url); if (req.method == 'POST' && req.url == '/webhook') { //設置github請求的請求頭,設置返回數據的格式爲json res.setHeader('Content-Type', 'application/json'); //返回通知github請求已經成功 res.end(JSON.stringify({ok:true})); } else { res.end('NOT Found'); } }) server.listen(4000, () => { console.log('webhook服務已經在4000端口啓動'); }) 複製代碼
當前端或者後端代碼提交後webhook收到github的post請求--至關於消息推送
關掉服務器鏈接以後webhook服務會自動斷開,爲了使得webhook持久化檢測,安裝pm2,當node服務斷開以後,pm2會自動重啓node服務
npm install pm2 -g
複製代碼
修改完成後從新提交代碼到github,服務器從新將webhook代碼pull便可
//package.json "scripts": { "start":"pm2 start ./webhook.js --name webhook --watch", "stop":"pm2 stop webhook" }, 複製代碼
在服務器webhook根目錄pull完代碼以後使用 npm start 實現經過pm2從新啓動webhook服務
npm start
複製代碼
1.查看pm2 日誌【能夠查看到全部關於提交的先後端兩個項目的代碼日誌】
pm2 logs
複製代碼
2.提交先後端兩個項目的代碼到github,測試是否可以檢測到提交
//webhook.js let http = require('http'); let cryto = require('crypto'); let SECRET = '123456'; //與在先後端項目github中設置的Secret相同 //生成簽名算法 //根據SECRET字符串使用哈希算法生成十六進制的新的字符串 function sign(body) { return `sha1=` + cryto.createHmac('sha1', SECRET).update(body).digest('hex') } let server = http.createServer(function (req, res) { //判斷github發送的是否是post 是否是webhook發送的請求 console.log('檢測到前端後端代碼更新,github發來的請求信息以下:') console.log(req.method, req.url); if (req.method == 'POST' && req.url == '/webhook') { //拿到github傳遞過來的參數--對請求的github進行簡單的驗證 let buffers = [] req.on('data', function (buffer) { buffers.push(buffer) }) req.on('end', function (buffer) { let body = Buffer.concat(buffers) //github傳的值請求事件類型:push事件 let event = req.headers['x-github-event'] //github傳遞了請求體body,同時傳遞了簽名,須要驗證簽名是否正確 let signatrue = req.headers['x-hub-signatrue'] if (signatrue !== sign(body)) { //sign不相等 直接返回錯誤 return res.end('Not Allowed') } //sign相同 執行贊成請求 //設置github請求的請求頭,設置返回數據的格式爲json res.setHeader('Content-Type', 'application/json'); //返回通知github請求已經成功 res.end(JSON.stringify({ ok: true })); }) } else { res.end('NOT Found'); } }) server.listen(4000, () => { console.log('webhook服務已經在4000端口啓動'); }) 複製代碼
在webhook項目的跟目錄下寫項目的快速部署 快速集成的腳本
#!/bin/bash #後端項目快速構建腳本 #後端項目路徑 WORK_PATH = '/usr/projects/back' cd $WORK_PATH echo "先清除老代碼" git reset --hard origin/master git clean -f echo "拉取新代碼" git pull origin master echo "開始執行構建後端項目:back爲docker鏡像名稱 1.0爲版本號" docker build -t back1.0 . echo "中止舊容器 並刪除舊容器" docker stop back-container docer rm back-container echo "啓動新容器" docker container run -p 3000:3000 --name back-container -d back1.0 複製代碼
對docker進行配置,生成項目鏡像
注意:在back項目中的gitignore裏面不要寫 Dockerfile dockerignore
FROM node LABEL name = "back" LABEL version ="1.0" COPY . /app WORKDIR /app RUN npm install EXPOSE 3000 CMD npm start 複製代碼
.gitignore
Dockerfile
node_moudules
複製代碼
拉取完成後端代碼和webhook最新代碼後,在服務器webhook項目根文件夾下執行命令查看是否可以成功構建:sh back.sh
sh back.sh
複製代碼
#提示報錯信息
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
#解決方案:在webhook項目跟目錄下運行一下命令,而後從新運行 sh back.sh便可:
sudo systemctl start docker
複製代碼
出現最後的下載構建的列表 表示啓動docker服務成功,開始構建
驗證是否docker 服務是否成功拉取最新代碼並完成自啓動
curl http://localhost:3000/api/users
複製代碼
圖片中的報錯信息是由於沒有新的版本能夠拉取,因此報錯,可略過
第二次使用 sh back.sh 就能夠實現完整的後端服務自動化構建,自動化部署的過程
新容器啓動後經過瀏覽器直接能夠訪問更新的接口地址:IP:端口/接口名,個人接口地址爲:http://47.99.192.199:3000/api/users;亂碼的緣由是由於json數據直接放到網頁轉碼的問題,用前端接口請求用在渲染到網頁就沒有這種亂碼了。自此後端項目自動化持續集成部署已經所有完成。
後端項目已經部署完成,下面部署稍微複雜的前端項目。
#!/bin/bash WORK_PATH='/usr/projects/font' cd $WORK_PATH echo "先清除老代碼" git reset --hard origin/master git clean -f echo "拉取新代碼" git pull origin master echo "編譯build" npm run build echo "開始執行構建後端項目:back爲docker鏡像名稱 1.0爲版本號" docker build -t font:1.0 . echo "中止舊容器 並刪除舊容器" docker stop font-container docker rm font-container echo "啓動新容器" docker container run -p 80:80 --name font-container -d font:1.0 複製代碼
From nginx LABEL name = "font" LABEL version ="1.0" COPY ./dist /usr/share/nginx/html COPY ./font.conf /etc/nginx/conf.d EXPOSE 80 複製代碼
server{
listen 80;
server_name 47.99.192.199;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://47.99.192.199:3000;
}
}
複製代碼
yum install nginx -y
複製代碼
注意:前端代碼的.gitignore文件不要排除Dockerfile .Dockerfileignore文件
在服務器webhook目錄下執行 sh font.sh後會自動去拉取前端最新代碼,並自動構建bulid
git pull origin marster
複製代碼
sh font.sh
複製代碼
完成webhook.js代碼後提交到服務器,在服務器webhook項目中pull最新的webhook配置代碼
//webhook.js 完整版代碼 let http = require('http'); let cryto = require('crypto'); let { spawn } = require('child_process'); //開啓部署的子進程 let SECRET = '123456'; //與在先後端項目github中設置的Secret相同 //生成簽名算法 //根據SECRET字符串使用哈希算法生成十六進制的新的字符串 function sign(body) { return `sha1=` + cryto.createHmac('sha1', SECRET).update(body).digest('hex') } let server = http.createServer(function (req, res) { //判斷github發送的是否是post 是否是webhook發送的請求 console.log('檢測到前端後端代碼更新,github發來的請求信息以下:') console.log('req----hedaers') console.log(req.headers['x-github-event']) console.log(req.method, req.url); if (req.method == 'POST' && req.url == '/webhook') { //拿到github傳遞過來的參數--對請求的github進行簡單的驗證 let buffers = []; req.on('data', function (buffer) { buffers.push(buffer); }) req.on('end', function (buffer) { let body = Buffer.concat(buffers); //github傳的值請求事件類型:push事件 let event = req.headers['x-github-event']; //github傳遞了請求體body,同時傳遞了簽名,須要驗證簽名是否正確 let signatrue = req.headers['x-hub-signature']; if (signatrue !== sign(body)) { //sign不相等 直接返回錯誤 return res.end('Not Allowed'); } //sign相同 執行贊成請求 //設置github請求的請求頭,設置返回數據的格式爲json res.setHeader('Content-Type', 'application/json'); //返回通知github請求已經成功 res.end(JSON.stringify({ ok: true })); //自動化部署 if (event == 'push') { let payload = JSON.parse(body); let name = './' + payload.repository.name + '.sh' //開啓子進程自動執行對應的sh部署腳本,提交back就執行 sh back.sh 的子進程 let child = spawn('sh', [name]) //打印操做日誌 //每當子進程有日誌輸入的時候,就拋出一個日誌,最後一次性輸出整個更改日誌 let buffers = [] child.stdout.on('data', function (buffer) { console.log('啓動子進程') buffers.push(buffer) }) child.stdout.on('end', function (buffer) { let log = Buffer.concat(buffers) console.log(log) }) } }) } else { res.end('NOT Found'); } }) server.listen(4000, () => { console.log('webhook服務已經在4000端口啓動'); }) 複製代碼
注意:命令中的單引號及單引號中的內容須要更換爲對應的container(容器名)
docker container ps
docker container rm 'container_name' 'container_name' -f
複製代碼
npm run stop
npm run start
pm2 logs
複製代碼
服務器自動啓動子進程對相應項目完成構建,並變動輸出日誌
每次的本地代碼提交,對應項目的線上版本都會自動完成拉取,構建,提交最新代碼到github後,兩分鐘左右線上版本便可完成更新
注意:郵件方式暫時不寫,後續有時間再貼代碼,具體實現思路:在webhook中引入 sendMail ,在構建成功以後發送通知郵件到指定的郵箱地址便可。