diff options
author | CoprDistGit <infra@openeuler.org> | 2024-09-03 03:24:28 +0000 |
---|---|---|
committer | CoprDistGit <infra@openeuler.org> | 2024-09-03 03:24:28 +0000 |
commit | e45819fcb4a96649a4030db7684f140d5ca46735 (patch) | |
tree | 544dac3e30a0448eabdc50add41aa3a18982d9f1 /0072-cdi-design-doc.patch | |
parent | 1a71e3afebb4b43be63949dcc8e882fe7643f13b (diff) |
automatic import of iSuladopeneuler24.03_LTS
Diffstat (limited to '0072-cdi-design-doc.patch')
-rw-r--r-- | 0072-cdi-design-doc.patch | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/0072-cdi-design-doc.patch b/0072-cdi-design-doc.patch new file mode 100644 index 0000000..78c3116 --- /dev/null +++ b/0072-cdi-design-doc.patch @@ -0,0 +1,391 @@ +From 72246a9e83ada3af7560817534013a93f40d5bae Mon Sep 17 00:00:00 2001 +From: liuxu <liuxu156@huawei.com> +Date: Sat, 20 Apr 2024 11:46:11 +0800 +Subject: [PATCH 72/73] cdi:design doc + +Signed-off-by: liuxu <liuxu156@huawei.com> +--- + docs/design/README.md | 3 + + docs/design/README_zh.md | 3 + + docs/design/detailed/CDI/cdi_design_zh.md | 341 ++++++++++++++++++++++ + 3 files changed, 347 insertions(+) + create mode 100644 docs/design/detailed/CDI/cdi_design_zh.md + +diff --git a/docs/design/README.md b/docs/design/README.md +index cf29c0a1..d2a3702d 100644 +--- a/docs/design/README.md ++++ b/docs/design/README.md +@@ -18,6 +18,9 @@ This section contains some design documents for users who want to learn more abo + + - You can see how the CRI startup process is refactored in [cri_cni_refactor](./detailed/CRI/cri_cni_refactor.md). + ++## CDI ++- You can see how the CDI is refactored in [cdi_design](./detailed/CDI/cdi_design_zh.md.md)。 ++ + ## Events + + - You can see how the events modules are designed in [events_design](./detailed/Events/events_design.md). +diff --git a/docs/design/README_zh.md b/docs/design/README_zh.md +index 3382bfbe..c6172b6f 100644 +--- a/docs/design/README_zh.md ++++ b/docs/design/README_zh.md +@@ -24,6 +24,9 @@ + + - 查看 CRI的启动程序的重构文档: [cri_cni_refactor](./detailed/CRI/cri_cni_refactor_zh.md) 。 + ++## CDI ++- 查看 CDI 的设计文档: [cdi_design](./detailed/CDI/cdi_design_zh.md.md)。 ++ + ## Events + + - 查看 events 模块的设计文档: [events_design](./detailed/Events/events_design_zh.md) 。 +diff --git a/docs/design/detailed/CDI/cdi_design_zh.md b/docs/design/detailed/CDI/cdi_design_zh.md +new file mode 100644 +index 00000000..15c88f93 +--- /dev/null ++++ b/docs/design/detailed/CDI/cdi_design_zh.md +@@ -0,0 +1,341 @@ ++| Author | liuxu | ++| ------ | --------------------- | ++| Date | 2024-02-27 | ++| Email | liuxu156@huawei.com | ++ ++# 背景介绍 ++## What is CDI? ++CDI(容器设备接口)是容器运行时的一种规范,用于支持第三方设备。 ++ ++它引入了device作为资源的抽象概念。device由完全限定的名称唯一指定,该名称由vendor ID、一个device class和在每个vendor ID-device class对中唯一的name构成。 ++``` ++vendor.com/class=unique_name ++``` ++vendor ID和device class (上例中的vendor.com/class)的组合称为device kind. ++ ++CDI只关心使容器能够感知设备。CDI明确地忽略了诸如资源管理之类的领域(并期望由编排器处理)。由于这个原因,CDI规范实现起来很简单,并且为运行时和编排器提供了极大的灵活性。 ++ ++注:CDI模型基于容器网络接口(CNI)模型和规范。 ++ ++## Why is CDI needed? ++在Linux上,使容器具有设备感知能力过去只需在该容器中暴露一个设备节点。但是,随着设备和软件变得越来越复杂,供应商希望执行更多的操作,例如: ++- 向容器公开设备可能需要公开多个设备节点、从运行时命名空间挂载文件或隐藏procfs条目。 ++- 执行容器和设备之间的兼容性检查(例如:检查容器是否可以在指定设备上运行)。 ++- 执行特定于运行时的操作(例如:虚拟机与基于Linux容器的运行时)。 ++- 执行特定于设备的操作(例如:清理GPU的内存或重新配置FPGA)。 ++ ++在缺乏第三方设备标准的情况下,供应商通常不得不为不同的运行时编写和维护多个插件,甚至直接在运行时中贡献特定于供应商的代码。此外,运行时不统一地暴露插件系统(甚至根本不暴露插件系统),导致在更高级别的抽象(例如Kubernetes设备插件)中重复功能。 ++ ++## How does CDI work? ++要使CDI正常工作,需要完成以下操作: ++- JSON格式的CDI文件应位于CDI规范目录中,它的作用是更新OCI spec。默认目录为/etc/cdi和/var/run/cdi ++- 应使用CRI的annotations与CDI_devices(本次特性支持)将唯一的设备名称传递给运行时 ++- 容器运行时应该能够通过设备名称找到CDI文件在内存中对应的缓存信息,并使用缓存的内容更新容器配置。 ++ ++## How to configure CDI? ++### iSulad ++daemon.json中开启cri-v1和cdi配置: ++ ++当 cdi-spec-dirs 不指定时,默认为"/etc/cdi", "/var/run/cdi" ++```json ++"enable-cri-v1": true, ++"cdi-spec-dirs": ["/etc/cdi", "/var/run/cdi"], # 指定CDI规范所在目录 ++"enable-cdi": true # 打开CDI特性 ++``` ++ ++在CRI创建容器的参数中使用CDI,以下两种方式均可: ++1. annotations中指定设备 ++```json ++{ ++ ... ... ++ "annotations": [ ++ ... ... ++ // key值格式要求含有cdi.k8s.io作为前缀,后面跟随pluginName ++ {"cdi.k8s.io/test": "vendor.com/device=myDevice"}, ++ ... ... ++ ] ++ ... ... ++} ++``` ++2. CDI_Devices中指定设备 ++```json ++{ ++ ... ... ++ "CDI_Devices": [ ++ ... ... ++ {"Name": "vendor.com/device=myDevice"}, ++ ... ... ++ ] ++ ... ... ++} ++``` ++ ++# 方案目标 ++## 概述 ++容器设备接口(Container Device Interface,简称CDI)描述了容器运行时创建能够与第三方设备交互的容器的机制。 ++ ++对于第三方设备,与这些设备进行交互通常需要容器运行时公开多个设备节点。例如,第三方设备可能需要加载内核模块、装载主机库、暴露/屏蔽特定procfs路径。 ++ ++容器设备接口描述了一种允许第三方供应商执行这些操作的机制,从而不需要更改容器运行时。 ++ ++使用的机制是一个JSON文件(类似于容器网络接口(CNI)),它允许供应商描述容器运行时应该对容器的OCI规范执行的操作。 ++ ++CDI 支持以下两个流程: ++ ++A.设备安装 ++1. 用户在机器上安装第三方设备驱动程序(和第三方设备/被测试的设备)。 ++2. 设备驱动程序安装软件会在一个已知路径(/etc/cdi/vendor.json)上写入一个 JSON 文件。 ++ ++B.容器运行时 ++1. 用户在创建容器时,CRI中指定设备名称 ++2. 容器运行时会读取 JSON 文件。 ++3. 容器运行时会验证 JSON 文件中是否描述了设备。 ++4. 容器运行时会根据 JSON 文件中的指令转换 OCI 规范,并插入OCI Spec中 ++# 总体设计 ++**iSulad支持CDI功能目前仅支持CRI方式调用,CLI方式暂不支持** ++## 整体结构 ++ ++```mermaid ++flowchart TD ++classDef unFinish fill:#c19,stroke:#216,stroke-width:2px,color:#fff,stroke-dasharray: 5 5; ++subgraph isulad ++ subgraph CDIOperate ++ RegistryOps ++ AnnotationsOps ++ ...... ++ end ++ ++ subgraph CDI ++ D[ContainerEdits] ++ E[Device] ++ F[Registry] ++ G[Cache] ++ H[Spec] ++ end ++ CDIOperate --> CDI ++ ++ OA[isula module] --> |call| CDIOperate ++ OB[CRI module] --> |call| CDIOperate ++ CDIOperate:::unFinish ++ CDI:::unFinish ++end ++ PA[CLI] --> OA ++ PB[CRI] --> OB ++``` ++ ++- CDIOperate封装了CDI模块,对外提供更合理的CDI功能的相关接口。 ++- CDI负责实现CDI Specs的读取、校验、解析、devices注入OCI Spec等具体功能。 ++## 时序设计 ++在isulad启动后,以创建一个容器为例。 ++ ++图中isulad启动后,拉起一个新的线程isulad-cdi_watcher,负责监控cdi-spec-dirs,当cdi-spec-dirs中的cdi Spec文件发生修改、删除等动作时,重新扫描cdi-spec-dirs中的cdi Spec文件。 ++ ++```mermaid ++sequenceDiagram ++ participant CRI ++ participant isulad ++ participant cdi_watcher ++ isulad ->> cdi_watcher: init cdi ++ par ++ loop ++ cdi_watcher ->> cdi_watcher:wait for inotify event ++ cdi_watcher ->> cdi_watcher:refresh cdi cache ++ end ++ and ++ opt CRI ++ CRI ->> isulad: create container ++ isulad ->> isulad:parse cdi annotations/CDI_devices ++ isulad ->> isulad:generates an OCI specification with cdi info ++ end ++ end ++``` ++ ++# 接口描述 ++## 3.1 结构体和常量说明 ++ ++```c ++// 实现CDI Spec规范中的json字段,参考 https://github1s.com/containerd/containerd/blob/main/vendor/tags.cncf.io/container-device-interface/specs-go/config.go#L9 ++typedef struct {} cdi_spec; ++typedef struct {} cdi_spec_device; ++typedef struct {} cdi_spec_container_edits; ++typedef struct {} cdi_spec_device_node; ++typedef struct {} cdi_spec_mount; ++typedef struct {} cdi_spec_hook; ++ ++struct cdi_cache_device { ++ const cdi_device *raw_device; ++ const struct cdi_cache_spec *cache_spec; ++}; ++ ++struct cdi_cache_spec { ++ cdi_spec *raw_spec; ++ char *vendor; ++ char *class; ++ char *path; ++ int priority; ++ map_t *devices; // MAP_STR_PTR devices[cdi_device.name] = cdi_cache_device* ++}; ++ ++struct cdi_cache_ops { ++ // injecting CDI devices into an OCI Spec. ++ // Resolver ++ int (*inject_devices)(struct cdi_cache *c, oci_runtime_spec *spec, string_array *devices); ++ ++ // refreshing the cache of CDI Specs and devices. ++ // Refresher ++ int (*configure)(struct cdi_cache *c, string_array *spec_dirs); ++ int (*refresh)(struct cdi_cache *c); ++}; ++ ++struct cdi_watch { ++ int watcher_fd; // inotify fd ++ map_t *tracked; // MAP_STR_BOOL tracked[spec_dirs[i]] = bool ++ map_t *wd_dirs; // MAP_INT_STR wd_dirs[wd] = spec_dirs[i] ++}; ++ ++// Cache stores CDI Specs loaded from Spec directories. ++struct cdi_cache { ++ pthread_mutex_t mutex; ++ string_array *spec_dirs; // cdi-spec-dirs will scan for CDI Spec files ++ map_t *specs; // MAP_STR_PTR specs[vendor] = common_array of cdi_cache_spec* ++ // This map holding the reference to cdi device, the devices will not released when the map is freed. ++ map_t *devices; // MAP_STR_PTR devices[cdi_device.name] = cdi_cache_device* ++ bool refresh_error_flag; ++ bool auto_refresh; ++ struct cdi_watch *watch; ++}; ++ ++struct cdi_registry { ++ struct cdi_cache *cdi_cache; ++ struct cdi_cache_ops *ops; ++}; ++``` ++涉及修改现有的结构体: ++```c ++// 用于从CRI向executor传递devices数据 ++typedef struct { ++ ... ... ++ char **cdi_requested_devices; ++ size_t cdi_requested_devices_len; ++} host_config; ++ ++// isulad的daemon.json增加cdi相关的基本配置 ++typedef struct { ++ ... ... ++ char **cdi_spec_dirs; ++ size_t cdi_spec_dirs_len; ++ bool enable_cdi; ++} isulad_daemon_configs; ++``` ++ ++## 3.2 接口说明 ++CDIOperate的设计目标:使得CDI规范有关的内容不过多的对外暴露,降低CDI模块和外部的耦合。 ++### RegistryOps ++```c ++int cdi_operate_registry_init(char **specs_dirs, size_t specs_dirs_len); ++ ++int cdi_operate_refresh(void); ++ ++int cdi_operate_inject_devices(oci_runtime_spec *spec, string_array *devices); ++ ++int cdi_operate_parse_annotations(json_map_string_string *annotations, string_array **keys, ++ string_array **devices, char **error); ++``` ++ ++# 详细设计 ++## daemon.json ++daemon.json中增加cdi配置: ++```json ++"cdi-spec-dirs": ["/etc/cdi", "/var/run/cdi"], ++"enable-cdi": true ++``` ++## CDIOperate被调用点 ++### CreateContainer ++创建新的Container时需要将devices插入OCI Spec。 ++本次开发暂不涉及isula支持CDI。 ++ ++为什么已经有isulad-cdi_watcher线程了,在create的时候还需要refresh? ++1. isulad-cdi_watcher在触发inotify event后,如果为Rename、Remove、Write事件,会直接执行refresh,将重新扫描cdi-spec-dirs中的CDI Specs到内存。 ++2. 而在create container时,cdi_refresh先检查tracked,tracked标记了是否所有目录都已被跟踪,如果不是才会触发refresh。tracked在cache生成时初始化为未跟踪。 ++ ++```mermaid ++flowchart TD ++O((begin)) ++A(ContainerManagerService::CreateContainer <br> CRI创建容器) ++B(ContainerManagerService::CDIParseDevices <br> 解析CDI有关的字段) ++C(container_cb::container_create_cb <br> 创建容器的前置准备) ++D(spec::merge_all_specs <br> 准备生成OCI Spec) ++E(spec::spec_inject_cdi_devices <br> 解析需要的设备名) ++F(CDIOperate::cdi_refresh <br> 刷新cdi的缓存) ++G(CDIOperate::cdi_inject_devices <br> 将容器需要的设备的相关信息插入OCI Spec) ++Z((create end)) ++O --> A --> B --> C --> D --> E --> F --> G --> Z ++``` ++ ++ContainerManagerService::CDIParseDevices 需要支持两种CDI devices解析方式: ++1. CDIOperate::cdi_parse_annotations 解析ContainerConfig.annotations() ++2. 解析ContainerConfig.CDI_devices() ++解析后放入container_create_request ++### main ++isulad 启动时,读取所有CDI Specs,初始化cache ++```mermaid ++flowchart TD ++O((begin)) ++A(main) ++B(isulad_server_init_common <br> isulad服务端初始化) ++C(cdi::cdi_registry_init <br> 读取现有的CDI Specs <br> 并拉起新的线程监控CDI Specs的变化) ++Z(end) ++O --> A --> B --> C --> Z ++``` ++ ++## CDI 模块设计 ++```mermaid ++flowchart TD ++ subgraph CDIoperate ++ operate ++ end ++ ++ subgraph CDI ++ annotations ++ registry ++ cache ++ subgraph behavior ++ spec-dirs ++ spec ++ device ++ container-edits ++ version ++ parser ++ end ++ end ++ ++ operate --> registry ++ operate --> annotations ++ registry --> cache ++ cache --> spec-dirs ++ cache --> device ++ cache --> spec ++ cache --> container-edits ++ device <--> spec ++ device --> parser ++ device --> container-edits ++ device --> parser ++ spec --> container-edits ++ spec --> version ++ version --> parser ++``` ++ ++### new cache ++```mermaid ++flowchart TD ++O((begin)) ++A(ContainerManagerService::CreateContainer <br> CRI创建容器) ++B(ContainerManagerService::CDIParseDevices <br> 解析CDI有关的字段) ++C(container_cb::container_create_cb <br> 创建容器的前置准备) ++D(spec::merge_all_specs <br> 准备生成OCI Spec) ++E(spec::spec_inject_cdi_devices <br> 解析需要的设备名) ++F(CDIOperate::cdi_refresh <br> 刷新cdi的缓存) ++G(CDIOperate::cdi_inject_devices <br> 将容器需要的设备的相关信息插入OCI Spec) ++Z((create end)) ++O --> A --> B --> C --> D --> E --> F --> G --> Z ++``` +-- +2.34.1 + |