LLM Zoomcamp 监控模块:用 Docker Compose 一键编排 Streamlit + PostgreSQL + Grafana
LLM Zoomcamp 监控模块用 Docker Compose 一键编排 Streamlit PostgreSQL Grafana【免费下载链接】llm-zoomcampLLM Zoomcamp - a free online course about real-life applications of LLMs. In 10 weeks you will learn how to build an AI system that answers questions about your knowledge base. Register here 项目地址: https://gitcode.com/GitHub_Trending/ll/llm-zoomcamp本指南来自 LLM Zoomcamp 2026 届 05-monitoring监控模块 的第 13 课讲解如何用 Docker Compose 将监控 RAG 应用所需的三个服务——Streamlit 聊天应用、PostgreSQL 数据库与 Grafana 可视化平台——统一编排进一条命令。读者学完后将能写出完整的 Dockerfile、Compose 配置与环境变量文件一键启动/停止整套监控栈并理解 Compose 默认网络与命名卷如何让服务互通且数据跨重启持久化。为什么需要 Docker Compose从三条命令到一条命令在前面的课程中监控栈的三个组件是分别手工启动的PostgreSQL 用docker run起容器见 Makefile 中的postgrestargetGrafana 与 Streamlit 各自运行。这种方式的痛点很快显现要记住自定义网络三个服务必须处于同一 Docker 网络中才能互相通信手工启动时得先docker network create monitoring再逐个--network monitoring要敲冗长的命令PostgreSQL 的启动命令要带用户名、密码、数据库名、端口映射和卷挂载等一大串参数容器名冲突上次启动的容器还在再次启动时 Docker 会报容器名已存在还得先去手动删除。Docker Compose 把三个服务写进一个 YAML 文件自动创建共享网络并一次启动所有服务——你只需要运行一条命令。这正是 Compose 的定位用声明式配置替代重复的手工操作。项目结构本课监控项目采用以下布局对应 code/ 目录code/ ├── docker-compose.yaml # 三个服务的编排文件 ├── Dockerfile # Streamlit 应用镜像 ├── .env # 环境变量数据库凭据、OpenAI 密钥 ├── pyproject.toml # uv 项目依赖定义 ├── uv.lock # 锁定依赖版本 ├── .python-version # Python 版本固定 ├── app.py # Streamlit 聊天应用 ├── assistant.py # RAG 流水线 LLM 调用 ├── db_init.py # 数据库表初始化 ├── db_save.py # 保存对话记录 └── dashboard.py # Streamlit 指标看板其中docker-compose.yaml、Dockerfile与.env是本课的核心产出app.py、assistant.py、db_init.py、db_save.py、dashboard.py是前序课程已经写好的业务代码Compose 把它们包成可一键运行的完整系统。Dockerfile为 Streamlit 应用构建容器Streamlit 应用需要自己的容器镜像Dockerfile 采用uv作为 Python 依赖管理工具FROM python:3.12-slim COPY --fromghcr.io/astral-sh/uv:latest /uv /uvx /bin/ WORKDIR /app ENV PATH/app/.venv/bin:$PATH COPY pyproject.toml uv.lock .python-version ./ RUN uv sync --locked COPY . . CMD [streamlit, run, app.py, --server.port8501, --server.address0.0.0.0]逐行拆解其设计意图指令作用FROM python:3.12-slim基于精简版 Python 3.12 镜像与 pyproject.toml 中requires-python 3.12一致COPY --from...uv:latest /uv /uvx /bin/从 uv 官方镜像复制uv/uvx二进制到容器免去手动安装WORKDIR /appENV PATH...设定工作目录并把虚拟环境 bin 加入 PATH后续uv、streamlit命令可直接调用COPY pyproject.toml uv.lock .python-version ./先只复制依赖清单利用 Docker 层缓存依赖未变时不重复解析RUN uv sync --locked严格按uv.lock安装依赖--locked保证与 lock 文件完全一致避免版本漂移COPY . .复制应用源码放在依赖安装之后源码变更不会破坏依赖层缓存CMD [streamlit, run, ...]容器启动命令运行app.py监听8501端口并绑定0.0.0.0以便容器外访问依赖清单可从 pyproject.toml 核实streamlit1.58.0Web 界面、openai2.40.0LLM 客户端、psycopg[binary]3.3.4PostgreSQL 驱动、minsearch0.1.0RAG 检索索引、python-dotenv1.2.2读取.env以及jupyter、requests。这些正是app.py、assistant.py、db_init.py等脚本运行所需的完整依赖集合。环境变量.env集中管理配置.env文件存放所有可配置项Compose 与业务代码都会读取它POSTGRES_DBcourse_assistant POSTGRES_USERuser POSTGRES_PASSWORDpassword POSTGRES_HOSTpostgres OPENAI_API_KEYyour-key-here这里POSTGRES_HOSTpostgres是关键点它不是 IP 地址而是 Compose 服务名。在 Compose 创建的网络里服务名即 DNS 主机名Streamlit 容器只要写postgres就能连到数据库容器。对比 db_init.py 中get_db_connection()的实现可以看到它用os.getenv(POSTGRES_HOST, localhost)读取该变量默认值是localhost本地直连场景而容器化场景下必须被覆盖为postgres。同理POSTGRES_DB、POSTGRES_USER、POSTGRES_PASSWORD的默认值course_assistant/user/password与.env保持一致。OPENAI_API_KEY会被 assistant.py 中的OpenAI()客户端读取配合python-dotenv的load_dotenv()用于 RAG 问答的 LLM 调用。Docker Compose 编排三个服务一个网络PostgreSQL 与 Grafana 服务Compose 文件定义postgres与grafana两个现成镜像服务version: 3.8 services: postgres: image: postgres:17 environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} ports: - 5432:5432 volumes: - postgres_data:/var/lib/postgresql/data grafana: image: grafana/grafana ports: - 3000:3000 volumes: - grafana_data:/var/lib/grafana environment: - GF_SECURITY_ADMIN_PASSWORDadmin depends_on: - postgres要点说明${POSTGRES_*}变量插值Compose 启动时自动读取同目录.env把POSTGRES_DB等值注入到容器环境变量中实现配置与编排分离端口映射5432:5432把 PostgreSQL 暴露到宿主机方便psql、uv run python db_query.py等本机工具直连3000:3000暴露 Grafana Web 界面命名卷postgres_data、grafana_data是顶层声明的持久化卷。PostgreSQL 数据文件/var/lib/postgresql/data与 Grafana 配置/面板数据/var/lib/grafana都存入卷中容器删除后数据仍在depends_ongrafana声明依赖postgresCompose 会先启动数据库再启动 Grafana注意它只保证启动顺序不保证数据库就绪因此数据初始化仍需单独步骤。Streamlit 服务从 Dockerfile 构建streamlit: build: context: . dockerfile: Dockerfile environment: - POSTGRES_HOSTpostgres - POSTGRES_DB${POSTGRES_DB} - POSTGRES_USER${POSTGRES_USER} - POSTGRES_PASSWORD${POSTGRES_PASSWORD} - OPENAI_API_KEY${OPENAI_API_KEY} ports: - 8501:8501 depends_on: - postgres volumes: postgres_data: grafana_data:与前面两个服务不同streamlit没有image字段而是用build指向 Dockerfile 现场构建镜像。它的环境变量中POSTGRES_HOSTpostgres直接写死为服务名因为只能在 Compose 网络内生效其余四个变量从.env注入。depends_on: postgres确保数据库先启动。文件末尾的volumes块声明两个命名卷供postgres与grafana服务引用。从 db_save.py 的源码可以印证这套配置的实际调用链app.py中每次问答后调用save_conversation(record, user_input, llm-zoomcamp)后者通过get_db_connection()同样读环境变量连接postgres服务把包含 question、answer、token 用量、响应时间、成本等字段的记录写入conversations表db_init.py 中的init_db()/init_feedback()则负责创建这两张表。也就是说Compose 打通了容器网络而数据流Streamlit → PostgreSQL由既有的 Python 代码完成。启动、初始化和停止一键启动全部服务docker-compose up该命令会读取.env→ 构建 Streamlit 镜像 → 拉取postgres:17与grafana/grafana镜像 → 创建共享网络 → 按依赖顺序启动三个容器。加-d可后台运行。初始化数据库容器启动后数据库还是空的需要先建表uv run python db_init.py从 db_init.py 的__main__分支可以看到它会依次执行init_db()和init_feedback()创建conversations表id、question、answer、course、model、instructions、prompt、token 统计、response_time、cost、timestamp 等字段与feedback表conversation_id 外键、source、relevance、explanation、score、timestamp。注意此命令在宿主机上执行uv是宿主机工具通过5432端口映射连到容器内的 PostgreSQL由于db_init.py的环境变量默认值与.env一致localhost/course_assistant/user/password在宿主机上无需额外设置即可连通。访问服务聊天应用http://localhost:8501StreamlitGrafana 看板http://localhost:3000默认登录账号admin / admin密码由GF_SECURITY_ADMIN_PASSWORDadmin指定在 Streamlit 界面提问后回答会连同响应时间、token 用量、成本等指标一起展示见 app.py 的实现同时写入 PostgreSQL你可以在 Grafana 中配置 PostgreSQL 数据源端口5432用 SQL 查询这些数据绘制监控面板。停止服务docker-compose down停止并移除三个容器以及 Compose 自动创建的默认网络。卷不会被删除因此 PostgreSQL 里的对话记录和 Grafana 的看板配置在下次docker-compose up后依然完好——这正是命名卷持久化的价值。手工启动 vs Compose来自 Makefile 的对比本课之前的做法记录在 Makefile 中与 Compose 方案形成鲜明对照network: docker network create monitoring postgres: network docker run -it \ --name course-assistant-pg \ --network monitoring \ -e POSTGRES_USERuser \ -e POSTGRES_PASSWORDpassword \ -e POSTGRES_DBcourse_assistant \ -p 5432:5432 \ -v pgdata:/var/lib/postgresql/data \ postgres:17手工方式需要先创建monitoring网络再启动容器并手动指定网络、环境变量、端口与卷且容器名course-assistant-pg固定——若上次的容器未清理再次运行就会报名称已被占用。而 Compose 文件把这些声明全部固化网络自动创建、服务名即主机名、容器删除由down统一管理。可以推断这正是本课把网络创建从 Makefile 手工命令演进为 Compose 声明式配置的原因把记得怎么做变成看文件就知道怎么做也让新成员能一键复现整套监控环境。小结Docker Compose 用单一docker-compose.yaml声明三个服务自动管理共享网络与启动顺序替代手工docker run.env集中管理数据库凭据与OPENAI_API_KEYCompose 通过${VAR}插值注入容器命名卷postgres_data、grafana_data保证数据跨容器生命周期持久化docker-compose down不会丢失数据启动流程为docker-compose up→uv run python db_init.py初始化表结构 → 访问:8501与:3000。至此本监控模块的完整闭环RAG 问答 → 指标采集 → PostgreSQL 存储 → Grafana 可视化就具备了一条命令启动、一套配置描述、数据持久可查的交付形态后续可在此基础上继续探索 OpenTelemetry、告警等生产级监控能力见 14-next-steps.md。【免费下载链接】llm-zoomcampLLM Zoomcamp - a free online course about real-life applications of LLMs. In 10 weeks you will learn how to build an AI system that answers questions about your knowledge base. Register here 项目地址: https://gitcode.com/GitHub_Trending/ll/llm-zoomcamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →