# Docker 教學 第 1 堂：Docker 概念、安裝與第一個容器


&gt; 本系列為 18 小時 Docker 基礎教學講義，適合初學者，使用 Windows 電腦。
&gt; 本篇為第 1 堂課，約 3 小時。

&lt;!--more--&gt;

## 第一部分：Docker 概念（約 1 小時）

### 1-1 Docker 是甚麼？容器是甚麼

#### Docker 是什麼？

**一句話解釋：**
Docker 是一個可以把你的應用程式「打包」起來的工具，打包完之後不管放到哪台電腦上都能跑。

**比喻說明：**
想像你要搬家。傳統的方式就像是把家具一件一件搬，到了新家還要重新組裝、調整。但如果你能把整間房間——包含家具、擺設、甚至空氣——直接整個搬過去呢？Docker 做的就是類似的事情。

它把你的程式、程式需要的套件、設定檔、甚至作業系統環境，全部打包成一個「容器（Container）」。這個容器可以在任何有安裝 Docker 的電腦上運行，而且行為完全一致。

&gt; **名詞解釋：伺服器與部署**
&gt;
&gt; - **伺服器（Server）**：一台 24 小時開著、專門用來提供服務的電腦。例如你每天在用的網站、App，背後都有伺服器在運行。它跟你的個人電腦本質上一樣，只是通常放在機房裡，透過網路提供服務。
&gt; - **部署（Deploy）**：把你在自己電腦上寫好的程式，放到伺服器上讓它正式運行、讓使用者可以使用的過程。就像餐廳做好菜之後要「出餐」，部署就是軟體的「出餐」。

**為什麼要使用容器化？三大特性：**

1. **可攜性（Portability）**：容器化的應用程式可以打包成 Image，無論在何種作業環境中，只要安裝了 Docker，就能夠正常運行。這消除了不同環境之間的兼容性問題，使得部署變得更加簡單和快速。
2. **隔離性（Isolation）**：使用容器化技術，應用程式之間的相互干擾會被隔離。這樣就能避免環境衝突的問題。例如，當一個應用程式需要特定版本的庫時，不會影響到其他應用程式的運行，提供了更加穩定的執行環境。
3. **一致性（Consistency）**：當應用程式打包成 Image 時，無論在開發、測試還是生產環境中，都能確保執行結果的一致性。這對於減少「本地運行正常，部署後失敗」的情況至關重要，從而提高了開發效率與品質。

此外，容器還有一個重要的優勢：**輕量化**——比虛擬機快很多、佔的資源少很多。

&gt; **注意：一致性的限制——CPU 架構差異**
&gt;
&gt; Docker 的一致性是在**相同 CPU 架構**下才完全成立。Docker 抽象化了作業系統層級的差異，但底層的晶片架構（ISA）仍然有影響：
&gt; - **Intel / AMD 處理器**（一般 Windows 和 Linux 電腦）：架構為 `linux/amd64`
&gt; - **Apple Silicon（M1/M2/M3/M4）**：架構為 `linux/arm64`
&gt;
&gt; 如果在 Mac（Apple Silicon）上建構的 Image 沒有指定平台，拿到 Windows/Linux 機器上可能會無法運行，或是透過 QEMU 模擬而效能大幅下降。撰寫 Dockerfile 時可以使用 `--platform linux/amd64` 來明確指定目標平台：
&gt; ```powershell
&gt; docker build --platform linux/amd64 -t my-app .
&gt; ```
&gt; 本課程的學員皆使用 Windows（amd64），因此課堂上不會遇到這個問題。但實務上如果團隊中有人使用 Mac，這是一個必須注意的地方。
&gt;
&gt; **進階知識：為什麼 CPU 架構會影響 Docker？**
&gt;
&gt; 因為 Docker 容器不是虛擬機——它不會模擬 CPU，而是直接用主機的 CPU 執行程式。程式最終會被編譯成機器碼，而 amd64 和 arm64 的 CPU 各自有不同的指令集，彼此看不懂對方的機器碼。Docker 幫你打包的是軟體環境（OS、函式庫、套件），但 CPU 是硬體層，Docker 管不了。

#### 傳統部署 vs VM 部署 vs 容器化部署

**傳統部署：**
- 所有應用程式直接安裝在同一台伺服器的作業系統上，共用系統函式庫
- 問題：應用程式之間可能發生衝突（例如 App A 需要 Python 3.8，App B 需要 Python 3.11），一個 App 出問題可能連帶影響其他 App

