4. Docker容器化部署:Dockerfile编写、镜像构建与优化、docker-compose编排多服务
说实话,量化策略的部署,最头疼的就是环境问题。
你想想看,策略在本地跑得好好的,一上服务器就各种报错。Python版本不对,依赖包冲突,系统库缺失……我早期做实盘的时候,光折腾环境就花了大半天。后来用了Docker,这些问题基本都解决了。
这一章,我就把Docker容器化部署的核心经验分享给你。包括怎么写Dockerfile、怎么构建和优化镜像、怎么用docker-compose编排多服务。
核心思路:把策略和它的运行环境打包成一个“集装箱”。不管搬到哪台机器上,开箱即用。
4.1 Dockerfile编写:从零开始打包你的策略
Dockerfile说白了就是一个“菜谱”。告诉Docker怎么一步步做出你的策略镜像。
我个人习惯,写Dockerfile之前先想清楚三件事:
- 基础镜像选什么?——Python官方镜像还是精简版?
- 依赖怎么装?——系统库、Python包、C扩展
- 策略代码放哪?——目录结构、配置文件
来看一个典型的量化策略Dockerfile:
# 1. 选择基础镜像
FROM python:3.9-slim-buster
# 2. 设置工作目录
WORKDIR /app
# 3. 安装系统依赖(ta-lib等C库需要)
RUN apt-get update && apt-get install -y \
build-essential \
libta-lib0 \
libta-lib-dev \
&& rm -rf /var/lib/apt/lists/*
# 4. 复制依赖文件并安装Python包
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 5. 复制策略代码
COPY . .
# 6. 设置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 7. 启动命令
CMD ["python", "main.py"]
小技巧:把requirements.txt单独复制,是为了利用Docker的层缓存。代码改了,依赖不用重装。我见过很多新手把COPY . .写在前面,每次改代码都要重新装一遍依赖,太慢了。
4.2 镜像构建与优化:让镜像更小、更快
镜像太大,传输慢、启动慢。我早期构建的镜像有1.2GB,部署到服务器要等好几分钟。后来优化到200MB左右,体验完全不一样。
4.2.1 多阶段构建
这是我最常用的优化手段。说白了就是:编译阶段用一个“大”镜像,运行阶段用另一个“小”镜像。
# 第一阶段:编译
FROM python:3.9-slim-buster AS builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 第二阶段:运行
FROM python:3.9-slim-buster
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/site-packages
COPY . .
CMD ["python", "main.py"]
你看,编译阶段的中间产物(比如C扩展的编译文件)不会带到最终镜像里。镜像体积能减少40%以上。
4.2.2 层数优化
Docker镜像是由一层层文件系统叠加的。层数越多,构建和拉取越慢。
我建议:
- 把多个
RUN命令合并成一个,用&&连接 - 清理不必要的缓存文件(比如
apt-get clean、pip --no-cache-dir) - 不经常变的内容放前面,经常变的内容放后面
注意:别为了合并而合并。如果某个RUN步骤经常变,单独写反而更好。因为Docker会缓存每一层,单独写可以复用前面的缓存。
4.2.3 使用.dockerignore
这个文件很多人忽略。它告诉Docker:哪些文件不要打包进镜像。
# .dockerignore
.git
__pycache__
*.pyc
*.pyo
*.pyd
.Python
env/
venv/
*.log
data/
config_local.yaml
我曾经见过一个同事,把整个.git目录(几百MB)打包进了镜像。嗯,那镜像能不胖吗?
4.3 docker-compose编排多服务:让策略、数据库、监控协同工作
量化实盘很少只有一个服务。通常有:
- 策略服务:跑核心策略逻辑
- 数据服务:行情数据、历史数据
- 数据库:存储交易记录、配置
- 监控服务:日志收集、告警
docker-compose就是用来编排这些服务的。一个docker-compose.yml文件,搞定所有。
version: '3.8'
services:
# 策略服务
strategy:
build: ./strategy
container_name: quant_strategy
restart: always
depends_on:
- redis
- postgres
environment:
- TZ=Asia/Shanghai
- DB_HOST=postgres
- REDIS_HOST=redis
volumes:
- ./logs:/app/logs
- ./config:/app/config
networks:
- quant_net
# 行情数据服务
datafeed:
image: python:3.9-slim-buster
container_name: quant_datafeed
restart: always
command: python data_feed.py
volumes:
- ./datafeed:/app
- ./data:/data
networks:
- quant_net
# Redis(缓存、消息队列)
redis:
image: redis:6-alpine
container_name: quant_redis
restart: always
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- quant_net
# PostgreSQL(持久化存储)
postgres:
image: postgres:13-alpine
container_name: quant_postgres
restart: always
environment:
POSTGRES_DB: quantdb
POSTGRES_USER: quantuser
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- pg_data:/var/lib/postgresql/data
networks:
- quant_net
# 监控服务(Prometheus + Grafana)
prometheus:
image: prom/prometheus
container_name: quant_prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
networks:
- quant_net
grafana:
image: grafana/grafana
container_name: quant_grafana
ports:
- "3000:3000"
depends_on:
- prometheus
networks:
- quant_net
volumes:
redis_data:
pg_data:
networks:
quant_net:
driver: bridge
关键点:
depends_on控制启动顺序,但不等服务就绪。我建议在策略代码里加重试逻辑volumes挂载日志和配置,方便调试和持久化networks让服务之间通过服务名通信,不用记IP- 敏感信息(如数据库密码)用环境变量或
.env文件,别写死在yml里
4.4 避坑指南:我踩过的那些坑
做量化容器化部署这几年,我踩过不少坑。分享几个典型的:
我曾经……把数据库密码直接写在docker-compose.yml里,然后不小心提交到了GitHub。第二天发现有人连上了我的数据库。从那以后,我所有敏感信息都用.env文件,并且加到.gitignore里。
坑一:时区问题
Docker容器默认是UTC时间。量化策略如果按本地时间交易,订单时间会错乱。记得在Dockerfile里设置TZ=Asia/Shanghai。
坑二:日志不持久化
容器重启后,日志就没了。排查问题的时候特别痛苦。一定要用volumes把日志目录挂载出来。
坑三:资源限制
多个容器跑在同一台机器上,可能会互相抢资源。我建议在docker-compose里加上资源限制:
services:
strategy:
deploy:
resources:
limits:
cpus: '2'
memory: 4G
reservations:
cpus: '1'
memory: 2G
坑四:镜像版本管理
别用latest标签。我建议用v1.0.0这样的语义化版本,或者加上Git commit hash。这样回滚的时候才知道哪个版本是稳定的。
4.5 部署与运维小贴士
最后,分享几个我日常用的命令和习惯:
| 场景 | 命令 | 说明 |
|---|---|---|
| 构建镜像 | docker build -t quant-strategy:v1.0 . |
打上版本标签 |
| 启动所有服务 | docker-compose up -d |
后台运行 |
| 查看日志 | docker-compose logs -f strategy |
实时跟踪策略日志 |
| 重启单个服务 | docker-compose restart strategy |
不用重启全部 |
| 进入容器调试 | docker exec -it quant_strategy bash |
排查问题用 |
| 清理无用镜像 | docker image prune -a |
释放磁盘空间 |
我的习惯:每次部署前,先在本地用docker-compose up跑一遍,确认所有服务都能正常启动。别直接推到生产环境,那太冒险了。
好了,Docker容器化部署的核心内容就这些。从Dockerfile编写,到镜像优化,再到多服务编排,每一步都有讲究。你按这个思路去实践,量化策略的部署会变得非常顺畅。
公众号:蓝海资料掘金营,微信deep3321