Docker部署基於Nodejs的Web應用-實戰篇

Docker

docker是一個開源的應用容器引擎,能夠爲咱們提供安全、可移植、可重複的自動化部署的方式。docker採用虛擬化的技術來虛擬化出應用程序的運行環境。此種方式具備如下優點:css

  • 每一個部署的應用程序都是一個容器,彼此隔離,互不影響;前端

  • 服務器只須要安裝docker便可運行構建好的應用程序鏡像,不會涉及複雜的服務器環境配置,由於配置都在特定的應用程序所在的鏡像中去配置便可;vue

  • 簡化了自動化部署和運維的繁瑣流程,只需將構建好的鏡像load到服務器的docker中便可運行咱們的應用程序;node

  • 能夠充分利用服務器的系統資源,一臺服務器上能夠同時運行多個容器;webpack

architecture

docker採用的是c/s架構,Client經過接口與Server進程通訊實現容器的構建,運行和發佈。docker比較重要的三個核心概念以下:git

  • 鏡像(images):一個只讀的模板,能夠理解爲應用程序的運行環境,包含了程序運行所依賴的環境和基本配置,鏡像能夠按照層級(從基礎鏡像開始)來構建,每一層包含特定的環境。程序員

  • 倉庫(repository):一個用於存放鏡像文件的倉庫,若是你對git的倉庫熟悉,應該很容易理解,對,就是那個。有私有倉庫和公有倉庫之分。github

  • 容器(container):一個運行應用程序的虛擬容器,在咱們運行鏡像時產生。容器包含本身的文件系統+隔離的進程空間和包含其中的進程。web

前言

sharplook是一款經過大數據分析來解決客戶在監控系統中存在的數據採集難、解析難、處理難的IT運維產品。在給客戶部署產品的過程當中涉及到比較多的環境配置和組件安裝以及複雜的依賴項,這些繁瑣的流程下降了安裝部署的效率和產品質量。基於此,咱們開發了一款能夠快速便捷的安裝部署套件,提供一種漂亮的安裝部署流程。產品採用 Nuxt + Koa 的基礎架構進行開發,其中採用nuxt來提供SSR(服務端渲染)功能,Nuxt.js是基於Vue.js的通用架構,其中集成了如下組件:vue-router

另外,Nuxt.js 使用 Webpack 和 vue-loader 、 babel-loader 來處理代碼的自動化構建工做(如打包、代碼分層、壓縮等等)。

咱們項目使用Nuxt.js做爲中間件來進行UI渲染,使用Koa啓動咱們本身的服務器,koa2 是由 Express 原班人馬打造的,致力於成爲一個更小、更富有表現力、更健壯的 Web 框架。

關於如何快速搭建這樣一個項目,小生以前在《vue-cli 「從入門到放棄」》中介紹過vue-cli的使用,這個項目咱們經過vue-cli工具,使用 nuxt-community/koa-template 模板,vue init nuxt-community/koa-template快速構建出來。具體的代碼邏輯,在此不作贅述。

關於爲何選擇docker來部署咱們的node服務,前面已經介紹了,咱們基於node的web應用涉及到的部署環境並不複雜,僅僅須要Node.js做爲平臺便可,因爲依賴的包文件太多,並且比較大,業界尚未特別好用的開源node打包工具。作前端的同窗都知道,webpack是一個功能強大的資源加載構建的打包工具,只須要將項目文件打包到一個dist文件下,打包後的文件體量小,解決了文件之間的依賴問題,提取出公共代碼庫,生產環境只須要部署dist文件夾便可。然而,Nodejs程序涉及到的依賴包,和資源卻無法進行打包,node服務開啓後僅僅是一個node進程而已。那麼咱們如何部署node程序呢?既然無法打包,只能將其所有文件進行部署(雖然可能存在別的問題,小生也在研究中,大神能夠給點建議),因而小生就但願將其放入docker中去部署,免去生產環境node版本不一致等問題。下面小生就將如何用docker來部署Node項目的過程分享給諸位。

實戰

如下將進入戰備狀態,請同志們準備好大腦和電腦,跟着我左手、右手一個慢動做。

