国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > JavaScript > 正文

如何自動(dòng)化部署項(xiàng)目?折騰服務(wù)器之旅~

2019-11-19 11:46:19
字體:
供稿:網(wǎng)友

本篇文章講的不是如何把一個(gè)項(xiàng)目部署上線,而是如何自動(dòng)化上線。

開發(fā)了一個(gè)需求管理和發(fā)布系統(tǒng)。

通過這個(gè)系統(tǒng),可以創(chuàng)建需求、創(chuàng)建發(fā)布計(jì)劃、創(chuàng)建分支、部署到測(cè)試環(huán)境、部署到生產(chǎn)環(huán)境、正式上線、合并代碼等。

一、功能設(shè)計(jì)

9.9元的阿里云服務(wù)器真的很慢,但還是足夠折騰完這個(gè)項(xiàng)目。
用3個(gè)目錄來模擬不同的環(huán)境。

目錄 存放
project 存放所有的項(xiàng)目,比如本系統(tǒng)的前后端代碼。
pre-dir 預(yù)發(fā)環(huán)境,當(dāng)然是用來測(cè)試的。
pro-dir 生產(chǎn)環(huán)境,測(cè)試沒問題,部署上線。

一圖勝千言。

二、系統(tǒng)頁(yè)面

我的任務(wù)

接到一個(gè)新的需求,可以新建一個(gè)需求,并創(chuàng)建開發(fā)分支。

發(fā)布隊(duì)列

開發(fā)結(jié)束之后,便可以到發(fā)布隊(duì)列中,部署到預(yù)發(fā)環(huán)境進(jìn)行測(cè)試。 測(cè)試通過指定Cookie 就可以訪問到測(cè)試的代碼。最終再進(jìn)行線上部署。

 

項(xiàng)目信息

二、技術(shù)棧

前端技術(shù)棧
Vue + elementUI,具體代碼在Github,感興趣的可以看下并點(diǎn)個(gè)star哈~✨
服務(wù)端技術(shù)棧
非常常見的Node.js(Koa2) + Mysql + Redis + Pm2。
具體代碼在Github,感興趣的可以看下并點(diǎn)個(gè)star哈~✨

三、Redis和Session配置

 

// utils/Store.jsconst Redis = require("ioredis");const { Store } = require("koa-session2"); class RedisStore extends Store {  constructor() {    super();    this.redis = new Redis();  }   async get(sid, ctx) {    let data = await this.redis.get(`SESSION:${sid}`);    return JSON.parse(data);  }   async set(session, { sid = this.getID(24), maxAge = 1000 * 60 * 60 } = {}, ctx) {    try {      console.log(`SESSION:${sid}`);      // Use redis set EX to automatically drop expired sessions      await this.redis.set(`SESSION:${sid}`, JSON.stringify(session), 'EX', maxAge / 1000);    } catch (e) {}    return sid;  }   async destroy(sid, ctx) {    return await this.redis.del(`SESSION:${sid}`);  }} module.exports = RedisStore;
// 入口文件const session = require("koa-session2");const Store = require("./utils/Store.js");// session配置app.use(session({  store: new Store(),  key: "SESSIONID",}));

 四、Router配置

為了Router看起來更優(yōu)雅,也是通過中間件

// 1、middleware配置文件const routers = require('../routers');module.exports = (app) => {  app.use(routers());}// 2、index.js入口文件const middleware = require('./middleware');middleware(app);// 3、routers 注冊(cè)文件const Router = require('koa-router');const router = new Router();const koaCompose = require('koa-compose');// 接口入口const {insertDemand} = require('../controllers/demand/insertDemand');const {deleteDemand} = require('../controllers/demand/deleteDemandByDid');const {updateDemand} = require('../controllers/demand/updateDemandByDid');// 加前綴router.prefix('/api');module.exports = () => {  // 新增需求  router.get('/insertDemand', insertDemand);  // 刪除需求  router.get('/deleteDemand', deleteDemand);  return koaCompose([router.routes(), router.allowedMethods()]);}

五、nginx配置

