Docker+Flask 实战:打造高并发微服务架构

news/2025/3/16 5:22:18/

Docker+Flask 实战:打造高并发微服务架构

今天我们要深入探讨一个非常热门且实用的主题:基于 Docker 部署 Python Flask 应用。Docker 作为当下最流行的容器化技术,已经广泛应用于各种开发和部署场景,尤其是在微服务架构中。而 Flask 作为 Python 世界里轻量级的 Web 框架,同样备受开发者青睐。将二者结合,能极大地提高我们应用的部署效率和可移植性。接下来,我们就一起通过一个完整的实例来学习如何实现这个过程。

测试虚拟机环境介绍

在开始之前,先给大家介绍一下我们使用的测试虚拟机环境。我们使用的是 VMware,配置为 4G 内存和 2 核心。这样的配置对于我们今天的演示来说是足够的,当然在实际生产环境中,你可能需要根据具体的应用需求来调整硬件资源。

Docker + Flask 部署实例

1. 项目代码

首先,我们来看一下 Flask 应用的代码,它在 app.py 文件中。

from flask import Flask
app = Flask(__name__)@app.route('/')
def hello():return "Hello Docker World!"if __name__ == '__main__':app.run(host='0.0.0.0', port=5000)

这段代码非常简单,我们导入了 Flask 框架,创建了一个 Flask 应用实例,然后定义了一个路由 /,当访问这个路由时,会返回一个简单的字符串。最后,我们通过 app.run 方法启动了这个应用,并将其监听在 0.0.0.0:5000 上,这样容器内的服务就能监听所有网络接口,而不仅仅是本地环回地址。

2. Dockerfile 配置

接下来,我们要在项目根目录创建一个 Dockerfile

# 使用轻量级 Python 基础镜像
FROM python:3.11-slim# 设置工作目录
WORKDIR /app# 代码到容器
COPY . .# 安装依赖(使用国内镜像加速)
RUN pip install --no-cache-dir -r requirements.txt# 暴露端口
EXPOSE 5000# 启动命令
CMD ["python", "app.py"]

这里面有几个关键的指令需要大家注意。首先是 FROM python:3.10-slim,我们使用的是官方的轻量级 Python 镜像,它的体积只有约 127MB,相比 centos 镜像更加高效,这对于我们构建和部署镜像来说可以节省很多时间和存储空间。然后是 --no-cache-dir 这个参数,它的作用是避免缓存依赖,确保每次构建时都能安装最新版本的依赖。EXPOSE 5000 声明了容器暴露的端口,不过需要注意的是,这只是一个声明,实际运行容器时还需要结合 -p 参数将容器端口映射到宿主机上。最后,CMD 指令定义了容器启动时要执行的命令。

3. 依赖管理

我们还需要创建一个 requirements.txt 文件,用来列出所有的依赖。

Flask==3.0.0

明确指定依赖的版本号是非常重要的,这样可以避免依赖冲突。建议大家在本地使用虚拟环境进行测试,确保所有依赖都能正常工作后,再进行打包。

4. 构建镜像

在项目目录下执行以下命令来构建镜像:

docker build --no-cache -t my-flask-app .

这里的 --no-cache 参数是强制重新构建镜像,避免缓存导致依赖未更新。

5. 运行容器

构建好镜像后,我们就可以启动容器并映射端口了。

docker run -d --name flask-container -p 8080:5000 my-flask-app

-d 参数表示后台运行容器-p 8080:5000 是将宿主机的 8080 端口映射到容器的 5000 端口,--name 则是为容器指定一个名称,方便我们后续管理。

6. 测试访问

我们可以通过浏览器或终端来访问我们的应用:

curl http://localhost:8080
# 或
http://127.0.0.1:8080

如果一切正常,你应该能看到 Hello Docker World! 这个输出。

7. 调试与维护

在实际开发过程中,调试和维护是非常重要的。我们可以通过以下命令来查看容器的日志:

docker logs flask-container

如果需要进入容器的终端进行一些操作,可以使用:

docker exec -it flask-container /bin/bash

当我们修改了 app.py 中的代码后,需要重新执行 docker builddocker run 命令,或者使用 docker-compose 来简化这个流程。

