返回部落格

如何在 Ubuntu 20.04 上使用 Docker 部署 Node.js (Express.js) 應用程式

如何在 Ubuntu 20.04 上使用 Docker 部署 Node.js (Express.js) 應用程式

簡介

Docker 是一個容器平台,它是一個輕量級、虛擬化、可移植、軟體定義的標準化環境。它允許軟體與運行在實體主機上的其他軟體隔離運行。Docker 是軟體開發中持續開發與整合(CI/CD)方面的一個關鍵組成部分。它提供了一個 虛擬機的輕量級替代方案,並讓開發人員能夠享受分散式應用程式架構。若要深入了解 Docker 生態系統的概覽,請參閱這篇文章.

使用 Docker 建置應用程式的過程始於開發人員為其應用程式建立映像檔。然後,該映像檔將被部署在容器中。映像檔包含應用程式的定義組件,例如應用程式程式碼、函式庫、設定檔、環境變數和執行環境。映像檔標準化了容器內部的環境,賦予了容器化可移植性的特性。 Node.js 是一個開源、跨平台的後端 JavaScript 執行環境,可以在網頁瀏覽器之外執行 JavaScript 程式碼。它建立在 Chrome 的 V8 JavaScript 引擎. Express.js 是一個運行在 Node.js 之上的極簡後端 JavaScript 框架。

在本教學中,我們將為一個運行在 Express 框架上的網站建立映像檔。我們將使用 Bootstrap(一個前端函式庫)來讓前端外觀更好看。建立映像檔後,我們將建置一個容器並將其推送到 Docker Hub。Docker Hub 允許開發人員託管容器化應用程式,以便輕鬆部署到任何 Docker 環境。一旦您的容器託管在 Docker Hub 上,我們將拉取它並建置另一個實際用於提供我們網站服務的映像檔。

先決條件

這將是一個動手實作的教學。您應該建立一個能夠讓您跟著操作的環境。

步驟 1:設定應用程式依賴項

在建立映像檔之前,您需要建立應用程式的原始碼。應用程式原始碼包括將複製到容器中的程式碼、靜態內容和依賴項。首先在非 root 使用者的家目錄中為您的專案建立一個目錄。我們將其命名為 node_express,但您可以自由使用您喜歡的目錄名稱:

接下來,進入此目錄:

這將是您的應用程式根目錄。一個 node.js 應用程式需要根資料夾中包含一個 package.json 檔案。Npm 使用此檔案來確定您的應用程式需要哪些依賴項。輸入以下指令來建立此檔案:

之後,將以下程式碼片段新增到該檔案中。您可以根據需要更新名稱、作者、描述和進入點檔案:

如您所見,此檔案指定了專案名稱、版本、作者以及共享應用程式程式碼所依據的授權條款。建議為您的專案使用簡短且具描述性的名稱,以避免在 npm registry 中重複。我們為該專案指定了 ISC license,它允許免費複製、修改或分發應用程式程式碼。

最重要的是,您應該注意檔案中的以下指令:

  • main」:此指令指定了應用程式的進入點,我們將其設定為 index.js。我們很快就會建立這個檔案。
  • dependencies」:此指令指定了當我們執行 npm 指令時,將從 npm registry 提取的應用程式相依性。在我們的案例中,我們需要 Express 4.17.1 及以上版本。

您現在可以按下 Ctrl + O 儲存檔案。然後,按下 Ctrl + X 關閉檔案。接下來,我們將透過執行以下指令來安裝相依性:

此指令會安裝 package.json 檔案中指定的應用程式相依性,並放入 node_modules 目錄中。這些目錄在您首次執行該指令時已自動建立。安裝好應用程式相依性後,您現在可以開始新增應用程式程式碼。

步驟 2:新增您的應用程式程式碼檔案

我們將建立一個基本的食譜網站,內容由 allrecipes 提供。應用程式的主要進入點是 index.js 檔案。我們將新增一個 views 目錄,用來存放專案的各個頁面和靜態資產。該網站將有一個到達頁面,其中包含介紹性資訊和一些食譜的連結。

我們的到達頁面程式碼將放在 home.html 檔案中。首先,輸入以下指令來建立 index.js 檔案:

新增以下程式碼,這會匯入並建立一個 Express 應用程式。它還指定了 Router 物件、基礎目錄以及此應用程式將提供服務的連接埠:

require 是一個載入模組的 JavaScript 函式。在此案例中,我們正在載入 express 模組。然後,我們將使用匯入的模組來建立 express 和 router 物件。router 物件透過回應 HTTP 方法呼叫來執行應用程式的路由功能,隨著教學課程的進行,這些呼叫將會新增到此物件中。

