簡介
docker容器的出現,徹底的改變了應用程式的執行方式,而nodejs同樣的也顛覆了後端應用程式的開發模式。兩者結合起來,就會產生意想不到的作用。
本文將會以一個常用的nodejs程式為例,分析怎麼使用docker來構建nodejs image.
準備nodejs應用程式
一個標準的nodejs程式,需要一個package.json檔案來描述應用程式的後設資料和依賴關係,然後通過npm install來安裝應用的依賴關係,最後通過node app.js來執行程式。
本文將會建立一個簡單的koa應用程式,來說明docker的使用。
首先建立package.json檔案:
{
"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檔案制定了專案的依賴。
接下來,我們需要使用npm install來安裝專案的依賴,安裝好的專案依賴檔案將會放在本地的node_modules資料夾中。
然後我們就可以編寫服務程式了:
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程式的最佳實踐。
建立Dockerfile檔案
為了建立docker image,我們需要一個Dockerfile檔案,作為該image的描述。
我們一步一步的講解,如何建立這個Dockerfile檔案。
- 引入base image。
為了執行docker程式,我們需要指定一個基本的image,比如作業系統,node為我們提供了一個封裝好的image,我們可以直接引用:
FROM node:12
我們指定了node的12版本,這個版本已經安裝好了最新的LTS node 12,使用這個image我們就可以不需要自己來安裝node的相關環境,非常的方便。
- 指定工作目錄
有了image,接下來就需要我們指定docker中的工作目錄:
# Create app directory
WORKDIR /data/app
- 安裝node_modules
接下來我們需要將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" ]
建立.dockerignore檔案
我們知道git會有一個.gitignore檔案,同樣的docker也有一個.dockerignore檔案,這個檔案的作用就是避免你的本地檔案被拷貝到docker image中。
node_modules
比如我們可以在其中指定node_modules,使其不會被拷貝。
建立docker image
建立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程式
最後,我們可以通過docker run命令來執行應用程式
docker run -p 54321:8080 -d flydean/koa-web-app
然後我們就可以通過本地的54321埠來訪問應用程式了。
node的docker image需要注意的事項
這裡我們來探討一下建立docker image需要注意的事項。
- 不要使用root使用者來執行應用程式
預設情況下,docker中的應用程式會以root使用者來執行,為了安全起見,建議大家以普通使用者來執行應用程式,我們可以在docker file中指定:
FROM node:12
...
# 在最後,以node使用者來執行應用程式
USER node
或者我們在執行的時候以 -u "node" 作為啟動引數來指定執行的使用者。
docker run \
-u "node"
flydean/koa-web-app
- 指定執行時候的NODE_ENV
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的部落格
歡迎關注我的公眾號:「程式那些事」最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!