AI Agent从无到有59: 容器化部署——用 Docker Compose 打包多服务应用
纲要
- 容器化部署的意义
- 核心概念
Docker镜像与容器Docker Compose多服务编排- 服务间内部网络通信与
DNS解析 - 数据卷
volumes持久化
- 项目部署文件拆解
docker-compose.yml服务定义Dockerfile构建指令- 多进程启动脚本
start.sh
- 完整可运行示例
- 项目结构
- 应用主程序
app/main.py(基于FastAPI与Redis交互) - 依赖文件
requirements.txt Dockerfile构建配置docker-compose.yml编排配置- 启动、验证与常用运维命令
- 总结
容器化部署的意义
在 AI Agent 类项目的实际落地过程中,通常需要依赖多个外部服务,例如:大模型 API 网关、向量数据库(如 Chroma、Milvus)、记忆存储组件(如 Redis)、消息队列(如 RabbitMQ)以及各种开放平台 Webhook 回调等。传统的部署方式要求在目标服务器上逐一安装、配置并启动这些组件,不仅操作繁琐,而且极易因为操作系统版本、依赖库冲突、环境变量差异等因素导致 “本地运行正常,上线后报错” 的经典困境。
Docker 技术通过将应用及其完整的运行环境(包括系统工具、依赖库、配置文件)打包为镜像,从根本上保证了开发、测试与生产环境的高度一致性。而 Docker Compose 则在此基础上进一步解决了多服务编排的难题,允许运维与开发人员使用一个统一的 YAML 文件定义整个技术栈的构成、网络规则与存储策略,从而实现一键启动与停止。
以下是容器化部署流程与传统部署流程的对比示意:
Docker 与 Docker Compose 核心概念精析
在深入配置文件之前,有必要对齐几个关键的基础概念,这对于后续自行扩展配置文件至关重要。
- 镜像 (Image):一个只读的静态文件,包含了运行某个应用所需的所有内容——代码、运行时、系统工具、库和设置。可以将其类比为面向对象编程中的“类”。
- 容器 (Container):镜像的运行态实例。每个容器默认运行在相互隔离的环境中,通过宿主机端口映射或自定义网络进行通信。可以类比为“对象”。
- Docker Compose:一个用于定义和运行多容器
Docker应用的工具。通过一个 YAML 文件,你可以配置应用需要的所有服务,然后通过一条命令创建并启动所有服务。 - 服务名解析 (Service Name Resolution):在
Docker Compose定义的同一个自定义网络中,服务名(如redis、db)会被自动注册为内部 DNS 记录。这意味着应用代码中可以直接使用服务名作为主机名,而不需要硬编码IP地址或依赖localhost。 - 数据卷 (Volumes):用于实现数据的持久化与共享。它将宿主机文件系统中的目录或命名卷挂载到容器内部,使得容器重建或删除时,关键数据(如数据库文件、应用日志)不会丢失。
项目部署配置详解
以一个典型的 AI Agent 示例项目“智能问答助手”为例,它包含两个核心服务:app(基于 FastAPI 的智能体应用)和 redis(用于存储对话记忆与缓存)。下面逐一拆解完整的配置文件。
项目结构
以下是推荐的项目文件布局,所有部署相关的资源均集中在 deploy_project 目录下:
deploy_project/
├── app/
│ ├── main.py # FastAPI 主应用
│ └── requirements.txt # Python 依赖
├── start.sh # 容器启动脚本
├── Dockerfile # 镜像构建文件
├── docker-compose.yml # 服务编排文件
└── .env # 环境变量(可选,通常不提交至 Git)
docker-compose.yml 服务编排详解
该文件定义了两个服务,共享一个桥接网络,并分别挂载数据卷以保证数据持久化。
version: '3.8'
services:
# Redis 缓存与记忆存储服务
redis:
image: redis:7-alpine # 使用官方轻量级镜像
container_name: xiaolang-redis # 固定容器名,便于识别
restart: always # 异常退出时自动重启
ports:
- "6379:6379" # 映射宿主机端口,便于本地调试
volumes:
- redis_data:/data # 挂载命名卷,持久化 RDB/AOF 数据
networks:
- app_network
# 适用版本: Docker Compose >= 1.29, Docker Engine >= 20.10
# 自定义智能体应用服务
app:
build: . # 基于当前目录的 Dockerfile 构建
container_name: xiaolang-app
restart: always
depends_on:
- redis # 显式声明依赖,确保 Redis 先启动
ports:
- "8000:8000" # 暴露 API 端口
environment:
- REDIS_URL=redis://redis:6379/0 # 利用 Compose DNS,直接使用服务名
- PYTHONUNBUFFERED=1 # 确保 Python 日志实时输出
volumes:
- app_logs:/app/logs # 挂载日志目录,方便查看持久化日志
networks:
- app_network
# 声明数据卷
volumes:
redis_data: # Docker 管理的命名卷,独立于容器生命周期
app_logs:
# 声明自定义网络
networks:
app_network:
driver: bridge # 默认桥接模式,开启内部 DNS 解析
关键设计细节:
depends_on虽然不保证redis完全就绪(仅控制启动顺序),但对于缓存服务,通常连接重试机制足以应对。REDIS_URL中的主机名redis会被 Compose 内部 DNS 解析为redis容器的虚拟IP,无需修改代码即可实现服务发现。- 定义了两个独立的数据卷
redis_data与app_logs,实现存储与计算的分离。
Dockerfile 构建指令解读
Dockerfile 描述了从基础镜像到可运行容器的构建步骤。此处选用 python:3.11-slim 作为基础镜像,兼顾体积与功能。
# 适用版本: Docker Engine >= 18.06
FROM python:3.11-slim
# 设置工作目录
WORKDIR /app
# 安装系统依赖(如 curl 用于健康检查,可根据需要增减)
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
# 复制依赖清单并安装 Python 包
COPY app/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码与启动脚本
COPY app/ ./app/
COPY start.sh .
# 赋予启动脚本可执行权限
RUN chmod +x start.sh
# 声明容器运行时监听的端口
EXPOSE 8000
# 设置默认启动命令
CMD ["./start.sh"]
多进程启动脚本 start.sh
在某些场景下,同一个容器中可能需要运行多个进程(例如:主 API 服务 + 后台文档更新服务)。虽然更推荐的模式是“一个容器一个进程”,但在 MVP(最小可行产品)阶段或资源受限时,借助脚本管理是实用的策略。
#!/bin/bash
set -e # 任何命令失败则退出脚本
cd /app/app
# 启动 FastAPI 主服务(后台运行)
python main.py &
# 如果有额外的辅助服务(例如文档索引更新),可在此取消注释
# python doc_updater.py &
# 等待所有后台进程结束(若主进程退出,容器将退出)
wait
应用代码 app/main.py:集成 Redis 记忆功能
以下 FastAPI 应用代码演示了如何通过环境变量获取 Redis 连接地址,并利用 Redis 提供简单的键值记忆读写能力。代码中不包含任何硬编码的主机名,完全依赖运行时的环境注入。
# 适用版本: Python 3.9+, fastapi >= 0.100.0, redis-py >= 4.5.0
import os
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import redis
app = FastAPI(title="AI Agent Memory Service")
# 从环境变量读取 Redis URL,若未设置则使用默认值(仅用于本地兜底)
REDIS_URL = os.getenv("REDIS_URL", "redis://localhost:6379/0")
r = redis.from_url(REDIS_URL)
class MemoryItem(BaseModel):
key: str
value: str
@app.get("/")
async def root():
return {"message": "AI Agent 服务已成功启动", "status": "healthy"}
@app.get("/memory/{key}")
async def get_memory(key: str):
"""获取指定键的记忆值"""
value = r.get(key)
if value is None:
return {"key": key, "value": None, "found": False}
return {"key": key, "value": value.decode("utf-8"), "found": True}
@app.post("/memory/{key}")
async def set_memory(key: str, value: str):
"""设置键值对到记忆缓存"""
r.set(key, value)
return {"key": key, "value": value, "status": "stored"}
@app.delete("/memory/{key}")
async def delete_memory(key: str):
"""删除指定的记忆键"""
deleted_count = r.delete(key)
return {"key": key, "deleted": deleted_count > 0}
依赖文件 app/requirements.txt:
fastapi==0.115.0
uvicorn[standard]==0.30.0
redis==5.0.0
启动、验证与日常运维
在项目根目录(即 docker-compose.yml 所在目录)执行以下命令:
# 构建镜像并后台启动所有服务
docker compose up -d --build
# 查看服务运行状态
docker compose ps
# 查看实时日志(组合输出)
docker compose logs -f
# 仅查看 app 服务的日志
docker compose logs -f app
服务启动后,可以通过 curl 或浏览器验证 API 功能:
# 测试根路径
curl http://localhost:8000/
# 写入记忆数据
curl -X POST "http://localhost:8000/memory/user_123?value=Hello%20Agent"
# 读取记忆数据
curl http://localhost:8000/memory/user_123
# 预期输出: {"key":"user_123","value":"Hello Agent","found":true}
若需要停止并清理所有资源(包括数据卷,请谨慎操作):
docker compose down -v
参考文档
-
官方文档
-
参考链接
总结
本文围绕 AI Agent 项目的容器化部署,系统性地介绍了 Docker 与 Docker Compose 的核心概念与实践方法。通过 Dockerfile 固化应用运行环境,借助 docker-compose.yml 实现 Redis 记忆存储与 FastAPI 应用服务的编排与联动,并利用 Compose 的内部 DNS 机制简化了服务间通信配置。此外,还通过数据卷实现了日志与缓存数据的持久化,通过多进程启动脚本解决了单容器多任务的临时需求。
本文覆盖的技术栈要点包括但不限于:Docker 镜像与容器基础、Docker Compose 服务编排语法、自定义桥接网络下的服务名解析、volumes 数据卷声明与挂载、depends_on 启动顺序控制、Python 应用中通过环境变量解耦配置、FastAPI 与 Redis 的集成模式,以及 docker compose 常用运维命令。
更多推荐



所有评论(0)