共計 6520 個字符,預計需要花費 17 分鐘才能閱讀完成。
本文丸趣 TV 小編為大家詳細介紹“Docker 容器化應用 Node.js 服務的方法是什么”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Docker 容器化應用 Node.js 服務的方法是什么”文章能幫助大家解決疑惑,下面跟著丸趣 TV 小編的思路慢慢深入,一起來學習新知識吧。
docker 化一個 node.js 應用程序
先創建一個簡單的 node.js 應用,然后為這個應用創建一個 docker 鏡像,并構建和運行它
創建 node.js 項目
首先我們需要創建一個 app.js 開啟一個 http 服務,后面會借助 docker 來運行這個程序
const http = require( http
const port = 30010;
const server = http.createserver((req, res) = {
res.end( hello docker
server.listen(port, () = { console.log( running on http://localhost: , port, node_env , process.env.node_env);
});
然后我們創建一個 package.json 文件,這里是描述你的應用程序以及需要的依賴,寫過 node.js 的同學應該會很熟悉的,這里我在 scripts 里面增加了 npm run dev、npm run pro 兩個命令,因為我想在這里介紹如何在構建時傳入參數來動態設置環境變量。
{
name : hello-docker ,
version : 1.0.2 ,
description : ,
author : may ,
main : app.js ,
scripts : {
dev : node_env=dev node app.js ,
pro : node_env=pro node app.js
}
}
dockerfile 文件
這是一個 dockerfile 文件所包含的信息,這些命令在 docker 入門與實踐中也有講解過
from node:10.0-alpine
run apk --update add tzdata \
cp /usr/share/zoneinfo/asia/shanghai /etc/localtime \
echo asia/shanghai /etc/timezone \
apk del tzdata
run mkdir -p /usr/src/nodejs/
workdir /usr/src/nodejs/
# add npm package
copy package.json /usr/src/nodejs/package.json
run cd /usr/src/nodejs/
run npm i
# copy code
copy . /usr/src/nodejs/
expose 30010
cmd npm run dev
在 dockerfile 的同級文件下創建一個 .dockerignore 文件,避免將你本地的調試文件、node_modules 等一些文件放入 docker 容器中
.git
node_modules
npm-debug.log
此時通過以下命令即可構建一個 docker 鏡像
$ docker image build -t mayjun/hello-docker
再通過 docker run -d -p 30010:30010 mayjun/hello-docker 命令可運行一個 docker 容器,但是有個疑問我是有生產和測試之分的,按照上面 cmd npm run dev 這樣寫死只能打包一種環境,當然你也可以在建一個文件來實現或者一些其它的方法。
動態設置環境變量
為了解決上面的疑問,我的想法是在鏡像構建時傳入參數來動態設置環境變量,對 dockerfile 文件做下修改,看以下實現:
expose 30010
arg node_env # 新增加
env node_env=$node_env # 新增加
cmd npm run ${node_env} # 修改
下面對上面的代碼做個解釋
通過 arg 指令定義了一個變量,用戶可以在構建時通過使用 –build-arg = 標志的 docker build 命令將其傳遞給構建器 arg node_env
在 dockerfile 中使用 env 引用這個變量 env node_env=$node_env
這一步就是使用了 cmd npm run ${node_env}
剩下的就是在構建鏡像時動態傳入參數了
$ docker image build --build-arg node_env=dev -t mayjun/hello-docker:1.0.2 . # 構建測試環境
$ docker image build --build-arg node_env=pro -t mayjun/hello-docker:1.0.2 . # 構建生產環境
運行容器
$ docker run -d -p 30010:30010 mayjun/hello-docker:1.0.2
$ docker ps
container id image command created status ports names
2bc6e62cd0e8 mayjun/hello-docker:1.0.2 /bin/sh -c npm run… 3 minutes ago up 3 minutes 0.0.0.0:30010- 30010/tcp elastic_bouman
查看容器日志
docker logs -f 2bc6e62cd0e8
hello-docker@1.0.0 dev /usr/src/nodejs
node_env=dev node app.js
running on http://localhost: 30010 node_env dev
我將以上代碼打包成了鏡像 mayjun/hello-docker:1.0.2,可以拉取查看 docker pull mayjun/hello-docker:1.0.2
docker 與 node.js 私有 npm 包
如果你的項目中使用了私有 npm 包,在 dcoker 構建鏡像過程中會出現 npm 私有包安裝 404 的錯誤,如果是在容器外部我們可以 npm login 登陸擁有 npm 私有包權限的賬戶,來解決這個問題,但是在 docker 的時候是不能這樣做的。
創建身份驗證令牌
為了安裝私有包我們需要“創建身份驗證令牌”以便在持續集成環境、docker 容器內部能訪問我們的私有 npm 包,如何創建可參考
實現方法
我們在創建 dockerfile 文件過程中就需要增加以下兩條命令:
# 528das62-e03e-4dc2-ba67-********** 這個 token 就為你創建的身份驗證令牌 token
run echo //registry.npmjs.org/:_authtoken=528das62-e03e-4dc2-ba67-********** /root/.npmrc
run cat /root/.npmrc
egg 框架 docker 容器化
在 egg 里面,如果是 egg-scripts start –daemon,去掉 –daemon 直接 egg-scripts start 即可,否則 docker 容器會無法啟動。
看以下代碼示例,修改下 package.json 即可,dockerfile 文件同上面第一個 docker 化一個 node.js 應用程序是一樣的
package.json
{
scripts : {
start : egg-scripts start // 去掉 --daemon
}
}
也可參考 egg issues“docker 容器不能 run 起來,請問有碰到的嗎?”
docker 鏡像體積與構建時間優化
如果一個鏡像在不經過優化的情況下體積通常都是會很大的,以下也是在實踐過程中做的幾點優化。
run/copy 分層
dockerfile 中的每條指令都會創建一個鏡像層,dockerfile 指令或復制的項目文件在沒有修改變動的情況下,每個鏡像層是可以被復用和緩存的。
以下代碼可在 mayjun/hello-docker:latest 鏡像倉庫找到,以下示例中,源碼改變之后,不管 package.json 有沒有改變的情況下都會重新安裝 npm 模塊,這樣顯然是不好的,因此下面我們要改進
# ...
workdir /usr/src/nodejs/hello-docker
copy . /usr/src/nodejs/hello-docker
run npm install
# ...
改進之后的代碼如下所示,我們讓 package.json 提前,在 package.json 沒有修改的情況下是不會重新安裝 npm 包的,也會減少部署的時間。
# ...
workdir /usr/src/nodejs/
# add npm package
copy package.json /usr/src/app/package.json
run cd /usr/src/app/
run npm i
# copy code
copy . /usr/src/app/
# ...
node.js alpine 鏡像優化
mayjun/hello-docker:1.0.0 這個鏡像在 docker 倉庫也可搜索到,在未優化之前大約在 688mb
$ docker imagesrepository tag image id created sizemayjun/hello-docker 1.0.0 7217fb3e9daa 5 seconds ago 688mb
使用 alpine 優化
alpine 是一個很小的 linux 發行版,想要大幅度減小鏡像體積選擇 node.js 的 alpine 版本也是最簡單的,另外 -alpine 的時區默認不是國內的,需要 dockerfile 配置時區。
from node:10.0-alpine
run apk --update add tzdata \
cp /usr/share/zoneinfo/asia/shanghai /etc/localtime \
echo asia/shanghai /etc/timezone \
apk del tzdata
run echo asia/shanghai /etc/timezone
run mkdir -p /usr/src/nodejs/
workdir /usr/src/nodejs/
# add npm package
copy package.json /usr/src/app/package.json
run cd /usr/src/app/
run npm i
# copy code
copy . /usr/src/app/
expose 30010
cmd npm start
重新打包了一個版本 mayjun/hello-docker:1.1.0 再次查看下效果,可以看到鏡像文件從 688mb 減少至 85.3mb,這個體積優化還是很大的
$ docker images
repository tag image id created size
mayjun/hello-docker 1.1.0 169e05b8197d 3 minutes ago 85.3mb
生產環境不要打包 devdependencies 包
有些測試環境用的包,在進行生產環境打鏡像時不要包含進去,也就是 package.json 文件 devdependencies 對象,通過在 npm i 之后指定 –production 參數過濾
改進如下所示:
from node:10.0-alpine
# 省略 ...
# add npm package
copy package.json /usr/src/app/package.json
run cd /usr/src/app/
run npm i --production # 改變在這了
# 省略 ...
重新打包了一個版本 mayjun/hello-docker:1.2.0 再次查看下效果,可以看到鏡像文件從 85.3mb 又減少至 72.3mb
$ docker images
repository tag image id created size
mayjun/hello-docker 1.2.0 f018aa578711 3 seconds ago 72.3mb
常見問題
question1
以下命令在刪除鏡像的時候報如下錯誤:
$ docker rmi 6b1c2775591e
error response from daemon: conflict: unable to delete 6b1c2775591e (must be forced) - image is referenced in multiple repositories
細心的你也許會發現鏡像 id 6b1c2775591e 同時指向了 hello-docker 和 mayjun/hello-docker 倉庫,這也是造成刪除失敗的原因
$ docker images
repository tag image id created size
mysql 5.7 383867b75fd2 6 days ago 373mb
hello-docker latest 6b1c2775591e 7 days ago 675mb
mayjun/hello-docker latest 6b1c2775591e 7 days ago 675mb
指定 repository 和 tag 來刪除,執行刪除命令之后再次查看 mayjun/hello-docker 倉庫就已經沒有了
$ docker rmi mayjun/hello-docker
$ docker images
repository tag image id created size
mysql 5.7 383867b75fd2 6 days ago 373mb
hello-docker latest 6b1c2775591e 7 days ago 675mb
question2
執行刪除鏡像命令報如下錯誤:
$ docker rmi 9be467fd1285
error response from daemon: conflict: unable to delete 9be467fd1285 (cannot be forced) - image is being used by running container 1febfb05b850
根據提示是有正在運行的容器,需先停止容器、刪除容器之后在刪除鏡像
$ docker container kill 1febfb05b850 # 停止容器
$ docker rm 1febfb05b850 # 刪除容器
$ docker rmi 9be467fd1285 # 刪除鏡像
question3
設定的工作目錄(workdir)要與下面的要保持一致
...
workdir /usr/src/nodejs/
# add npm package
copy package.json /usr/src/node/package.json # 目錄不一致
run cd /usr/src/node/ # 目錄不一致
run npm i
...
例如,如以上配置因為工作目錄與實際 copy 的目錄不一致,會導致報以下錯誤:
再按照以下方式更改為一致即可
...
workdir /usr/src/nodejs/
# add npm package
copy package.json /usr/src/nodejs/package.json # 更改為一致
run cd /usr/src/nodejs/ # 更改為一致
run npm i
...
讀到這里,這篇“Docker 容器化應用 Node.js 服務的方法是什么”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注丸趣 TV 行業資訊頻道。