纲要

  • 容器化部署的意义
  • 核心概念
    • Docker 镜像与容器
    • Docker Compose 多服务编排
    • 服务间内部网络通信与 DNS 解析
    • 数据卷 volumes 持久化
  • 项目部署文件拆解
    • docker-compose.yml 服务定义
    • Dockerfile 构建指令
    • 多进程启动脚本 start.sh
  • 完整可运行示例
    • 项目结构
    • 应用主程序 app/main.py(基于 FastAPIRedis 交互)
    • 依赖文件 requirements.txt
    • Dockerfile 构建配置
    • docker-compose.yml 编排配置
    • 启动、验证与常用运维命令
  • 总结

容器化部署的意义

在 AI Agent 类项目的实际落地过程中,通常需要依赖多个外部服务,例如:大模型 API 网关、向量数据库(如 Chroma、Milvus)、记忆存储组件(如 Redis)、消息队列(如 RabbitMQ)以及各种开放平台 Webhook 回调等。传统的部署方式要求在目标服务器上逐一安装、配置并启动这些组件,不仅操作繁琐,而且极易因为操作系统版本、依赖库冲突、环境变量差异等因素导致 “本地运行正常,上线后报错” 的经典困境。

Docker 技术通过将应用及其完整的运行环境(包括系统工具、依赖库、配置文件)打包为镜像,从根本上保证了开发、测试与生产环境的高度一致性。而 Docker Compose 则在此基础上进一步解决了多服务编排的难题,允许运维与开发人员使用一个统一的 YAML 文件定义整个技术栈的构成、网络规则与存储策略,从而实现一键启动与停止。

以下是容器化部署流程与传统部署流程的对比示意:

Docker Compose 部署

编写 Dockerfile

编写 docker-compose.yml

执行 docker compose up

自动拉取镜像/构建

一键启动所有服务

传统部署

安装操作系统依赖

配置环境变量

安装数据库/缓存

手动修改配置文件

启动应用进程

Docker 与 Docker Compose 核心概念精析

在深入配置文件之前,有必要对齐几个关键的基础概念,这对于后续自行扩展配置文件至关重要。

  • 镜像 (Image):一个只读的静态文件,包含了运行某个应用所需的所有内容——代码、运行时、系统工具、库和设置。可以将其类比为面向对象编程中的“类”。
  • 容器 (Container):镜像的运行态实例。每个容器默认运行在相互隔离的环境中,通过宿主机端口映射或自定义网络进行通信。可以类比为“对象”。
  • Docker Compose:一个用于定义和运行多容器 Docker 应用的工具。通过一个 YAML 文件,你可以配置应用需要的所有服务,然后通过一条命令创建并启动所有服务。
  • 服务名解析 (Service Name Resolution):在 Docker Compose 定义的同一个自定义网络中,服务名(如 redisdb)会被自动注册为内部 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_dataapp_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 项目的容器化部署,系统性地介绍了 DockerDocker Compose 的核心概念与实践方法。通过 Dockerfile 固化应用运行环境,借助 docker-compose.yml 实现 Redis 记忆存储与 FastAPI 应用服务的编排与联动,并利用 Compose 的内部 DNS 机制简化了服务间通信配置。此外,还通过数据卷实现了日志与缓存数据的持久化,通过多进程启动脚本解决了单容器多任务的临时需求。

本文覆盖的技术栈要点包括但不限于:Docker 镜像与容器基础、Docker Compose 服务编排语法、自定义桥接网络下的服务名解析、volumes 数据卷声明与挂载、depends_on 启动顺序控制、Python 应用中通过环境变量解耦配置、FastAPIRedis 的集成模式,以及 docker compose 常用运维命令。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