docker是一個開源的應用容器引擎,能夠爲咱們提供安全、可移植、可重複的自動化部署的方式。docker採用虛擬化的技術來虛擬化出應用程序的運行環境。如上圖同樣。docker就像一艘輪船。而輪船上面的每一個小箱子能夠當作咱們須要部署的一個個應用。使用docker能夠充分利用服務器的系統資源,簡化了自動化部署和運維的繁瑣流程,減小不少由於開發環境中和生產環境中的不一樣引起的異常問題。從而提升生產力。html
docker三個核心概念以下:node
鏡像(images):一個只讀的模板,能夠理解爲應用程序的運行環境,包含了程序運行所依賴的環境和基本配置。至關於上圖中的每一個小箱子裏面裝的東西。linux
倉庫(repository):一個用於存放鏡像文件的倉庫。能夠看作和gitlab同樣。git
容器(container):一個運行應用程序的虛擬容器,他和鏡像最大的區別在於容器的最上面那一層是可讀可寫的。 至關於上圖中的每一個小箱子裏。docker
本文主要是教你們瞭解如何在Docker容器中設置Node JS:express
有一個可運行工做的NodeJS應用程序npm
經過確保進程在出錯時不退出,使節點應用程序具備彈性瀏覽器
經過在代碼更改時自動從新啓動服務器,使Node應用程序易於使用安全
利用Docker:bash
快速設置與生產相同的開發環境。
輕鬆地可以在本地和服務器上切換節點版本
Docker的全部其餘 好處
先決條件
Docker已經安裝好了
至少入門級節點知識和NPM
1.獲取一個簡單的Node應用程序
咱們將使用Express,由於它的設置是容易的。
在一個乾淨的目錄中,讓咱們從初始化NPM開始,繼續運行此命令並按照提示進行操做:
npm init
安裝Express:
npm install --save-prod express
編制代碼src/index.js
<b>const</b> express = require('express') <b>const</b> app = express() <b>const</b> port = 3000 app.get('/', (req, res) => res.send('Hello World!')) app.listen(port, () => {console.log(`Example app listening on port ${port}!`))
啓動一個偵聽端口3000並使用Hello World響應的"/"這個URL路由。
2.設置Docker以運行咱們的Node應用程序
咱們將使用docker-compose.yml文件來啓動和中止咱們的Docker容器,而不是鍵入長長的Docker命令。您能夠將此文件視爲多個Docker容器的配置文件。
docker-compose.yml:
version: "3" services: app: container_name: app # How the container will appear when listing containers from the CLI image: node:10 # The <container-name>:<tag-version> of the container, in this case the tag version aligns with the version of node user: node # The user to run as in the container working_dir: "/app" # Where to container will assume it should run commands and where you will start out if you go inside the container networks: - app # Networking can get complex, but for all intents and purposes just know that containers on the same network can speak to each other ports: - "3000:3000" # <host-port>:<container-port> to listen to, so anything running on port 3000 of the container will map to port 3000 on our localhost volumes: - ./:/app # <host-directory>:<container-directory> this says map the current directory from your system to the /app directory in the docker container command: "node src/index.js" # The command docker will execute when starting the container, this command is not allowed to exit, if it does your container will stop networks: app:
讓咱們用這個命令啓動docker容器。在後臺運行(-d)
docker-compose up -d
在瀏覽器中訪問http://localhost:3000並看到 Hello World!
3. 使得應用變得彈性
若是您以前使用過Node,那麼您可能知道若是應用程序中發生錯誤(如未捕獲的異常),那麼它將關閉該Node進程。這對咱們來講真的是個壞消息,由於咱們的代碼中確定會有一個錯誤,而且沒法保證咱們的代碼100%無錯誤。此問題的解決方案一般是另外一個監視咱們的Node應用程序並在其退出時從新啓動它的過程。有這麼多的解決方案,好比linux的supervisord,NPM包永遠和PM2等......咱們只須要爲本指南選擇一個。
將專一於 PM2, 由於我最熟悉它,除了進程管理以外還有一些其餘功能,例如文件監視,這將在下一節中派上用場。
安裝PM2
npm install --save-prod pm2
PM2能夠經過命令行使用,但咱們將設置一個簡單的配置文件,就像咱們使用docker-compose.yml文件同樣,以防止咱們重複輸入長命令
ecosystem.config.js:
const path = require('path') module.exports = { apps: [{ name: 'app', script: 'src/index.js', // Your entry point instances: 1, autorestart: true, // THIS is the important part, this will tell PM2 to restart your app if it falls over max_memory_restart: '1G' }] }
如今咱們應該更改docker-compose.yml文件以使用PM2啓動咱們的應用程序,而不是直接從index.js啓動它。
docker-compose.yml(僅更改了的選項)
version: "3" services: app: container_name: app # How the container will appear when listing containers from the CLI image: node:10 # The <container-name>:<tag-version> of the container, in this case the tag version aligns with the version of node user: node # The user to run as in the container working_dir: "/app" # Where to container will assume it should run commands and where you will start out if you go inside the container networks: - app # Networking can get complex, but for all intents and purposes just know that containers on the same network can speak to each other ports: - "3000:3000" # <host-port>:<container-port> to listen to, so anything running on port 3000 of the container will map to port 3000 on our localhost volumes: - ./:/app # <host-directory>:<container-directory> this says map the current directory from your system to the /app directory in the docker container command: "npx pm2 start ecosystem.config.js --no-daemon" # The command docker will execute when starting the container, this command is not allowed to exit, if it does your container will stop networks: app:
更改docker-compose.yml文件不會影響已經運行的容器。爲了進行更改,您應該從新啓動容器:
docker-compose restart
4.使咱們的應用程序易於開發
您可能已經注意到,一旦Node進程啓動,那麼在從新啓動Node進程以前,更改代碼實際上並無作任何事情,對於咱們而言,每次都會涉及從新啓動Docker容器以激活咱們作出的改變。若是咱們在進行代碼更改時自動爲咱們從新啓動Node進程,那將是理想的選擇。
在過去,我已經完成了諸如引入文件監視實用程序和使用該文件監視實用程序來從新啓動Docker進行文件更改之類的操做,或者我會使用Nodemon可是在使用Docker時會有一些警告。
最近,當文件發生變化時,我一直在使用PM2來從新啓動個人Node進程,並且因爲咱們已經從上一步中獲取了它,所以咱們沒必要安裝另外一個依賴項。
ecosystem.config.js(僅添加了watch選項):
const path = require('path')
module.exports = { apps: [{ name: 'app', script: 'src/index.js', instances: 1, autorestart: true, watch: process.env.NODE_ENV !== 'production' ? path.resolve(__dirname, 'src') : false, max_memory_restart: '1G' }] }
若是咱們沒有將NODE_ENV環境變量設置爲production,則上面的配置文件如今將監視src目錄。您能夠經過更改index.js文件來測試它,除了Hello World以外還能夠將其餘內容打印到瀏覽器中!。在此以前,您須要從新啓動Docker容器,由於您更改了PM2運行容器的方式:
docker-compose restart
從新啓動Node進程可能須要一秒鐘才能完成,若是你想觀察它什麼時候完成,你能夠看到你的Docker日誌告訴PM2什麼時候完成重啓你的Node Process:
docker-compose logs -f
總結
咱們的目標之一是可以輕鬆更改Node版本,您能夠經過更改docker-compose.yml文件中的image選項來完成此操做。
本地安裝依賴項是使用本地NPM和Node版本完成的,若是您的本地版本與Dockers不一樣,有時可能會致使衝突。使用相同的Docker容器來安裝依賴項更安全。您可使用此命令來使用該容器來安裝依賴項,而後將其刪除
docker run --rm -i -v <absolute-path-to-your-project-locally>:/app -w /app node:10 npm install
如上所述,具備與Docker運行的Node不一樣的本地版本多是有問題的。最好在容器內部運行命令以保持一致性。你能夠進入一個容器
docker exec -it app bash
上面的命令將把你放到容器中,這樣你就能夠繼續從裏面運行命令,即npm run start或npm run test
若是您不想進入容器內部,能夠運行這樣的命令
docker exec -t app bash -c "npm run start"
參考文章: