使用 Docker 部署 NodeJS + MongoDB 項目

最近在學習 Docker,並用 Docker 從新部署了cdfang-spider項目,使用 docker 後確實大幅度地下降了部署難度。若是你也想用 Docker 來部署本身的項目,那就讓咱們一塊兒往下看。node

本文經過如下 3 個方面來聊聊 Docker:git

  • Docker 發展史。
  • Docker 基礎。
  • Docker 項目實戰。

Docker 發展史

上古時代

在好久之前,發佈一個 App 應用,應該是這樣的。首先購買一臺物理服務器,而後手動安裝對應的操做系統,搭建 App 應用運行環境,部署 App 應用,最後才能被其餘人訪問。這樣作看似沒毛病,但可能會形成幾個問題:github

  • 部署很是慢。
    • 購買物理服務器到收貨須要時間。
    • 手動安裝操做系統須要時間。
    • 安裝 App 應用以及對應的環境須要時間。
  • 成本很是高。
    • 物理服務器很貴。
  • 資源浪費。
    • 若是項目很小,不能充分利用這臺服務器的資源。
  • 難於遷移和擴展。
    • 若是 CPU,內存,硬盤不夠,只能加物理設備,但這個是有上限的。
  • 可能會被限定硬件廠商。

虛擬化時代

爲了解決物理設備的諸多問題,出現了虛擬機。虛擬機出現以後大大地下降了部署難度,要想部署一個應用程序,新建一個虛擬機就能夠了,還能夠根據應用程序的大小,分配合適的系統資源。web

虛擬技術有如下幾個特色:docker

  • 一個物理機的資源分配到了不一樣的虛擬機裏。
  • 很容易擴展,加物理機 / 虛擬機。
  • 很容易雲化,阿里雲,AWS 等。

虛擬化技術實現了物理層的隔離,但卻還有如下問題:shell

  • 每個虛擬機都是一個完整的操做系統,每次新建都得手動安裝一遍。
  • 虛擬機中的項目環境每次也須要從新安裝。
  • 虛擬機自己消耗的系統資源也比較多。

容器化時代

爲了更方便的部署項目,出現了容器化技術,主要有如下幾個特色:npm

  • 實現應用程序及其環境打包。
  • 實現應用之間相互隔離、共享同一個操做系統內核。
  • 容器自己比較輕,相比虛擬機,佔用的系統資源更少。

Docker 是容器化技術的一種,也是最流行的一個。Docker 提供了一種隔離機制,它將不一樣應用程序的依賴項和庫打包在一塊兒,運行在不一樣的容器中,從而實現應用層的隔離bash

容器化技術大都是基於 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 上去拉取。

Dockerfile 是一個文本文件,其中包含構建 Image 的全部命令。Docker 能夠經過 docker build 從 Dockerfile 中讀取命令來自動構建 Image。經常使用配置信息能夠參考下文 Dockerfile 文件中的註釋,也建議你們閱讀官方文檔 Dockerfile reference

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 mhart/alpine-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 mhart/alpine-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 來管理,目前還在學習中,爭取早日整理好分享給你們,感謝你們支持!

相關文章
相關標籤/搜索