Skip to content

Commit 98bbf56

Browse files
authored
Add API convention about condition. (RainbowMango#21)
1 parent 04ef16a commit 98bbf56

File tree

3 files changed

+86
-1
lines changed

3 files changed

+86
-1
lines changed

SUMMARY.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,6 @@
3232
* [第十章:ResourceQuota]
3333
* [10.1 ResourceQuota概述](chapter10/1.1-resourcequota_overview.md)
3434
* [第十六章:API设计约定]
35-
* [16.1 字段可选性约定](chapter16/1.1-optional_vs_required.md)
35+
* [16.1 字段可选性设计约定](chapter16/1.1-api_convention_optional_vs_required.md)
36+
* [16.2 condition设计约定](chapter16/1.2-api_convention_condition.md)
3637

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
## 导读
2+
绝大部分`Kubernetes`资源对象都包含`status.conditions`字段,用来表示资源状态,比如`deployment`资源中的`status.conditions`如下所示:
3+
```
4+
conditions:
5+
- lastTransitionTime: "2020-12-15T01:52:53Z"
6+
lastUpdateTime: "2020-12-15T01:52:53Z"
7+
message: Deployment has minimum availability.
8+
reason: MinimumReplicasAvailable
9+
status: "True"
10+
type: Available
11+
- lastTransitionTime: "2020-12-15T01:52:39Z"
12+
lastUpdateTime: "2020-12-15T01:52:53Z"
13+
message: ReplicaSet "nginx-deployment-85b45874d9" has successfully progressed.
14+
reason: NewReplicaSetAvailable
15+
status: "True"
16+
type: Progressing
17+
```
18+
以上`conditions`的信息是很容易读懂的(后面还会详细解释),然而有个问题曾经令笔者非常困惑,那就是:
19+
- `conditions``status`到底有什么区别?
20+
- `conditions`的设计原则是什么?在设计API扩展时,该如何定义`conditions`
21+
22+
本节会先从`conditions`的设计原则讲起,再介绍一些设计`conditions`时的一些经验总结。
23+
24+
## conditions设计原则
25+
`conditions`寄居于资源对象的`status`字段中,与`status`其他字段值一样都用来表示资源的状态。不过`conditions`的设计初衷是提供一种通用的数据结构表示资源的状态,它通常能够提供比`status`其他字段更详细的信息(比如状态切换时间、更新时间),`conditions`实际上是一种扩展机制,外部监控程序可以根据`conditions`无差别地监控各种资源的状态,而不必过分关注资源对象`status`中的其他信息。
26+
27+
通常`status.conditions`字段类型为切片,切片中的每个元素表示资源的某个状态,该状态由特定的控制器更新,比如`Deployment`控制器会更新`deployment`对象的`status.conditions`信息。`conditions`作为扩展机制,它还支持第三方控制器增加新的状态。通常`status.conditions`中的信息由控制器根据资源的`status`其他字段计算出来。
28+
29+
## condition字段内容
30+
通常一个`condition`必须包含`type`(状态类型)和`status`(状态值)两个信息。在`Kubernetes` v1.19版之前,关于`condition`并没有统一的标准,导致众多API都自行定义了`condition`。比如:
31+
- Deployment使用的Condition为`type DeploymentCondition struct`;
32+
- Pod使用的Condition为`type PodCondition struct`;
33+
34+
庆幸的是,在`Kubernetes`v1.19版本社区提供了一个标准的`condition`类型定义,由于兼容性考虑,`Kubernetes`既有的API不一定能采用这一标准类型,但对于后续新增的API将会使用这一标准类型,并且笔者建议用户设计的CRD扩展也应使用这一标准类型。
35+
36+
标准的`condition`类型定义如下所示:
37+
```golang
38+
type ConditionStatus string
39+
40+
const (
41+
ConditionTrue ConditionStatus = "True"
42+
ConditionFalse ConditionStatus = "False"
43+
ConditionUnknown ConditionStatus = "Unknown"
44+
)
45+
46+
type Condition struct {
47+
// 类型(使用驼峰风格),如”Available“。
48+
Type string
49+
// 状态(枚举值:”True“、”False“和”Unknown“)。
50+
Status ConditionStatus
51+
// 观察到的generation。
52+
// 如果ObservedGeneration 比metada.generation小,说明不是最新状态。
53+
// +optional
54+
ObservedGeneration int64
55+
// 上次变化时间
56+
LastTransitionTime Time
57+
// 状态变化原因(使用驼峰风格),如”NewReplicaSetAvailable“
58+
Reason string
59+
// 描述信息,如”Deployment has minimum availability“
60+
Message string `json:"message" protobuf:"bytes,6,opt,name=message"`
61+
}
62+
```
63+
64+
标准的`condition`类型定义对`condition`的各个字段做了进一步约定。除了`ObservedGeneration`是可选的以外,其他字段都是必填的。
65+
66+
## condition设计约定
67+
为了让`condition`起到最大的作用,需要遵守一定的设计约定:
68+
69+
### 约定一:condition定义要有明确的信息
70+
每个`condition`需要传递一个用户关心的明确信息,用户读取到该信息不需要再根据资源的其他状态来揣测和计算。
71+
72+
### 约定二:condition需要保持兼容
73+
`condition`一旦被定义,它就成了API中的一部分,需要跟API一样提供稳定性保证。如果需要新的`condition`仍然可以增加(没有破坏兼容性),但既有的`condition`是否能够改变就需要根据API成熟度来决定,比如`stable`的API不可以改变,`alpha`的API可以改变。
74+
75+
## 约定三:condition需要控制器第一次处理资源时更新
76+
控制器需要尽快地更新`condition`状态值(`condition.status`),即便该状态值为`Unknown`,这么做的好处是可以让其他组件了解到控制器正在`调谐`这个资源。
77+
78+
然而,并不是所有的控制器都能遵守这个约定,即控制器并不会报告特定的`condition`(此时该`condition`状态值可能为`Unknown`),可能该`condition`还无法确定,需要在下一次`调谐`时决定。此种情况下,外部组件无法读取到特定的`condition`,可以假设该`condition``Unknown`
79+
80+
## 约定四:condition类型名需要确保可读性
81+
`condition`类型名要使用人类可读的名称,而且尽量避免出现双重否定的语境。例如,类型名`Ready`比使用`Failed`要好,因为`condition`状态为`False`时,`Failed = False`将出现双重否定,不如`Ready = False`容易理解。
82+
83+
## 约定五:condition不要定义成状态机
84+
`condition`需要描述当前资源的确定状态,而不是当前资源状态机中的状态。通俗地讲,`condition`类型需要使用形容词(如`Ready`)或过去动词(`Succeeded`),而不是使用当前运行时(如`Deploying`)。

0 commit comments

Comments
 (0)