服务部署:自定义镜像

EAS支持使用自定义镜像的方式来部署模型服务。您可以使用docker镜像来构建自己完整的运行环境,并通过服务存储挂载将模型或代码在运行时挂载至服务实例中。本文介绍使用自定义镜像部署模型服务的详细步骤。

背景信息

在模型服务开发过程中,通常会有较为复杂的业务逻辑,无法通过简单的模型部署的方式实现复杂的业务需求。同时自定义的推理代码对于环境也有较为复杂的依赖,比如需要使用yum install/apt-get install命令在系统目录中安装依赖包等,因此EAS推出了使用自定义镜像的方式来部署模型服务。

您可以通过控制台或客户端工具EASCMD(详情请参见下载并认证客户端)来进行模型服务的部署,本文会分别介绍如何通过这两种方式使用自定义镜像来部署模型服务。

在服务运行过程中,EAS的服务引擎会以Sidecar的方式注入到服务实例中,主要进行流量或系统监控数据的采集,以及对服务请求增加认证信息等。镜像部署支持在镜像中以HTTP、WebSocket、gRPC(HTTP2)三种协议提供API服务。

说明

镜像中使用GRPC协议时需要在服务部署时指定额外参数:"metadata.enable_grpc": true

镜像仓库选择

EAS支持以下两种形式的自定义镜像仓库:

  • 镜像服务ACR。关于如何创建ACR镜像,请参见什么是容器镜像服务ACR

    • 个人版:ACR个人版会在每个区域提供统一的内网地址,例如:registry-vpc.cn-shanghai.aliyuncs.com

      说明

      由于EAS默认不通公网,如果使用个人版镜像仓库部署服务,请使用同区域内网地址来部署。

    • 企业版:ACR企业版有更多高级功能,例如:镜像加速功能按需加载容器镜像

      说明

      企业版镜像内网地址仅在用户VPC中可访问,因此在EAS中拉取ACR企业版内网镜像地址,需要打通EAS到用户VPC的网络,详情请参见配置网络连通

  • 用户自建镜像仓库:如果您在阿里云VPC中使用Harbor自建的镜像仓库,地址仅支持在您的VPC中访问,与ACR企业版类似,需要打通EAS到您的VPC网络,具体操作,请参见配置网络连通

说明

EAS默认不通公网,如需要通过公网拉取镜像仓库,则需要开通公网访问,详情请参见公网连接及白名单配置

镜像仓库认证

使用私有镜像仓库部署时,您需要提供认证信息才能够在EAS中拉取镜像,分如下两种情况:

  • ACR镜像仓库:您在开通EAS中选择授权给EAS之后,对于同账号下的ACR个人版和企业版镜像仓库部署时,无需指定认证信息,EAS可实现跨服务免密拉取。

  • 自建私有镜像仓库:若自建仓库需要用户名密码访问,则在服务部署时需要在服务配置中通过dockerAuth来提供用户名密码信息,详情请参见部署模型服务章节的dockerAuth参数说明。

镜像服务开发

说明

如果您已经有一个开发好的镜像,并能够提供HTTP、WebSocket、gRPC协议的访问,则可跳过该章节,直接进行服务部署。

您可以使用多种方式开发一个镜像服务,例如使用Flask拉起一个Webserver来进行服务访问,示例代码如下。

from flask import Flask
 
app = Flask(__name__)
 
@app.route('/hello/model')
def hello_world():
    return 'Hello World'
 
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000)  

您也可使用EAS提供的高性能服务框架allspark来进行镜像服务的开发,详情请参见:使用Python开发自定义Processor,示例代码如下。

# -*- coding: utf-8 -*-
import allspark


class MyProcessor(allspark.BaseProcessor):
    def initialize(self):
        """
        This function is only executed once when the service starts, 
        and traffic will not be imported until it is completed. 
        It can be used to load models and service initialization.
        """
        pass

    def process(self, data):
        """
        Each time a request is received, this function is called.
        The input parameter of the function is the request body of the HTTP request, 
        and the function returns two parameters: 
        1. the first parameter will be used as the HTTP response body, 
        2. the second parameter is the HTTP response status code.
        """
        data = 'hello eas'

        return bytes(data, encoding='utf8'), 200

if __name__ == '__main__':
    runner = MyProcessor(endpoint='0.0.0.0:8000')
    runner.run()

开发好的代码可以直接通过docker build打包在待部署的镜像中,也可保存在NasGit仓库中,通过存储挂载的方式在运行时挂载进服务实例,详情请参见高级配置:服务存储挂载

部署模型服务

