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

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

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

测试虚拟机环境介绍

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

Docker + Flask 部署实例

1. 项目代码

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

python 复制代码
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 配置(5 分钟)

接下来,我们要在项目根目录创建一个 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. 构建镜像

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

bash 复制代码
docker build --no-cache -t my-flask-app .

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

5. 运行容器

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

bash 复制代码
docker run -d --name flask-container -p 8080:5000 my-flask-app

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

6. 测试访问

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

bash 复制代码
curl http://localhost:8080
# 或
http://127.0.0.1:8080

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

7. 调试与维护

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

bash 复制代码
docker logs flask-container

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

bash 复制代码
docker exec -it flask-container /bin/bash

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

完整高级优化实例

文件结构

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

bash 复制代码
.
├── docker-compose.yml      # 编排配置
├── Dockerfile              # 多阶段构建
├── app
│   ├── app.py             # Flask 主程序
│   └── requirements.txt   # 精确依赖
└── nginx
    └── nginx.conf         # 反向代理配置
Dockerfile(含多阶段构建)
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(含监控端点)
python 复制代码
from flask import Flask
from prometheus_client import generate_latest, Counter

app = 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

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

docker-compose.yml(生产编排)
yaml 复制代码
version: '3.11'

services:
  web:
    build: .
    ports:
      - "5000:5000"
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 1GB
    logging:
      driver: "json-file"
      options:
        max-size: "100m"

  nginx:
    image: nginx:1.25
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - web

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

nginx/nginx.conf(反向代理配置)
nginx 复制代码
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 端口上。

部署流程
bash 复制代码
# 构建镜像
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:v1 Python:3.11 +Flask3.0 138MB 1000.95
flask-app:v2 Python:3.11-alpine +Flask3.0 58.6MB 899.78
flask-nginx-web:v1 Python:3.11-slim-bullseye +Flask3.0+gunicorn21.2.0+ gevent23.9.1+prometheus-client0.20.0 162MB 1125.04
flask-nginx-web:v2 Python:3.11-alpine +Flask3.0+gunicorn21.2.0+ gevent23.9.1+prometheus-client0.20.0 92.7MB 1049.89

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

总结

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

相关推荐
o0o_-_4 分钟前
【瞎折腾/ragflow】构建docker镜像并部署使用ragflow
运维·docker·容器
Watink Cpper40 分钟前
[多线程]基于环形队列(RingQueue)的生产者-消费者模型的实现
linux·运维·服务器·消费者·生产者·生产者消费者模型
渗透测试老鸟-九青1 小时前
我与红队:一场网络安全实战的较量与成长
运维·服务器·网络·经验分享·安全·web安全·代码审计
一碗手擀面1 小时前
docker镜像发布的应用程序,其配置https的流程
docker·容器·https
Albert XUU2 小时前
nettrace rtt分析器
linux·运维·网络·网络协议·网络安全·腾讯云·运维开发
追风林2 小时前
mac 本地 docker 安装 kafka
macos·docker·kafka
小小的木头人2 小时前
CentOS 8 更换软件源
linux·运维·centos
珹洺3 小时前
数据库系统概论(三)数据库系统的三级模式结构
java·运维·服务器·数据库·oracle
正经教主3 小时前
【菜鸟飞】Conda安装部署与vscode的结合使用
运维·vscode·python·conda
刊wo3 小时前
Websoft9 运维面板,全网真正的一键部署应用
运维