Docker-實戰:使用 Docker 部署一個完整的 Web 應用(Nginx + MySQL)_#docker 多容器

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 整體架構


Docker-實戰:使用 Docker 部署一個完整的 Web 應用(Nginx + MySQL)_#MySQL Docker_02


  • Nginx:監聽 80 端口,反向代理到 Flask;
  • Flask:運行在 5000 端口,提供 /users 接口;
  • MySQL:運行在 3306 端口,存儲用户數據;
  • 所有容器通過自定義 Docker Network 互聯。

1.2 技術棧説明

組件

鏡像

説明

數據庫

mysql:8.0

官方 MySQL 鏡像

後端

自定義 Flask 鏡像

基於 python:3.11-slim 構建

反向代理

nginx:alpine

輕量級 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/

Docker-實戰:使用 Docker 部署一個完整的 Web 應用(Nginx + MySQL)_#Nginx 反向代理_03