2. 使用Docker容器化机器学习模型
任务目标
将训练好的机器学习模型(以scikit-learn的LogisticRegression为例)打包为Docker镜像,实现模型服务的容器化部署。通过HTTP接口接收推理请求并返回预测结果,验证容器内外调用一致性。
环境与依赖
- Docker Engine 20.10+(本机已安装并启动)
- Python 3.9+(仅用于本地生成模型文件,容器内自带运行时)
- 依赖库:
scikit-learn==1.3.0、pandas==2.0.3、flask==2.3.3、joblib==1.3.2
实现步骤
整体分为三步:训练并导出模型文件 → 编写Flask推理服务与Dockerfile → 构建镜像并运行容器验证。
1. 生成模型文件(本地执行)
在项目目录下创建 train_model.py,运行后生成 model.joblib。使用鸢尾花数据集训练一个简化分类器,仅保留前两个特征以减小模型体积。
# train_model.py
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
import joblib
X, y = load_iris(return_X_y=True)
X = X[:, :2] # 仅用前两个特征,简化演示
model = LogisticRegression(max_iter=200)
model.fit(X, y)
joblib.dump(model, "model.joblib")
print("模型已保存为 model.joblib")
2. 创建推理服务与Dockerfile
在项目目录下创建 app.py,提供 /predict 接口接收JSON格式的特征数组,返回预测类别。
# app.py
from flask import Flask, request, jsonify
import joblib
import numpy as np
app = Flask(__name__)
model = joblib.load("/app/model.joblib")
@app.route("/predict", methods=["POST"])
def predict():
data = request.get_json()
features = np.array(data["features"]).reshape(1, -1)
pred = model.predict(features)[0]
return jsonify({"prediction": int(pred)})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
创建 Dockerfile,使用轻量级Python基础镜像,复制模型与代码并安装依赖。
# Dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY model.joblib /app/
COPY app.py /app/
RUN pip install flask==2.3.3 joblib==1.3.2 scikit-learn==1.3.0 numpy==1.24.3
EXPOSE 5000
CMD ["python", "app.py"]
3. 构建与运行
在项目目录下依次执行以下命令:
# 1. 生成模型文件
python train_model.py
# 2. 构建镜像
docker build -t ml-model-server .
# 3. 运行容器(映射宿主机8080端口)
docker run -d -p 8080:5000 --name ml-server ml-model-server
验证方法
容器启动后,向宿主机8080端口发送推理请求,观察返回结果是否符合预期。
# 发送测试请求(使用鸢尾花样本特征)
curl -X POST http://localhost:8080/predict \
-H "Content-Type: application/json" \
-d '{"features": [5.1, 3.5]}'
预期输出:
{"prediction":0}
通过条件:
- curl命令返回HTTP 200且JSON中包含
prediction字段; - 预测值在0、1、2范围内(对应鸢尾花三种类别);
- 执行
docker logs ml-server无报错堆栈。
常见问题
- 端口冲突:若8080被占用,改用其他宿主机端口并同步修改curl命令。
- 模型文件缺失:构建前必须确认
model.joblib已生成,否则容器启动即报错。 - 依赖版本不一致:本地训练与容器内推理需使用相同版本的scikit-learn,否则可能加载失败。