summaryrefslogtreecommitdiff
path: root/0072-cdi-design-doc.patch
blob: 78c311652d138099395fa7a60a2be71cbdbc5c70 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
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