使用 Docker 部署 NodeJS + MongoDB 项目

最近在学习 Docker,并用 Docker 从新部署了cdfang-spider项目,使用 docker 后确实大幅度地下降了部署难度。若是你也想用 Docker 来部署本身的项目,那就让咱们一块儿往下看。node

本文经过如下 3 个方面来聊聊 Docker:git

  • Docker 发展史。
  • Docker 基础。
  • Docker 项目实战。

Docker 发展史

上古时代

在好久之前,发布一个 App 应用,应该是这样的。首先购买一台物理服务器,而后手动安装对应的操做系统,搭建 App 应用运行环境,部署 App 应用,最后才能被其余人访问。这样作看似没毛病,但可能会形成几个问题:github

  • 部署很是慢。web

    • 购买物理服务器到收货须要时间。
    • 手动安装操做系统须要时间。
    • 安装 App 应用以及对应的环境须要时间。
  • 成本很是高。docker

    • 物理服务器很贵。
  • 资源浪费。shell

    • 若是项目很小,不能充分利用这台服务器的资源。
  • 难于迁移和扩展。npm

    • 若是 CPU,内存,硬盘不够,只能加物理设备,但这个是有上限的。
  • 可能会被限定硬件厂商。

虚拟化时代

为了解决物理设备的诸多问题,出现了虚拟机。虚拟机出现以后大大地下降了部署难度,要想部署一个应用程序,新建一个虚拟机就能够了,还能够根据应用程序的大小,分配合适的系统资源。服务器

虚拟技术有如下几个特色:网络

  • 一个物理机的资源分配到了不一样的虚拟机里。
  • 很容易扩展,加物理机 / 虚拟机。
  • 很容易云化,阿里云,AWS 等。

虚拟化技术实现了物理层的隔离,但却还有如下问题:架构

  • 每个虚拟机都是一个完整的操做系统,每次新建都得手动安装一遍。
  • 虚拟机中的项目环境每次也须要从新安装。
  • 虚拟机自己消耗的系统资源也比较多。

容器化时代

为了更方便的部署项目,出现了容器化技术,主要有如下几个特色:

  • 实现应用程序及其环境打包。
  • 实现应用之间相互隔离、共享同一个操做系统内核。
  • 容器自己比较轻,相比虚拟机,占用的系统资源更少。

Docker 是容器化技术的一种,也是最流行的一个。Docker 提供了一种隔离机制,它将不一样应用程序的依赖项和库打包在一块儿,运行在不一样的容器中,从而实现应用层的隔离

容器化技术大都是基于 Linux 内核提供的两个机制:Cgroups(实现资源按需分配)和 Namespace(实现任务隔离)。

虚拟化 vs 容器化

虚拟化和容器化都是目前主流的的部署技术,二者之间的差异以下:

  • 虚拟机技术已经发展了不少年,配套技术和标准都已经标准化了,而容器最近几年才兴起,配套技术和标准还在完善中。
  • 虚拟机因为有 GuestOS(虚拟机操做系统) 存在,能够和宿主机运行不一样 OS,而容器只能支持和宿主机内核相同的操做系统,隔离性相对较差。
  • 容器比虚拟机明显更轻量级,对宿主机操做系统而言,容器就跟一个进程差很少。所以容器有着更快的启动速度、更方便的集群管理等优势。同时因为没有 GuestOS 存在,在容器中运行应用和直接在宿主机上几乎没有性能损失,性能上优于虚拟机。

Docker 基础

Docker 的核心是在 Docker Engine 层实现应用层的隔离。

Docker 分层
Application(应用层)
Container(容器层)
Docker Engine (隔离层)
Host OS 操做系统
infrastructure(基础设施)

Docker 分为 Client 和 Server 两个部分,咱们在 Client 中执行 Docker 命令,最后建立的 Container 和 Image 则会在 Server 中运行。Dcoker 架构以下图所示:

Docker 架构

Image

Image 主要用来打包应用程序以及它的依赖环境,为 Container 提供必要的环境以及安装好的应用程序。Image 自己并不能执行,只能经过 Container 去运行。

Image 主要有如下几点特征:

  • 文件和 meta data 的集合(root filesystem)。
  • 分层的,而且每一层均可以添加改变删除文件,成为一个新的 Image。
  • 不一样 Image 能够共享相同的底层。
  • Image 自己是只读的。

Image 能够经过 Dockerfile 去构建,也能够经过 DockerHub 上去拉取。

Container

Container 是运行 Image 的实例,经过 docker run image便可启动并运行一个 Container。

Container 主要有如下几点特征:

  • 经过 Image 建立。
  • 在 Image 之上创建一个 Container 层(可读写)。
  • 类比面向对象:类(Image) 和实例(Container)。
  • Image 负责 App 的存储和分发,Container 负责运行 App。

Networks

使用 Dcoker 部署项目经常会生成不少个容器,这些容器默认只能经过 ip 地址进行访问,但新建一个容器所产生的 ip 地址是不可控的,这就给容器之间通讯带来了必定的麻烦。Docker 中使用 Network 来管理容器之间的通讯,只要两个 Conteiner 处于同一个 Network 之中,就能够经过容器名去互相通讯。

Docker 中内置 5 中类型的 Network :

  • bridge(相同 bridge 中的 container 能够相互访问)。
  • host(将 container 与宿主机的网络相连通,虽然很直接,可是却破获了 container 的隔离性)。
  • none 禁用全部网络。
  • overlay 集群使用。
  • macvlan。

