2. 初始化Git仓库与项目结构

任务目标

将训练好的机器学习模型(以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,否则可能加载失败。
本地环境 train_model.py 训练 + 导出 model.joblib + app.py + Dockerfile docker build 构建 Docker容器 ml-model-server 镜像: python:3.9-slim Flask 服务 端口 5000 docker run -p 8080:5000 请求 curl 客户端 POST /predict localhost:8080