Mixer 这块,主要看官方文档中的 Istio Mixer: Adapter Developer's Guide。这里我举一些实例辅助理解。
Template 中定义的字段,像是一个 placeholder,供运行时填写实际请求相关的字段,比如:
# mixer/template/listentry/template.proto
message Template {
// Specifies the entry to verify in the list.
string value = 1;
}
# mixer/testdata/config/listcheck.yaml
apiVersion: "config.istio.io/v1alpha2"
kind: listentry
metadata:
name: appversion
namespace: istio-system
spec:
value: source.labels["version"]
adapter 需要指定使用哪(几)个 template,在 GetInfo()
的 SupportedTemplate
中定义。Template 的 Protobuf 文件中有 template_variety
,表明它是 Check
还是 Report
等,比如:
// mixer/template/checknothing/template.proto
option (istio.mixer.adapter.model.v1beta1.template_variety) = TEMPLATE_VARIETY_CHECK;
Template 里提供了一个 value
字段,供运维配置运行时时,用哪个请求相关的字段填充。这个例子中,会用 source.labels["version"]
填充。然后运行时就会生成一个 instance 给 adapter 去取 value
,也就是调用方的版本号:
// mixer/adapter/list/list.go
func (h *handler) HandleListEntry(_ context.Context, entry *listentry.Instance) (adapter.CheckResult, error) {
// 此时你就可以从 entry 中拿到调用方的版本号,做相关的逻辑
}
adapter 也有自己的配置,主要跟运行时的业务逻辑有关:
# mixer/adapter/list/config/config.proto
message Params {
// Where to find the list to check against. This may be ommited for a completely local list.
string provider_url = 1;
// Determines how often the provider is polled for
// an updated list
google.protobuf.Duration refresh_interval = 2 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true];
// Indicates how long to keep a list before discarding it.
// Typically, the TTL value should be set to noticeably longer (> 2x) than the
// refresh interval to ensure continued operation in the face of transient
// server outages.
google.protobuf.Duration ttl = 3 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true];
// ...
// List entries that are consulted first, before the list from the server
repeated string overrides = 6;
// ...
// Whether the list operates as a blacklist or a whitelist.
bool blacklist = 8;
}
这上面的 refresh_interval
表示 listchecker
这个 adapter,它会在多长时间去访问 provider_url
去刷新黑白名单列表。这上面的配置,可以由运维通过配置文件配置:
apiVersion: "config.istio.io/v1alpha2"
kind: listchecker
metadata:
name: staticversion
namespace: istio-system
spec:
# providerUrl: ordinarily black and white lists are maintained
# externally and fetched asynchronously using the providerUrl.
overrides: ["v1", "v2"] # overrides provide a static list
blacklist: false
同时你可以在代码中配置默认值:
// mixer/adapter/list/list.go
func GetInfo() adapter.Info {
return adapter.Info{
Name: "listchecker",
Impl: "istio.io/istio/mixer/adapter/list",
Description: "Checks whether an entry is present in a list",
SupportedTemplates: []string{listentry.TemplateName},
DefaultConfig: &config.Params{
RefreshInterval: 60 * time.Second,
Ttl: 300 * time.Second,
CachingInterval: 300 * time.Second,
CachingUseCount: 10000,
EntryType: config.STRINGS,
Blacklist: false,
},
NewBuilder: func() adapter.HandlerBuilder { return &builder{} },
}
}
配置好了 template 所定义的 instance 数据,adapter 所定义的业务逻辑配置,你需要再写一个 rule 把它们串起来,就完成了:
apiVersion: "config.istio.io/v1alpha2"
kind: rule
metadata:
name: checkwl
namespace: istio-system
spec:
# If an attribute could be potentially absent, use the '|' operator
# to provide a default value. In the below example if 'destination.labels'
# is absent, "unknown" is used in its place (this happens in non kubernetes env).
match: (destination.labels["app"]|"unknown") == "ratings"
actions:
- handler: staticversion.listchecker # 对应上面配置的 listchecker,里面写了 adapter 配置
instances:
- appversion.listentry # 对应上面配置的 listentry,里面配置了 instance 数据
这上面所有可以配置的内容,最终会由运维写进一个 yaml 文件中,再由 istioctl
命令应用进这套系统中。
- Note
listentry
跟listchecker
都可以配置多个。多个listcheck
时,运行时就有多个 adapter 实例存在 mixer 中。多个listentry
时,每个请求就有多个 instance 生成给 adapter(当然也看匹配规则)。