这多是网络上惟一一篇给前端写的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)拍砖、聊前端。

参考资料:

相关文章
相关标签/搜索