環境準備

  • 安裝docker,未安裝的同窗,請根據本身的開發環境採用不一樣的安裝方式去安裝,具體操做參考教程,不作贅述。

  • 安裝成功後,能夠經過docker -v查看版本號(儘可能使用最新的穩定版本)。

項目準備

  • 在你的項目根目錄下,添加Dockerfile文件,此文件用來配置咱們自定義一個鏡像所須要指定的依賴項、環境以及執行的命令等。內容格式以下:

    # 指定咱們的基礎鏡像是node,版本是v8.0.0
     FROM node:8.0.0
     # 指定製做咱們的鏡像的聯繫人信息(鏡像建立者)
     MAINTAINER EOI
     
     # 將根目錄下的文件都copy到container(運行此鏡像的容器)文件系統的app文件夾下
     ADD . /app/
     # cd到app文件夾下
     WORKDIR /app
     
     # 安裝項目依賴包
     RUN npm install
     RUN npm rebuild node-sass --force
     
     # 配置環境變量
     ENV HOST 0.0.0.0
     ENV PORT 8000
     
     # 容器對外暴露的端口號
     EXPOSE 8000
     
     # 容器啓動時執行的命令,相似npm run start
     CMD ["npm", "start"]
  • 關於Dockerfile文件中的關鍵字,解釋以下:

    • FROM

      語法:FROM <image>[:<tag>]
      解釋:設置要製做的鏡像基於哪一個鏡像,FROM指令必須是整個Dockerfile的第一個指令,若是指定的鏡像不存在默認會自動從Docker Hub上下載。
    • MAINTAINER

      語法:MAINTAINER <name>
      解釋:MAINTAINER指令容許你給將要製做的鏡像設置做者信息。
    • ADD

      語法:ADD <src> <dest>
      解釋:ADD指令用於從指定路徑拷貝一個文件或目錄到容器的指定路徑中,<src>是一個文件或目錄的路徑,也能夠是一個url,路徑是相對於該Dockerfile文件所在位置的相對路徑,<dest>是目標容器的一個絕對路徑。
    • WORKDIR

      語法:WORKDIR /path/to/workdir
       解釋:WORKDIR指令用於設置Dockerfile中的RUN、CMD和ENTRYPOINT指令執行命令的工做目錄(默認爲/目錄),該指令在Dockerfile文件中能夠出現屢次,若是使用相對路徑則爲相對於WORKDIR上一次的值,例如WORKDIR /data,WORKDIR logs,RUN pwd最終輸出的當前目錄是/data/logs。
    • RUN

      語法:① RUN <command>   #將會調用/bin/sh -c <command>
            ② RUN ["executable", "param1", "param2"] #將會調用exec執行,以免有些時候shell方式執行時的傳遞參數問題,並且有些基礎鏡像可能不包含/bin/sh
       解釋:RUN指令會在一個新的容器中執行任何命令,而後把執行後的改變提交到當前鏡像,提交後的鏡像會被用於Dockerfile中定義的下一步操做,RUN中定義的命令會按順序執行並提交,這正是Docker廉價的提交和能夠基於鏡像的任何一個歷史點建立容器的好處,就像版本控制工具同樣。
    • ENV

      語法:ENV <key> <value>
       解釋:ENV指令用於設置環境變量,在Dockerfile中這些設置的環境變量也會影響到RUN指令,當運行生成的鏡像時這些環境變量依然有效,若是須要在運行時更改這些環境變量能夠在運行docker run時添加–env <key>=<value>參數來修改。
       注意:最好不要定義那些可能和系統預約義的環境變量衝突的名字,不然可能會產生意想不到的結果。
    • EXPOSE

      語法:EXPOSE <port> [ ...]
      解釋:EXPOSE指令用來告訴Docker這個容器在運行時會監聽哪些端口,Docker在鏈接不一樣的容器(使用–link參數)時使用這些信息。
    • CMD

      語法: ① CMD ["executable", "param1", "param2"]    #將會調用exec執行,首選方式
            ② CMD ["param1", "param2"]        #當使用ENTRYPOINT指令時,爲該指令傳遞默認參數
            ③ CMD <command> [ <param1>|<param2> ]        #將會調用/bin/sh -c執行
      解釋:CMD指令中指定的命令會在鏡像運行時執行,在Dockerfile中只能存在一個,若是使用了多個CMD指令,則只有最後一個CMD指令有效。當出現ENTRYPOINT指令時,CMD中定義的內容會做爲ENTRYPOINT指令的默認參數,也就是說可使用CMD指令給ENTRYPOINT傳遞參數。
      注意:RUN和CMD都是執行命令,他們的差別在於RUN中定義的命令會在執行docker build命令建立鏡像時執行,而CMD中定義的命令會在執行docker run命令運行鏡像時執行,另外使用第一種語法也就是調用exec執行時,命令必須爲絕對路徑。

    其中還有其餘的一些關鍵字:USER、ENTRYPOINT、VOLUME、ONBUILD等,若是你有興趣能夠自行研究。

  • 在項目根目錄下添加.dockerignore文件,此文件的做用相似.gitignore文件,能夠忽略掉添加進鏡像中的文件,寫法、格式和.gitignore同樣,一行表明一個忽略。本項目添加的忽略以下:

    .DS_Store
      npm-debug.log*
      selenium-debug.log
      .nuxt/
      /package-lock.json
      *.tar
      *.md
    
      # Editor directories and files
      .idea
      *.suo
      *.ntvs*
      *.njsproj
      *.sln