除了这 5 中 Network 以外,用户也能够自定义编写 Network Plugin。

Docker Compose

Docker Compose 是一个工具,这个工具能够经过一个 yml 文件定义多容器的 Docker 应用。经过一条命令就能够根据 yml 文件的定义去建立或者管理多个容器。接下来分别使用命令行和 Docker Compose 的方式来对比一下建立容器的方式。

不使用 Docker Compose 建立容器

docker pull yhlben/cdfang-spider
docker pull mongo
docker network create webapp-network
docker run -d --network webapp-network -v ~/data/db:/data/db mongo
docker run -p 8082:8082 --network webapp-network -d yhlben/cdfang-spider

可见,手动建立容器,须要在命令行中手动执行不少命令,这些命令一旦敲错了,就得重来,不便于容器的管理。

使用 Docker Compose 建立容器

一、新建 docker-compose.yml 文件。

version: '3.7'
services:
  database:
    image: mongo
    restart: always
    volumes:
      - ~/data/db:/data/db
    networks:
      - webapp-network
  web:
    image: yhlben/cdfang-spider
    depends_on:
      - database
    ports:
      - 8082:8082
    networks:
      - webapp-network
networks:
  webapp-network:
    driver: bridge

二、运行 docker-compose

docker-compose up -d

可见,使用 Docker Compose 建立容器只须要提早编写好 yml 文件,而后执行一条命令就好了,比起手动敲命令,更加方便。

除此以外,Docker Compose 还可使用 docker-compose -scale 扩展多个相容的容器,用来实现负载均衡,能够扩容,也能够减容。例如:实现无缝部署项目,先扩容一个新的 Container,当 Container 启动完毕后,加入到集群中,而后更新老容器,更新完后再加入集群中。

Docker Compose 配置

Docker Compose 的配置文件通常定义在 docker-compose.yml 文件中,主要的配置项以下:

  • services

    • 一个 service 表明一个 container,这个 container 能够从 dockerHub 中的镜像来建立,也可使用本地 dockerfile build 出来的镜像来建立。
    • service 的启动相似 docker run,能够给 service 指定 network 和 volume 的引用。
  • networks

    • 定义 networks ,至关于执行 docker network create xxxx
  • volumes

    • 定义 volume ,至关于执行 docker volume create xxx

更多配置项能够参考官方文档 compose-file

Docker 项目实战

接下来以 cdfang-spider 项目为例,使用 Docker 部署项目。

全手动部署

一、编写 Dockerfile 文件。

# 加载基础镜像
FROM node

# 注释
LABEL maintainer = "yhlben <yinhengliben@gmail.com>"

# 建立工做目录
RUN rm -rf /app
RUN mkdir /app
WORKDIR /app

# 安装项目依赖
COPY . /app
RUN npm install
RUN npm run build
RUN mv ./dist/* ./

# 对外暴露端口
EXPOSE 8082

# 启动 Image 时执行命令
CMD BUILD_ENV=docker node app.js

二、经过 Dockerfile 文件构建 Image。

docker build -t yhlben/cdfang-spider .

三、拉取 mongo 官方 Image。

docker pull mongo

四、建立 network,让两个容器能够相互通讯。

docker network create webapp-network

五、运行容器

docker run -d --network webapp-network -v ~/data/db:/data/db mongo
docker run -p 8082:8082 --network webapp-network -d yhlben/cdfang-spider

六、经过访问 localhost:8082 访问项目。

自动化部署

一、编写 Dockerfile 文件。

# 加载基础镜像
FROM node

# 注释
LABEL maintainer = "yhlben <yinhengliben@gmail.com>"

# 建立工做目录
RUN rm -rf /app
RUN mkdir /app
WORKDIR /app

# 安装项目依赖
COPY . /app
RUN npm install
RUN npm run build
RUN mv ./dist/* ./

# 对外暴露端口
EXPOSE 8082

# 启动 Image 时执行命令
CMD BUILD_ENV=docker node app.js

二、在 dockerHub 上受权 github 项目,这样当 github 项目有更新时,会自动执行 Dockerfile 进行构建,并将构建结果保存到 dockerHub 仓库中。

三、编写 docker-compose.yml 文件。

version: '3.7'
services:
  database:
    image: mongo
    restart: always
    volumes:
      - ~/data/db:/data/db
    networks:
      - webapp-network
  web:
    image: yhlben/cdfang-spider
    depends_on:
      - database
    ports:
      - 8082:8082
    networks:
      - webapp-network
networks:
  webapp-network:
    driver: bridge

四、一键启动,确保已安装 docker-compose。

docker-compose up -d

五、经过访问 localhost:8082 访问项目。

总结

经过 Docker 部署完项目后,感觉很不错,主要分如下几点:

  • 使用 Docker Compose 一键启动项目。
  • 不再用在服务器上安装各类杂七杂八的环境,所有封装到 Image 里,启动一个 Container 跑起来就好了,不用的时候直接删除 Container 就好了,服务器上不会受到任何污染。
  • 对于耗时的 Image 构建过程,直接交给 dockerHub 去自动构建。

最后,附上项目源码地址:cdfang-spider

本项目使用单机部署,即全部的容器都在同一台服务器上。除此以外,docker 还支持分布式容器部署,可使用 docker swarm 或者 kubernetes 来管理,目前还在学习中,争取早日整理好分享给你们,感谢你们支持!
相关文章
相关标签/搜索