Docker-實戰:使用 Docker 部署一個完整的 Web 應用(Nginx + MySQL)
文章目錄
- Docker-實戰:使用 Docker 部署一個完整的 Web 應用(Nginx + MySQL)
- 摘要
- 一、項目結構與技術選型
- 1.1 整體架構
- 1.2 技術棧説明
- 二、第一步:啓動 MySQL 容器(帶持久化)
- 2.1 創建專用網絡
- 2.2 啓動 MySQL 容器
- 2.3 初始化測試數據
- 三、第二步:構建並運行 Flask 應用容器
- 3.1 編寫 Flask 應用代碼
- 3.2 編寫 Dockerfile
- 3.3 構建並運行 Flask 容器
- 四、第三步:配置 Nginx 作為反向代理
- 4.1 編寫 Nginx 配置文件
- 4.2 啓動 Nginx 容器
- 五、最終驗證:訪問完整應用
- 六、常見問題排查指南
- ❌ 問題 1:Flask 無法連接 MySQL,報 “Can’t connect to MySQL server”
- ❌ 問題 2:Nginx 返回 502 Bad Gateway
- ❌ 問題 3:數據在容器重啓後丟失
- 七、清理環境
- 八、進階思考:為什麼不用 docker-compose?
- 結語
關鍵字:
Docker 多容器部署、
Nginx 反向代理、
Flask Docker、
MySQL Docker、
Docker Network
容器互聯、
Web 應用部署
摘要
紙上得來終覺淺,絕知此事要躬行。
前三篇我們學習了 Docker 的核心概念與基礎操作,現在是時候把它們串起來,完成一次真實的部署演練。
在現代 Web 開發中,一個典型應用往往由多個組件構成:前端靜態資源、後端服務、數據庫、緩存等。而 Docker 的強大之處,就在於能將這些組件獨立封裝、按需組合、快速部署。
本文將以一個極簡的 Python Flask 應用為例,演示如何使用 Docker 分別部署:
- MySQL 數據庫容器(帶數據持久化)
- Flask 應用容器(連接數據庫並提供 API)
- Nginx 容器(作為反向代理,對外暴露服務)
我們將通過 Docker Network 實現容器間通信,最終實現:訪問 http://localhost 即可看到從數據庫讀取的數據。
準備好了嗎?讓我們動手搭建屬於你的第一個多容器應用!
一、項目結構與技術選型
1.1 整體架構
- Nginx:監聽 80 端口,反向代理到 Flask;
- Flask:運行在 5000 端口,提供
/users接口; - MySQL:運行在 3306 端口,存儲用户數據;
- 所有容器通過自定義 Docker Network 互聯。
1.2 技術棧説明
|
組件
|
鏡像
|
説明
|
|
數據庫
|
|
官方 MySQL 鏡像
|
|
後端
|
自定義 Flask 鏡像
|
基於 |
|
反向代理
|
|
輕量級 Nginx
|
💡 為簡化流程,本文直接使用
docker run命令部署。第五篇將改用 Docker Compose 實現“一鍵部署”。
二、第一步:啓動 MySQL 容器(帶持久化)
2.1 創建專用網絡
為了讓容器能通過服務名互相訪問,先創建一個自定義 bridge 網絡:
docker network create app-network
✅ 默認 bridge 網絡不支持 DNS 解析(即不能通過容器名通信),必須使用自定義網絡。
2.2 啓動 MySQL 容器
docker run -d \
--name mysql-db \
--network app-network \
-e MYSQL_ROOT_PASSWORD=MySecretPass123! \
-e MYSQL_DATABASE=appdb \
-v mysql-data:/var/lib/mysql \
-p 3306:3306 \
mysql:8.0 \
--default-authentication-plugin=mysql_native_password
參數説明:
-e:設置環境變量(MySQL 初始化必需);-v mysql-data:/var/lib/mysql:使用 Docker Volume 持久化數據(即使容器刪除,數據仍在);--network app-network:加入自定義網絡;--default-authentication-plugin:兼容舊版客户端(如 Python 的 PyMySQL)。
📌 安全提示:生產環境中不要暴露 3306 端口給宿主機!此處僅為方便本地連接調試。
2.3 初始化測試數據
進入容器,創建測試表:
docker exec -it mysql-db mysql -uroot -pMySecretPass123!
在 MySQL shell 中執行:
USE appdb;
CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50));
INSERT INTO users (name) VALUES ('Alice'), ('Bob');
SELECT * FROM users;
確認數據已寫入。
三、第二步:構建並運行 Flask 應用容器
3.1 編寫 Flask 應用代碼
創建項目目錄 flask-app/,並新建 app.py:
# flask-app/app.py
from flask import Flask
import pymysql
app = Flask(__name__)
def get_db_connection():
return pymysql.connect(
host='mysql-db', # ← 關鍵:使用容器名作為 hostname
user='root',
password='MySecretPass123!',
database='appdb',
charset='utf8mb4'
)
@app.route('/users')
def get_users():
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute("SELECT id, name FROM users")
users = cursor.fetchall()
conn.close()
return {'users': [{'id': u[0], 'name': u[1]} for u in users]}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
🔑 關鍵點:
host='mysql-db'—— 因為我們在app-network中,Docker 內置 DNS 會自動解析mysql-db為對應容器 IP。
3.2 編寫 Dockerfile
在 flask-app/ 目錄下創建 Dockerfile:
# flask-app/Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]
同時創建 requirements.txt:
flask==2.3.3
PyMySQL==1.1.0
3.3 構建並運行 Flask 容器
# 構建鏡像
docker build -t my-flask-app ./flask-app
# 運行容器
docker run -d \
--name flask-app \
--network app-network \
-p 5000:5000 \
my-flask-app
驗證是否能訪問 API:
curl http://localhost:5000/users
# 應返回 {"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]}
✅ 成功!Flask 已連接 MySQL 並返回數據。
四、第三步:配置 Nginx 作為反向代理
4.1 編寫 Nginx 配置文件
創建 nginx.conf:
# nginx.conf
events {}
http {
server {
listen 80;
location / {
proxy_pass http://flask-app:5000; # ← 使用容器名
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
🔑 同樣,
flask-app會被 Docker DNS 解析為 Flask 容器的 IP。
4.2 啓動 Nginx 容器
docker run -d \
--name nginx-proxy \
--network app-network \
-p 80:80 \
-v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \
nginx:alpine
-v ...:ro:以只讀方式掛載配置文件;- 映射宿主機 80 端口,對外提供服務。
五、最終驗證:訪問完整應用
打開瀏覽器,訪問:
http://localhost/users
或終端執行:
curl http://localhost/users
你應該看到 JSON 格式的用户列表!
整個鏈路打通:
瀏覽器 → Nginx(80) → Flask(5000) → MySQL(3306)
六、常見問題排查指南
❌ 問題 1:Flask 無法連接 MySQL,報 “Can’t connect to MySQL server”
可能原因:
- 未加入同一 Docker Network;
- MySQL 容器名拼寫錯誤;
- MySQL 尚未完成初始化(剛啓動時不可用)。
解決:
# 檢查網絡
docker network inspect app-network
# 查看 MySQL 日誌
docker logs mysql-db
# 等待出現 "ready for connections" 再啓動 Flask
❌ 問題 2:Nginx 返回 502 Bad Gateway
可能原因:
- Flask 容器未運行;
- Nginx 配置中
proxy_pass地址錯誤; - Flask 未監聽
0.0.0.0(默認只監聽 localhost)。
解決: 確保 Flask 啓動命令為 app.run(host='0.0.0.0')。
❌ 問題 3:數據在容器重啓後丟失
原因:未使用 Volume 持久化。
解決:務必使用 -v mysql-data:/var/lib/mysql,而不是綁定宿主機目錄(開發可用,但 Volume 更規範)。
七、清理環境
實驗結束後,記得清理資源:
# 停止並刪除容器
docker stop nginx-proxy flask-app mysql-db
docker rm nginx-proxy flask-app mysql-db
# 刪除 Volume(謹慎!會丟失數據)
docker volume rm mysql-data
# 刪除網絡
docker network rm app-network
# 刪除鏡像(可選)
docker rmi my-flask-app
八、進階思考:為什麼不用 docker-compose?
你可能會問:“這麼多命令,為什麼不直接用 Compose?”
答:先理解原理,再使用工具。
通過手動 run 每個容器,你能清晰看到:
- 網絡如何連接;
- 端口如何映射;
- 數據如何持久化;
- 服務依賴順序。
這正是學習的價值所在。下一講,我們將把這些命令濃縮成一個 docker-compose.yml 文件,實現“一鍵部署”,體驗 DevOps 的真正效率。
結語
從單個容器到多容器協作,你已經邁出了構建現代化應用的關鍵一步。Docker 不僅簡化了部署,更改變了我們對“應用”的認知——它不再是一個整體,而是一組鬆耦合、可獨立演進的服務。
現在,你有能力在本地快速搭建任何基於微服務架構的應用原型。
系列預告:
下一篇 → 《Docker 數據持久化:詳解 Volume 和 Bind Mount》
我們將深入探討如何讓容器數據“活”下來,徹底告別“一刪就丟”!
參考資料:
- Docker Networking Guide: https://docs.docker.com/network/
- Flask + MySQL 示例:https://flask.palletsprojects.com/
- Nginx Reverse Proxy: https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/