前端運(yùn)維部署那些事

?聊到運(yùn)維,很長一段時間我覺得跟前端就是毫無關(guān)聯(lián)的玩意,應(yīng)該說半毛錢關(guān)系都木。但隨著前端工程化的發(fā)展,前端基本運(yùn)維部署相關(guān)知識甚至也逐步被重視,如果你公司的運(yùn)維部門很強(qiáng)大,那么你也可以完全忽略運(yùn)維相關(guān)的。只是樹醬覺得,如果你想更多了解前端架構(gòu),還是需要具備一定的運(yùn)維相關(guān)知識儲備。當(dāng)然,現(xiàn)在云廠商都想應(yīng)推出自己的Serverless服務(wù)(下一篇會講~),號稱讓前端更專注業(yè)務(wù)的開發(fā),而不用擔(dān)心底層應(yīng)用的部署和維護(hù),對開發(fā)者而言可以更多聚焦到業(yè)務(wù)領(lǐng)域的開發(fā),有興趣的童鞋可以去玩玩
?

1.npm
?npm 是 Node.js 官方提供的包管理工具,主要用來管理項(xiàng)目依賴,發(fā)布等等,下面介紹幾個比較常見的部署應(yīng)用場景,常用的npm命令這里不作介紹了
?
1.1 nrm
?nrm(npm registry manager )是npm的鏡像源管理工具,因?yàn)閚pm默認(rèn)建立的鏈接訪問的是國外的資源,訪問速度較慢,使用這個就可以快速地在 npm 源間切
?
如何安裝
npm install -g nrm
查看可選的資源
nrm ls
*npm ---- https://registry.npmjs.org/
cnpm --- http://r.cnpmjs.org/
taobao - http://registry.npm.taobao.org/
eu ----- http://registry.npmjs.eu/
...
添加私有倉庫鏈接
nrm add name http://registry.npm.tree.com/ # 私有倉庫鏈接
nrm use name # 使用本址的鏡像地址
nrm 更多用于如果公司內(nèi)網(wǎng)部署了私有倉庫,也就是方便用nrm作來源切換,也有益于依賴的版本管理,如果你想搭建自己的私有倉庫,可以使用verdaccio,可以看這個具體的教程 點(diǎn)我??
1.2 發(fā)布npm包
?當(dāng)我們想發(fā)布一個npm包,需要完成什么樣的流程呢?
?
先注冊npm賬號 ?? 配置package.json
{
"name": "kutil",
"version": "1.0.0", #版本名稱
"scripts":[], # 可執(zhí)行的腳本命令
"repository": "https://github.com/xxx/xxx.git", #github倉庫地址
"author": "tree <[email protected]>", #作者
"description": "工具包“, #包的說明
"keywords": [
"utils",
]
}
配置打包機(jī)制
?如果是工具類打包,推薦使用rollup,webpack比較適合打包一些應(yīng)用,例如SPA或者同構(gòu)項(xiàng)目
?
添加單元測試
?優(yōu)質(zhì)的開源包,都有單元測試模塊,來保證包的穩(wěn)定性和代碼質(zhì)量,常見會有build-passing的標(biāo)記,有興趣的童鞋可以閱讀樹醬之前寫的前端單元測試那些事
?
開發(fā)文檔readme.me
?readme方便開發(fā)者快速熟悉,包括具體的Api介紹、使用例子、項(xiàng)目介紹等等,還可以加入包括單元測試覆蓋率、下載量、證書等等
?
最后完成上面一系列操作之后,到了最終的發(fā)布環(huán)節(jié)
npm login # 登錄你上面注冊的npm賬號
npm publish # 登錄成功后,執(zhí)行發(fā)布命令
+ [email protected] # 發(fā)布成功顯示npm報名及包的版本號
2. jenkins
?jenkins作為一個可擴(kuò)展的自動化服務(wù)器,可以用作簡單的 CI 服務(wù)器,具有自動化構(gòu)建、測試和部署等功能,簡而言之,jenkins可以方便我們?nèi)粘5那岸隧?xiàng)目版本更新迭代(開發(fā)、測試、生產(chǎn)環(huán)境等),也可以通過它自動化完成一系列的操作包括:編譯打包元測試、代碼掃描等,官方文檔
?
2.1 如何安裝
下載 Jenkins.
打開終端進(jìn)入到下載目錄.
運(yùn)行命令
java -jar jenkins.war --httpPort=8080.打開瀏覽器進(jìn)入鏈接 http://localhost:8080.
按照說明完成安裝.
詳細(xì)流程圖可參考 Jenkins+github 前端自動化部署
2.2 配合前端項(xiàng)目自動化部署
?這里主要介紹jenkins流水線配置的使用,流水線的代碼定義了整個的構(gòu)建過程, 他通常包括構(gòu)建, 測試和交付應(yīng)用程序的階段,下面是路徑和倉庫的配置
?

