這多是網絡上惟一一篇給前端寫的Docker+Node+Nginx+Mongo的本地開發+部署實戰

先來交代下應用場景,我以爲看這篇文章的同窗大部分是網上找不到 Docker + Node + Nginx + Mysql這種組合的配置教學,包括我在研究這個項目的時候找了好久只有國外幾篇有價值的文章,文末我也會把一些參考貼出來供你們學習。這個項目的起底是由於團隊內部但願有一個本身的雲平臺,上面搭載一些如圖片上傳、OSS 管理、發佈管理、釘釘推送服務、語音合成等,而且這些服務在咱們的預想當中是徹底不須要後端來參與的。團隊內部同窗的服務端水平不一,同一種架構十我的能配出十種環境出來(這個我相信是大部分前端甚至後端 Team 的通病),在這種契機下,我嘗試用 Docker 去包裹着咱們這一套體系。前端

若是你已經瞭解過 Docker,只是在尋找一種解決方案,想看 DockerFile,能夠直接跳到編寫 Docker-Compose 的地方。node

另外,我已經準備好了一個模板庫,能夠根據這個模板庫來做爲基底來構建你的項目,也歡迎你們圍觀吃瓜學習、issue、star(點我就能夠啦)linux

粗暴的講一下Docker

還記得在上學的時候學校機房裏的 VMware Workstation 嗎?他可讓咱們在 windows 或 mac 上運行許多系統的虛擬機,而VMware Workstation裏重要的一個概念就是宿主機-虛擬機nginx

初學者能夠先把Docker理解爲跟VMware Workstation相似的產品,但若是須要深究他們區別在哪,咱們則須要記住:他們類似的僅僅是提供了在系統上運行另一個隔離系統。git

一般狀況下,虛擬機的性能相對差,對電腦配置、服務器配置自己要求高,而Docker下降了那個門檻,性能接近裸機。github

咱們要虛擬機幹啥?直接啥應用都往服務器上坨不行嗎?Docker 的具體應用在哪裏?sql

我先來講說爲啥要用 Docker:mongodb

  • 一致的運行環境(多個開發之間、開發與生產環境以及其餘的任意環境)
  • 更高效的交付部署流程
  • 易於拓展、遷移(現有系統可直接成爲鏡像,分佈式拓展簡易)
  • 更輕鬆的維護:你的 nginx 配置、node配置、mongo配置全都是活性化且可統一的管理
  • 比其餘虛擬機產品性能更好,速度更快,系統利用率更高

在這些優勢的對立面,尤爲是部署和環境統一這個問題,就足夠讓非 Docker 體系的工程成本提升。docker

安裝 Docker

若是是你 MacOS 或 Windows ,直接下載Docker Desktop,下載很慢的話,能夠去 DaoCloud。 若是是 linux 的話,須要如下幾個步驟,若是你的服務器沒有yum的話,須要先去安裝 yum,安裝yum篇幅不小就不在這邊展開。 以防萬一,清理 Dockershell

sudo yum remove docker \
	docker-client \
        docker-client-latest \
        docker-common \
        docker-latest \
        docker-latest-logrotate \
        docker-logrotate \
        docker-selinux \
        docker-engine-selinux \
        docker-engine
複製代碼

安裝依賴

sudo yum install -y yum-utils device-mapper-persistent-data lvm2
複製代碼

設置 yum 源(能夠任意其餘的,我這裏用的阿里)

sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
複製代碼

更新緩存

sudo yum makecache fast
複製代碼

安裝 Docker-ce(CE 是指社區版,無償使用,Docker 還有 EE 版)

sudo yum -y install docker-ce
複製代碼

啓動 Docker

sudo systemctl start docker
複製代碼

測試命令

docker -v
複製代碼

到這裏安裝就完成了。下面咱們開始安裝 Docker-Compose

Docker-Compose

傳統的Docker,一個容器須要一個Dockerfile來描述,若是說一個項目比較大,用到了較多的技術,就會有不少個容器,若是須要挨個執行 Dockerfile,甚至啓動的時候也是挨個去啓動,開發會累死,運維也會累死。Docker-Compose解決了這個問題,爲每一個項目提供一個描述文件,而且批處理項目中的全部容器。

安裝docker-compose

curl -L https://get.daocloud.io/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
複製代碼

驗證

$ docker-compose -v
> docker-compose version 1.24.1, build 4667896b
複製代碼

項目架構

首先看一下咱們項目目錄是如何編排的,須要注意的是,項目存放的位置對於 Docker 的配置是有影響的。咱們的 node 框架使用了阿里的Egg.js

