# 建立前端的 Dockerfile

首先我們需要在前端專案中建立一個 `Dockerfile`。這個檔案將定義如何將 Angular 應用打包成 Docker 映像檔。

這個 `Dockerfile` 做了兩件主要的事情：

1. **建置階段**：使用 Node.js 環境來安裝相依套件和建置 Angular 應用
2. **執行階段**：使用輕量級的 Nginx 伺服器來提供應用服務，並將建置好的檔案複製到 Nginx 的網頁目錄

在前端專案的根目錄建立一個 `Dockerfile`，內容如下：

```dockerfile
# 建置階段
FROM node:20 as build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build

# 執行階段
FROM nginx:alpine
COPY --from=build /app/dist/voting-system/browser /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```

### Dockerfile 詳細解說

`Dockerfile` 是用來定義如何建構 Docker 映像檔的文字檔案。它包含一系列的指令，這些指令會告訴 Docker 如何一步一步地建立一個映像檔。以下是對前端應用 `Dockerfile` 的詳細解釋：

#### 建置階段

```dockerfile
FROM node:20 as build
```

這行指定了基礎映像檔為 Node.js 20 版本，並將這個階段命名為 "build"。這是多階段建構的第一階段，主要用於編譯程式碼。

```dockerfile
WORKDIR /app
```

設定容器內的工作目錄為 /app。後續的命令都會在這個目錄中執行。

```dockerfile
COPY package.json package-lock.json ./
```

複製專案中的 `package.json` 和 `package-lock.json` 檔案到容器的工作目錄。這兩個檔案定義了應用的相依套件。

```dockerfile
RUN npm install
```

執行 `npm install` 命令來安裝所有相依套件。放在複製完整程式碼之前有助於利用 Docker 的快取機制，提高建構速度。

```dockerfile
COPY . .
```

複製專案中的所有檔案到容器的工作目錄。

```dockerfile
RUN npm run build
```

執行 Angular 應用的建置命令，產生生產環境用的靜態檔案。

#### 執行階段

```dockerfile
FROM nginx:alpine
```

開始第二階段建構，使用輕量級的 `nginx:alpine` 作為基礎映像檔。這個階段將用於實際執行應用。

```dockerfile
COPY --from=build /app/dist/voting-system/browser /usr/share/nginx/html
```

COPY 命令的格式是 `COPY <來源路徑> <目標路徑>`

從第一階段（名為 "build" 的階段）複製建置好的靜態檔案到 Nginx 的網頁目錄。

```dockerfile
EXPOSE 80
```

聲明容器將會使用 80 連接埠。這主要是文件用途，告訴使用者這個容器預期通過哪個連接埠存取。

```dockerfile
CMD ["nginx", "-g", "daemon off;"]
```

設定容器啟動時執行的命令，這裡是以前景模式啟動 Nginx 伺服器。

### 多階段建構的優點

這種多階段建構的方法有幾個優點：

* 最終映像檔只包含執行應用所需的檔案，不包含建構工具和原始碼
* 映像檔體積更小
* 減少了潛在的安全風險

這個 `Dockerfile` 的設計適合大多數 Angular 應用，將應用編譯為靜態檔案並使用 Nginx 提供服務。

### 不同技術堆疊的 `Dockerfile` 差異

從這裡可以看出，`Dockerfile` 中的指令有些是前端專用的。不同的框架、語言或技術堆疊需要不同的 `Dockerfile` 設定，主要因為以下差異：

#### 不同的基礎映像檔

每種語言通常有專用的基礎映像檔：

* Node.js 應用使用 node 映像檔
* Python 應用使用 python 映像檔
* Java 應用可能使用 openjdk 映像檔

#### 不同的建構流程

* Angular/React/Vue 等前端框架需要 npm 建構步驟
* Python 應用可能使用 pip 安裝相依套件
* Java 應用通常使用 Maven 或 Gradle 建構
* Go 應用有自己的建構命令和流程

#### 不同的執行環境

* 前端應用通常使用 Nginx 等靜態伺服器
* Java 應用可能執行在 Tomcat 或直接使用 JRE
* Python 應用可能使用 uWSGI 或 Gunicorn
* Node.js 後端應用直接使用 Node 執行環境

#### 不同的檔案結構和設定

各框架有自己特定的目錄結構和設定檔要求

#### 範例：Python Django 後端應用的 Dockerfile

```dockerfile
FROM python:3.9
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
```

#### 範例：Node.js Express 後端的 Dockerfile

```dockerfile
FROM node:16
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
```

### Dockerfile 執行時機

Dockerfile 中的指令不需要手動執行。`docker-compose.yml` 檔案會引用 Dockerfile 的位置，而執行 `docker-compose up` 命令時，Docker Compose 會自動處理以下流程：

1. 檢查是否已有對應的映像檔
2. 如果沒有或指定需要重新建構，則根據 Dockerfile 建構映像檔
3. 根據 docker-compose.yml 的設定建立和啟動容器

整個過程是自動化的，你只需要執行 `docker-compose up` 命令即可。
