Docker 教學 第 3 堂:MySQL、Docker Compose 與多容器管理
本系列為 18 小時 Docker 基礎教學講義,適合初學者,課堂指令統一使用 Linux/macOS shell 風格。 本篇為第 3 堂課,約 3 小時。
3-1 啟動 MySQL 容器與基本設定(約 1 小時)
為什麼用 Docker 跑資料庫?
傳統安裝 MySQL:
- 下載安裝程式
- 設定安裝路徑
- 設定使用者密碼
- 設定服務
- 如果要移除,還要清掉一堆殘留檔案
用 Docker:
- 一行指令搞定
- 不想要了?直接刪容器,乾乾淨淨
開發環境 vs 生產環境:資料庫該不該放在容器裡?
開發環境(你的電腦) 生產環境(正式上線) 用途 工程師寫程式、測試 真正的使用者在用 資料 測試資料,丟了沒關係 真實資料,不能丟 用 Docker 跑 DB? ✅ 非常適合 ❌ 不建議 開發環境用 Docker 跑資料庫是最佳實踐——一行指令裝好、不用的時候刪掉、還能同時跑不同版本。
生產環境不建議,因為資料庫需要高效能磁碟 I/O、資料不能丟、備份和主從複製在容器裡更複雜。正式環境通常使用雲端託管服務(如 AWS RDS、GCP Cloud SQL)。
實務上的流程:開發環境(Docker 跑 MySQL)→ 測試沒問題 → 部署到生產環境(用託管服務)。
如何看 Docker Hub 官方文件找參數
在直接教指令之前,先學一個更重要的技能——怎麼自己去 Docker Hub 查參數。因為不同的映像檔支援的環境變數和設定都不一樣,不可能全部背下來。
步驟 1:進入 Docker Hub 搜尋映像檔
前往 hub.docker.com,搜尋 mysql,點進官方映像檔頁面。
步驟 2:看 Overview 說明
往下滑,官方映像檔都會有詳細的說明文件,重點看這幾個區塊:
- How to use this image:教你怎麼啟動容器,通常會有範例指令
- Environment Variables:列出所有支援的環境變數(
-e參數) - Where to Store Data:告訴你資料存在容器的哪個路徑(
-v要掛載的路徑)
步驟 3:找到你需要的參數
以 MySQL 為例,官方文件會列出這些環境變數:
| 環境變數 | 說明 | 是否必填 |
|---|---|---|
MYSQL_ROOT_PASSWORD | root 密碼 | 必填 |
MYSQL_DATABASE | 自動建立一個資料庫 | 選填 |
MYSQL_USER | 自動建立一個使用者 | 選填 |
MYSQL_PASSWORD | 該使用者的密碼 | 選填 |
MYSQL_ALLOW_EMPTY_PASSWORD | 允許空密碼 | 選填 |
MYSQL_RANDOM_ROOT_PASSWORD | 自動產生隨機 root 密碼 | 選填 |
文件也會告訴你資料存放路徑是 /var/lib/mysql,所以你就知道 -v 要掛載這個路徑。
養成好習慣:每次使用新的映像檔之前,先去 Docker Hub 看一下官方文件。這比 Google 搜尋「怎麼用 Docker 跑 XXX」更準確,因為官方文件永遠是最新的。
實作:啟動 MySQL 容器
docker run -d \
--name my-mysql \
-e MYSQL_ROOT_PASSWORD=my-secret-pw \
-e MYSQL_DATABASE=testdb \
-e MYSQL_USER=testuser \
-e MYSQL_PASSWORD=testpass \
-p 3306:3306 \
mysql:8.0參數解釋:
-d:背景執行--name my-mysql:容器名稱-e:設定環境變數(Environment Variable)MYSQL_ROOT_PASSWORD:root 密碼(必填)MYSQL_DATABASE:自動建立一個資料庫MYSQL_USER/MYSQL_PASSWORD:自動建立一個使用者
-p 3306:3306:映射 MySQL 預設端口mysql:8.0:使用 MySQL 8.0 映像檔
環境變數就像是啟動容器時傳入的「設定值」。不同的映像檔支援不同的環境變數,可以在 Docker Hub 的說明頁面找到。
確認 MySQL 已啟動:
docker ps
docker logs my-mysql等看到 ready for connections 就代表啟動成功了。
連線到 MySQL
方法 1:從容器內部連線
docker exec -it my-mysql mysql -u root -p輸入密碼 my-secret-pw,然後來實際操作資料庫,確認它是真的能用的:
-- 顯示所有資料庫
SHOW DATABASES;
-- 使用 testdb
USE testdb;建立產品資料表:
CREATE TABLE Product (
Id INT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '產品編號',
Name VARCHAR(100) NOT NULL COMMENT '產品名稱',
Price DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT '售價',
Stock INT NOT NULL DEFAULT 0 COMMENT '庫存數量',
CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='產品資料表';插入測試資料:
INSERT INTO Product (Name, Price, Stock) VALUES
('藍牙耳機', 1290.00, 50),
('USB-C 線', 299.00, 150),
('27吋螢幕', 5990.00, 20),
('無線滑鼠', 590.00, 80),
('機械鍵盤', 2490.00, 35);查詢資料,驗證資料庫正常運作:
-- 查看所有產品
SELECT * FROM Product;
-- 查詢庫存低於 50 的產品
SELECT Name, Stock FROM Product WHERE Stock < 50;
-- 查詢總庫存價值
SELECT SUM(Price * Stock) AS '總庫存價值' FROM Product;
-- 更新價格
UPDATE Product SET Price = 1190.00 WHERE Name = '藍牙耳機';
-- 確認更新
SELECT * FROM Product WHERE Name = '藍牙耳機';
-- 刪除一筆資料
DELETE FROM Product WHERE Name = 'USB-C 線';
-- 確認刪除
SELECT * FROM Product;
-- 離開 MySQL
EXIT;透過以上操作,你可以確認 Docker 容器裡的 MySQL 是一個完整可用的資料庫,支援 CREATE、INSERT、SELECT、UPDATE、DELETE 所有基本操作。
方法 2:從主機用工具連線
因為我們有做端口映射(-p 3306:3306),你也可以用外部工具連線:
- 主機:
localhost - 端口:
3306 - 帳號:
root/ 密碼:my-secret-pw - 或帳號:
testuser/ 密碼:testpass
推薦工具:DBeaver、MySQL Workbench、HeidiSQL
資料持久化
問題演示:
先在 MySQL 裡新增一些資料,然後:
# 刪除容器
docker rm -f my-mysql
# 重新建立一個
docker run -d --name my-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -p 3306:3306 mysql:8.0
# 進去看看
docker exec -it my-mysql mysql -u root -pSHOW DATABASES;
-- testdb 不見了!之前的資料全部消失!解決方案:使用 Volume
docker rm -f my-mysql
docker run -d \
--name my-mysql \
-e MYSQL_ROOT_PASSWORD=my-secret-pw \
-e MYSQL_DATABASE=testdb \
-p 3306:3306 \
-v mysql-data:/var/lib/mysql \
mysql:8.0-v mysql-data:/var/lib/mysql:建立一個名為mysql-data的 Volume,掛載到容器內 MySQL 存放資料的目錄
Volume 管理指令:
# 查看所有 Volume
docker volume ls
# 查看 Volume 詳情
docker volume inspect mysql-data
# 刪除 Volume
docker volume rm mysql-data現在即使刪掉容器再重建,只要掛載同一個 Volume,資料就不會消失。
練習:加入資料 → 刪除容器 → 重建容器(掛同一個 Volume) → 確認資料還在。
3-2 Docker Compose:一次管理多個容器(約 1 小時)
為什麼需要 Docker Compose?
回想一下,前面我們啟動 MySQL 的指令有多長:
docker run -d --name my-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -e MYSQL_DATABASE=testdb -e MYSQL_USER=testuser -e MYSQL_PASSWORD=testpass -p 3306:3306 -v mysql-data:/var/lib/mysql mysql:8.0如果同時要啟動 Web + 資料庫 + 快取,每個都要打一長串指令,而且還要記得建立網路、設定連線。這很麻煩,也很容易打錯。
Docker Compose 就是用來解決這個問題的——把所有容器的設定寫在一個 compose.yaml 檔案裡,一個指令就能全部啟動。
檔名提醒:新版 Docker Compose 常見檔名是
compose.yaml或compose.yml。舊檔名docker-compose.yml仍然可以用,但本課程從這裡開始統一使用compose.yaml。新版 Compose V2 也不需要再寫舊式的頂層version: "3.8"。
什麼是 YAML?
compose.yaml 使用 YAML 格式。YAML 是一種簡潔的設定檔格式,用來告訴電腦「這個服務要怎麼啟動」、「資料在哪裡」、「名字是什麼」等等。
YAML 的基本規則:
- 用縮排(空格)表示層級關係,不能用 Tab
- 用
:分隔 key 和 value - 用
-表示清單項目 #開頭是註解
# 這是一個 YAML 範例
name: my-app # key: value
ports: # 底下是清單
- "8080:80" # 清單項目用 - 開頭
- "443:443"
environment: # 底下也是 key: value
DB_HOST: mysql
DB_PORT: 3306注意:YAML 對縮排非常敏感,多一個或少一個空格都會出錯。建議用 VS Code 等編輯器,它會幫你自動對齊。
示範:把剛才的 MySQL 改寫成 Docker Compose
前面我們已經用 docker run 啟動過 MySQL。現在不要換題目,先把同一個 MySQL 改寫成 compose.yaml,學生才會知道每一行是從哪裡來的。
先建立一個新的練習資料夾:
mkdir -p ~/docker-lab/mysql-compose
cd ~/docker-lab/mysql-compose如果前面還有同名容器,先清掉,避免名稱或 port 衝突:
docker rm -f my-mysql在 ~/docker-lab/mysql-compose/ 目錄下建立 compose.yaml:
services:
db:
image: mysql:8.0
container_name: my-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: my-secret-pw
MYSQL_DATABASE: testdb
MYSQL_USER: testuser
MYSQL_PASSWORD: testpass
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
volumes:
mysql-data:這份檔案就是前面那串 docker run 的設定檔版本:
docker run -d --name my-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -e MYSQL_DATABASE=testdb -e MYSQL_USER=testuser -e MYSQL_PASSWORD=testpass -p 3306:3306 -v mysql-data:/var/lib/mysql mysql:8.0對照一下,每個設定對應哪個 docker run 參數:
| compose.yaml | docker run 參數 | 說明 |
|---|---|---|
image: | 映像檔名稱 | 要用哪個映像檔 |
container_name: | --name | 容器名稱 |
restart: | --restart | 重啟策略 |
ports: | -p | 端口映射 |
volumes: | -v | 掛載目錄 |
environment: | -e | 環境變數 |
關於
container_name:這裡保留container_name是為了讓學生對照前面的--name my-mysql。實務專案通常可以省略,讓 Compose 自己用 project name 和 service name 產生容器名稱,避免不同專案互相撞名。
restart 重啟策略:
| 值 | 說明 |
|---|---|
no | 預設值,不自動重啟 |
always | 不管什麼原因停止,都自動重啟 |
unless-stopped | 自動重啟,除非你手動 stop 它 |
on-failure | 只有程式出錯(非正常結束)才重啟 |
開發環境推薦用
unless-stopped,這樣電腦重開機後 Docker Desktop 啟動時,容器也會自動跟著啟動。
執行這個 MySQL Compose
# 進入專案目錄
cd ~/docker-lab/mysql-compose
# 先檢查 Compose 檔案是否能被正確解析
docker compose config
# 啟動服務(背景執行)
docker compose up -d
# 查看狀態
docker compose ps
# 查看 log
docker compose logs
# 即時追蹤 log
docker compose logs -f
# 確認 MySQL 可以登入
docker compose exec db mysql -u root -p登入後輸入 my-secret-pw,再做一次簡單確認:
SHOW DATABASES;
USE testdb;
SELECT DATABASE();
EXIT;停止與清理:
# 停止並刪除 Compose 建立的容器與網路
docker compose down
# 連 Volume 也刪掉,MySQL 資料會一起消失
docker compose down -v注意:舊版 Docker 使用
docker-compose(有連字號),新版已整合為docker compose(空格)。如果你的 Docker Desktop 是近期安裝的,直接用docker compose就對了。
Compose project name 是什麼?
當你在某個資料夾執行 docker compose up,Compose 會把「目前資料夾名稱」當成預設的 project name。同一個 project 裡的 container、network、volume 會被視為同一組環境。
例如你在 ~/docker-lab/mysql-compose 執行:
docker compose up -dCompose 通常會建立類似這樣的資源:
mysql-compose-db-1
mysql-compose_default
mysql-compose_mysql-data所以同一份 compose.yaml 放在不同資料夾執行,會變成不同 project,不容易互相干擾。如果想明確指定 project name,可以用:
docker compose -p mysql-demo up -d
docker compose -p mysql-demo down初學階段先記住一句話:service name 是容器彼此連線用的名字,project name 是 Compose 管理整組環境用的名字。
Docker Compose 的好處
- 一個檔案管理所有容器:不用記一堆長指令
- 可重複使用:
compose.yaml可以 commit 進 git,團隊成員 clone 下來直接docker compose up就能跑 - 自動建立網路:同一個 compose 檔案裡的容器會自動放在同一個網路,可以用服務名稱(如
app、db)互相連線 - 一鍵啟動/關閉:不用一個一個 start/stop
教學順序提醒:這一堂先把 Compose 的「自動網路」當成會用的功能就好。也就是說,同一份
compose.yaml裡的服務可以用服務名稱互相連線,例如web連app、app連db。至於 Docker Network 是什麼、怎麼手動建立 network、--network怎麼用,第四堂會再正式拆解。
Docker Compose 適合開發環境和小型部署。大規模生產環境通常會使用 Kubernetes(K8s)來管理,但那是進階主題,不在本課程範圍內。
ports、expose 與 depends_on 先講清楚
接下來會開始做多容器互連,所以先把三個設定分清楚:
| 設定 | 用途 | 初學者要記住 |
|---|---|---|
ports | 把容器 port 開到主機 | 瀏覽器或主機工具要連進來才需要 |
expose | 標示容器內服務 port | 只給 Compose network 裡的服務連,不開到主機 |
depends_on | 控制容器啟動順序 | 只保證先啟動,不保證服務已經 ready |
例如 web 可以用 http://app:5000 連到 Flask,不需要知道 app 容器的 IP。這是 Compose 自動網路和 service name DNS 的效果。
重要:
depends_on不是健康檢查。MySQL 容器開始啟動,不代表 MySQL 已經可以連線,所以應用程式仍然要能重試連線。
練習 P2:照解答跑 Nginx + Flask
這一題不是要學生憑空寫。做法是:先照完整解答建立檔案,跑起來後再改一兩個設定確認自己懂了什麼。
這次不要只是把兩個沒有關係的容器放在同一份 Compose 裡,而是做一個真的會互相連線的結構:
Browser -> Nginx -> Flask重點是:瀏覽器只連到 Nginx,Flask 不對主機開 port。Nginx 會透過 Compose network,用服務名稱 app 連到 Flask。
目標:
- 啟動一個 Nginx,瀏覽器用
http://localhost:8080開啟 - 啟動一個 Flask,容器內使用
5000port - Flask 不寫
ports,只寫expose: "5000" - Nginx 設定
proxy_pass http://app:5000; - 兩個服務都設定
restart: unless-stopped - 用
docker compose ps確認兩個服務都是Up
建立資料夾:
mkdir -p ~/docker-lab/nginx-flask-compose
cd ~/docker-lab/nginx-flask-compose
mkdir app
mkdir nginx建立 app/app.py:
from flask import Flask, jsonify
import socket
app = Flask(__name__)
@app.get("/")
def home():
return jsonify(
message="Hello from Flask behind Nginx",
hostname=socket.gethostname(),
)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)建立 app/requirements.txt:
flask==3.0.3建立 nginx/default.conf:
server {
listen 80;
location / {
proxy_pass http://app:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}建立 compose.yaml:
services:
web:
image: nginx:alpine
container_name: compose-nginx
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- app
app:
image: python:3.11
container_name: compose-flask
working_dir: /app
restart: unless-stopped
volumes:
- ./app:/app
expose:
- "5000"
command: bash -c "pip install -r requirements.txt && python app.py"啟動與驗證:
docker compose config
docker compose up -d
docker compose ps
docker compose logs打開瀏覽器看 http://localhost:8080,應該會看到 Flask 回傳的 JSON。
也可以從 Nginx 容器裡直接打 Flask 的服務名稱:
docker compose exec web wget -qO- http://app:5000這裡的 app 不是主機名稱,也不是 IP,而是 Compose network 自動提供的 service name DNS。
練習改一行:
把 ports 的 "8080:80" 改成 "8081:80",重新啟動:
docker compose down
docker compose up -d再打開 http://localhost:8081。這一步是在練習 port 映射,不是在考學生背 YAML。
實作:用 Docker Compose 建立 Nginx + Flask + MySQL 環境
現在來動手做!我們要用一個 compose.yaml 同時啟動 Nginx、Flask 應用和 MySQL 資料庫。
這個例子會真的用到 Compose network:
Browser -> Nginx -> Flask -> MySQL瀏覽器從主機連到 Nginx;Nginx 在 Compose network 裡用服務名稱 app 連到 Flask;Flask 再用服務名稱 db 連到 MySQL。
步驟 1:建立專案資料夾
mkdir -p ~/docker-lab/nginx-flask-mysql-compose
cd ~/docker-lab/nginx-flask-mysql-compose
mkdir app
mkdir nginx步驟 2:建立 Flask 應用
在 ~/docker-lab/nginx-flask-mysql-compose/app/ 下建立 app.py:
import os
import time
import pymysql
from flask import Flask, jsonify
app = Flask(__name__)
def connect_db():
return pymysql.connect(
host=os.environ["DB_HOST"],
user=os.environ["DB_USER"],
password=os.environ["DB_PASSWORD"],
database=os.environ["DB_NAME"],
charset="utf8mb4",
cursorclass=pymysql.cursors.DictCursor,
)
@app.get("/")
def index():
last_error = None
for _ in range(10):
try:
with connect_db() as conn:
with conn.cursor() as cursor:
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS visits (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
)
"""
)
cursor.execute("INSERT INTO visits () VALUES ()")
conn.commit()
cursor.execute("SELECT COUNT(*) AS count FROM visits")
row = cursor.fetchone()
return jsonify(
message="Flask connected to MySQL through the Compose network",
db_host=os.environ["DB_HOST"],
visits=row["count"],
)
except Exception as error:
last_error = error
time.sleep(2)
return jsonify(error=str(last_error)), 500
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)建立 app/requirements.txt:
flask==3.0.3
pymysql==1.1.1
cryptography==42.0.8步驟 3:建立 Nginx 設定檔
在 ~/docker-lab/nginx-flask-mysql-compose/nginx/ 下建立 default.conf:
server {
listen 80;
location / {
proxy_pass http://app:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}步驟 4:建立 compose.yaml
在 ~/docker-lab/nginx-flask-mysql-compose/ 下建立 compose.yaml:
services:
# Nginx 反向代理
web:
image: nginx:alpine
container_name: demo-nginx
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- app
# Flask 應用程式
app:
image: python:3.11
container_name: demo-flask
working_dir: /app
restart: unless-stopped
volumes:
- ./app:/app
environment:
DB_HOST: db
DB_NAME: demo_db
DB_USER: demo_user
DB_PASSWORD: demo_pass
depends_on:
- db
expose:
- "5000"
command: bash -c "pip install -r requirements.txt && python app.py"
# MySQL 資料庫
db:
image: mysql:8.0
container_name: demo-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: root1234
MYSQL_DATABASE: demo_db
MYSQL_USER: demo_user
MYSQL_PASSWORD: demo_pass
ports:
- "3306:3306"
volumes:
- db-data:/var/lib/mysql
volumes:
db-data:這裡最重要的是兩個 service name:
- Nginx 用
app:5000連 Flask - Flask 用
db:3306連 MySQL
MySQL 的 "3306:3306" 是為了讓你也能從主機用 DBeaver、Workbench 或 CLI 連進去觀察資料;Flask 連 MySQL 不靠這個對外 port,而是靠 Compose network 裡的 db:3306。
步驟 5:啟動所有服務
cd ~/docker-lab/nginx-flask-mysql-compose
docker compose config
docker compose up -d你會看到 Docker 同時拉取 Nginx、Python 和 MySQL 的映像檔,然後啟動三個容器。
步驟 6:驗證服務
# 查看容器狀態,應該看到三個都是 Up
docker compose ps
# 查看 log,確認 Nginx、Flask 與 MySQL 沒有錯誤
docker compose logs打開瀏覽器:
http://localhost:8080→ 看到 Flask 回傳 JSON- 重整幾次,
visits數字會增加,代表 Flask 成功寫入 MySQL
也可以從 Nginx 容器驗證它能用 service name 連 Flask:
docker compose exec web wget -qO- http://app:5000步驟 7:試試看修改 Flask 程式
因為我們用了 bind mount 把本機的 app 資料夾掛載進去,所以可以直接修改 app/app.py。修改後重啟 app 服務:
docker compose restart app步驟 8:連線到 MySQL 確認資料庫可用
docker compose exec db mysql -u demo_user -p輸入密碼 demo_pass:
SHOW DATABASES;
USE demo_db;
SELECT * FROM visits;
EXIT;步驟 9:體驗一鍵關閉
# 停止並刪除所有容器
docker compose down
# 確認都清乾淨了
docker ps -a如果要連 Volume 也刪掉(資料庫資料也不要了):
docker compose down -v回顧一下:剛才我們用一個
compose.yaml同時啟動 Nginx + Flask + MySQL。瀏覽器只對外連 Nginx;Nginx 用app找 Flask;Flask 用db找 MySQL。這才是多容器 Compose 最重要的概念。
3-3 實戰練習與清理(約 1 小時)
實務情境題:同時跑兩個版本的 MySQL
情境: 你現在主機已經有 mysql:8.0 的容器在跑舊專案。主管說有新客戶,他們公司用的是 mysql:9.0。但你的開發機因為要維護舊專案還是需要 8.0,這時候請再建一個 mysql:9.0 的容器出來。
為什麼這個情境很重要? 傳統安裝 MySQL,同一台電腦要跑兩個版本幾乎不可能——port 衝突、路徑衝突、服務名稱衝突,搞半天搞不定。但 Docker 的隔離性讓這件事變得超簡單。
方法 A:使用 docker run
# 舊專案的 MySQL 8.0(假設已經在跑了,用 3306 port)
docker run -d --name mysql8 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root123 mysql:8.0
# 新客戶的 MySQL 9.0(port 改成 3307,避免衝突)
docker run -d --name mysql9 -p 3307:3306 -e MYSQL_ROOT_PASSWORD=root123 mysql:9.0重點:兩個容器內部都是 3306,但對外的 port 要錯開(3306 和 3307)。
方法 B:使用 Docker Compose
services:
mysql8:
image: mysql:8.0
container_name: mysql8
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: old_project
ports:
- "3306:3306"
volumes:
- mysql8-data:/var/lib/mysql
mysql9:
image: mysql:9.0
container_name: mysql9
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: new_project
ports:
- "3307:3306"
volumes:
- mysql9-data:/var/lib/mysql
volumes:
mysql8-data:
mysql9-data:驗證兩個都能用:
# 連線到 MySQL 8.0
docker exec -it mysql8 mysql -u root -p -e "SELECT VERSION();"
# 連線到 MySQL 9.0
docker exec -it mysql9 mysql -u root -p -e "SELECT VERSION();"這就是 Docker 隔離性的威力——同一台電腦輕鬆跑多個版本,互不干擾。在開發環境中,這是非常常見的需求。
挑戰 C1:補完 Nginx + Flask + MySQL 三服務 Compose
前面老師已經帶著做完整版本,這一題改成學生自己補完 compose.yaml。
請打開範例資料夾:
cd docker-course-examples/session-03-mysql-compose/c1-nginx-flask-mysql/starter目標架構:
Browser -> Nginx -> Flask -> MySQL要求:
web:使用nginx:alpine,對外開8084:80app:使用python:3.11,只在內部expose 5000db:使用mysql:8.0,資料掛到 named volume- Nginx 用
app:5000連 Flask - Flask 用
DB_HOST=db連 MySQL
驗證:
docker compose config
docker compose up -d
docker compose ps
docker compose exec web wget -qO- http://app:5000
docker stats --no-stream
docker compose down -v這題的重點不是再抄一次 YAML,而是確認你真的理解三段關係:主機連 Nginx、Nginx 連 Flask、Flask 連 MySQL。
挑戰 C2:自己查 Docker Hub 跑起來
以下兩個映像檔請同學自行練習——去 Docker Hub 查看說明,找出需要的參數,把它跑起來:
| 映像檔 | 說明 | Docker Hub 頁面 |
|---|---|---|
ramuses/photopea | 線上版 Photoshop 替代品,跑在瀏覽器裡 | hub.docker.com/r/ramuses/photopea |
xinsodev/drawdb | 資料庫 ER 圖設計工具,視覺化設計資料表關聯 | hub.docker.com/r/xinsodev/drawdb |
練習重點:
- 到 Docker Hub 頁面閱讀說明
- 找出容器使用的 port 是什麼
- 用
docker run跑起來並在瀏覽器開啟 - 玩完後用
docker rm -f清理
這個練習的目的不是學這兩個工具,而是練習「看 Docker Hub 文件 → 自己把容器跑起來」的能力。以後工作上遇到任何新的映像檔,都是用同樣的流程。
不要選本堂已經大量使用的 nginx、mysql、python / flask。
可選延伸:Docker Hub 有趣映像檔
用 Docker 玩復古遊戲
這一節是課後可選延伸,不是第三章主線。目的只是讓大家體驗 Docker 的另一面——它不只能跑正經的伺服器程式,還能跑各種有趣的東西。
實作 1:DOS 遊戲映像檔
Docker Hub 上有人把經典的 DOS 遊戲打包成映像檔,可以在瀏覽器裡直接玩!
# 下載 DOS 遊戲映像檔
docker pull oldiy/dosgame-web-docker
# 啟動容器
docker run -d --name dos-game -p 8080:262 oldiy/dosgame-web-docker打開瀏覽器前往 http://localhost:8080,你會看到一個懷舊的 DOS 遊戲選單,裡面有上百款經典遊戲可以玩!
同學可以自行到 Docker Hub 搜尋
dosgame-web-docker查看這個映像檔的說明。這也是一個練習「看官方文件找參數」的好機會。
實作 2:2048 網頁版
docker run -d --name game-2048 -p 9090:80 alexwhen/docker-2048打開瀏覽器前往 http://localhost:9090 就能玩 2048!
實作 3:命令列小遊戲
# 用 Alpine Linux 容器體驗命令列遊戲
docker run -it --name game-box alpine sh在容器裡安裝文字遊戲:
# 安裝遊戲套件
apk add --no-cache bsd-games
# 玩貪食蛇
snake
# 或玩其他遊戲
tetris
worm透過這些有趣的例子:
- 練習從 Docker Hub 找映像檔並查看說明
- 練習
-p端口映射(注意每個映像檔的容器 port 不一樣)- 練習
docker run、docker stop、docker rm等基本操作- 體驗 Docker 可以運行各種類型的應用,不只是正經的伺服器程式
鼓勵同學自己去 Docker Hub 探索其他有趣的映像檔!
清理練習
趁這個機會練習容器和映像檔的清理:
# 停止所有執行中的容器
docker stop $(docker ps -q)
# 刪除所有已停止的容器
docker container prune
# 刪除不再使用的映像檔
docker image prune
# 核彈級清理(小心使用!)
docker system prune -a