.
├── docker-compose.yml ## docker-compose 配置入口
├── logs ## 日誌存放位置
│   └── nginx
│       ├── access.log
│       └── error.log
├── mongo ## mongo 配置入口
│   ├── Dockerfile ## Mongo的 Dockerfile
│   └── mongo.conf ## mongo 配置
├── nginx ## nginx 配置
│   ├── cert ## SSL 證書存放目錄
│   ├── conf.d
│   │   └── MicroServer.conf ## nginx 下咱們服務的配置文件
│   ├── Dockerfile  ## nginx 的 Dockerfile
│   └── nginx.conf
└── node ## node 項目存放目錄
    ├── Dockerfile
    └── Microservice ## 項目目錄 如下爲 Egg 的架構目錄
        ├── app
        │   ├── controller
        │   ├── database
        │   │   ├── init.js
        │   │   └── schemas
        │   ├── extend
        │   │   └── application.js
        │   ├── middleware
        │   │   ├── gzip.js
        │   │   └── jwt_error_handler.js
        │   ├── public
        │   └── router.js
        ├── app.js
        ├── appveyor.yml
        ├── config
        │   ├── config.default.js
        │   └── plugin.js
        ├── config.js
        ├── jsconfig.json
        ├── logs
        ├── node_modules
        ├── package.json
        ├── README.md
        ├── test
        └── typings
複製代碼

而後先講一下 Dockerfile 是個啥,裏面配置了虛擬機裏的鏡像底層系統是什麼,用了什麼端口,跑什麼命令,而後 Docker 會根據這些命令生成一個鏡像包。

總體上架構比較清晰,這邊咱們打算給每個程序都單獨起一個容器,nodenode的,nginxnginx 的,mongomongo 的。Do it,上大菜。

nginx 的 Dockerfile

# 使用社區裏的 nginx:alpine 爲基礎鏡像
FROM nginx:alpine

# 拷貝 nginx 全局配置文件
COPY nginx.conf /etc/nginx/

# apk 國內源
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/' /etc/apk/repositories

# 安裝 nginx
RUN apk update \
    && apk upgrade \
    && apk add --no-cache openssl \
    && apk add --no-cache bash
    
# 啓動 nginx
CMD nginx

# 暴露 80 端口和 443 端口給容器外部
EXPOSE 80 443
複製代碼

node 的 Dockerfile

# 這裏我用的鏡像是 node 的穩定版
FROM node:10.16.3-alpine

# 拷貝項目文件進行構建
WORKDIR /app/Microservice
COPY ./Microservice/package.json ./
RUN npm install --registry=https://registry.npm.taobao.org