我們也設定了 pathport。path 常數定義了程式碼的基礎目錄。在我們的案例中,它是專案根目錄下的 views 子目錄。而 port 指定了 express 應用程式應該接聽的連接埠,在我們的範例中,我們將其設定為 8090.

一旦有了這些常數,我們就可以使用 router 物件來為應用程式指定一些路由。將以下程式碼新增至 index.js 檔案以指定路由:

您可以使用 add middleware 到路由,透過使用 router.use 函式。在此案例中,我們新增了一個函式,在將路由器的請求傳遞給應用程式路由之前先記錄它們。對應用程式基礎路徑發送 GET 請求將會傳回 home.html 頁面。然後,我們為三個食譜添加了頁面,這些頁面也將使用對特定食譜頁面的 GET 請求來檢索。

最後,添加以下程式碼以掛載 router 中介軟體和應用程式靜態資產。此外,告訴 express 應用程式監聽連接埠 8090:

您完整的 index.js 檔案應該像這樣:

您現在可以儲存並關閉檔案。下一步是將靜態網頁新增至 views 目錄。首先輸入以下指令來建立該目錄:

輸入以下指令以開啟 home.html 首頁檔案:

將以下程式碼新增至檔案中。此程式碼會匯入 Bootstrap,並向網站訪客提供一些關於此網站主題的資訊:

除了匯入 Bootstrap 之外,該頁面還新增了一個基本的 導覽選單 ,以協助我們在頁面之間切換並返回首頁。我們還新增了一行來匯入我們的自訂 CSS 檔案:

稍後我們將使用此檔案為應用程式新增自訂樣式。現在,讓我們為食譜建立三個頁面。我們首先從建立 千層麵 頁面開始。使用以下指令以 nano 編輯器開啟該檔案:

在開啟的檔案中,新增以下程式碼。此檔案將匯入 Bootstrap、custom.css 檔案、指定導覽選單並提供一些千層麵食譜資訊:

讓我們按照相同的步驟來為 酪梨醬 食譜頁面建立檔案。執行以下指令以 nano 開啟檔案:

然後將此程式碼新增至檔案中:

最後,讓我們建立 banana_bread.html 檔案,輸入以下指令:

然後,將以下 HTML 程式碼新增至檔案中:

現在,我們已經建立了所有頁面。如果您還記得,我們需要新增 css/custom.css 檔案。輸入以下指令來建立目錄:

然後使用以下指令在 nano 編輯器中建立並開啟檔案:

您可以根據需要新增更多 CSS 程式碼來設計您的網站樣式。為求簡潔,讓我們將以下程式碼片段新增到檔案中:

完成後儲存並關閉檔案。

由於我們現在已經安裝了應用程式原始碼和專案依賴項,您可以啟動應用程式。

我們已將應用程式設定為接聽連接埠 8090,請執行以下指令以指示防火牆允許流量通過此連接埠。如果您指定了不同的連接埠,請替換指令中的連接埠號碼:

現在,您可以啟動應用程式。但首先,請執行以下指令以確保您位於專案根目錄中:

使用 node index.js 啟動應用程式。如果您指定了不同的進入點,請將其替換為您的進入點:

如果您將瀏覽器導向至 http://your_public_server_ip:8090,您將會看到如定義的食譜首頁:

Recipes

 

您可以在導覽列中看到各個食譜的連結。讓我們點擊一些。下面是 Lasagna 食譜頁面:

Node.js app install on Ubuntu 1

而這裡是 Guacamole 食譜頁面:

Guacamole

至此,您已建立應用程式並測試其運作是否符合預期。您可以按下 Ctrl + C 結束伺服器,然後繼續建立 Dockerfile。Dockerfile 有助於擴充性,因為它可以在需要時重新建立應用程式的執行個體。

步驟 3:建立 Dockerfile

Docker 在建置映像檔時會讀取 Dockerfile 中指定的指令。它指定了應用程式的執行階段環境。因此,它能幫助開發人員避免相依性或變更執行階段版本所產生的差異。輸入以下指令來建立 Dockerfile:

Docker 映像檔是使用多個相互建構的映像檔層建立的。您首先要新增一個基礎映像檔,作為應用程式的起點。