圖片相關(guān)配置如下:
SCM:選擇git或者svn作為代碼觸發(fā)器 腳本路徑:在項(xiàng)目根目錄創(chuàng)建jenkinsfile來編寫流水線
下面介紹一個簡單版的jenkinsfile的流水線任務(wù)寫法,完成整個前端工程化部署涉及的編譯打包、靜態(tài)掃描、單元測試等環(huán)節(jié)
def gitUrl = "http://gitlab.****.com/shc/****.git"//GIT入口(隨不同工程改變)
def gitCred = "***-***-4f00-a926-1848b670d97b" //GIT 身份憑據(jù)
if ("DEV" == buildType) {
buildScript = "build_development"
try {
node('k8s') {
stage('下拉源碼') {
checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${gitCred}", url: "${gitUrl}"]]])
#可由片段生成器生成,選擇示例步驟 “checkout:Check out from version control”,生成流水線腳本獲取
}
checkStatus('下拉源碼')
stage('代碼構(gòu)建編譯') {
sh "yarn run ${buildScript}"
}
checkStatus('代碼構(gòu)建編譯')
stage('代碼靜態(tài)掃描') {
sh 'yarn run lint'
}
checkStatus('代碼靜態(tài)掃描')
stage('單元測試') {
sh 'yarn run unit'
}
checkStatus('單元測試')
}
} catch(Exception e) {
}
}
完成后,即可構(gòu)建項(xiàng)目,分階段完成,首先是下拉源碼、代碼構(gòu)建編譯、代碼掃描等等,所有環(huán)節(jié)成功才算自動化部署成功,如下所示

3.Docker
?Docker是一個虛擬環(huán)境容器,可以將開發(fā)環(huán)境、代碼、配置文件等一并打包到這個容器中,最后發(fā)布應(yīng)用
?
3.1 如何使用
?通過將部署的操作集中成一個部署腳本完成傳統(tǒng)的部署流程,通過在服務(wù)器上運(yùn)行docker容器來運(yùn)行前端應(yīng)用
?
如何安裝
yum install docker-ce
項(xiàng)目目錄,部署項(xiàng)目需要準(zhǔn)備Dockerfile和nginx.conf(如果nginx不作定制化,可以直接用官方鏡像)

3.2 Dockerfile 配置
?dockerfile是一個配置文件,用來讓docker build命令清楚運(yùn)行那些操作,創(chuàng)建dockerfile并編寫相關(guān)配置
?
FROM node:latest as builder
WORKDIR /app
COPY package.json
RUN npm install
COPY . .
RUN npm run build
FROM nginx:latest
COPY nginx.conf /etc/nginx
COPY --from=builder /app/dist /usr/share/nginx/html
//ps: 每一個指令的前綴都必須是大寫的。
ADD和COPY: 將文件或目錄復(fù)制到Dockerfile構(gòu)建的鏡像中 EXPOSE: 指定運(yùn)行該鏡像的容器使用的端口,可以是多個。 RUN :指令告訴docker 在鏡像內(nèi)執(zhí)行命令 FROM :通過FROM指定的鏡像名稱,這個鏡像稱之為基礎(chǔ)鏡像,必須位于第一條非注釋指令 WORKDIR: 在容器內(nèi)部設(shè)置工作目錄
Nginx.conf 配置如下
events {
worker_connections 1024;
}
http{
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
}
創(chuàng)建文件并編寫后,用docker創(chuàng)建鏡像
3.3 如何創(chuàng)建鏡像
?使用當(dāng)前目錄的 Dockerfile 創(chuàng)建鏡像,標(biāo)簽為 frontend
?
docker build -t frontend .
-t :指定要創(chuàng)建的目標(biāo)鏡像 . :Dockerfile 文件所在目錄,可以指定Dockerfile 的絕對路徑


鏡像成功生成
3.4 查看鏡像
docker image ls | grep frontend

出現(xiàn)結(jié)果則應(yīng)用鏡像 frontend 成功創(chuàng)建,然后我們基于該鏡像啟動一個Docker容器
4.5 如何啟動
?使用docker鏡像frontend:latest以指定80端口映射模式啟動容器,并將容器命名為frontend
?
docker run --name frontend -p 80:80 frontend:latest
-p: 指定端口映射,格式為:主機(jī)(宿主)端口:容器端口 將宿主的80端口映射到容器的80端口 -name: 為容器指定一個名稱;
完成 docker 部署
docker也可以集成到上一節(jié)講的jenkins自動化部署流水線中去
stage('部署到開發(fā)聯(lián)調(diào)環(huán)境') {
echo "auto deploy to test environment"
sh "docker build -t frontend ."
sh "docker run --name frontend -p 80:80 frontend:latest"
}
4.PM2
?PM2是node進(jìn)程管理工具,可以利用它來簡化很多node應(yīng)用管中繁瑣任務(wù),是Nodejs應(yīng)用程序守護(hù)進(jìn)程必不可少的選擇,方便管理基于nodejs平臺下能夠有獨(dú)立運(yùn)行訪問的web服務(wù),如nextjs、express、koa等前端應(yīng)用
?
4.1 常見的應(yīng)用場景
部署node koa2 或 express 項(xiàng)目應(yīng)用 部署 前端SSR(后端渲染)應(yīng)用,如nuxt.js(Vue)和 next.js(React)等構(gòu)建服務(wù)端渲染應(yīng)用框架
4.2 如何使用
安裝 : npm install -g pm2啟動node項(xiàng)目 : pm2 start app.js 或者 pm2 start bin/www停止pm2服務(wù): pm2 stop bin/www停止所有pm2服務(wù): stop all重啟pm2服務(wù): pm2 restart bin/wwwpm2所有進(jìn)程信息: pm2 list
啟動后如下所示
4.3 高階應(yīng)用
?在項(xiàng)目根目錄中添加一個processes.json
?
{
#apps是一個數(shù)組,每一個數(shù)組成員就是對應(yīng)一個pm2中運(yùn)行的應(yīng)用
"apps": [{
"name": "app", #名稱
"script": "./", #程序入口
"cwd": "./", #應(yīng)用程序所在的目錄
"error_file": "./logs/err.log",#錯誤輸出日志
"log_date_format": "YYYY-MM-DD HH:mm Z" #日期格式
}]
}
結(jié)合packjson腳本命令,可以用processes來管理多應(yīng)用
"script":{
"pm2":"pm2 start processes.json"
}
更多命令和配置信息查看 pm2文檔
5.Nginx
?Nginx它既可以作為 Web 服務(wù)器,也可以作為負(fù)載均衡服務(wù)器,具備高性能、高并發(fā)連接等
?
5.1 前端Nginx那些事

詳細(xì)信息請看之前梳理的前端Nginx那些事
5.2 補(bǔ)充
灰度發(fā)布
?灰度發(fā)布即是讓一部分人繼續(xù)用舊版本的產(chǎn)品A,然后一部分用戶開始用新版本特征的產(chǎn)品B,如果用戶對B沒有什么問題反饋,則逐步擴(kuò)大范圍。一方面可以保證整體系統(tǒng)的穩(wěn)定,而且在初始灰度的時候就可以發(fā)現(xiàn)、調(diào)整問題,以保證其影響度
?
傳統(tǒng)的灰度是通過Nginx分發(fā)流量到服務(wù)器,這里介紹一下簡單的灰度規(guī)則配置,通過在nginx里面配置路由規(guī)則就好,如果是規(guī)則復(fù)雜的話,可以結(jié)合nginx+lua 做一些些灰度的業(yè)務(wù)邏輯
1.根據(jù)Cookie實(shí)現(xiàn)灰度發(fā)布
?通過獲取cookie設(shè)置的版本號來區(qū)分
?
upstream test1 {
server 192.168.0.1:8080 max_fails=1 fail_timeout=60;
}
upstream default {
server 192.168.0.0:8080 max_fails=1 fail_timeout=60;
}
server {
listen 80;
server_name www.****.com;
set $group "default";
if ($http_cookie ~* "version=V1"){
set $group test1;
}
location / {
proxy_pass http://$group;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
index index.html index.htm;
}
}
根據(jù)IP實(shí)現(xiàn)灰度發(fā)布
?通過內(nèi)外網(wǎng)IP來區(qū)分
?
upstream test1 {
server 192.168.0.1:8080 max_fails=1 fail_timeout=60;
}
upstream default {
server 192.168.0.0:8080 max_fails=1 fail_timeout=60;
}
server {
listen 80;
server_name www.xxx.com;
set $group default;
if ($remote_addr ~ "10.0.0.110") {
set $group test1;
}
location / {
proxy_pass http://$group;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
index index.html index.htm;
}
}
請你喝杯?? 記得三連哦~
1.閱讀完記得給?? 醬點(diǎn)個贊哦,有?? 有動力
2.關(guān)注公眾號前端那些趣事,陪你聊聊前端的趣事
3.文章收錄在Github frontendThings 感謝Star?
