docker容器的出現,完全的改變了應用程序的運行方式,而nodejs一樣的也顛覆了後端應用程序的開發模式。二者結合起來,就會產生意想不到的做用。node
本文將會以一個經常使用的nodejs程序爲例,分析怎麼使用docker來構建nodejs image.git
一個標準的nodejs程序,須要一個package.json文件來描述應用程序的元數據和依賴關係,而後經過npm install來安裝應用的依賴關係,最後經過node app.js來運行程序。web
本文將會建立一個簡單的koa應用程序,來講明docker的使用。docker
首先建立package.json文件:npm
{ "name": "koa-docker", "description": "怎麼將nodejs koa程序打包成docker應用", "version": "0.0.1", "dependencies": { "ejs": "^2.5.6", "fs-promise": "^2.0.3", "koa": "^2.2.0", "koa-basic-auth": "^2.0.0", "koa-body": "^4.0.8", "koa-compose": "^4.0.0", "koa-csrf": "^3.0.6", "koa-logger": "^3.0.0", "@koa/router": "^8.0.5", "koa-session": "^5.0.0", "koa-static": "^3.0.0", "koa-views": "^6.0.2" }, "scripts": { "test": "NODE_ENV=test mocha --harmony --reporter spec --require should */test.js", "lint": "eslint ." }, "engines": { "node": ">= 7.6" }, "license": "MIT" }
上面的package.json文件制定了項目的依賴。json
接下來,咱們須要使用npm install來安裝項目的依賴,安裝好的項目依賴文件將會放在本地的node_modules文件夾中。後端
而後咱們就能夠編寫服務程序了:promise
const Koa = require('koa'); const app = module.exports = new Koa(); app.use(async function(ctx) { ctx.body = 'Hello www.flydean.com'; }); if (!module.parent) app.listen(3000);
上面是一個很是簡單的koa服務端程序,監聽在3000端口,而且對每次請求都會返回‘Hello www.flydean.com’。緩存
運行node app.js 咱們就能夠開啓web服務了。安全
好了,咱們的服務程序搭建完畢,接下來,咱們看一下docker打包nodejs程序的最佳實踐。
爲了建立docker image,咱們須要一個Dockerfile文件,做爲該image的描述。
咱們一步一步的講解,如何建立這個Dockerfile文件。
爲了運行docker程序,咱們須要指定一個基本的image,好比操做系統,node爲咱們提供了一個封裝好的image,咱們能夠直接引用:
FROM node:12
咱們指定了node的12版本,這個版本已經安裝好了最新的LTS node 12,使用這個image咱們就能夠不須要本身來安裝node的相關環境,很是的方便。
有了image,接下來就須要咱們指定docker中的工做目錄:
# Create app directory WORKDIR /data/app
接下來咱們須要將package*.json文件拷貝進image中,而且運行npm install來安裝依賴庫:
COPY package*.json ./ RUN npm install
上面咱們拷貝的是package*.json,由於若是咱們本地運行過npm install命令的話,將會生成一個pacakge-lock.json文件。這個文件是爲了統一依賴包版本用的。咱們須要一併拷貝。
拷貝完以後就能夠運行npm install來安裝依賴包了。
問題?爲何咱們只拷貝了pacakge.json,而不是拷貝整個工做目錄呢?
回答:docker file中的每個命令,都會致使建立一個新的layer,上面的docker file中,只要pakage.json沒有被修改,新建立的docker image實際上是能夠共享layer緩存的。
可是若是咱們直接添加本地的工做目錄,那麼只要咱們的工做目錄有文件被修改,會致使整個docker image從新構建。因此爲了提高構建效率和速度,咱們只拷貝package.json。
最後的工做就是拷貝應用程序app.js而後運行了:
# 拷貝應用程序 COPY app.js . # 暴露端口 EXPOSE 8080 # 運行命令 CMD [ "node", "app.js" ]
最後,咱們的dockerfile文件應該是這樣的:
FROM node:12 # Create app directory WORKDIR /data/app COPY package*.json ./ RUN npm install # 拷貝應用程序 COPY app.js . # 暴露端口 EXPOSE 8080 # 運行命令 CMD [ "node", "app.js" ]
咱們知道git會有一個.gitignore文件,一樣的docker也有一個.dockerignore文件,這個文件的做用就是避免你的本地文件被拷貝到docker image中。
node_modules
好比咱們能夠在其中指定node_modules,使其不會被拷貝。
建立docker image很簡單,咱們可使用下面的命令:
docker build -t flydean/koa-web-app .
建立完畢以後,咱們可使用docker images來查看剛剛建立好的image :
docker images # Example REPOSITORY TAG ID CREATED node 12 1934b0b038d1 5 days ago flydean/koa-web-app latest d64d3505b0d2 1 minute ago
最後,咱們能夠經過docker run命令來運行應用程序
docker run -p 54321:8080 -d flydean/koa-web-app
而後咱們就能夠經過本地的54321端口來訪問應用程序了。
這裏咱們來探討一下建立docker image須要注意的事項。
默認狀況下,docker中的應用程序會以root用戶來運行,爲了安全起見,建議你們以普通用戶來運行應用程序,咱們能夠在docker file中指定:
FROM node:12 ... # 在最後,以node用戶來運行應用程序 USER node
或者咱們在運行的時候以 -u "node" 做爲啓動參數來指定運行的用戶。
docker run \ -u "node" flydean/koa-web-app
node的應用程序不少時候須要依賴於NODE_ENV來指定運行時環境,咱們能夠以參數的形式傳遞給docker run命令:
docker run \ -e "NODE_ENV=production" flydean/koa-web-app
本文做者:flydean程序那些事本文連接:http://www.flydean.com/nodejs-docker-best-practices/
本文來源:flydean的博客
歡迎關注個人公衆號:「程序那些事」最通俗的解讀,最深入的乾貨,最簡潔的教程,衆多你不知道的小技巧等你來發現!