准备工作

  • 准备条件,自定义镜像部署需要如下三要素:

    • 镜像仓库地址,例如:registry-vpc.cn-shanghai.aliyuncs.com/xxx/yyy:zzz

    • 镜像的启动执行命令,例如:/data/eas/ENV/bin/python /data/eas/app.py

    • 镜像中进程监听的网络端口号,例如:8000 。

      说明

      端口号在一些场景中为可选。例如用户服务中不依赖由EAS网关导入的流量,而是用户在镜像中自行通过订阅消息队列的方式获取消息,则此场景中镜像端口号可选填。

  • 部署服务时需准备JSON格式的配置文件,文件内容的示例如下。

    通过控制台交互式页面部署时最终也会生成下面的配置文件,您也可以使用该文件通过eascmdopenapi来进行服务部署。

    {
      "name": "image_test",
      "containers": [
        {
          "image": "registry-vpc.cn-shanghai.aliyuncs.com/xxx/yyy:zzz",
          "env": [
            {
              "name": "var_name",
              "value": "var_value"
            }
          ],
          "command": "/data/eas/ENV/bin/python /data/eas/app.py",
          "port": 8000
        }
      ],
      "metadata": {
        "cpu": 1,
        "instance": 1
      }
    }

    JSON文件内的参数解释如下表所示。

    参数

    是否必选

    描述

    containers

    image

    用于部署模型服务的镜像地址。

    由于EAS不开放公网访问权限,因此您需要使用VPC内网Registry地址进行部署。例如,registry-vpc.cn-shanghai.aliyuncs.com

    env

    name

    镜像执行时的环境变量名称。

    value

    镜像执行时的环境变量取值。

    command

    二者必选其一

    镜像的入口命令,只支持单一命令形式,不支持复杂脚本,如:cd xxx && python app.py,这种形式请使用下面的script参数来指定,command字段适应于镜像中无/bin/sh命令的场景。

    script

    镜像的入口执行的脚本,可指定较为复杂的脚本形式,多行以\n或分号分隔。

    port

    容器端口。

    重要
    • 由于EAS引擎监听固定的8080/9090端口,因此容器端口需要避开8080/9090端口。

    • 该端口一定要和command中的xxx.py文件配置的端口保持一致。

    prepare

    pythonRequirements

    实例启动前安装的python requirements列表,要求镜像中在系统路径中存在pythonpip命令,list格式,如:

    "prepare": {
      "pythonRequirements": [
        "numpy==1.16.4",
        "absl-py==0.11.0"
      ]
    }

    pythonRequirementsPath

    实例启动前安装的python requirements.txt文件地址,要求镜像中在系统路径中存在Pythonpip命令,requirements.txt可直接打在镜像中,也可以由外部存储挂载的方式挂载到服务实例中,如:

    "prepare": {
      "pythonRequirementsPath": "/data_oss/requirements.txt"
    }

    health_check

    tcp_socket.port

    使用TCP方式健康检查时,检查的TCP端口号。

    http_get.path

    使用HTTP方式健康检查时,检查的HTTP Server访问地址。

    http_get.port

    使用HTTP方式健康检查时,检查的HTTP Server端口号。

    initial_delay_seconds

    默认健康检查开始的延时时间,默认为3秒。

    period_seconds

    配置每次健康检查请求的间隔时间,默认为3秒。

    timeout_seconds

    配置每次健康检查请求的超时时间,超过该时间请求为正确返回则判定为健康检查失败,默认为1秒。

    success_threshold

    健康检查成功的阈值,如设置为2,则表示健康检查成功2次判定为实例健康,开始启动流量导入。

    failure_threshold

    健康检查失败的阈值,如设置为4,则表示健康检查失败4次后则判断实例为不健康,开始停止流量导入。

    dockerAuth

    如果使用私有仓库中的镜像,则需要通过该参数指定Docker Registry的认证信息。目前,认证信息仅支持username:passwordBase 64编码形式。

    例如,username:password取值为abcd:abcde12345时,命令echo -n "abcd:abcde12345" | base64返回YWJjZDphYmNkZTEy****,即为dockerAuth的取值。

    metadata

    服务的Meta信息,详细参数请参见命令使用说明

    name

    服务名称,必须在同一地域内唯一。

使用客户端工具部署

  1. 通过客户端工具的create命令部署模型服务。

eascmd create image.json

其中image.json表示上一步中创建的服务描述文件。

系统返回如下类似结果,包括服务的访问地址和访问Token。