最頭痛的就是nginx配置了,因?yàn)椴皇呛苁煜ぃ恢痹谠囧e(cuò)、踩坑。不過還好終于成功了!
前后端項(xiàng)目通過Nignx提供服務(wù),Node服務(wù)通過Nginx轉(zhuǎn)發(fā),主要是為了驗(yàn)證各種環(huán)境。
如果不設(shè)置Cookie,默認(rèn)訪問的就是線上環(huán)境,設(shè)置Cookie 就會(huì)走到預(yù)發(fā)布測(cè)試環(huán)境,用于測(cè)試。

# cookie 取TEST 賦值給$proxy_nodemap $cookie_TEST $proxy_node {  default "";  "1"   "1";  "2"   "2";  "3"   "3";}# 發(fā)布管理系統(tǒng)前端設(shè)置server {  listen    80;  server_name test.xue.com;  if ($proxy_node = ''){    set $dollar "/data/pro-dir/dandelion/dist/";  }  if ($proxy_node = "1") {    set $dollar "/data/pre-dir/dandelion/dist/";  }  location / {    root $dollar;    index index.html;    try_files $uri $uri/ /index.html;  }}# 發(fā)布管理系統(tǒng)后端設(shè)置# 反向代理到node服務(wù)server {  listen    80;  server_name m.xue.com;  if ($proxy_node = ''){    set $dollar "/data/pro-dir/study-demo/";  }  if ($proxy_node = "2") {    set $dollar "/data/pre-dir/study-demo/";  }  location / {    root $dollar;    index index.html;  }}# demo項(xiàng)目前端設(shè)置server {  listen    80;  server_name api.xue.com;  location / {    if ($proxy_node = "") {      set $from 3001;      proxy_pass http://47.107.188.55:3001;    }    if ($proxy_node = "3") {      set $from 3002;      proxy_pass http://47.107.188.55:3002;    }  }}

六、一些中間件

常用的HTTP設(shè)置

解決跨域,OPTIONS請(qǐng)求,攜帶Cookie憑證等問題。

