在Kubernetes (K8S)上托管Aim

由于Aim可以通过FastAPI作为本地服务器运行,因此可以部署到K8S集群!在K8S上托管Aim具有以下优势:

  • 您组织的多个用户可以在一个地方访问Aim,这样ML从业者就不需要自己运行Aim了

  • Aim运行可以集中在一个远程存储卷上,这为远程模型训练和监控提供了额外的支持和便利

  • 部署到K8S抽象了Aim CLI,使用户能够专注于Aim提供的价值(可视化/应用程序 vs. 理解CLI uprepo

以下部分说明如何在K8S上部署和运行Aim。这些部分假设:

  • 访问云服务提供商,例如GCP、AWS或Azure

  • 可以托管Dockerfile的代码仓库,例如Google Artifact Registry或Dockerhub

  • 具备配置ReadWriteMany卷的权限/能力,或将现有卷绑定到K8S部署

Dockerfile

以下Dockerfile镜像足以让Aim在容器中运行:

# python3.7 should be sufficient to run Aim
FROM python:3.7

# install the `aim` package on the latest version
RUN pip install --upgrade aim

# make a directory where the Aim repo will be initialized, `/aim`
RUN mkdir /aim

ENTRYPOINT ["/bin/sh", "-c"]

# have to run `aim init` in the directory that stores aim data for
# otherwise `aim up` will prompt for confirmation to create the directory itself.
# We run aim listening on 0.0.0.0 to expose all ports. Also, we run
# using `--dev` to print verbose logs. Port 43800 is the default port of
# `aim up` but explicit is better than implicit.
CMD ["echo \"N\" | aim init --repo /aim && aim up --host 0.0.0.0 --port 43800 --workers 2 --repo /aim"]

假设你将上述内容保存在当前目录中,可以使用docker build . -t my-aim-container:1命令构建容器,并通过docker push my-docker-repository.dev/deployments/aim:1将其推送到你的代码仓库。

数据量

使用K8S卷存储Aim运行记录的核心优势在于,其他K8S部署可以挂载同一个卷并在其上存储运行记录!这样,核心Aim K8S部署就能读取新的运行记录,并将其展示给想要可视化结果的用户。例如,可以设置一个执行模型训练并记录Aim运行的部署,该部署使用与Aim部署挂载相同的卷!该模型如下图所示:

通常来说,支持ReadWriteMany属性的存储卷需要手动配置,例如Google Cloud上的Filestore实例,或者通用的GlusterFS卷。一旦磁盘配置完成,就可以通过IP地址将其绑定到持久卷。假设您可以在云服务提供商上配置这样的磁盘并获取IP地址,我们就可以创建一个存储卷表示及其对应的声明。持久卷(aim-pv.yaml)可以这样定义:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: aim-runs
spec:
  capacity:
    storage: 1Ti # or whatever size disk you provisioned
  accessModes:
    - ReadWriteMany
  nfs:
    path: /aim
    server: 123.12.123.12  # add your own IP here

持久卷声明 (aim-pvc.yaml) 内容如下:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: aim-runs-claim
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: "" # if you have a custom storage class, use it! Otherwise, it's `default`
  volumeName: aim-runs
  resources:
    requests:
      storage: 1Ti

这些可以通过以下方式提供:

> kubectl apply -f aim-pv.yaml
> kubectl apply -f aim-pvc.yaml

一旦卷被配置完成,我们就可以将其挂载到我们的部署中!

部署

主要的Aim部署将包含一个运行Aim的独立容器。该部署会挂载之前配置的存储卷,主Aim仓库将在存储卷挂载路径下初始化。例如,如果存储卷挂载到/aim路径,那么部署将从该路径初始化和读取Aim运行记录。对应的K8S部署如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: my-aim-deployment
  name: my-aim-deployment
  namespace: default
spec:
  selector:
    matchLabels:
      app: my-aim-deployment
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: my-aim-deployment
    spec:
      containers:
        image: my-docker-repository.dev/deployments/aim:1
        name: my-aim-deployment
        ports:
          - containerPort: 43800
            protocol: TCP
        resources:
          limits:
            cpu: "1"
            memory: 2Gi
          requests:
            cpu: 100m
            memory: 1Gi
        volumeMounts:
          - mountPath: /aim
            name: aim-runs
      volumes:
        - name: aim-runs
          persistentVolumeClaim:
            claimName: aim-runs-claim

这个K8S部署:

  • 定义一个包含单个副本的pod,运行由Dockerfile定义的Aim服务器

  • 通过持久卷声明 aim-run-claim 挂载持久卷 aim-run

  • Dockerfile 将 /aim 目录初始化为 Aim 代码仓库。请注意,如果仓库已初始化(首次部署创建后就会出现这种情况,因为仓库只需初始化一次),Dockerfile 已自动向确认提示传递 N 参数以避免手动操作

  • 在端口43800上启动Aim服务器,该服务器读取存储在/aim中的所有运行记录

服务

现在部署已经完成,Aim服务器可以通过K8S服务暴露出来!根据您的集群设置,您有多种方式来暴露该部署。其中一个选项是运行:

> kubectl expose deployment my-aim-deployment --type=LoadBalancer --name=my-aim-service

另一种选择是自行创建服务定义并应用它。定义文件 (aim-svc.yaml) 可以是:

apiVersion: v1
kind: Service
metadata:
  name: my-aim-service
spec:
  selector:
    app: my-aim-deployment
  ports:
    - protocol: TCP
      port: 80
      targetPort: 43800

服务定义可以通过以下方式应用:

> kubectl apply -f aim-svc.yaml

结论

就这样!现在您已拥有以下结构来服务用户的Aim运行:

假设您的用户可以向某个运行模型训练的pod/deployment提交训练任务,并且该部署中包含正确的aim代码来在路径/aim记录运行信息,那么您的Aim部署在下一次执行实时更新时就能显示该运行记录!