構建鏡像

  • 查看目前本地docker的鏡像

    > docker images
    
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
  • cd 到項目根目錄下,執行如下命令

    > docker build -t deploy:1.0 .
    
        Sending build context to Docker daemon  1.436GB
      .... 此處省略1000個字符。
      Successfully built d8f0875e967b
      Successfully tagged deploy:1.0

    deploy是鏡像名,1.0是鏡像的版本號,到此你已經成功構建了一個新的鏡像,你能夠經過docker images,查看你的鏡像。

    > docker images
     REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
     deploy              1.0                 d8f0875e967b        3 minutes ago        2.11GB
  • 啓動鏡像,測試是否成功。

    > docker run -d -p 9000:8000 deploy:1.0
    8aec5ee037bb253901d2c2e02c7be546580546c493576139f3789fb660f3401d
    
    > docker ps -a
    CONTAINER ID    IMAGE        COMMAND          CREATED           STATUS         PORTS                  NAMES
    8aec5ee037bb    deploy:1.0   "npm start"     57 seconds ago    Up 56 seconds  0.0.0.0:9000->8000/tcp amazing_bassi

    docker run -d -p 9000:8000 deploy:1.0-d表示後臺運行,-p 9000:8000表示指定本地的9000端口隱射到容器內的8000端口。 deploy:1.0爲咱們要運行的鏡像。經過docker ps -a查看docker的進程(容器的運行自己就是一種特殊的進程)運行狀況,發現咱們的容器已經在運行。本地能夠訪問localhost:9000

    經過docker logs能夠查看咱們容器內應用進程的運行日誌。docker logs <CONTAINER ID>

    > docker logs 8aec5ee037bb
      npm info it worked if it ends with ok
      npm info using npm@5.0.0
      npm info using node@v8.0.0
      npm info lifecycle newlook-deploy@1.0.0~prestart: newlook-deploy@1.0.0
      npm info lifecycle newlook-deploy@1.0.0~start: newlook-deploy@1.0.0
      
      > newlook-deploy@1.0.0 start /app
      > node ./server/index.js
      
      Server listening on 0.0.0.0:8000
       DONE  Compiled successfully in 9310ms06:55:56
      
      > Open http://0.0.0.0:8000
    docker stop <CONTAINER ID>能夠中止容器運行
    
     docker start <CONTAINER ID>能夠啓動容器運行
    
     docker restart <CONTAINER ID>能夠重啓容器
    
     docker rm <CONTAINER ID> -f能夠強制刪除在運行的容器