完整高级优化实例

文件结构

下面我们来看一个更高级的优化实例,首先看一下文件结构:

.
├── docker-compose.yml      # 编排配置
├── Dockerfile              # 多阶段构建
├── app
│   ├── app.py             # Flask 主程序
│   └── requirements.txt   # 精确依赖
└── nginx└── nginx.conf         # 反向代理配置
Dockerfile(含多阶段构建)
# 构建阶段
FROM python:3.11-slim-bullseye AS builder
WORKDIR /build
COPY app/requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt# 运行阶段
FROM python:3.11-slim-bullseye
WORKDIR /app# 安全配置
RUN adduser --disabled-password --gecos '' appuser && chown -R appuser:appuser /app
USER appuser# 依赖安装
# 这里要注意的是 /root/.local 不要写成 /home/appuser/.local,因为你的系统内没有这个目录
# 我是在 root 用户下执行的操作,所以是/root/.local
COPY --from=builder /root/.local /home/appuser/.local  
ENV PATH=/home/appuser/.local/bin:$PATH# 应用代码
COPY app .# 健康检查
HEALTHCHECK --interval=30s --timeout=5s CMD curl -f http://localhost:5000/health || exit 1
# 启动命令
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "9", "--worker-class", "gevent", "app:app"]

这里使用了多阶段构建的方式,在构建阶段我们只安装依赖,然后在运行阶段将依赖复制过来,并使用非 root 用户运行应用,提高了容器的安全性。同时,我们还添加了健康检查,确保容器内的服务正常运行。启动命令使用了 gunicorn 作为 WSGI 服务器,并使用 gevent 作为工作类,提高了应用的并发性能。

app/app.py(含监控端点)
from flask import Flask
from prometheus_client import generate_latest, Counterapp = Flask(__name__)
REQUEST_COUNTER = Counter('http_requests_total', 'Total HTTP Requests')@app.route('/')
def hello():REQUEST_COUNTER.inc()return "Hello Production Docker World!"@app.route('/health')
def health():return "OK", 200@app.route('/metrics')
def metrics():return generate_latest()

在这个 app.py 中,我们添加了一些监控端点。/health 端点用于健康检查,/metrics 端点用于提供 Prometheus 监控数据,这样我们就能更好地监控应用的运行状态。

app/requirements.txt(精确版本控制)
Flask==3.0.0
gunicorn==21.2.0
gevent==23.9.1
prometheus-client==0.20.0

精确控制依赖的版本号可以避免因依赖版本不一致而导致的问题。

dockercomposeyml_199">docker-compose.yml(生产编排)
version: '3.11'services:web:build: .ports:- "5000:5000"deploy:resources:limits:cpus: '2.0'memory: 1GBlogging:driver: "json-file"options:max-size: "100m"nginx:image: nginx:1.25ports:- "80:80"volumes:- ./nginx/nginx.conf:/etc/nginx/nginx.confdepends_on:- web

docker-compose.yml 是用于生产编排的,我们可以通过它来定义多个服务,并进行资源管控和日志配置。这里我们定义了 webnginx 两个服务,web 服务构建我们的 Flask 应用,nginx 服务作为反向代理,将请求转发到 web 服务上。

