手摸手,帶你實現程式碼自動部署

dendoink發表於2018-12-06

為什麼?

為什麼要實現自動部署?

在2個月的時間裡,一直都在忙著整理部落格,每一個程式設計師都有一個部落格夢(當然也不排除有些是沒有的),我先後使用過各種部落格系統:

這些都因為前前後後的原因,我沒有采用,而是自己寫了一個部落格系統:vue-blog-generater【請允許我再求一波star】點選這裡檢視說明文件

為什麼呢?因為我需要一個自己對其高度熟悉的系統,這樣有什麼問題,我都知道問題出在哪,因為之前的這些系統,當然很好,但是無論是主題的編輯,還是程式碼的部署以及自定義,這些都不能滿足我的要求。

話說回來,當我實現好了基礎功能和頁面之後,我開心了好一會兒,然後把一些還有意義的博文轉移過來,這就涉及到了釋出和部署。

我們都知道一個vue-cli生成的專案,通常打包的目錄都是dist,那麼我實際上需要掛載到伺服器上的程式碼就是這個dist中的程式碼。

那按照常理,整個文章的更新流程應該是這樣:

  1. 新建檔案,編寫markdown博文
  2. npm run build 編譯到dist
  3. dist的檔案上傳到對應的程式碼倉庫dist
  4. 將當前生成器的檔案同步上傳到對應程式碼倉庫main
  5. 登入伺服器,git clone dist倉庫到指定的位置

看到了吧,只是更新一篇文章,卻需要這麼多步驟,是不是覺得很麻煩呢?麻煩就對了,在這裡我們就是來解決這個麻煩的。

如何做?

我明白了為什麼要做自動部署,但是我從哪下手呢?

做一件事情之前,我們要理清楚思路,有哪些步驟呢?其實非常簡單:

  1. 新建檔案,編寫markdown博文【這一步是跑不掉的】
  2. npm run build 編譯到dist,執行build.js中判斷config.js中是否配置了dist的遠端倉庫地址。
    如果配置了就對當前專案的dist目錄,進行git初始化,同時將整體程式碼上傳到Main倉庫這裡預設不配置,Main倉庫相當於本地倉庫關聯的遠端倉庫
  3. 給本地dist目錄關聯遠端倉庫,並把程式碼推送到指定的dist對應的遠端倉庫中。
  4. 伺服器進行配置,當接受到託管平臺傳送的POST請求時,做出對應的響應:拉取遠端dist倉庫的master分支並且強制覆蓋本地的master分支

具體實現?

我們先來看看在第2,3個所說的內容怎麼實現。

  • 準備工作:安裝需要的庫
    shell 幫助我們在nodejs中執行命令
    chalk 豐富列印資訊
//安裝shell
yarn add shell --save
yarn add chalk --save
複製程式碼
  • 我們在build.js中設計一個函式autoUpdate,來幫助我們提交main倉庫和我們的dist倉庫的更新,我們先實現更新main倉庫:請注意:這裡需要使用await確保程式碼的執行順序
const config = require('../config')
const shell = require('shelljs')

async function autoUpdate() {
  console.log(chalk.cyan(
    `Start to upload whole project to coding.net`
  ))
  if (!shell.which('git')) {
    //向命令列列印git命令不可用的提示資訊
    shell.echo('Sorry, this script requires git');
    //退出當前程式
    shell.exit(1);
  }
  // 推送當前目錄[main 目錄]的程式碼
  await shell.exec('git add .')
  await shell.exec(`git commit -m '${config.commitMessage}'`).code
  await shell.exec('git push origin master -f');
  console.log(chalk.green(
    `main dir-> succeed`
  ))
}
複製程式碼
  • @/config/index.js中配置 dist遠端倉庫 相關的屬性的值
module.exports = {
   ...
   distOriginSSh: 'git@github.com:xxx/xxx-blog-xxx.git',
   ...
}
複製程式碼
  • autoUpdate中新增提交dist倉庫的更新的程式碼:請注意:這裡需要使用await確保程式碼的執行順序
  //進入到dist目錄下
  await shell.cd('dist');
  //執行 git init
  await shell.exec(config.initLocal)
  //刪除本地的dist已經對應的遠端倉庫
  await shell.exec(config.deleteRemote)
  //新增目標遠端倉庫到dist
  await shell.exec(`git remote add origin '${config.distOriginSSh}'`)
  //提交
  await shell.exec('git add .')
  let code = await shell.exec(`git commit -m '${config.commitMessage}'`).code
  if (code !== 0) {
    await shell.echo('Error: Git commit failed');
    await shell.exit(code);
  } else {
    await shell.exec('git push origin master -f');
    //chalk 這個庫是為了豐富列印資訊的
    console.log(chalk.green(
      `dist-> succeed`
    ))
  }
複製程式碼

實現了本地上傳到遠端倉庫,那麼接下來我們需要去做幾件事,來實現步驟4:
這裡預設你已經在伺服器上完成了對dist程式碼的部署

  1. 在自己的伺服器上啟動一個服務,監聽POST的請求,如果確定這個請求是通知我們需要更新伺服器上對應dist目錄對應的原始碼的話,執行對應的git命令來更新。
  2. 配置遠端倉庫的hooks,在監聽到我們的push請求時,就會自動POST一個請求到我們配置的hooks對應的地址中。這個地址也就是我們在伺服器上啟動的服務地址。

Okay,知道了要做什麼,那我們就開始吧。首先在伺服器上啟動一個node server,我們新建一個server.js,並且進入到編輯狀態

touch server.js
//如果你安裝了vim
vim server.js
//如果沒有安裝vim,可以用vi
vi server.js
//進入檔案後,我們可以按a健進入 insert狀態
複製程式碼

可以參考我的server.js進行配置 請注意,需要你自己配置埠和路徑,我已經去除了我自己的配置

var http = require('http')
  , exec = require('exec')

// 配製你的埠號
const PORT = XXX
  , PATH = './xxx'
//PATH:你的dist目錄的路徑,相對於server.js所在的目錄而言。
var deployServer = http.createServer(function(request, response) {
  if (request.url.search(/deploy\/?$/i) > 0) {

    var commands = [
      'cd ' + PATH,
      'git fetch --all',
      'git reset --hard origin/master',
      'git pull'
    ].join(' && ')

    exec(commands, function(err, out, code) {
      if (err instanceof Error) {
        response.writeHead(500)
        response.end('Server Internal Error.')
        throw err
      }
      process.stderr.write(err)
      process.stdout.write(out)
      response.writeHead(200)
      response.end('Deploy Done.')

    })

  } else {

    response.writeHead(404)
複製程式碼

編輯完成後,然後我們先按下esc然後輸入:wq!儲存檔案。然後node server.js啟動一個服務。但是你又會發現,node server.js這樣啟動的服務會在一段時間後自動停止,所以我們需要來用一個守護程式的工具來守護我們的服務,推薦大家使用forever

#安裝
npm install forever -g
#啟動
forever server.js
複製程式碼

還沒有結束,我們還需要在nginx配置檔案中設定一個代理,將對應子域名代理到我們剛剛配置的埠上。這樣做的原因是因為我只有一個域名···

你可能會問什麼是子域名,比如我有一個一級域名dendoink.com那麼我可以在解析的時候多新增一條新記錄xxx.dendoink.com,這個就是子域名,他同樣可以訪問到我們域名對應的伺服器。

如果你使用的也是nginx來管理服務,那可以參考我下面的配置

    server {
    listen       80;
    # 配置你的子域名
    server_name  xxx.你的域名.com;

    #charset koi8-r;
    access_log  /var/log/nginx/githook.dendoink.com.access.log  main;
    
    # 這裡是重點
    location / {
        proxy_pass http://127.0.0.1:1024;
    }
    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}
複製程式碼

這樣配置好以後我們就可以通過外部訪問到我們定義好的服務啦。只需要把這個地址加入到對應的githook的配置中【具體的hook配置參考你的託管平臺教程】。

是不是很簡單呢?有任何問題可以掘金和我聯絡,或者郵件 dendise7en@gmail.com

另外求一波關注和star -> 看這裡,最美部落格系統~
另外求一波關注和star -> 看這裡,最美部落格系統~
另外求一波關注和star -> 看這裡,最美部落格系統~


特別宣告:題圖來源unsplash

相關文章