Reflex 双端口 Docker 生产部署实战:Node 前端与 Gunicorn 后端架构解析

发布时间:2026/9/11 8:48:38
Reflex 双端口 Docker 生产部署实战:Node 前端与 Gunicorn 后端架构解析 Reflex 双端口 Docker 生产部署实战Node 前端与 Gunicorn 后端架构解析【免费下载链接】reflex️ Web apps in pure Python 项目地址: https://gitcode.com/GitHub_Trending/re/reflex本指南以 Reflex 仓库中 simple-two-port 示例 为核心完整讲解如何在单个 Docker 容器内以生产模式prod运行一个 Reflex 应用由 Node/Vite 服务器在3000端口提供优化后的前端构建由 Python Gunicorn 服务器在8000端口托管后端并内置本地 Redis 承担用户状态存储。读完本文你将掌握该部署方式的 Dockerfile 构建流程、双端口路由原理、Caddy 反向代理配置、状态持久化方案以及 Reflex 底层源码中后端服务器与状态管理器的选择逻辑可直接复用到自己的 Reflex 项目生产部署中。部署架构总览一台容器、两个 HTTP 端口simple-two-port 的核心思想是在生产模式下把 Reflex 应用的前端与后端分别暴露为两个独立的 HTTP 端口交由容器外部的负载均衡器或反向代理按路由规则分发流量。┌──────────────────────────── 容器 ────────────────────────────┐ │ │ │ :3000 ┌──────────────────────────────────┐ │ │ ─────► │ Node / Vite 服务器 │ │ │ │ 前端优化生产构建静态资源 │ │ │ └──────────────────────────────────┘ │ │ │ │ :8000 ┌──────────────────────────────────┐ ┌───────────┐ │ │ ─────► │ Python Gunicorn 服务器后端 │◄─┤ Redis │ │ │ │ 事件处理、状态管理、数据库 │ │用户状态│ │ │ └──────────────────────────────────┘ └───────────┘ │ └──────────────────────────────────────────────────────────────┘3000—— Node 服务器使用优化后的生产构建optimized production build提供前端页面与静态资源8000—— Python Gunicorn 服务器承载 Reflex 后端处理事件/_event/*、健康检查/ping、文件上传/_upload等请求容器内还运行一个本地 Redis 服务器用于为每个用户存储会话状态。这种双端口模式适合已有负载均衡器/反向代理负责 TLS 终止与流量分发的部署环境例如自建 VPS 配合 Nginx、Caddy、Traefik或云厂商的 LB 服务。若你的运行平台只允许暴露单个端口可参考仓库中的 simple-one-port 示例那里使用 Caddy 在同一端口上同时托管静态前端并代理后端请求。Dockerfile 逐步解析从基础镜像到可运行的生产镜像完整的 Dockerfile 位于 docker-example/simple-two-port/Dockerfile以下是各阶段的要点拆解。1. 基础镜像与运行时依赖FROM python:3.13 RUN apt-get update apt-get install -y redis-server rm -rf /var/lib/apt/lists/* ENV REFLEX_REDIS_URLredis://localhost PYTHONUNBUFFERED1基于python:3.13官方镜像容器内同时承担 Python 后端与 Node 前端构建前端编译过程需要 Node.js由 Reflex 的安装流程提供通过 apt 安装redis-server为后续的本地状态存储做准备两个关键环境变量REFLEX_REDIS_URLredis://localhost告诉 Reflex 使用本机 Redis。从源码看该变量在 reflex/utils/prerequisites.py 的parse_redis_url()中被解析且值必须以redis://、rediss://或unix://开头否则会抛出ValueErrorPYTHONUNBUFFERED1保证 Python 日志实时输出到 stdout便于容器日志采集。2. 拷贝代码与安装依赖WORKDIR /app COPY . . RUN pip install -r requirements.txt将当前目录含rxconfig.py、应用代码、requirements.txt、.dockerignore过滤后的文件拷贝到容器内的/app安装应用依赖。注意 docker-example/README.md 的全局要求requirements.txt必须保持最新并且包含reflex包否则构建或运行会失败。3. 初始化与前端生产构建RUN reflex init RUN reflex export --frontend-only --no-zipreflex init生成/补齐模板文件准备应用结构reflex export --frontend-only --no-zip下载全部 npm 依赖并编译前端产出优化后的生产构建产物。这里不打包为 zip而是将构建结果保留在工作目录中供运行时由 Node 服务器直接提供。4. 进程信号与启动命令STOPSIGNAL SIGKILL CMD [ -d alembic ] reflex db migrate; \ redis-server --daemonize yes \ exec reflex run --env prodSTOPSIGNAL SIGKILL在 Reflex 后端尚未正确处理 SIGTERM 之前强制容器停止时直接以 SIGKILL 终止进程避免优雅关闭流程卡死导致容器无法退出Dockerfile 注释明确说明了这一临时性原因启动时依次执行若存在alembic目录先执行reflex db migrate应用数据库迁移以守护进程方式启动本地redis-serverexec reflex run --env prod以生产模式启动应用——由于未传--backend-only或--frontend-onlyReflex 会同时启动前端Node 服务器监听3000与后端Gunicorn监听8000。构建与运行两条命令完成部署在应用根目录含 Dockerfile 的目录执行docker build -t reflex-simple-two-port .构建成功后运行docker run -p 3000:3000 -p 8000:8000 reflex-simple-two-port-p参数将容器内的3000、8000端口分别映射到宿主机同名端口浏览器访问http://宿主机IP:3000即可看到前端页面。反向代理与 TLS 终止Caddy 配置详解该容器自身不处理 TLS应置于负载均衡器/反向代理之后。README 给出了一个可直接使用的 Caddyfile 示例my-domain.com encode gzip backend_routes path /_event/* /ping /_upload /_upload/* handle backend_routes { reverse_proxy localhost:8000 } reverse_proxy localhost:3000逐段说明my-domain.com站点地址Caddy 会自动为其申请并续期 TLS 证书终止 TLS 的角色由反向代理承担encode gzip对所有响应启用 gzip 压缩减少前端资源与事件响应的传输体积backend_routes path /_event/* /ping /_upload /_upload/*定义后端路由集合——/_event/*是 Reflex 的事件处理端点/ping是健康检查端点/_upload是文件上传端点这些请求必须被转发到8000后端handle backend_routes { reverse_proxy localhost:8000 }上述路径统一代理到后端 Gunicornreverse_proxy localhost:3000其余所有请求页面、静态资源代理到前端 Node 服务器。若你使用 Nginx、Traefik 或其他代理路由规则的核心同样是把/_event/*、/ping、/_upload*与其余流量分开前者指向8000后者指向3000。状态持久化与数据生命周期README 明确提示该容器没有持久化容器停止后所有数据都会丢失。需要保留的数据通常包括数据库文件应用使用的 SQLite 数据库位于database相关目录uploaded_files目录中的用户上传文件。解决方案是使用bind mounts 或 named volumes挂载这两个目录例如docker run -p 3000:3000 -p 8000:8000 \ -v $(pwd)/data:/app/data \ -v $(pwd)/uploaded_files:/app/uploaded_files \ reflex-simple-two-port具体挂载路径需与应用实际配置的数据目录一致可按需调整。至于用户会话状态由于REFLEX_REDIS_URL已指向容器内的本地 Redis状态本身保存在 Redis 中Redis 同样不持久化如果需要跨容器重启保留会话可进一步将 Redis 替换为外部托管实例或为 Redis 配置持久化。源码视角Reflex 如何选择后端服务器与状态管理器状态管理检测到 Redis 后自动切换在 reflex/istate/manager/init.py 的StateManager.create()中可以看到当配置中未显式设置state_manager_mode且parse_redis_url()返回非空值时Reflex 会自动把状态管理器切换为REDIS模式并基于redis_token_expiration、redis_lock_expiration、redis_lock_warning_threshold等配置项构造StateManagerRedis。这正是本示例设置REFLEX_REDIS_URL后各用户状态能够存放于 Redis 的底层原因。后端服务器Gunicorn 的默认调用与参数覆盖在 reflex/utils/exec.py 的run_uvicorn_backend_prod()中Reflex 在生产模式下以如下方式启动 Gunicornpython -m gunicorn --preload \ --worker-class uvicorn.workers.UvicornH11Worker \ --threads worker数 \ --bind 0.0.0.0:8000 \ --log-level loglevel \ app_module()采用uvicorn.workers.UvicornH11Worker作为 worker 类即以 ASGI 方式处理请求通过GUNICORN_CMD_ARGS环境变量可追加/覆盖默认参数环境变量参数优先级更高从 exec.py 的should_use_granian()还可以看到当镜像中既未安装uvicorn也未安装gunicorn时Reflex 会自动回退到 Granian 作为后端服务器。也就是说README 中所说的 Python gunicorn server 是默认路径实际运行的后端服务器取决于镜像内安装的依赖生产环境应通过requirements.txt固定。与其他 Docker 部署模式对比仓库 docker-example/README.md 汇总了四种部署方式simple-two-port 是其中最基础的形态示例端口形态前端提供方式适用场景simple-two-port双端口3000 8000Node/Vite 生产构建服务器已有负载均衡器/反向代理的通用生产环境simple-one-port单端口默认 8080Caddy 托管静态前端导出 代理后端仅支持单端口、或内存受限的平台Render、Heroku 等production-compose多服务编排独立 Web 服务器单台 VPS 自托管完整栈含 Redis、PostgreSQLproduction-app-platform平台托管静态前端 独立托管后端Azure、AWS、Google Cloud Run 等 App 托管平台选择建议如果你的平台只开放一个端口或希望省去 Node 进程以节省内存优先考虑 simple-one-port如果追求单机自托管且需要完整的数据库与 Web 服务器栈则直接使用 production-composesimple-two-port 更适合已有网关、只差容器化应用的接入式部署。常见问题与注意事项不要忘记reflex依赖requirements.txt必须包含reflex且版本应与本地开发环境一致避免构建出的镜像行为与预期不符停止时数据丢失是预期行为数据库与上传目录务必通过卷或挂载持久化Redis 会话状态亦然不要直接在容器上暴露 TLSTLS 终止交给外部的 Caddy/Nginx/负载均衡器容器只负责按端口提供 HTTP 服务健康检查可用/ping端点后端 8000 端口做容器健康探活确认后端就绪后再接入流量镜像体积前端构建产物.web与 npm 依赖会显著增大镜像体积若追求更小镜像可参考 simple-one-port 中导出静态文件后清理.web的做法或改用多阶段构建。至此你已经掌握了 Reflex 双端口 Docker 生产部署的完整链路理解了两端口各自的职责、Dockerfile 的构建阶段、反向代理路由规则、持久化方案以及 Reflex 源码中状态管理器与后端服务器的自动选择逻辑足以在此基础上按需定制自己的生产镜像。【免费下载链接】reflex️ Web apps in pure Python 项目地址: https://gitcode.com/GitHub_Trending/re/reflex创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考