nginx/nginx.conf(反向代理配置)
worker_processes auto;events {worker_connections 1024;
}http {upstream flask {server web:5000;}server {listen 80;location / {proxy_pass http://flask;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;}}
}

这个 nginx.conf 文件配置了反向代理,将所有请求转发到 web 服务的 5000 端口上。

部署流程
# 构建镜像
docker-compose build# 启动集群
docker-compose up -d# 验证部署
curl http://localhost/health

通过这几个简单的命令,我们就可以完成整个应用的部署和验证。

关键优化点说明

最后,我们来看一下这个高级优化实例的关键优化点:

优化方向实现方案
镜像体积多阶段构建(162MB 镜像)
并发性能Gunicorn + Gevent(9 workers)
安全基线非 root 用户运行 + 文件权限控制
可观测性Prometheus 监控端点 + 健康检查
资源管控CPU/内存限制 + 日志滚动策略

我们还进行了压力测试,所有参数均通过 wrk -t12 -c400 -d30s http://localhost/ 压力测试验证,QPS 为1125,可能是虚拟机的原因吧。

下面的几个版本的对比:

镜像组件镜像大小QPS
flask-app:v1Python:3.11 +Flask3.0138MB1000.95
flask-app:v2Python:3.11-alpine +Flask3.058.6MB899.78
flask-nginx-web:v1Python:3.11-slim-bullseye +Flask3.0+gunicorn21.2.0+
gevent23.9.1+prometheus-client0.20.0
162MB1125.04
flask-nginx-web:v2Python:3.11-alpine +Flask3.0+gunicorn21.2.0+
gevent23.9.1+prometheus-client0.20.0
92.7MB1049.89

alpin镜像确实小,从QPS的角度来看,并不是什么都用alpin镜像就好的。

总结

今天我们学习了如何基于 Docker 部署 Python Flask 应用,从简单的实例到高级优化实例,希望大家能对 Docker 的使用有更深入的理解。在实际开发中,大家可以根据自己的需求进行调整和优化,充分发挥 Docker 的优势。如果大家有任何问题,欢迎随时提问。谢谢大家!


http://www.ppmy.cn/news/1579501.html

相关文章

深入理解 HTML 链接:网页导航的核心元素

在网页开发的广袤领域中,HTML 链接无疑扮演着举足轻重的角色,它是实现网页之间无缝跳转、构建互联网络世界的核心部分。无论是引导用户在不同页面间穿梭,还是关联各类资源,HTML 链接都发挥着关键作用。 一、HTML 链接基础认知 HT…

Pycharm中脚本执行的3种模式——unittest框架、pytest框架及普通模式

一. Python 运行脚本的三种模式 a. unittest 框架 b. pytest 框架 c. 普通模式 二、PyCharm 默认使用 pytest 框架执行 unittest 框架的测试用例 三、如何修改Pycharm的脚本运行的模式? 方法1. 修改 PyCharm 默认的测试框架 方法2. 设置运行脚本时的默认框架 四、mai…

【每日学点HarmonyOS Next知识】拖拽调整列表顺序、tab回弹、自定义弹窗this、状态变量修饰枚举

1、HarmonyOS 功能实现(拖拽调整列表顺序)? 可参考: import curves from ohos.curves; import Curves from ohos.curvesEntry Component struct ListItemExample {State private arr: number[] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]…

【openGauss】物理备份恢复

文章目录 1. gs_backup(1)备份(2)恢复(3)手动恢复的办法 2. gs_basebackup(1)备份(2)恢复① 伪造数据目录丢失② 恢复 3. gs_probackup(1&#xf…

MySQL隐式依赖引发的字段长度溢出:一次触发器事故的深度剖析

MySQL隐式依赖引发的字段长度溢出:一次触发器事故的深度剖析 场景还原:诡异的字段不存在报错 某日接到生产环境报警,发现核心业务表order_main(A表)的插入操作频繁报错,错误提示却显示ERROR 1406 (22001)…

极客天成 NVFile 并行文件存储:端到端无缓存新范式,为 AI 训练按下“快进键”

在人工智能的世界里,AI 训练就像一场“数据马拉松”。模型需要从海量数据中学习规律,而这些数据的读取速度往往决定了训练的效率。今天,我们就来聊聊一个有趣的话题:极客天成的 NVFile 并行文件存储,以及它的端到端无缓…

C语言基础知识04

指针 指针概念 指针保存地址,地址是字节的编号 指针类型和保存的地址类型要一直 使用时注意,把地址转换为&变量的格式来看 int a[3]; a转为&a[0] 指针的大小 64bit 固定8字节, 32bit 固定4字节 指针…

【机械视觉】C#+VisionPro联合编程———【五、硬币检测小项目实现(C#+VisionPro联合编程和csv文件格式操作)】

【机械视觉】C#VisionPro联合编程———【五、硬币检测小项目实现(C#VisionPro联合编程和csv文件格式操作)】 项目介绍 总共有十二张检测的图片,当点击检测按钮时检测当前展示的图片并且将检测效果展示在表格中,当点击上一页或下一页时换检测图片&…