**VM 部署：**
- 用虛擬機在一台實體機器上模擬出多台完整的電腦，每台 VM 有自己的作業系統
- 解決了隔離問題，但每台 VM 都要跑一整個 OS，啟動慢（幾十秒到幾分鐘）、佔用資源多（每台 VM 吃掉幾 GB 記憶體）
- 工具：VirtualBox、VMware、Hyper-V

**容器化部署：**
- 不需要模擬整個作業系統，所有容器共用主機的 OS 核心，每個容器只包含應用程式和它需要的依賴
- 既有隔離性，又非常輕量——啟動只要幾秒，佔用通常只有幾十 MB

**三種架構比較圖：**

```
傳統部署：              VM 部署：                容器化部署：

┌─────┬─────┬─────┐    ┌──────┐ ┌──────┐       ┌──────┐ ┌──────┐ ┌──────┐
│App A│App B│App C│    │ VM A │ │ VM B │       │容器 A│ │容器 B│ │容器 C│
├─────┴─────┴─────┤    │Guest │ │Guest │       │App&#43;  │ │App&#43;  │ │App&#43;  │
│   Bins / Libs   │    │ OS   │ │ OS   │       │依賴  │ │依賴  │ │依賴  │
├─────────────────┤    │App&#43;  │ │App&#43;  │       └──┬───┘ └──┬───┘ └──┬───┘
│ OS &amp; Shared     │    │依賴  │ │依賴  │          │       │       │
│ Services        │    └──┬───┘ └──┬───┘       ┌──┴───────┴───────┴──┐
├─────────────────┤    ┌──┴────────┴──┐        │    Docker Engine    │
│    Hardware     │    │  Hypervisor  │        ├─────────────────────┤
└─────────────────┘    ├──────────────┤        │      Host OS       │
                       │   Host OS   │        ├─────────────────────┤
                       ├──────────────┤        │     Hardware       │
                       │  Hardware   │        └─────────────────────┘
                       └──────────────┘
```

| 比較項目 | 傳統部署 | VM 部署 | 容器化部署 |
|---------|---------|---------|----------|
| 隔離性 | 無，互相干擾 | 完全隔離 | 程序級隔離 |
| 啟動速度 | 快（直接跑） | 慢（分鐘級） | 快（秒級） |
| 資源佔用 | 低 | 高（每台 VM 一個 OS） | 低（共用 OS 核心） |
| 可攜性 | 差 | 中 | 優 |

#### Docker 的缺點

Docker 優點很多，但也不是完美的，了解它的限制才能在實務中做出更好的選擇：

| 缺點 | 說明 |
|------|------|
| **學習曲線** | 指令多、概念多（Image、Container、Volume、Network...），新手容易搞混 |
| **安全性** | 容器預設用 root 執行，且所有容器共用主機的 OS 核心，隔離性不如虛擬機 |
| **不適合有狀態的服務** | 容器天生是「用完即丟」的設計，資料庫這類需要持久化資料的服務要靠 Volume 額外處理，正式環境通常會用託管的資料庫服務（如 AWS RDS）而非自己用容器跑 |
| **Windows/Mac 的效能開銷** | 在 Linux 上幾乎無損，但 Windows/Mac 需要透過 WSL2 或 VM 跑 Docker，會額外佔用 1~2 GB 記憶體 |
| **磁碟空間** | Image 和 Container 很容易越積越多，佔掉幾十 GB 磁碟空間，需要定期清理 |
| **除錯較複雜** | 容器之間的網路問題較難排查，Log 分散在各個容器裡，沒有工具輔助的話不容易追蹤 |

&gt; 這些缺點大多有對應的解決方案，Docker 的優點仍然遠大於缺點，這也是它能夠如此普及的原因。

#### Docker 的核心概念

Docker 有三個最重要的概念：

**1. 映像檔（Image）**
- 就像一張「光碟」或「安裝檔」
- 它是唯讀的，包含了應用程式和所有需要的東西
- 例如：一個 Python 映像檔裡面就已經裝好了 Python

**2. 容器（Container）**
- 映像檔跑起來之後就變成容器
- 就像把光碟放進電腦裡執行
- 容器是活的、可以互動的
- 一個映像檔可以同時跑出多個容器

**3. 倉庫（Registry）**
- 存放映像檔的地方
- 最大的公開倉庫叫 Docker Hub（hub.docker.com）
- 就像 App Store，你可以上去下載別人做好的映像檔

