您好,登錄后才能下訂單哦!
這篇“Node.js服務Docker容器化應用實例分析”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Node.js服務Docker容器化應用實例分析”文章吧。
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 ...
以上就是關于“Node.js服務Docker容器化應用實例分析”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。