跳转至

容器镜像控制

控制器操作数据库和worker节点的工作流程被封装为一系列Python脚本

容器控制

初始化容器

脚本名称 container_init.py
输入内容 iid(镜像编号),uid(用户编号),name(容器名称),cpu(容器CPU需求),mem(容器内存需求),gid(GPU编号,可选)
  1. 核验身份:查询数据库,确保镜像存在,并且用户有权限使用该镜像。如果没有相应的镜像记录,返回错误信息。
  2. 查询数据库,获取容器所使用的设备(did)的 IP 地址、CPU、内存及其他资源信息,并获取设备的相关目录路径(如数据目录、公共目录)。
  3. 查询数据库,获取该设备已运行容器所占用的 CPU 和内存资源,如果新容器所需资源加上现有资源超出设备总资源,则返回错误信息。
  4. 检查 GPU 可用性:如果容器请求使用 GPU,查询指定 GPU 是否已被其他容器占用。如果 GPU 不可用,则返回错误信息。
  5. 获取端口信息:通过执行远程脚本获取容器所需的 SSH、Jupyter 和 TensorBoard 端口。远程脚本会尝试绑定三个随机端口,如果成功绑定,就将端口号返回
  6. 生成16位的随机密码,作为容器的ssh和jupyter登录密码
  7. 启动容器:构造并执行 Docker 命令,通过 SSH 启动容器,并映射资源(如挂载卷、暴露端口等)。
  8. 更新 containers 表,记录新容器的状态(running)、资源配置、端口和密码。
  9. 如果容器使用了 GPU,更新 container_gpu 表,标记该 GPU 已被容器使用。
  10. 返回结果:如果容器启动成功,返回容器的随机密码、SSH 端口、Jupyter 端口和 TensorBoard 端口信息。

查询容器状态

脚本名称 container_status.py
输入内容 cid(容器编号),uid(用户编号)
  1. 查询数据库,验证容器是否属于用户,以及容器是否存在
  2. 查询数据库中旧的容器状态
  3. 查询数据库获取容器所在worker的ip,用于启动ssh控制连接
  4. ssh连接到容器所在worker,执行查询容器状态的指令
  5. 比较新旧状态,如果不同,则更新数据库中的容器状态

启动容器

脚本名称 container_start.py
输入内容 cid(容器编号),uid(用户编号)
  1. 验证用户身份:查询数据库,验证指定容器是否属于用户,以及容器是否存在。
  2. 检查容器状态:调用 container_status 函数查询容器当前的状态。如果容器已经在运行,直接返回错误信息,表示容器已经启动。
  3. 获取容器资源信息:查询数据库,获取容器的 CPU 和内存需求。
  4. 获取设备资源信息:查询容器所在设备的资源情况(如 CPU、内存等)以及已分配的资源。
  5. 检查资源是否足够:计算当前设备已使用的 CPU 和内存,并与设备的总资源进行比较。如果容器需求超出设备剩余资源,返回错误信息。
  6. 检查 GPU 可用性:查询容器是否使用 GPU,如果有 GPU 使用需求,则检查该 GPU 是否已被其他容器占用。如果 GPU 不可用,返回错误信息。
  7. 启动容器:通过 SSH 连接到容器所在的设备,并执行 Docker 启动命令来启动容器。
  8. 更新容器状态:如果容器启动成功,更新数据库中容器的状态为 "running"。
  9. 更新 GPU 使用情况:如果容器分配了 GPU,则更新数据库中 container_gpu 表的状态,标记该 GPU 为正在使用。

停止容器

脚本名称 container_stop.py
输入内容 cid(容器编号),uid(用户编号,可选)
  1. 查询数据库,验证指定容器是否属于该用户,确保容器存在且用户有权限访问该容器。
  2. 获取容器当前状态,如果容器已经停止(exited),直接返回错误信息,表示容器已处于停止状态。
  3. 获取容器 GPU 信息:查询数据库获取容器是否分配了 GPU。如果容器有 GPU 资源,记录该 GPU ID。
  4. 查询容器所在设备的 IP 地址,以便通过 SSH 连接到该设备。
  5. 停止容器:通过 SSH 命令执行 docker stop 来停止容器。
  6. 更新容器状态:如果容器成功停止,更新数据库中容器的状态为 "exited"。
  7. 更新 GPU 使用情况:如果容器分配了 GPU,则更新数据库中 container_gpu 表,标记该 GPU 为未使用状态。

删除容器

脚本名称 container_rm.py
输入内容 cid(容器编号),uid(用户编号)
  1. 验证用户身份:查询数据库,验证容器是否属于指定用户,并且容器是否存在。确保用户有权限删除该容器。
  2. 获取容器当前状态:获取容器当前状态。如果容器正在运行,先调用 container_stop 函数停止容器。
  3. 查询容器所在设备的 IP 地址,通过 SSH 连接到该设备,执行删除操作。
  4. 更新数据库,删除 containers 表中的容器记录。

镜像控制

创建镜像

脚本名称 image_create.py
输入内容 cid(容器编号),name(镜像名称),uid(用户编号),public(是否公开)
  1. 查询数据库,确认用户是否有权限访问指定的容器。如果用户没有访问权限或容器不存在,则返回错误信息。
  2. 获取设备信息:查询数据库,获取容器所属设备的 did 和设备的 IP 地址,用于后续通过 SSH 连接到设备。
  3. 容器转镜像:使用 docker commit 命令通过 SSH 连接到设备,创建一个新的镜像。镜像的 ID 会通过命令的标准输出返回,并从输出中提取出镜像的 real_id(SHA256 哈希)。
  4. 从数据库获取一个新的镜像 ID (iid),该 ID 是数据库中 images 表的下一个可用 ID。
  5. 再次SSH 连接到设备,获取刚刚创建的镜像的大小。
  6. images 表中插入新镜像的记录,包括镜像的 iid、所属设备 did、镜像名称、real_id、是否公开和镜像大小。
  7. user_images 表中插入记录,表示用户拥有该镜像。

删除镜像

脚本名称 image_rm.py
输入内容 iid(镜像ID),uid(用户ID)

实现细节如下:

  1. 查询数据库 user_images 表,验证用户是否拥有该镜像。如果用户没有访问权限或者镜像不存在,返回错误信息。
  2. 验证镜像是否关联容器:通过查询 containers 表,检查是否有容器依赖于该镜像。如果存在依赖的容器,则无法删除镜像,返回错误信息。
  3. 获取设备IP:通过查询 images 表,找到该镜像所在设备的 IP 地址。镜像对应的设备是通过 did 关联的。
  4. 获取镜像真实ID:查询 images 表,获取该镜像的真实 ID(real_id),这是 Docker 用来标识镜像的实际哈希值。
  5. 删除镜像:使用 docker rmi 命令通过 SSH 连接到设备,删除指定的镜像
  6. images 表中删除该镜像记录。
  7. user_images 表中删除用户与该镜像的关联记录。