---
## 🐳 Docker 入門與實務分享會文件(含 Demo 引導)
---
## 1️⃣ Docker 與 Docker Compose 快速介紹
### 📦 Docker 是什麼?
- 一種輕量級的虛擬化技術
- 透過 Image 和 Container 執行應用程式
- 解決「在我電腦可以跑」的問題
### 🧱 Docker Compose 是什麼?
- 用 YAML 檔案定義多個 Container 的運作關係
- 適合微服務架構、開發與測試環境建置
---
## 2️⃣ 範例一:Next.js + Nginx Production 架構
### 🧪 實作 Demo 引導筆記
#### ✅ Demo 目標:
> 架設一個 Next.js 應用,透過 Nginx 反向代理,從 `http://localhost` 就能訪問
---
#### 🪜 Demo 步驟:
1. **建立資料夾結構**
```bash
mkdir -p next-nginx/app nginx
cd next-nginx
```
2. **建立 Next.js 專案**
```bash
cd app
npx create-next-app@latest . --ts
npm run build # 確保可以編譯成功
cd ..
```
```
next-nginx/
├── src/
│ └── app/ # App Router 主目錄
├── public/
├── nginx/
│ └── default.conf
├── Dockerfile
├── docker-compose.yml
├── package.json
```
> 使用 `create-next-app` 時記得選擇 App Router (`src/app`) 架構,或自己建立 `src/app/page.tsx`
3. **建立 Dockerfile**
```Dockerfile
# 以 node:lts 為基底
FROM node:lts-alpine
# 設定工作目錄
WORKDIR /app
# 複製 package.json 和 lock 檔
COPY package*.json ./
# 安裝依賴
RUN npm install
# 複製專案檔案(包含 src/)
COPY . .
# 編譯 Next.js App
RUN npm run build
# 開啟 Port 3000(供 Nginx Proxy)
EXPOSE 3000
CMD ["npm", "start"]
```
4. **建立 Nginx 設定檔**
```nginx
# nginx/default.conf
server {
listen 80;
location / {
proxy_pass http://nextjs:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
```
5. **建立 docker-compose.yml**
```yaml
services:
nextjs:
build: .
container_name: next-app
environment:
-NEXT_PUBLIC_API_URL=https://codehelp-backend-production.up.railway.app
-NEXT_PUBLIC_MOCK=off
-NEXTAUTH_SECRET=8+eObjGKYVRZPE7L8xf+BNHEs32pMlXICDAPvoMQODc=
-MOCK=false
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- nextjs
```
6. **啟動服務**
```bash
docker compose up --build
```
7. **瀏覽器打開 `http://localhost`**
- 若畫面出現 Next.js 的首頁,恭喜成功!
---
## 3️⃣ 範例二:Node.js Express + PostgreSQL 開發環境
### 🧪 實作 Demo 引導筆記
#### ✅ Demo 目標:
> 架設一個簡易 Express API,並接上 PostgreSQL 資料庫
---
#### 🪜 Demo 步驟:
1. **建立資料夾結構**
```bash
mkdir -p express-db/app
cd express-db
```
2. **建立 Express 專案**
```bash
cd app
npm init -y
npm install express pg
touch server.js
```
3. **撰寫 `server.js`**
```js
const express = require("express");
const { Pool } = require("pg");
const pool = new Pool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
});
const app = express();
const port = 80;
app.get("/", async (req, res) => {
const result = await pool.query("SELECT NOW()");
res.send(result.rows[0]);
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
```
4. **建立 Dockerfile**
```Dockerfile
FROM node:lts-alpine
WORKDIR /app
COPY app/package*.json ./
RUN npm install
COPY app .
EXPOSE 80
CMD ["node", "server.js"]
```
5. **建立 docker-compose.yml**
```yaml
version: '3'
services:
app:
build: .
ports:
- "3000:3000"
volumes:
- ./app:/app
depends_on:
- db
environment:
- DB_HOST=db
- DB_USER=postgres
- DB_PASSWORD=password
- DB_NAME=mydb
db:
image: postgres:14
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: mydb
volumes:
- dbdata:/var/lib/postgresql/data
volumes:
dbdata:
```
6. **啟動服務**
```bash
docker compose up --build
```
7. **測試 API**
```bash
curl http://localhost:3000
# 預期結果:{ now: '2025-04-15T12:34:56.789Z' }
```
---
## 📎 建議補充小知識
| 主題 | 說明 |
|------|------|
| `.dockerignore` | 避免 node_modules 被複製進 container |
| `volumes` | 方便開發時 hot reload / 保留資料庫資料 |
| `env` 檔案管理 | 更乾淨的環境變數管理方式 |
| `healthcheck` | 可加入服務健康狀態檢查 |
| log 顯示 | `docker compose logs -f` 方便除錯 |
---
當然可以~下面是你在分享時可以介紹或自己使用的 **常用 Docker 指令大全**,適合用來觀察 container 裡面的狀態、資料夾結構、日誌等。
---
## 🛠 常用 Docker 指令速查(適合觀察機器內部)
### 📂 查看容器內資料夾與檔案
| 目的 | 指令 | 說明 |
|------|------|------|
| 進入容器互動模式 | `docker exec -it <container_name> sh` | Alpine Linux 用 `sh` |
| 進入 bash(若容器支援) | `docker exec -it <container_name> bash` | Ubuntu-based 容器可用 |
| 查看容器內檔案結構 | `ls`, `cd`, `cat` | 在上面進入後可操作 |
#### 🧪 範例:
```bash
docker exec -it next-app sh
cd /app
ls -al
```
---
### 📜 查看日誌(logs)
| 目的 | 指令 | 說明 |
|------|------|------|
| 查看某 container 的 log | `docker logs <container_name>` | 一次性輸出全部 log |
| 持續監聽 log(實時) | `docker logs -f <container_name>` | 像 tail -f 的效果 |
| 查看最近 N 行 log | `docker logs --tail 50 <container_name>` | 很適合排錯 |
| 加上時間戳記 | `docker logs -t <container_name>` | 看 log 發生的時間 |
---
### 🧾 查看容器狀態與詳細資訊
| 目的 | 指令 | 說明 |
|------|------|------|
| 查看目前跑的容器 | `docker ps` | 加上 `-a` 看已停止容器 |
| 查看某 container 詳細資訊 | `docker inspect <container_name>` | 包含網路、mount、env 等 |
| 查看容器佔用資源 | `docker stats` | 類似 `top` 的效果 |
---
### 💡 開發時特別實用
| 用途 | 指令 |
|------|------|
| 重建並啟動所有服務 | `docker compose up --build` |
| 關閉所有服務 | `docker compose down` |
| 只重啟某一個服務 | `docker compose restart <service>` |
| 查看 compose 的 log | `docker compose logs -f` 或 `docker compose logs -f <service>` |
| 查看網路設定 | `docker network ls`、`docker network inspect <network>` |
---
### 🪛 進階觀察技巧(bonus)
- 🔍 **查看資料卷(volumes)**
```bash
docker volume ls
docker volume inspect <volume>
```
- 🧰 **複製檔案從容器 ➜ 本機**
```bash
docker cp <container_name>:<path-in-container> <local-path>
```
- 🔄 **在 container 裡熱修改程式碼(開發模式)**
- 使用 `volumes:` 掛載 local 資料夾 ➜ container
---
`RUN` 和 `CMD` 都是在 Dockerfile 中使用的指令,但它們的用途和行為有顯著的區別:
### 1️⃣ `RUN`
- **用途**:在建立 Docker image 時執行命令。這個命令會在構建過程中被執行一次,並且其結果會保留在影像中。
- **執行時機**:在 `docker build` 過程中執行。
- **常見用途**:安裝套件、編譯程式、設定檔案、建立檔案等。
#### 範例:
```Dockerfile
RUN apt-get update && apt-get install -y curl
```
這個命令會在建構過程中執行,並安裝 `curl`。它的結果會被寫入 Docker image,所以每次從這個 image 啟動容器時,`curl` 就會存在於容器裡。
---
### 2️⃣ `CMD`
- **用途**:指定容器啟動後執行的預設命令。如果你啟動容器時沒有提供命令,`CMD` 中的命令將會被執行。
- **執行時機**:當容器被啟動時執行。
- **常見用途**:指定容器啟動時運行的應用程式、服務或腳本。
#### 範例:
```Dockerfile
CMD ["node", "index.js"]
```
這個命令會在容器啟動時運行 `node index.js`。如果容器啟動時沒有提供其他命令,則會執行這個命令。
---
### ✅ 區別總結
| 指令 | 用途 | 執行時機 | 常見用途 |
|---------|---------------------------------------------------------|-------------------|----------------------------------|
| `RUN` | 用來構建 image 時執行命令。 | 在 `docker build` 時執行 | 安裝套件、編譯程式、設置環境等 |
| `CMD` | 用來設定容器啟動時要執行的命令。 | 在容器啟動時執行 | 啟動應用程式、服務、腳本等 |
---
### 🧑💻 組合使用範例
假設你在 Dockerfile 中需要先安裝依賴,再啟動應用程式:
```Dockerfile
FROM node:20
WORKDIR /app
# 1. 使用 RUN 安裝依賴
RUN corepack enable && corepack prepare yarn@stable --activate
COPY package.json yarn.lock ./
RUN yarn install
# 2. 使用 RUN 編譯程式
COPY . .
RUN yarn build
# 3. 使用 CMD 啟動應用程式
CMD ["yarn", "start"]
```
這樣的寫法會先安裝依賴,然後編譯程式,最後設定容器啟動時執行 `yarn start` 來啟動應用程式。
---
如果你還有其他 Dockerfile 的疑問或需要更多範例,隨時告訴我!