**三者的關係：**
```
Docker Hub（倉庫）  --下載--&gt;  Image（映像檔）  --啟動--&gt;  Container（容器）
```

#### 小結

- Docker 把程式和環境打包在一起
- 容器比虛擬機更輕量、更快
- 三大核心概念：Image、Container、Registry

---

## 第二部分：安裝環境（約 1 小時）

### 1-2 如何安裝 Docker

#### Docker Desktop 介紹

在 Windows 上使用 Docker，我們需要安裝 **Docker Desktop**。它提供了：
- Docker Engine（核心引擎）
- Docker CLI（命令列工具）
- Docker Compose（多容器管理工具）
- 圖形化介面（GUI），方便觀察容器狀態

#### 系統需求確認

**Windows 10/11 系統需求：**
- Windows 10 64-bit: Home 或 Pro 21H2 以上，或 Windows 11
- 開啟 WSL 2（Windows Subsystem for Linux 2）
- 至少 4 GB 記憶體
- BIOS 需要開啟虛擬化功能（通常預設是開的）

**檢查虛擬化是否開啟：**
1. 按 `Ctrl &#43; Shift &#43; Esc` 打開工作管理員
2. 點「效能」分頁
3. 看 CPU 區塊右下角，「虛擬化」是否顯示「已啟用」

#### 什麼是 WSL 2？

**WSL（Windows Subsystem for Linux）** 是微軟開發的功能，讓你在 Windows 上直接跑 Linux 環境，不需要另外裝虛擬機。

WSL 有兩個版本：
- **WSL 1**：用轉譯的方式把 Linux 指令翻譯給 Windows 執行，相容性較差
- **WSL 2**：跑一個輕量的 Linux 核心，效能和相容性都大幅提升

Docker Desktop 就是利用 WSL 2 提供的 Linux 環境來運行容器。

&gt; **為什麼用 WSL 2 而不是 Hyper-V？**
&gt;
&gt; Docker Desktop 早期使用 Hyper-V 作為後端，但現在官方已經全面建議改用 WSL 2。原因是：
&gt; - WSL 2 的效能比 Hyper-V 更好（啟動更快、記憶體使用更少）
&gt; - Hyper-V 僅支援 Windows Pro / Enterprise 版本，WSL 2 則 **Home 版也能用**
&gt; - Docker 官方文件和社群資源都以 WSL 2 為主
&gt;
&gt; 簡單來說：**不要再使用 Hyper-V 了**，直接用 WSL 2 就對了。

#### 安裝 WSL 2

**步驟 1：開啟 PowerShell（以系統管理員身分執行）**

在搜尋欄輸入 `PowerShell`，右鍵點選「以系統管理員身分執行」

**步驟 2：安裝 WSL**
```powershell
wsl --install
```

這個指令會自動：
- 啟用 WSL 功能
- 啟用虛擬機平台功能
- 下載並安裝最新的 Linux 核心
- 預設安裝 Ubuntu 發行版

**步驟 3：重新啟動電腦**

安裝完成後需要重新開機。

**步驟 4：設定 Ubuntu 使用者**

重開機後，Ubuntu 會自動啟動並要求你設定：
- 輸入一個使用者名稱（小寫英文）
- 設定密碼（輸入時不會顯示字元，這是正常的）

**步驟 5：確認安裝成功**
```powershell
wsl --version
```

應該會看到類似的輸出：
```
WSL 版本: 2.x.x.x
核心版本: 5.x.x.x
```

確認預設版本是 WSL 2：
```powershell
wsl --list --verbose
```

輸出：
```
  NAME      STATE           VERSION
* Ubuntu    Running         2
```

VERSION 欄位顯示 `2` 就代表是 WSL 2。

#### WSL 2 常用指令

安裝好之後，這幾個指令平常會用到：

```powershell
# 啟動 WSL（進入 Linux 環境）
wsl

# 關閉所有 WSL 執行個體
wsl --shutdown

# 查看已安裝的 Linux 發行版
wsl --list --verbose

# 更新 WSL 核心
wsl --update

# 將預設版本設為 WSL 2（確保之後安裝的發行版都用 WSL 2）
wsl --set-default-version 2
```

&gt; 安裝完 WSL 2 之後，平常不需要手動啟動它。Docker Desktop 啟動時會自動使用 WSL 2，你只要確保 Docker Desktop 有在跑就好。