[RequestId]: BFFFE5F5-1F07-437E-B59A-AF1F2B66****
+-------------------+-----------------------------------------------------------------------------------+
| Internet Endpoint | http://182848887922***.cn-shanghai.pai-eas.aliyuncs.com/api/predict/image_test    |
| Intranet Endpoint | http://182848887922***.vpc.cn-shanghai.pai-eas.aliyuncs.com/api/predict/image_test|
|             Token | NjA4MzQxOWQ0MTY2M2Y4OGY0NjgwODkwZTZmYWJmZWU1ZmY0Njhk****                          |
+-------------------+-----------------------------------------------------------------------------------+
[OK] Service is now creating
[OK] Waiting [Total: 2, Pending: 2, Running: 0]
[OK] Running [Total: 2, Pending: 0, Running: 2]
[OK] Service is running
  1. 如果需要修改服务配置,则通过客户端工具的modify命令实现。

修改上述服务的示例命令如下,关于modify命令的详情信息,请参见修改服务配置

eascmd modify registry_test -s image.json

其中:registry_test表示服务名称;image.json表示服务描述文件。

使用控制台部署image

上图的示例中演示了使用用户自建私有仓库来部署的场景,同时配置了访问仓库的用户名和密码。模型和代码均以OSS存储挂载的方式挂载到服务实例中,生成的完整配置如下所示。

{
  "metadata": {
    "name": "image_test",
    "instance": 1
  },
  "storage": [
    {
      "mount_path": "/models/",
      "oss": {
        "path": "oss://example-cn-beijing/models/",
        "readOnly": true
      }
    },
    {
      "mount_path": "/root/code",
      "oss": {
        "path": "oss://example-cn-beijing/processors/",
        "readOnly": true
      }
    }
  ],
  "containers": [
    {
      "image": "myharbor.com/xxx/yyy:zzz",
      "script": "python /root/code/app.py",
      "port": 8000,
      "prepare": {
        "pythonRequirementsPath": "/root/code/requirements.txt"
      },
      "env": [
        {
          "name": "var_name",
          "value": "var_value"
        }
      ]
    }
  ],
  "dockerAuth": "YWJjOmJjZA=="
}

服务请求

模型服务部署后,可在控制台服务详情页面中获取到服务的访问地址,通过eascmd desc命令也可以获取到服务的访问地址。假设为用户使用如下Flask代码在镜像中构建了一个API服务。

from flask import Flask
 
app = Flask(__name__)
 
@app.route('/hello/model')
def hello_world():
    return 'Hello World'
 
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000)

上述代码中提供了一个Web服务,访问路径为/hello/model,则对于同步服务在进行访问服务时,需要在该访问地址后加上镜像中的访问路径。

例如在服务调用页面获取到的服务的公网访问地址为:http://182848887922***.cn-shanghai.pai-eas.aliyuncs.com/api/predict/image_test

则对于上述的镜像服务要请求/hello/model路径时,最终的访问地址为:

http://182848887922***.cn-shanghai.pai-eas.aliyuncs.com/api/predict/image_test/hello/model

关于服务请求的更多信息,详情请参见服务调用方式

附录:服务配置示例

使用PythonRequirements

{
  "name": "image_test",
  "containers": [
    {
      "image": "registry-vpc.cn-shanghai.aliyuncs.com/xxx/yyy:zzz",
      "prepare": {
        "pythonRequirements": [
          "numpy==1.16.4",
          "absl-py==0.11.0"
        ]
      },
      "command": "python app.py",
      "port": 8000
    }
  ],
  "metadata": {
    "instance": 1
  }
}

自定义健康检查

{
   "name": "image_test",
   "containers": [
     {
       "image": "registry-vpc.cn-shanghai.aliyuncs.com/xxx/yyy:zzz",
       "command": "python app.py",
       "port": 8000,
       "health_check":{
         "http_get": {
           "path": "/",
           "port": 8000
         },
         "initial_delay_seconds": 3,
         "period_seconds": 3,
         "timeout_seconds": 1,
         "success_threshold": 2,
         "failure_threshold": 4
       }
     }
   ],
   "metadata": {
      "instance": 1
     }
}

使用GRPC协议

{
  "name": "image_test",
  "containers": [
    {
      "image": "registry-vpc.cn-shanghai.aliyuncs.com/xxx/yyy:zzz",
      "command": "python app.py",
      "port": 8000
    }
  ],
  "metadata": {
    "instance": 1,
    "enable_grpc": true
  }
}

相关文档

  • 关于服务部署原理,详情请参见服务部署概述

  • 服务部署成功后,在业务负载出现显著的波峰波谷时,您可以开启水平自动扩缩容功能,详情请参见水平自动扩缩容功能