上傳鏡像(這裏用上傳到公共倉庫來演示)

  • 沒註冊DockerHub的同窗,請註冊DockerHub

  • 登陸docker

    > docker login
    Username: XXX
    Password: XXX
    Login Succeeded
  • docker tag <name:tag> <namespace>/<name:tag>上傳以前必須給鏡像打上tag,namespace能夠指定爲你的docker Id

    > docker tag deploy:1.0 lzqs/deploy:1.0
  • docker push <namespace>/<name:tag>將鏡像上傳至docker的公共倉庫

    > docker push lzqs/deploy:1.0
  • 上傳成功後,docker logout 退出,登陸 https://hub.docker.com/ 查看上傳的鏡像。

下載鏡像

  • 經過docker pull <namespace>/<name:tag>下載咱們的鏡像。

    > docker pull lzqs/deploy:1.0

生產部署

前面說了,咱們能夠將上傳到倉庫的鏡像下載下來部署,可是若是鏡像比較大或者部署環境壓根沒法聯網,你是否是要跪了。因此咱們採起另外一種方法,將開發好的鏡像直接打包保存到安裝盤裏面,到客戶生產環境再將鏡像包上傳並加載到服務器的docker中便可。

  • 在開發環境打包,docker save <namespace>/<name:tag> <name>.tar

    > docker save lzqs/deploy:1.0 > deploy.tar

    這裏ls會發現目錄下生成了deploy.tar的文件。部署時將此文件copy到生產環境服務器上。

  • 確保生產服務器上已經安裝了docker,若沒裝,請參考相關文檔,若不裝,對不起小生也無力了,而後在服務器上加載上傳的鏡像包deploy.tar

    > docker load < deploy.tar
    
      007ab444b234: Loading layer [==================================================>] 129.3 MB/129.3 MB
      4902b007e6a7: Loading layer [==================================================>] 45.45 MB/45.45 MB
      bb07d0c1008d: Loading layer [==================================================>] 126.8 MB/126.8 MB
      ecf5c2e2468e: Loading layer [==================================================>] 326.6 MB/326.6 MB
      7b3b4fef39c1: Loading layer [==================================================>] 352.3 kB/352.3 kB
      677f02386f07: Loading layer [==================================================>] 137.2 kB/137.2 kB
      7333bb4665b8: Loading layer [==================================================>] 55.66 MB/55.66 MB
      e292e64ffb88: Loading layer [==================================================>] 3.757 MB/3.757 MB
      ee76d0e6f6d9: Loading layer [==================================================>] 1.436 GB/1.436 GB
      33dca533c6e5: Loading layer [==================================================>] 331.8 kB/331.8 kB
      24630015679d: Loading layer [==================================================>] 35.18 MB/35.18 MB
      Loaded image: lzqs/deploy:1.0

    加載成功後,docker images便可看到加載的鏡像

    > docker images
    
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    lzqs/deploy         1.0                 d8f0875e967b        About an hour ago   2.115 GB
  • 運行lzqs/deploy鏡像,成功後,在外部訪問服務器的9000端口, <服務器的IP>:9000

    > docker run -d -p 9000:8000 lzqs/deploy
    1d0db9a5d0c8826171e501b0e86afd444fca8144b1105e63dae8d621bdda7a77
    
    > docker ps -a
    CONTAINER ID  IMAGE           COMMAND      CREATED              STATUS             PORTS                    NAMES
    1d0db9a5d0c8  lzqs/deploy:1.0 "npm start"  About a minute ago   Up About a minute  0.0.0.0:9000->8000/tcp goofy_curran
  • docker exec -it <CONTAINER ID> /bin/bash 能夠進入容器中執行,方便咱們查看內部文件和調試

    > docker exec -it 1d0db9a5d0c8 /bin/bash
    
    root@1d0db9a5d0c8:/app#
  • 戰功,訪問部署的docker應用,<服務器的IP>:9000,效果以下圖:

deploy

小結

七月流火,程序員的好日子要到了,固然也是你們的好日子快到了,適宜的溫度應該更加高產。關於docker的研究還在進行中,爲了前端更好的發展,讓咱們繼續燥起來吧,畢竟沒有什麼是一段JS解決不了的。

相關文章
相關標籤/搜索