--- ## 🐳 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 的疑問或需要更多範例,隨時告訴我!