tags: docker Frontend Dockerfile 創建時間:2023年11月25日

初探 Docker:認識 Docker 以及了解如何建立前端專案 Dockerfile

Docker 簡介 #

Docker 是一個平台軟體,用於打包、部屬、運行應用程式及其相依套件。

Docker container,也被稱為 Docker 容器,與傳統虛擬機器類似,不過 Docker container 虛擬化作業系統層級,共享主機操作系統核心,更加輕量化;而傳統虛擬機則是虛擬化硬體。Docker container 可以無視環境的基礎設施差別,被部屬到任何地方。

docker

什麼是 Docker container、Docker image?

Docker container 等於 Docker image 運行的實體,不過光這麼說其實蠻文謅謅的,這裡我覺得可以先看過 larry 大大的這篇文章 Docker 實戰系列(一):一步一步帶你 dockerize 你的應用,內容講得很好。那究竟什麼是 Docker container、Docker image 讓我們先脫離名詞,來聽情境:

舉例來說,今天後端如果要部屬應用程式 B 到伺服器上,過往要考慮伺服器的環境,以及伺服器內是否有既有專案 A 的版本與專案 B 不同,比方專案 A 用 php5.x 但 B 專案若是用 php8.x 就十分麻煩,這時候若使用 Docker 技術,則可以有效解決問題,我們可以把每個專案獨立打包成一包 Docker image,並各自運行在一個獨立的箱子 Docker container,不用再擔心環境以及版本不同等問題。我們可以把 Docker image 想像每個專案獨立打包的結果,Docker container 想像成實際運作專案的箱子,放置每個專案使其不互相干擾。第一段其實就有提及這個概念:Docker container 可以無視環境的基礎設施差別,被部屬到任何地方。

docker

什麼是虛擬化硬體?

指的是硬體資源的抽象化,讓我們可以在同一個主機上運行不同的作業系統。例如以往聽見別人要在 Window 電腦上跑 macOS,就是使用虛擬化技術達成在一台主機上運行不同作業系統的實際案例。

什麼是作業系統?

作業系統 OS,是一組主管並控制 電腦 操作、運用和執行 硬體軟體資源 和提供公共 服務 來組織使用者互動的相互關聯的 系統軟體程式

參考: https://zh.wikipedia.org/zh-tw/操作系统

前端與 Docker #

我們已經藉由以上大致瞭解了 Docker 是什麼,繼續深入前,先來說明前端學習 Docker 的理由。

以前端建立的後台管理系統 這裡說明的是不需要 SSR 的專案 為例,部屬專案需要經歷 打包、設置 nginx 等步驟,看似不多,但使用 Docker 來構建部屬,會簡化前端部署專案的設置步驟。

前端部屬靜態網站時,不一定需要 Docker,但使用 Docker 會讓部屬過程更簡易容易管理。

前端如何建立專案的 Docker image #

使用 Docker 前,需要先安裝 Docker,請至官網先行安裝 官網安裝網址,並且安裝後開啟 Docker,並透過以下指令確認 Docker 有確實被安裝

如果有確實安裝 Docker,以下指令會跳出 Docker 版本

docker - v # 會顯示版本

我安裝 Docker 時遇到的小問題

一開始安裝完後,發現 Docker app 不能使用。

查詢過官網的支援後,發現 Docker Desktop mac 版本只支援最新兩個版本的 macOS,然後因為我的版本與最新 macOS 差三版,所以不支援,所以安裝 Docker 前,若是使用 mac 的人需要注意 masOS 的版本是否被 Docker 支援。

接著,我們將用實際範例來說明如何建構 Docker image,目標是構建一個前端 Vue3 CSR 專案的 Docker image,並在本地運行其 Docker container,再透過 localhost:3000 訪問

我們將依次依照下列部分執行:

  1. 搭起前端測試專案
  2. 撰寫該前端專案的 Dockerfile
  3. 建立前端專案的 Docker image
  4. 運行該專案的 Docker container
  5. 微調該專案的 Dockerfile 並重新運行 Docker container

1. 搭起前端測試專案 #

這裡我們使用 Vite 搭建 Vue3 CSR 專案,過程不詳細說明,可以使用 Vite 提供的 template 建立,也可以參考此處提供的 範本專案

2. 撰寫該前端專案的 Dockerfile #

接著我們要將專案 Containerize,意思是容器化我們的專案,要運行專案的 Docker container 前,要生成專案的 Docker image,我們需要建立一個名為 Dockerfile 的文件去告訴 Docker 如何生成專案的 Docker image。

建立前端專案的對應 Dockerfile 方法是在專案的 root 位置建立 Dockerfile 並寫入以下內容:

# 使用最新版本的 node lts 作為基礎 image
FROM node:lts-alpine as build-stage

# 設定工作目錄,稍後的工作目錄為 app
WORKDIR /app

# 複製 package.json 到 app 工作目錄
COPY package*.json ./