由於應用程式預期在 node.js 環境中執行,我們將首先新增 node:10-alpine 映像檔 用於 node.js。目前在我們撰寫本教學課程時,這是 推薦的 Node.js LTS 版本。我們選擇這個特定的映像檔,是因為它衍生自 Alpine Linux 專案。因此,它將有助於將我們的映像檔大小保持在最小。在 Docker Hub Node 映像檔頁面 下有幾種映像檔變體,您可以根據自己的需求進行選擇。

新增以下程式碼,使用 FROM 指令來設定應用程式的基礎映像檔:

此映像檔包含 Node.js 和 npm。每個 Dockerfile 都必須以 FROM 指令開始。Docker node 映像檔預設帶有一個非 root 的 node 使用者,您可以使用它來以 root 身份執行您的應用程式容器。 Docker 安全性建議 不要以 root 身份執行容器,並將權限限制為僅執行其資源所需的權限。

在這種情況下,我們將使用 node 使用者的家目錄作為應用程式的工作目錄,以及容器內的使用者。您可以查看這份 Docker Node 映像檔最佳做法 指南以取得更多資訊。

我們將在 node_modules 內建立 /home/node 子目錄以及 app 目錄,以協助簡化應用程式程式碼的權限。建立這些目錄可確保當我們在容器內部本機執行 npm install 指令時,它們具有正確的權限。建立目錄後,您必須將其所有權設定給 node 使用者。我們將在 Dockerfile 中加入以下行來執行此操作:

然後,您將透過新增以下行來設定工作目錄:

最好一律設定 WORKDIR ,這樣 Docker 就不必預設建立一個。

新增以下行以複製 package.jsonpackage-lock.json 檔案:

建議在執行 npm install 或複製應用程式原始碼之前新增 COPY 指令。這能讓您利用 Docker 的快取機制。在建置過程中,Docker 會檢查是否為每個指令快取了一個圖層。這意味著如果您沒有變更 package.json 檔案,則 Docker 將使用現有的映像檔層,並避免重新安裝 node modules,從而加快建置過程。

在執行 npm install 之前,新增以下行以將使用者切換為 node ,以確保所有應用程式檔案和 node_modules 目錄都歸非 root 的 node 使用者所有:

我們的容器現在已準備好執行 npm install 指令。將以下行新增至 Dockerfile:

安裝好 node_modules 後,新增以下行,這將指示 Docker 將應用程式程式碼複製到容器上的應用程式目錄中,並具有正確的權限和所有權,即非 root 的 node 使用者:

最後一步是公開容器上的連接埠 8090 ,正如我們在入口 index.js 檔案中所定義的:

EXPOSE 設定在執行階段將開啟容器上的哪些連接埠。 CMD 執行啟動應用程式的指令,在此例中為 node index.js。

Dockerfile 中只能有一個 CMD 指令,因為只有最後一個會生效。請查看 Dockerfile 參考文件,以獲取您可以使用 Dockerfile 執行的操作列表。

您完整的 Dockerfile 應該像這樣:

您現在可以儲存並關閉該檔案。

接下來您要執行的是新增 .dockerignore 檔案。就像 .gitignore 檔案一樣,.dockerignore 指定了專案目錄中哪些檔案和目錄不應複製到容器中。

使用 nano 編輯器開啟檔案:

在檔案中新增以下幾行:

如果使用的是 git 存放庫,那麼您還應該新增 .git 目錄和 .gitignore 檔案。儲存並關閉檔案。

如果一切順利,現在是時候使用 docker build 指令來建置應用程式映像檔了。您可以將 –t 旗標新增至 docker build 指令,以便為映像檔標記一個易記的名稱,而不是使用 Docker 預設設定的隨機字串。我們也將把映像檔推送到 Docker Hub,因此最好在標籤中包含您的 Docker Hub 使用者名稱。

我們將使用 nodejs-express-image 作為標籤名稱。您可以自由選擇自己喜歡的標籤名稱。以下是建置映像檔的指令:

請記住將 your_dockerhub_username 替換為您實際的 Docker Hub 使用者名稱。末尾的 . (點) 指定建置上下文為目前目錄。

建置過程需要一到兩分鐘。完成後,輸入指令以檢查您的映像檔:

您應該會看到類似以下的內容:

sudo docker images

請記住,我們已將 your_dockerhub_username 替換為實際的使用者名稱。

確認您的映像檔已建置完成後,您現在可以使用 docker run 來建立容器。將包含以下旗標:

  • -p:發布容器上的連接埠並將其對應到主機系統上的連接埠。為了示範目的,我們將在主機系統上使用連接埠 80。但是,如果您在該連接埠上運行了其他程序,請根據需要隨時進行修改。深入了解 Docker 文件中的連接埠繫結.
  • -d:用於分離模式。允許容器在背景繼續運行。
  • --name:您可以使用此旗標來設定一個易記的名稱,而不是讓 Docker 分配一個隨機字串。

