1. 程式人生 > >使用 JS 開發 Github Actions 實現自動部署前後臺專案到自己伺服器

使用 JS 開發 Github Actions 實現自動部署前後臺專案到自己伺服器

不想看前面這麼多廢話的可以直接跳到[具體實現](#開始動手了) ## Github Actions 是什麼? 說到 Github Actions 不得不提一下。 - **持續整合**(continuous integration):高質量的讓產品快速迭代 - **持續交付**(continuous delivery):交付給團隊測試 - **持續部署**(continuous deployment):持續交付的下一步核心概念團隊測試完成後自動部署到生產環境 CI/CD 是由很多操作組成的(如:執行單元測試、語法檢查、打包、部署等等)。Github 把這些操作稱為`action`,不同的專案很多的操作都是類似,Github 把這些操作整合成了一個[市場](https://github.com/marketplace?type=actions)允許大家釋出或使用別人寫好的`action`。 ## Github Actions 的核心概念 ![action](https://user-gold-cdn.xitu.io/2020/7/10/17336d21dfb92115?w=1331&h=625&f=png&s=64778) ### 操作(Action) - `action`是工作流中最小的可移植模組 - 可以建立屬於自己的`action`,使用 Github 社群提供的`action`以及自定義公開的`action` - 在工作流中使用需要將其作為`steps`包含 - 使用是 使用者名稱/倉儲名/版本(或分支) 如:`actions/checkout@master` ### 事件(Event) - 觸發工作流執行的特定事件 - Github 本身事件`提交`、`建立問題`、`PR`等 - 使用 webhook 配置發生在外部的事件 [具體事件請參閱](https://docs.github.com/en/actions/reference/events-that-trigger-workflows) ### GitHub-hosted runner | 虛擬主機環境 | YAML 工作流標籤 | | -------------------- | ---------------------------------- | | Windows Server 2019 | `windows-latest` or `windows-2019` | | Ubuntu 20.04 | `ubuntu-20.04` | | Ubuntu 18.04 | `ubuntu-latest` or `ubuntu-18.04` | | Ubuntu 16.04 | `ubuntu-16.04` | | macOS Catalina 10.15 | `macos-latest` or `macos-10.15` | ### 作業(Job) - 在同一個執行程式上執行的一組步驟。 - 可以為作業在工作流檔案中的執行方式定義依賴關係規則。 - 作業可以同時並行執行,也可以按順序執行,具體取決於前一個作業的狀態。例如,一個工作流可以有兩個連續的作業來生成和測試程式碼,其中測試作業取決於生成作業的狀態。如果生成作業失敗,測試作業將不會執行。 - 對於 GitHub 託管的執行程式,工作流中的每個作業都在虛擬環境的新例項中執行。 [具體作業詳細配置請參閱](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobs) ### 步驟(Step) - 步驟是可以執行命令或操作的單個任務。 - 一個作業可配置**一個**或**多個**步驟。 - 作業中的每個步驟都在同一個執行器上執行,從而允許該作業中的操作使用**檔案系統共享資訊**。 ### 工作流(Workflow) - 可配置的自動化過程。測試、打包、釋出或部署等等。 - 工作流由**一個**或**多個**作業組成,可以通過事件計劃或啟用。 ### 工作流配置檔案(Workflow file) - 所有需要執行的工作流都必須放在 GitHub 儲存庫的根目錄下的`.gitHub/workflows` 目錄中。 - 需要使用`YAML`檔案配置並以`.yml`字尾結尾 ## 我為什麼要使用 Github Actions 在沒有使用 Github Actions 我部署程式是這樣的。 ![之前](https://user-gold-cdn.xitu.io/2020/7/8/1732eb909f211a87?w=345&h=515&f=png&s=13437) ![我太難了](https://user-gold-cdn.xitu.io/2020/7/8/1732eb90a0a8628c?w=300&h=225&f=jpeg&s=43005) ## 如何使用? 使用 Github Actions 後。 ![之後](https://user-gold-cdn.xitu.io/2020/7/8/1732eb90a0cb4527?w=161&h=169&f=png&s=4150) ## 為什麼要自己寫一個 Github Actions 1. 出來很久一直在用有點好奇是怎麼處理的 2. 網上找了一些各種測試不成功(~~其實這才是主要原因哈哈~~) ## 開始動手了 ### 目錄結構 ``` shh-deploy |—— dist(編譯後的目錄可用直接執行) | |—— index.js |—— lib(TS輸出檔案) |—— src(原始碼檔案) | |—— main.ts | |—— sftp.ts | |—— ssh-deploy.ts | action.yml(Github Actions的配置檔案) | tsconfig.json(TS配置檔案) ``` ### 思考? 我們既然要實現自動部署。 1. 需要連線到伺服器`ip`、`port`、`username`、`password` 1. 需要哪些檔案(`source`) 1. 部署到伺服器哪個目錄下(`target`) 1. 檔案複製完後需要執行安裝依賴重啟服務等等之內的工作(`after command`) 知道我們需要什麼後,接下來就來看具體實現。 ### Github Actions 具體實現 ```yml # action.yml 配置檔案 name: 'SSH Auto Deploy' # 名稱 description: 'ssh auto deploy' # 描述 author: 'hengkx' # 作者 branding: icon: 'crosshair' # 使用的是Feather的圖示 color: 'gray-dark' # 圖示顏色 inputs: # 輸入引數 HOST: # 伺服器地址 description: 'remote host' # 引數描述 required: true # 是否必填 USERNAME: # 使用者名稱 description: 'username' required: true PASSWORD: # 密碼 description: 'password' required: true PORT: # 埠 description: 'port' default: 22 # 預設值 SOURCE: # 源目錄 description: 'local path' required: true TARGET: # 目標目錄 description: 'remote target' required: true AFTER_COMMAND: # 檔案上傳文成後執行 description: 'upload success execute command' runs: # 執行環境 using: 'node12' main: 'dist/index.js' # 所執行的檔案 ``` 有一點需要注意我們所提交的程式碼包含`node_modules`或者使用`@zeit/ncc`直接打包成可執行檔案 ```ts // main.ts import * as core from '@actions/core'; import { Client } from 'ssh2'; import Sftp from './sftp'; function exec(conn: Client, command: string) { return new Promise((resolve, reject) => { conn.exec(command, (err, stream) => { if (err) return reject(err); stream .on('close', function (code) { resolve(code); }) .on('data', function (data) { core.info(data.toString()); }) .stderr.on('data', function (data) { core.error(data.toString()); }); }); }); } export async function run() { try { const host = core.getInput('HOST'); // 使用這個方法來獲取我們在action.yml配置檔案中設定的輸入引數 const port = parseInt(core.getInput('PORT')); const username = core.getInput('USERNAME'); const password = core.getInput('PASSWORD'); const src = core.getInput('SOURCE'); const dst = core.getInput('TARGET'); const afterCommand = core.getInput('AFTER_COMMAND'); // 下面為ssh連結伺服器上傳檔案並執行命令 const conn = new Client(); conn.on('ready', async () => { const sftp = new Sftp(conn); core.info('begin upload'); await sftp.uploadDir(src, dst); core.info('end upload'); let code: any = 0; if (afterCommand) { core.info('begin execute command'); // 輸出一條日誌 code = await exec(conn, `cd ${dst} && ${afterCommand}`); core.info('end execute command'); } conn.end(); if (code === 1) { core.setFailed(`command execute failed`); // 告訴Github Actions執行失敗了 } }); conn.connect({ host, port, username, password }); } catch (error) { core.setFailed(error.message); } } ``` 我的專案配置檔案 ```yml name: Deploy on: # 在master分支上提交程式碼執行 push: branches: [master] jobs: # 作業 build-and-deploy: # 作業名稱 runs-on: ubuntu-latest # 執行的環境 steps: #步驟 - name: Checkout # 步驟名 uses: actions/checkout@master # 所使用的action - name: Setup Node.js environment uses: actions/[email protected] with: node-version: '12.x' - name: Build Project run: yarn && yarn run ci - name: Deploy to Server uses: hengkx/[email protected] with: # 以下為引數 USERNAME: ${{ secrets.DEPLOY_USER }} # 為了使用者資訊保安對敏感資料可以在secrets中配置請看下圖 PASSWORD: ${{ secrets.DEPLOY_PASSWORD }} HOST: ${{ secrets.DEPLOY_HOST }} SOURCE: 'dist' TARGET: '/root/task-market/api' AFTER_COMMAND: 'npm run stop && npm install --production && npm run start' ``` ![secrets](https://user-gold-cdn.xitu.io/2020/7/10/17336d21e2378048?w=1087&h=428&f=png&s=88669) [原始碼地址](https://github.com/hengkx/ssh-deploy) ## 參考連結 - [GitHub Actions 官方文件](https://docs.github.com/en/actions) - [GitHub Actions 入門教程](http://www.ruanyifeng.com/blog/2019/09/getting-started-with-github-actions.html) ![](https://user-gold-cdn.xitu.io/2020/7/10/17336dbf31634d13?w=1710&h=624&f=png&s=34906)