React+Koa+MongoDB+Docker開發環境

前言

本次博文依然是對 multi-spa-webpack-cli 的擴充和完善。

  1. 集成 mongoose
  2. 集成 Docker 開發環境。

multi-spa-webpack-cli 已經發布到 npm,只要在 node 環境下安裝即可。

npm install multi-spa-webpack-cli -g

使用步驟如下:

# 1. 初始化項目

multi-spa-webpack-cli init spa-project

# 2. 進入文件目錄

cd spa-project

# 未使用 Docker
# 3. 打包不變的部分

npm run build:dll

# 4. 啓動項目(手動打開瀏覽器:localhost:8090)

npm start

# 5. 啓動 MongoDB

mongod

# 6. 啓動服務

cd server
npm install
npm start

# 使用 Docker(需安裝docker)
# 3. 啓動項目(手動打開瀏覽器:localhost:8090)

npm run docker:dev

從上面的步驟可以看出,Docker 只需要 3 步就可以啓動項目了。

mongoose

mongoose 是在 node.js 環境下對 MongoDB 進行便捷操作的對象模型工具。

在沒開始之前,要先安裝 MongoDB。安裝 MongoDB 的過程中,可能有些小麻煩,尤其是公司的電腦(誰也不知道電腦裏配置了什麼東西)。安裝過程可參照 【官網:安裝MongoDB

還要知道 MongoDB 的一些概念。

SQL術語/概念 MongoDB術語/概念 解釋/說明
database database 數據庫
table collection 數據庫表/集合
row document 數據記錄行/文檔
column field 數據字段/域
index index 索引
table joins 表連接,MongoDB不支持
primary key primary key 主鍵,MongoDB自動將_id字段設置爲主鍵

數據庫服務和客戶端:

SQL MongoDB
Mysqld/Oracle mongod
mysql/sqlplus mongo

mongoose 相關概念看看官網就好了【mongoose 中文文檔

用法很簡單,定義 Schema,轉換成 Model,操作 Model,生成實例。

/* model.js */
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// 定義 Schema
const UserSchema = new Schema({
  username: {
    type: String,
    unique: true,
    require: true
  },
  password: {
    type: String,
    require: true
  }
});

// 轉換成 Model
const UserModel = mongoose.model('User', UserSchema);

module.exports = UserModel;

/* user.js */
// 操作 Model
let user = await UserModel.findOne({ username });
    if (!user) {
        try {
            // 生成實例
            await new UserModel({
            username,
            password
            }).save();
            ctx.body = {
            "success": true,
            "message": "註冊成功"
            }
        } catch (error) {
            ctx.body = {
            "success": false,
            "message": "註冊失敗"
            }
        }
    } else {
    ctx.body = {
        "success": false,
        "message": "用戶名已存在"
    }
}

Docker

由上面的步驟,我們可以看出來,項目啓動步驟麻煩,而且在安裝 MongoDB 環境時,容易受干擾。

下面通過 Docker 來構建開發環境,提高開發體驗。

在使用 Docker 之前,先了解下幾個概念。

  • 鏡像: 鏡像只是一個虛擬的概念,其實際體現並非由一個文件組成,而是由一組文件系統組成,或者說,由多層文件系統聯合組成。
鏡像構建時,會一層層構建,前一層是後一層的基礎。每一層構建完就不會再發生改變,後一層上的任何改變只發生在自己這一層。比如,刪除前一層文件的操作,實際不是真的刪除前一層的文件,而是僅在當前層標記爲該文件已刪除。在最終容器運行的時候,雖然不會看到這個文件,但是實際上該文件會一直跟隨鏡像。因此,在構建鏡像的時候,需要額外小心,每一層儘量只包含該層需要添加的東西,任何額外的東西應該在該層構建結束前清理掉。

所以,在生產部署時,確保每一層的純淨,剔除不必要文件。比如開發編譯時的文件等( node_module )。這樣也避免了鏡像不必要的臃腫。

  • 容器:容器的實質是進程,但與直接在宿主執行的進程不同,容器進程運行於屬於自己的獨立的 命名空間。
容器內的進程是運行在一個隔離的環境裏,使用起來,就好像是在一個獨立於宿主的系統下操作一樣。這種特性使得容器封裝的應用比直接在宿主運行更加安全。

每一個容器運行時,是以鏡像爲基礎層,在其上創建一個當前容器的存儲層,我們可以稱這個爲容器運行時讀寫而準備的存儲層爲容器存儲層。

容器存儲層的生存週期和容器一樣,容器消亡時,容器存儲層也隨之消亡。因此,任何保存於容器存儲層的信息都會隨容器刪除而丟失。

按照 Docker 最佳實踐的要求,容器不應該向其存儲層內寫入任何數據,容器存儲層要保持無狀態化。所有的文件寫入操作,都應該使用 數據卷(Volume)、或者綁定宿主目錄,在這些位置的讀寫會跳過容器存儲層,直接對宿主(或網絡存儲)發生讀寫,其性能和穩定性更高。

開發環境經常對文件修改,就可以利用這裏的數據卷綁定宿主目錄。

  • 上下文:傳給 Docker 引擎的文件目錄。

Docker 在運行時分爲 Docker 引擎(也就是服務端守護進程)和客戶端工具。在構建鏡像時,會將上下文複製到 Docker 引擎。然後通過 Docker 客戶端發出指令,而指令的執行是在 Docker 引擎中。所以,上下文的範圍要合理,範圍過大,就會導致文件複製到 Docker 引擎的時間長;範圍過小,則會導致無法操作範圍外的文件。

Docker 部署開發環境

部署開發環境其實很簡單,只需要配置 Dockerfile 和 docker-compose 即可。相關文檔可見:【Dockerfile 指令詳解】和【Compose 模板文件

docker-compose 使用的是 YAML 語言,【YAML 語言教程

version: '3.6'

services:
  client:
    container_name: "client"
    build:
      context: ../
      dockerfile: Dockerfile.client.dev
    volumes:
      - ../src:/app/client/src
    ports:
      - "8090:8090"
    depends_on:
      - server

  server:
    container_name: "server"
    build:
      context: ../server
      dockerfile: Dockerfile.server.dev
    volumes:
      - ../server:/app/server
    ports:
      - "8080:8080"
    depends_on:
      - database


  database:
    container_name: mongo
    image: mongo
    volumes:
      - ../data:/data/db
    ports:
      - "27017:27017"

開發環境需要的就是實時展現效果,前端頁面是這樣,後端服務亦是如此。
如上文提到,上下文已經提交到鏡像,前端項目如何才能夠在容器中實現熱替換?其實很簡單,就是 volumes 這個配置。同理,後端也是,不過還需要 modemon 工具協助。

在部署時,也要到了一些問題,就是在鏡像中,localhost 無法使用,需要用 IP 代替。

// 前端項目
/* webpack.dev.js */
  devServer: {
    publicPath: '/',
    contentBase: path.resolve(__dirname, '..', 'dist'),
    port: APP_CONFIG.port,
    host: '0.0.0.0', // 需指明
    hot: true,
    historyApiFallback: {
      index: '/'
    }
  }

// 後端項目
/* config.js */
module.exports = {
  'database': 'mongodb://database:27017/yexiaochen'  // 與 docker-compose 中 database 服務名匹配
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章