建置容器的指令如下。請適當替換您的 Docker Hub 使用者名稱:

等待容器建置並開始運行。您可以使用此指令來檢查所有正在運行的容器:

您應該會看到類似以下的輸出:

Node.js app install on Ubuntu 3

如輸出所示,容器現在正在運行。如果您在瀏覽器中造訪伺服器的公共 IP 位址(不含連接埠),您就可以在瀏覽器中查看它。您的首頁將會載入:

awesome recipe

 

您已成功使用 Docker 部署了 Node Express 靜態網站。讓我們看看如何將此映像檔推送到 Docker Hub,以便將來使用和擴充。

步驟 4:使用 Docker 映像檔存放庫

您可以將映像檔推送到 Docker Hub 等映像檔登錄庫,並將其儲存以供日後使用、與其他開發人員共享或用於擴充您的容器。我們可以將建立的映像檔推送到 Docker Hub,並使用它來重新建立容器。

使用以下指令登入您的 Docker Hub 帳戶。請將其替換為您實際的 Docker Hub 使用者名稱:

系統提示時輸入您的密碼。登入後,系統會在您的使用者家目錄中建立一個 ~/.docker/config.json 檔案,其中包含您的 Docker Hub 憑證。

設定完成後,輸入以下指令將映像檔推送到 Docker Hub,並指定您先前建置映像檔時設定的標籤:

此指令會將 Docker 映像檔推送到您的 Docker Hub 帳戶。如果您造訪您的帳戶,您可以看到最近推送的映像檔:

Docker Hub

我們可以透過銷毀目前的應用程式容器,並使用存放庫中的映像檔重新建置它,來測試映像檔存放庫的實用性。

輸入以下指令來列出您目前的容器:

您應該會看到類似以下的輸出:

Docker Hub

請注意輸出中列出的 CONTAINER ID,複製它,並使用以下指令停止您的容器,請將 ID 替換為您的 ID:

輸入以下指令以列出系統中所有可用的 Docker 映像檔:

輸出將顯示您的映像檔名稱、Node.js 映像檔以及建置過程中的其他映像檔。

輸入以下指令以移除映像檔,包括未使用的或懸空的映像檔:

輸入 y 以確認。這會移除已停止的容器和映像檔。如果您列出它們,您將在輸出中看到一個空列表:

output

現在,您已經移除了執行應用程式的容器以及映像檔本身。若要深入了解如何 透過我們的教學課程來移除 Docker 容器、映像檔和資料卷.

我們現在可以透過先使用以下指令從 Docker Hub 拉取映像檔來重新建立整個過程。請適當地替換您的 Docker Hub 使用者名稱:

再次使用以下指令列出您的 Docker 映像檔:

您應該會在輸出中看到該映像檔:

sudo docker

您現在可以使用來自 步驟 3 的指令重新建置您的容器。當然,請在適當的地方替換您的 Docker Hub 使用者名稱:

列出您的容器以確認它已重新建置:

您應該會看到類似的輸出:

在瀏覽器中,導覽至您伺服器的公用 IP 位址,您應該會看到您的應用程式正在執行。

結論

如果您已按照本教學課程進行到此處,您現在已經擁有一個使用 Express 和 Bootstrap 製作並使用 Docker 部署的靜態網站。您使用靜態網站檔案建置了 Docker 映像檔,並使用該映像檔建立了容器。接著,您將映像檔推送到 Docker 映像檔登錄庫,Docker Hub,使其可用於日後使用或擴充。為了測試映像檔登錄庫的使用,您銷毀了映像檔和容器,從登錄庫拉取了映像檔,並重新建置了容器。

本教學課程說明了如何部署 Node.js 應用程式。如果您想了解如何使用不同的網頁開發技術棧,我們有一篇關於在 Nginx 上使用 Docker Compose 部署 Laravel 應用程式.

如需更多關於利用 Docker 的資源,請參考以下教學課程:

祝您運算愉快!

author

Hark Labs

作者 · CloudSigma

Preslav Dobrev 是 CloudSigma 的創意設計師,專注於透過傳統與創新行銷渠道建立一致的企業形象。他擅長將藝術願景與策略行銷相融合,創造具有影響力的品牌敘事。

留言

目前尚無留言。成為第一個留言的人吧。