module.exports = () => {  return async (ctx, next) => {    ctx.set('Access-Control-Allow-Origin', 'http://test.xue.com');    ctx.set('Access-Control-Allow-Credentials', true);    ctx.set('Access-Control-Allow-Headers', 'content-type');    ctx.set('Access-Control-Allow-Methods', 'OPTIONS, GET, HEAD, PUT, POST, DELETE, PATCH');    // 這個(gè)響應(yīng)頭的意義在于,設(shè)置一個(gè)相對(duì)時(shí)間,在該非簡(jiǎn)單請(qǐng)求在服務(wù)器端通過檢驗(yàn)的那一刻起,    // 當(dāng)流逝的時(shí)間的毫秒數(shù)不足Access-Control-Max-Age時(shí),就不需要再進(jìn)行預(yù)檢,可以直接發(fā)送一次請(qǐng)求。    ctx.set('Access-Control-Max-Age', 3600 * 24);    if (ctx.method == 'OPTIONS') {      ctx.body = 200;     } else {      await next();    }  }}

登錄

這個(gè)系統(tǒng)屬于強(qiáng)制登錄的,登錄統(tǒng)一進(jìn)行了處理。

const Store = require("../../utils/Store");const redis = new Store();module.exports = () => {  return async (ctx, next) => {    // 白名單    if (ctx.request.url === '/api/login') {      return await next();    }     const SESSIONID = ctx.cookies.get('SESSIONID');    if (!SESSIONID) {      return ctx.body = {        mes: '沒有攜帶SESSIONID~',        data: '',        err_code: 1,        success: false,      };    }    const redisData = await redis.get(SESSIONID);    if (!redisData) {      return ctx.body = {        mes: 'SESSIONID已經(jīng)過期~',        data: '',        err_code: 1,        success: false,      };    }    if (redisData && redisData.uid) {      console.log(`登錄了,用戶uid為${redisData.uid}`);      await next();    }  }}

七、操作shell腳本

舉個(gè)例子,創(chuàng)建項(xiàng)目分支

let path = ''; // 項(xiàng)目路徑// 創(chuàng)建分支const branch_name = `branch_${new Date().getTime()}`;cp.execSync(`/data/dandelion-server/shell/createBranch.sh ${path} ${branch_name}`);
#!/bin/bashcd $1git pull origin mastergit checkout -b $2git push --set-upstream origin $2

八、連接數(shù)據(jù)庫(kù)

config.js配置文件

let dbConf = null;const DEV = {  database: 'dandelion',  //數(shù)據(jù)庫(kù)  user: 'root',  //用戶  password: '123456',   //密碼  port: '3306',    //端口  host: '127.0.0.1'   //服務(wù)ip地址}const PRO = {  database: 'dandelion',  //數(shù)據(jù)庫(kù)  user: 'root',  //用戶  password: '123456',   //密碼  port: '3306',    //端口  host: 'xx.xx.xx.xx'   //服務(wù)ip地址}dbConf = PRO; //這個(gè)可以通過判斷區(qū)分開發(fā)環(huán)境module.exports = dbConf;

數(shù)據(jù)庫(kù)連接文件

const mysql = require('mysql');const dbConf = require('./../config/dbConf');const pool = mysql.createPool({ host: dbConf.host, user: dbConf.user, password: dbConf.password, database: dbConf.database,})let query = function( sql, values ) {  return new Promise(( resolve, reject ) => {    pool.getConnection(function(err, connection) {      if (err) {        reject( err )      } else {        connection.query(sql, values, ( err, rows) => {          if ( err ) {            reject( err )          } else {            resolve( rows )          }          connection.release()        })      }    })  })}module.exports = {  query,}

就可以在model層調(diào)用了~

const {query} = require('../common/mysql');class UserModel {  constructor() {}  /**   * @description: 根據(jù)pid和did創(chuàng)建一個(gè)分支   * @param {pid} 項(xiàng)目id   * @param {did} 需求id   * @param {branch_name} 分支名   * @return: 分支信息   */  async insertBranchInfo(sqlParams) {    const sql = 'insert branch_info (pid, bid, branch_name, pub_time) values(?,?,?,?)';    console.log(sql)    let data = await query(sql, sqlParams, (err, result) => {      return result;    });    return data;   }}

九、域名

沒有買域名,通過本地修改hosts(可以直接用工具)

47.107.188.xx為服務(wù)器IP

47.107.188.xx test.xue.com
47.107.188.xx api.xue.com
47.107.188.xx m.xue.com

 總結(jié)

算是第一次自己搭建一個(gè)完整的項(xiàng)目,從前端到后端。

尤其是后端,作為一個(gè)前端小白,從學(xué)習(xí)如何使用服務(wù)器,到Linux/Vim/Shell/Nignx/Pm2/Redis/Session/Mysql/Koa2。沒有像以前一樣,直接拿別的項(xiàng)目看,而是一步一個(gè)腳印的學(xué)習(xí),雖然也都是皮毛,但是感覺自己的知識(shí)體系豐富了很多。也去了解了很多持續(xù)集成的知識(shí),當(dāng)然我做的小項(xiàng)目還是比較簡(jiǎn)單的啦~ 喜歡就點(diǎn)個(gè)贊鼓勵(lì)一下吧,(^__^) 嘻嘻……
詳細(xì)的使用都在前端項(xiàng)目后端項(xiàng)目,感興趣的可以看下并點(diǎn)個(gè)star哈~✨

 以上所述是小編給大家介紹的自動(dòng)化部署項(xiàng)目詳解整合,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)武林網(wǎng)網(wǎng)站的支持!

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 灌云县| 天柱县| 南澳县| 宁晋县| 金昌市| 江油市| 凤山市| 阆中市| 馆陶县| 上林县| 拜泉县| 满城县| 工布江达县| 敦化市| 淮安市| 四子王旗| 夹江县| 闽侯县| 陕西省| 泰宁县| 邹平县| 北安市| 阳城县| 芮城县| 佛山市| 绿春县| 福州市| 贵港市| 河北省| 贺州市| 绥德县| 徐水县| 钦州市| 马边| 元江| 衡南县| 千阳县| 唐河县| 阿瓦提县| 镇康县| 个旧市|