# 拷貝項目文件
COPY ./Microservice/* ./

# 啓動服務
CMD ["npm","run","dev"]

# 暴露 7001 端口到宿主機
EXPOSE 7001
複製代碼

須要注意的是,這裏咱們跑的是npm run dev,由於 docker 的進程須要你的程序跑在前臺,若是用了npm run start,容器內沒有東西持續佔用輸出,會致使容器認爲程序已經執行完畢。 另外這裏咱們單獨把 package.json 拷了一份,是爲了應對下面咱們須要單獨爲node_modules建立一個映射卷而作的。下面會說爲何須要單獨爲node_modules作一個卷

mongo 的 Dockerfile

# 使用 mongo 最新版鏡像
FROM mongo:latest
# 把宿主機的 Mongo 配置文件拷貝到容器內
COPY mongo.conf /usr/local/etc/mongo/mongo.conf
# 映射外部 DB 的存儲文件到容器內
VOLUME /data/db /data/configdb
# 啓動 mongo
CMD ["mongod"]

# 暴露 27017 端口到宿主機
EXPOSE 27017
複製代碼

在docker-compose.yml中編寫Node/Nginx/Mongo的配置文件

version: "3"

networks:				# 自定義網絡
  my-network:           # 網絡名字
    driver: bridge      # 由網關驅動

volumes:                # 建立自定義卷
    node_modules:       # 卷名
    mongo_data:

services:               # 定義每一個服務的容器

### nginx #################
  nginx:                # nginx 容器 這裏的名字能夠當作變量使用
    build:              # 定義須要構建的內容
      context: ./nginx  # 選取 nginx 文件夾
    ports:              # 映射端口
      -  80:80
      -  443:443
    volumes:            # 掛載文件夾,配置咱們能夠寫在宿主機,而後掛載進去
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/cert:/etc/nginx/cret
      - ./logs/nginx:/var/log/nginx
    restart: always     # 服務掛了的時候始終自動重啓
    depends_on:         # 定義容器啓動順序 附帶容器間的依賴關係
      - nodejs
    networks:           # 使用咱們上面定義的網絡
      - my-network

### node ##############
  nodejs:
    build:
      context: ./node   # 構建 node 目錄 他會去 node 下面尋找 Dockerfile
    ports:
      - 127.0.0.1:7001:7001    # 映射 7001
    volumes:
      - ./node/Microservice:/app/Microservice    # 項目文件映射
      - node_modules:/app/Microservice/node_modules    # 單獨處理 node_modules
    restart: always
    depends_on:
      - mongo
    networks:
      - my-network

### mongoDB ########################
  mongo:
    build:
      context: ./mongo
    ports:
      - 127.0.0.1:27017:27017
    volumes:
      - mongo_data:/data/db    # 這裏的 mongo_data 用的是上面的自定卷
    restart: always
    networks:
      - my-network
複製代碼

以上有幾個點須要注意:

一、內部端口防火牆

ports 端口的地方,若是咱們在前面的端口前加上127.0.0.1,docker 會阻止外網訪問這個端口,只容許內部訪問,像上面咱們給數據庫和 node 加了,正常數據庫是不容許外網訪問的,node 咱們也用 nginx 作過了代理因此不須要直接訪問,你能夠根據本身的須要來決定是否開放。

二、node_modules單獨處理

nodejsnode_modules須要單獨處理,這裏是爲了咱們本地開發的時候用的,當咱們在本地開發的時候,容器起來了,咱們去寫業務代碼,不須要再build 容器,docker 會自動映射進去,但 node_modules 是咱們每次執行 nodenpm run install跑出來的,這個文件夾只會在容器內產生,不會在宿主機產生,而咱們更改宿主機的業務代碼須要自動同步到容器內,這個同步的操做由於咱們宿主機是沒有node_modules的,那麼同步的時候也會致使容器裏的node_modules也沒了,代碼就不能正常運行。把node_modules做爲獨立卷拎出來之後,除開須要更新依賴包包咱們要從新 build鏡像,正常更改應用代碼只須要保存便可。

運行

OK,至此你的環境基本上是準備好了,執行

docker-compose up -d
複製代碼

看看是否在正常跑

CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                                      NAMES
4bedfab2a306        front-end-microservice_nginx    "/bin/sh -c nginx"       18 seconds ago      Up 15 seconds       0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   front-end-microservice_nginx_1
d1d539672df5        front-end-microservice_nodejs   "docker-entrypoint.s…"   20 seconds ago      Up 18 seconds       127.0.0.1:7001->7001/tcp                   front-end-microservice_nodejs_1
8f1b1401a4dc        front-end-microservice_mongo    "docker-entrypoint.s…"   24 seconds ago      Up 20 seconds       127.0.0.1:27017->27017/tcp                 front-end-microservice_mongo_1
複製代碼

完成,你的項目應該跑起來了,接下來送佛送到西,咱們配上 mongo 看看 進入 mongo 的容器

docker exec -it front-end-microservice_mongo_1 /bin/sh
複製代碼

進入到容器後打開mongo shell

$ mongo
// 用戶表
> use admin
// 建立管理員
> db.createUser(
{
    user: "admin",    // 用戶名
    pwd: "admin",     // 密碼
        roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
)
> use test // 建立 test 數據庫
> db.createUser( // 建立 test 庫帳號
{
    user: "test",
    pwd: "test",
    roles: [
        { role: "readWrite", db: "test" }   #讀寫賬號
    ]
}
)
複製代碼

ok ,而後打開你的mongo鏈接工具,我這邊用的是 mongo 官方的 MongoDB Compass

mongodb compass
mongodb compass
連接成功便可
mongodb compass
mongodb compass
而後本地用 Postman 訪問 127.0.01:7001 ,你的任意一個接口
postman
postman
配置已經完成。

部署上線

得益於 Docker,咱們部署上線很是簡單,只須要在服務器上也安裝好 Dockerdocker-compose(其實我相信這些都不用你裝,公司的後端正常是須要這玩意的,加上公司運維也搞這個...),而後跑一句

docker-compose up -d
複製代碼

其餘要修改的,無非是你的配置,如 nodejs 裏連接數據庫的域名、端口,以及數據庫跟上面同樣,配置好帳號密碼。額外說一下,因爲咱們用 docker-compose 註冊了 mongo 的變量名,因此在 nodejs 中,咱們能夠直接使用 mongo 這個名字充當主機名,好比個人在 Node 中的配置文件.env就是這樣的:

DB_USER=test
DB_PASSWD=#test
DB_HOST=mongo
DB_PORT=27017
DB_NAME=test
複製代碼

這樣他會自動連接跟 node 在一塊兒的本地 mongo。

Nginx 部分,你只須要修改咱們在 nginx 文件下的 nginx.conf,裏面定義好你本身的 nginx 配置,須要注意的是,在這個文件中你編寫的路徑須要是容器內的路徑,好比咱們引用 SSL 文件,SSL 文件在宿主機的完整路徑是: /data/front-end-microservice/nginx/cert/xxx.crt,通過 Docker 拷貝後,咱們容器內的位置是: /etc/nginx/cret/xxx.crt 這是由於,咱們在docker-compose.yml中有指定鏡像卷:

nginx:
    build:
      context: ./nginx
    ports:
      -  80:80
      -  443:443
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/cert:/etc/nginx/cret
      - ./logs/nginx:/var/log/nginx
    restart: always
    depends_on:
      - nodejs
    networks:
      - my-network
複製代碼

每次修改完nginx相關配置文件,須要重啓一下 nginx: docker-compose restart nginx

以上,基本就完成整個開發-生產的流程,全部的代碼均可以在模板庫裏找到:egg-docker-template.

若是有錯誤歡迎指正,另外也但願有更多的架構師能一塊兒交流前端領域的架構、工程化,歡迎加個人微信(t1556207795)拍磚、聊前端。

參考資料:

相關文章
相關標籤/搜索