# 執行 npm 安裝
RUN npm install

# 複製應用程式中的所有檔案到容器中
COPY . .

# 打包 Vue3 程式碼
RUN npm run build

# 使用 stable 版本的 nginx 作為 image
FROM nginx:stable-alpine as production-stage

# 複製 Vue3 的打包結果到 nginx 中
COPY --from=build-stage /app/dist /usr/share/nginx/html

# 指定容器內部的 port 80 可以被外部訪問
EXPOSE 80

# 告訴 Docker 啟用 nginx 服務器
CMD ["nginx", "-g", "daemon off;"]

3. 建立前端專案的 Docker image #

接著使用剛剛建立的 Dockerfile,來建立 Docker image。記得下指令的位置要在剛剛建立 Dockerfile 的專案 root 位置,其中的 image 名稱可以依照你的需求命名,在範例中我們將此 image 命名為 test-01

docker build -t test-01 .

docker build -t [你的image名稱] .

指令意義:

  • docker build - 该 docker build 命令使用 Dockerfile 生成新 Docker image
  • -t - 會標記你的 Docker image,之後執行 Docker container 可以用 [你的 image 名稱] 引用 image
  • [你的image名稱] - 代表你的 image 命名
  • . - 代表告訴 Docker 在當前檔案位置找尋 Dockerfile 構建 Docker image

完成上述指令後,如果執行成功,可以看到以下成功訊息,代表 Docker image 成功建立:

3

運行失敗怎麼辦?

假如出現以下錯誤,你可能沒有開啟 Docker desktop,請去打開 Docker desktop app。

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

4. 運行專案的 Docker container #

建立好專案的 Docker image 後,接著我們來運行 Docker container。

docker run -dp 127.0.0.1:3000:80 test-01

docker run -dp [你本機的端口]:[docker端口] [你的image名稱]

指令意義:

  • docker run - 運行 Docker container
  • -dp - -d 在後台運行 docker container -p 只在本機和 docker container 間創建端口映射
  • [你本機的端口]:[docker端口] - 指的是將 docker container 端口映射到本機端口,讓應用程需可以從你的本機訪問
  • [你的image名稱] - 指的是 Docker 要運行的 Docker image

成功運行後,我們便可以訪問我們的專案 http://localhost:3000/

success-result docker container

5. 若是需要微調該專案的內容,該如何重新建立 Docker image,並運行 Docker container #

本地開發時,會頻繁更新程式碼,但若是在專案內容更新後再建立新的 Docker image,並運行新 Docker image 的 Docker container,我們會發現更新專案內容後,重新運行 Docker Container 會失敗。

docker build -t [你的image名稱] .
docker run -dp [你本機的端口]:[docker端口] [你的image名稱]

你會得到類似的失敗訊息:

2996d4847fb30e5df734786f83d7b0a06b379679daeb4accc9b6476c7834ce3b
docker: Error response from daemon: driver failed programming external connectivity on endpoint zen_kilby (5022993168aaca834530b63c260bf18ec8a74e6bcc905615a5c0d40cf0e565cb): Bind for 127.0.0.1:3000 failed: port is already allocated.

這個錯誤是 Docker 舊 Container 啟用時,無法啟用新 Container,原因是本地主機的 port 3000 已經被使用,若是要處理此問題,有兩個解法:

  1. 壞方法 改使用另一個本地 port docker run -dp 127.0.0.1:3001:80 test-01 。這是不好的,等於你改一次,就要佔用一個新的本機 port,且舊的 port 仍被佔用,舊的 container 也仍在運作。
  2. 好方法 刪除舊的 Docker container,建立新的 docker container。

按照以下方法可以刪除舊有 container:

# 列出所有 Docker-container-id
docker ps

# 使用 Docker container id 暫停 docker(要先暫停才可以刪除)
docker stop [the-container-id]

# 使用 id 刪除 Docker container
docker rm [the-container-id]

指令意義

  • docker ps - 列出所有 docker container id
  • docker stop [the-container-id] - 暫停運行中的 Docker container
  • docker rm [the-container-id] - 刪除 Docker container

接著重新運行 Docker Container 即可成功,我們可以看到網站更新了。

docker build -t [你的image名稱] .

docker run -dp [你本機的端口]:[docker端口] [你的image名稱]

success result rebuild docker container

結語 #

本文件介紹了 Docker 的基本概念,以及如何將前端專案整合至 Docker 中。透過 Docker,我們可以輕鬆打包、部署和運行應用程式,有效解決不同環境和版本的問題。有任何問題也歡迎和筆者討論交流歐 ʕ•ᴥ•ʔ。

參考資料 #

  1. Containerize an application

  2. Docker - 維基百科,自由的百科全書

  3. Docker 實戰系列(一):一步一步帶你 dockerize 你的應用


tags: docker Frontend Dockerfile 創建時間:2023年11月25日


下一篇 ...  深入理解 Event loop