#### 安裝 Docker Desktop

**步驟 1：下載 Docker Desktop**
- 開啟瀏覽器，前往 Docker 官方網站下載頁面
- 點選「Download for Windows」

**步驟 2：執行安裝程式**
- 雙擊下載的 `Docker Desktop Installer.exe`
- 確認勾選「Use WSL 2 instead of Hyper-V」
- 按照指示完成安裝

**步驟 3：首次啟動**
- 安裝完成後，從開始功能表啟動 Docker Desktop
- 第一次啟動會需要一些時間初始化
- 看到系統匣（右下角）的 Docker 圖示變成穩定狀態就代表啟動成功

**步驟 4：同意服務條款**
- 首次啟動會要求同意 Docker 的服務條款
- 個人學習使用是免費的

#### 驗證安裝是否成功

打開命令提示字元（cmd）或 PowerShell：

```powershell
# 檢查 Docker 版本
docker --version
```

應該看到類似：
```
Docker version 27.x.x, build xxxxxxx
```

```powershell
# 跑一個測試容器
docker run hello-world
```

如果看到以下訊息，恭喜你安裝成功了！
```
Hello from Docker!
This message shows that your installation appears to be working correctly.
...
```

**解讀 hello-world 發生了什麼事：**
1. Docker 在本機找不到 `hello-world` 映像檔
2. 自動從 Docker Hub 下載了這個映像檔
3. 用這個映像檔建立了一個容器
4. 容器執行後印出了歡迎訊息
5. 容器執行完畢後自動停止

#### Docker Desktop 介面導覽與 GUI 操作

Docker Desktop 提供了圖形化介面（GUI），讓你不用打指令也能管理容器和映像檔。打開 Docker Desktop，認識主要介面：

**左側選單：**

1. **Containers**：查看所有容器的狀態（執行中 / 已停止）
2. **Images**：查看本機已下載的映像檔
3. **Volumes**：查看資料卷（後面會用到）
4. **Settings**（齒輪圖示）：
   - General：一般設定
   - Resources：調整 Docker 可以使用的 CPU、記憶體
   - Docker Engine：進階設定

**Containers 頁面的 GUI 操作：**

在 Containers 頁面，每個容器旁邊都有操作按鈕：

| 按鈕 | 功能 | 等同的 CLI 指令 |
|------|------|---------------|
| ▶ (Play) | 啟動已停止的容器 | `docker start` |
| ⏹ (Stop) | 停止執行中的容器 | `docker stop` |
| 🔄 (Restart) | 重新啟動容器 | `docker restart` |
| 🗑 (Delete) | 刪除容器 | `docker rm` |
| 📋 (Logs) | 查看容器的輸出 log | `docker logs` |
| &gt;_ (Terminal) | 進入容器的終端 | `docker exec -it ... bash` |
| 🔍 (Inspect) | 查看容器的詳細設定 | `docker inspect` |

**Images 頁面的 GUI 操作：**

- 點選映像檔旁的 **▶ Run** 可以直接建立容器，會跳出設定視窗讓你填入：
  - Container name（容器名稱）
  - Ports（端口映射）
  - Volumes（掛載目錄）
  - Environment variables（環境變數）
- 這個設定視窗其實就是幫你組合 `docker run` 的參數
- 點選 🗑 可以刪除映像檔（等同 `docker rmi`）

**Volumes 頁面：**

- 查看所有 Volume 的名稱、建立時間、大小
- 點進去可以瀏覽 Volume 裡面的檔案內容
- 可以直接刪除不需要的 Volume

**Settings 重要設定：**

- **Resources → Advanced**：調整 Docker 可以使用的 CPU 核心數和記憶體上限。如果你的電腦只有 8GB 記憶體，建議不要分超過 4GB 給 Docker
- **Docker Engine**：可以修改 Docker 的進階設定（JSON 格式），初學者通常不需要動

&gt; **CLI 還是很重要！**
&gt;
&gt; Docker Desktop 的 GUI 方便新手入門，也適合快速查看狀態。但在實務工作中，**CLI 才是主角**：
&gt; - 伺服器上通常沒有圖形化介面，只能用 CLI
&gt; - CI/CD 自動化部署只能用指令
&gt; - Dockerfile 和 docker-compose.yml 都是文字檔，要用指令操作
&gt; - 遇到問題時，網路上的解答和文件幾乎都是 CLI 指令
&gt;
&gt; 建議：**用 GUI 學概念，用 CLI 做操作**。本課程的所有實作都會以 CLI 為主，但你隨時可以打開 Docker Desktop 來觀察容器狀態。

#### 常見安裝問題排解

**問題 1：WSL 2 安裝失敗**
- 確認 Windows 更新到最新版本
- 手動啟用功能：控制台 → 程式和功能 → 開啟或關閉 Windows 功能 → 勾選「虛擬機器平台」和「Windows 子系統 Linux 版」

**問題 2：Docker Desktop 啟動卡住**
- 檢查 WSL 2 是否正常：`wsl --status`
- 嘗試重新啟動 WSL：`wsl --shutdown` 然後重開 Docker Desktop

**問題 3：虛擬化未啟用**
- 需要進入 BIOS 設定（開機時按 F2、Del 或 F10，依主機板而異）
- 找到 Virtualization Technology（VT-x / AMD-V），設為 Enabled

---

## 第三部分：第一個容器（約 1 小時）

### 1-3 拉取映像檔與建立 Nginx 容器

#### 什麼是映像檔（Image）

**映像檔是什麼？**
- 映像檔是一個唯讀的模板，用來建立容器
- 它包含了執行應用程式所需的一切：程式碼、執行環境、函式庫、環境變數、設定檔
- 映像檔是「分層（Layered）」結構的

**分層的概念：**

```
┌─────────────────────────────┐
│  你的應用程式程式碼          │  ← 最上層（最常變動）
├─────────────────────────────┤
│  pip install 安裝的套件     │
├─────────────────────────────┤
│  Python 3.11                │
├─────────────────────────────┤
│  Ubuntu / Alpine Linux      │  ← 最底層（基礎系統）
└─────────────────────────────┘
```

**分層的好處：**
- 不同映像檔可以共用相同的底層，節省空間
- 只有變動的層需要重新下載或建構

#### Docker Hub 巡禮

Docker Hub（hub.docker.com）是一個公共的映像檔倉庫，開發者可以上傳和下載各種映像檔。它就像是「程式世界的 App Store」，提供官方和社群的多樣映像檔選擇，開發者也可以輕鬆地存儲和分享自己的映像檔，促進團隊協作。

**使用 Docker Hub 的好處：**
- 簡化了映像檔的管理，開發者可以在不同環境中快速拉取所需的映像檔
- 支援版本控制，開發者可以根據需要選擇使用特定版本的映像檔
- 除了公共倉庫，Docker Hub 也提供**私有倉庫**選項，適合企業用戶存放敏感資料

**帶你逛 Docker Hub：**

1. 搜尋 `python`，會看到官方映像檔
2. 點進去看映像檔的說明頁面
3. 注意「Tags」——不同版本的映像檔

**什麼是 Tag？**
- Tag 就是映像檔的版本標籤
- 例如 `python:3.11`、`python:3.11-slim`、`python:3.11-alpine`
- `latest` 是預設 tag，代表最新版本
- 建議：生產環境永遠指定具體版本，不要用 `latest`

**常見的 Tag 命名規則：**
- `python:3.11`：完整版，基於 Debian
- `python:3.11-slim`：精簡版，移除了不常用的套件
- `python:3.11-alpine`：超輕量版，基於 Alpine Linux（很小但可能有相容性問題）

#### 基本映像檔操作指令

**拉取映像檔：**
```powershell
# 拉取 Python 官方映像檔
docker pull python:3.11

# 拉取特定版本
docker pull python:3.11-slim
```

**查看本機的映像檔：**
```powershell
docker images
```

輸出解讀：
```
REPOSITORY   TAG        IMAGE ID       CREATED        SIZE
python       3.11       abc123def456   2 weeks ago    1.01GB
python       3.11-slim  789ghi012jkl   2 weeks ago    155MB
```

- `REPOSITORY`：映像檔名稱
- `TAG`：版本標籤
- `IMAGE ID`：唯一識別碼
- `SIZE`：映像檔大小

&gt; 比較 `python:3.11` 和 `python:3.11-slim` 的大小差異，理解為什麼精簡版很重要。

**刪除映像檔：**
```powershell
# 用名稱刪除
docker rmi python:3.11

# 用 ID 刪除
docker rmi abc123def456
```

&gt; **注意**：如果還有容器正在使用該映像檔（不管是執行中還是已停止），就無法刪除。必須先把相關容器都刪掉（`docker rm`），才能刪除映像檔。
&gt;
&gt; **建議**：定期清理不再使用的映像檔，釋放磁碟空間。映像檔很容易越積越多，佔掉幾十 GB 都不奇怪。

**搜尋映像檔：**
```powershell
docker search nginx
```

#### 實作：Pull 一個 Nginx 映像檔並跑起來

在學更複雜的 Flask 之前，先用最簡單的方式體驗「拉取映像檔 → 跑容器 → 看到結果」的完整流程。

**Nginx 是什麼？**

Nginx（唸作 &#34;engine-x&#34;）是目前全世界最多人使用的 Web 伺服器之一。它由俄羅斯工程師 Igor Sysoev 在 2004 年發布，最初是為了解決當時 Apache 伺服器在高流量下效能不足的問題（稱為 C10K 問題——同時處理一萬個連線）。

**Nginx 的角色：**
- **靜態檔案伺服器**：傳送 HTML、CSS、JS、圖片等網頁檔案給瀏覽器
- **反向代理（Reverse Proxy）**：站在使用者和後端伺服器之間，把請求轉發到對的地方。例如你的 Flask 跑在 5000 port，Nginx 可以把 80 port 的請求轉給它
- **負載均衡（Load Balancer）**：當流量很大時，把請求分散到多台伺服器

**Nginx vs Apache：**

| | Nginx | Apache |
|---|---|---|
| 誕生年份 | 2004 年 | 1995 年 |
| 架構 | 事件驅動（非同步），處理大量連線很強 | 每個請求一個線程，連線多了容易吃資源 |
| 市佔率 | 目前第一（約 34%） | 第二（約 29%） |
| 適合場景 | 高流量網站、反向代理 | 傳統網站、需要 .htaccess |

現在幾乎所有大型網站（Netflix、Dropbox、WordPress.com）都在用 Nginx。透過 Docker，我們可以一行指令就把它跑起來。

**為什麼不能直接用 localhost 上線？**

很多初學者寫好一個網站，用 `python app.py` 跑起來後在瀏覽器看到 `http://localhost:5000` 能動，就以為「網站完成了」。但 localhost 只是你自己的電腦，別人完全連不到。

要讓網站真正上線、讓全世界的人都能用，中間還需要很多東西：

```
初學者以為的流程：
  寫好程式 → localhost 能跑 → 完成！

實際上線的流程：
  寫好程式 → Web 伺服器（Nginx）→ 網域（Domain）→ HTTPS 憑證 → 部署到伺服器
```

**localhost 和正式上線的差別：**

| | localhost 開發環境 | 正式上線環境 |
|---|---|---|
| 誰能連 | 只有你自己 | 全世界 |
| 網址 | `http://localhost:5000` | `https://your-domain.com` |
| 效能 | 一個人用沒問題 | 100 人同時連就可能掛掉 |
| 安全性 | 沒有 HTTPS | 需要 SSL 憑證加密 |
| 穩定性 | 電腦關機就斷了 | 24 小時不中斷 |

**Web 伺服器（如 Nginx）扮演的角色：**

Flask、Django 這類框架自帶的開發伺服器（`python app.py`）是專門給開發時測試用的，**不適合直接拿來上線**，原因是：
- 一次只能處理很少的請求，多人同時連線就會卡住
- 沒有安全防護，容易被攻擊
- 沒有快取機制，效能很差

正式上線時會在前面擋一個 Nginx，由它負責：
1. 接收所有使用者的請求
2. 處理靜態檔案（圖片、CSS、JS）——這些 Nginx 處理得比 Python 快幾十倍
3. 把需要運算的請求轉發給後端的 Flask/Django（這就是反向代理）
4. 處理 HTTPS 加密

```
使用者 → Nginx（80/443 port）→ Flask（5000 port）
            ↓
     靜態檔案直接回傳
```

&gt; 記住：`localhost` 是開發用的，不是上線用的。真正的網站都需要 Web 伺服器來處理流量和安全性。

**步驟 1：拉取 Nginx 映像檔**
```powershell
docker pull nginx
```

**步驟 2：啟動容器**

在執行指令之前，先了解兩個重要的概念：

&gt; **什麼是宿主機（Host）？**
&gt;
&gt; 在 Docker 的世界裡，你正在用的這台電腦就叫做**宿主機（Host）**，而 Docker 跑出來的環境叫做**容器（Container）**。兩者是隔離的：
&gt;
&gt; ```
&gt; ┌─────────────────────────────────┐
&gt; │  宿主機（你的 Windows 電腦）     │
&gt; │                                 │
&gt; │   ┌──────────┐  ┌──────────┐   │
&gt; │   │ 容器 A   │  │ 容器 B   │   │
&gt; │   │ (Nginx)  │  │ (MySQL)  │   │
&gt; │   └──────────┘  └──────────┘   │
&gt; │                                 │
&gt; └─────────────────────────────────┘
&gt; ```
&gt;
&gt; - 容器有自己的檔案系統、程序、網路，跟宿主機是**分開的**
&gt; - 要讓宿主機和容器之間溝通，需要用 `-p`（端口映射）和 `-v`（掛載目錄）來「開通道」
&gt; - Docker 指令中看到的「主機:容器」格式，「主機」就是指宿主機

&gt; **什麼是 Port（連接埠）？**
&gt;
&gt; 你的電腦只有一個 IP 位址，但上面可能同時跑很多服務（網頁、資料庫、信件...）。Port 就是用來區分這些服務的「門牌號碼」，範圍是 0 ~ 65535。
&gt;
&gt; 常見的 Port：
&gt; | Port | 用途 |
&gt; |------|------|
&gt; | 80 | HTTP 網頁（瀏覽器預設） |
&gt; | 443 | HTTPS 加密網頁 |
&gt; | 3306 | MySQL 資料庫 |
&gt; | 5000 | Flask 預設 |
&gt; | 8080 | 常用的替代 HTTP Port |
&gt;
&gt; 當你在瀏覽器輸入 `http://localhost:8080` 時，就是在連線到你自己電腦（localhost）的 8080 號門。

```powershell
docker run -d --name my-web -p 8080:80 nginx
```

這裡的 `-p 8080:80` 就是**端口映射**——把主機的 8080 port 對應到容器內部的 80 port。容器裡的 Nginx 監聯 80，但從外面要透過 8080 才能連進去。

&gt; **Windows 小提醒：**
&gt; - `-p` 和 `-v` 的格式都是「**主機:容器**」，冒號左邊是你的電腦，右邊是容器內部
&gt; - Windows 路徑用 `-v` 掛載時**要用雙引號**，單引號會失敗：
&gt;   ```powershell
&gt;   # 正確 ✓
&gt;   -v &#34;C:\my-project:/app&#34;
&gt;
&gt;   # 錯誤 ✗
&gt;   -v &#39;C:\my-project:/app&#39;
&gt;   ```

**步驟 3：打開瀏覽器**

前往 `http://localhost:8080`，你會看到 &#34;Welcome to nginx!&#34; 的歡迎頁面。

恭喜！你剛剛用一行指令就架好了一個 Web 伺服器。

**步驟 4：用 `docker exec` 進去容器裡面逛**

容器裡面到底長什麼樣？我們可以用 `docker exec` 進去看看：

```powershell
# 進入 Nginx 容器（Nginx 用的是 sh，不是 bash）
docker exec -it my-web sh
```

現在你已經「進入」容器內部了，來探索一下：

```sh
# 1. 看看現在在哪裡
pwd

# 2. 看看根目錄有什麼
ls /

# 3. 去找 Nginx 的網頁檔案在哪裡
cd /usr/share/nginx/html

# 4. 看看有哪些檔案
ls

# 5. 看看歡迎頁面的內容
cat index.html

# 6. 離開容器
exit
```

&gt; 你會看到 `/usr/share/nginx/html/index.html` 就是剛才瀏覽器顯示的歡迎頁面。這就是容器裡面的檔案系統——跟宿主機完全獨立。
&gt;
&gt; **思考一下**：如果你用 `-v` 把宿主機的資料夾掛載到 `/usr/share/nginx/html`，容器裡看到的就會是你宿主機的檔案，這就是 Volume 掛載的原理。

**步驟 5：練習容器操作**
```powershell
# 查看容器狀態
docker ps

# 查看 log
docker logs my-web

# 停止容器
docker stop my-web

# 重新啟動
docker start my-web

# 用完後刪除
docker rm -f my-web
```


---

> 作者: luk  
> URL: https://yoru-karu-blog-lalaluk-52581ac5e0cef170a3c8922c19182ecb6f7bd604.gitlab.io/posts/tutorial/docker/docker-session1-basics-setup/  

