Ultron旨在通过一系列定制服务和HTTP处理器来解决多云工作负载分配的挑战。该应用是用Go语言编写的,采取结构化的方式来处理缓存、证书管理和与外部API交互等任务。在这篇文章中,我们将通过分析main.go
入口点、核心服务以及内部处理器(负责突变和验证Pod)来探讨Ultron的架构,并通过关键代码示例来展示其设计和功能。
奥创概念架构
Ultron的核心是main.go
文件
乌隆特(Ultron)的[main.go](https://github.com/be-heroes/ultron/blob/main/main.go)
文件作为应用的入口点,负责服务初始化、设置HTTP服务器和确保安全通信。首先值得注意的是,使用Uber的Zap日志库实现的结构化日志系统,用于关键性能场景的日志记录。
这是Ultron设置日志记录器的方法。
logger, _ := zap.NewProduction()
defer logger.Sync()
sugar := logger.Sugar()
sugar.Info("正在初始化Ultron")
在启用日志记录后,Ultron 加载其配置,初始化 Redis 客户端并初始化核心服务模块。以下代码片段展示了 Ultron 如何把这些组件连接起来:
config, err := ultron.LoadConfig()
if err != nil {
sugar.Fatalf("加载配置时出错: %v", err)
}
ctx := context.Background()
// 从配置初始化Redis客户端
redisClient := ultron.InitializeRedisClientFromConfig(ctx, config, sugar)
mapperInstance := mapper.NewMapper()
algorithmInstance := algorithm.NewAlgorithm()
cacheService := services.NewCacheService(nil, redisClient)
certificateService := services.NewCertificateService()
// 计算服务使用算法实例、缓存服务和映射实例
computeService := services.NewComputeService(algorithmInstance, cacheService, mapperInstance)
在通过InitializeRedisClientFromConfig()
初始化 Redis 客户端之后,将会实例化[IMapper]
和 [IAlgorithm]
这两个对象,来作为核心服务(比如缓存服务[CacheService]
和证书管理服务[CertificateService]
)的依赖。这些服务分别处理缓存和 TLS 证书管理。例如,缓存服务[CacheService]
(如其代码在[此处]
所示)和证书管理服务[CertificateService]
处理 TLS 证书管理。
设置好所需的服务后,奥创开始配置其用于 Pod 变体、验证和健康检查的 HTTP 路由配置,健康检查,。
(Note: There is a minor grammatical issue with the trailing comma after "健康检查". The corrected version should omit this trailing comma for proper sentence structure.)
Final corrected translation:
设置好所需的服务后,奥创开始配置其用于 Pod 变体、验证和健康检查的 HTTP 路由配置。
mux := http.NewServeMux() // 创建一个新的ServeMux实例
mux.HandleFunc("/mutate", mutationHandler.MutatePodSpec) // 将/mutate路径与mutationHandler.MutatePodSpec函数关联
mux.HandleFunc("/validate", validationHandler.ValidatePodSpec) // 将/validate路径与validationHandler.ValidatePodSpec函数关联
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) // 将/healthz路径设置为健康检查,返回状态码表示健康检查成功
// 返回状态码表示健康检查成功
// PodSpec: 容器组规格
这三条关键步骤使Ultron能够在pod规格信息被提供给Kubernetes集群中的节点之前进行拦截和增强。
核心服务乌特隆中的服务,位于[pkg/services](https://github.com/be-heroes/ultron/tree/main/pkg/services)
目录,是应用程序的实际工作主力所在。每个服务都承担着一组特定的责任,从与外部系统(如Redis)的交互,到执行复杂的内部任务,比如生成证书或缓存。
[CacheService](https://github.com/be-heroes/ultron/blob/main/pkg/services/cache_service.go)
管理与 Redis 服务器的交互,抽象处理缓存结果和检索存储数据的过程。此服务对于提高 Ultron 的性能至关重要,通过避免冗余计算,减少外部 API 调用,并加快对常用数据的访问,从而让我们能在“Ultron 查询”的 5 秒内快速完成任务。
下面是一个包含服务接口的内容:
type ICacheService interface {
AddCacheItem(key string, value interface{}, d time.Duration) error
GetCacheItem(key string) (interface{}, error)
GetAllComputeConfigurations() ([]ultron.ComputeConfiguration, error)
GetEphemeralComputeConfigurations() ([]ultron.ComputeConfiguration, error)
GetDurableComputeConfigurations() ([]ultron.ComputeConfiguration, error)
GetWeightedNodes() ([]ultron.WeightedNode, error)
GetWeightedInterruptRates() ([]ultron.WeightedInterruptRate, error)
GetWeightedLatencyRates() ([]ultron.WeightedLatencyRate, error)
}
在代码中,ICacheService
提供了从 Redis 设置和获取缓存数据的方法。该服务使用一个 Redis 客户端初始化,便于注入其他系统组件。
certificate_service.go
Ultron的[证书服务](https://github.com/be-heroes/ultron/blob/main/pkg/services/certificate_service.go)
负责生成TLS证书,这是实现安全通信的重要功能。在main.go
文件中,我们看到该服务被用来生成自签名证书。
下面来深入了解一下它是如何工作的:
func (cs *CertificateService) GenerateSelfSignedCert(organization string, commonName string, dnsNames []string, ipAddresses []net.IP) (tls.Certificate, error) {
if organization == "" || commonName == "" {
return tls.Certificate{}, fmt.Errorf("组织名和通用名都必须提供")
}
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return tls.Certificate{}, err
}
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return tls.Certificate{}, err
}
certTemplate := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{organization},
CommonName: commonName,
},
NotBefore: time.Now(),
NotAfter: time.Now().Add(365 * 24 * time.Hour),
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
DNSNames: dnsNames,
IPAddresses: ipAddresses,
}
certDERBytes, err := x509.CreateCertificate(rand.Reader, &certTemplate, &certTemplate, &priv.PublicKey, priv)
if err != nil {
return tls.Certificate{}, err
}
certPEM := pem.EncodeToMemory(&pem.Block{Type: "BlockTypeCertificate", Bytes: certDERBytes})
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "BlockTypeRsaPrivateKey", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
if err != nil {
return tls.Certificate{}, err
}
return tlsCert, nil
}
该服务封装了证书生成和管理的复杂流程,提供了创建和导出证书的方法。通过抽象这些功能,Ultron使安全相关操作变得易于管理和扩展,并避免了在开发和测试环境中依赖外部证书颁发机构。
Ultron的脑部代码:compute_service.go
[ComputeService](https://github.com/be-heroes/ultron/blob/a23d3c8487a05907c12325c0caea58c26da23425/pkg/services/compute_service.go#L27)
是 Ultron 最重要的服务之一,负责处理 pod 变体和校验的核心逻辑。该服务与其他组件(如算法和缓存等)集成,执行计算操作,以修改或校验 Kubernetes pod 规格。
这里看看它的结构:
// 匹配Pod规格函数
func (cs *ComputeService) MatchPodSpec(pod *corev1.Pod) (*ultron.WeightedNode, error) {
// 将Pod映射为加权Pod对象
wPod, err := cs.mapper.MapPodToWeightedPod(pod)
if err != nil {
return nil, err
}
// 根据加权Pod匹配加权节点
wNode, err := cs.MatchWeightedPodToWeightedNode(&wPod)
if err != nil {
return nil, err
}
// 如果wNode为空,则根据加权Pod匹配计算配置
if wNode == nil {
computeConfiguration, err := cs.MatchWeightedPodToComputeConfiguration(&wPod)
if err != nil {
return nil, err
}
// 如果计算配置不为空,则初始化wNode
if computeConfiguration != nil {
var instanceType string
// 根据计算类型设置实例类型
if computeConfiguration.ComputeType == ultron.ComputeTypeDurable {
instanceType = ultron.DefaultDurableInstanceType
} else {
instanceType = ultron.DefaultEphemeralInstanceType
}
// 初始化加权节点对象
wNode = &ultron.WeightedNode{
Selector: map[string]string{ultron.LabelInstanceType: instanceType, ultron.AnnotationManaged: "true"},
AvailableCPU: float64(*computeConfiguration.VCpu),
TotalCPU: float64(*computeConfiguration.VCpu),
AvailableMemory: float64(*computeConfiguration.RamGb),
TotalMemory: float64(*computeConfiguration.RamGb),
AvailableStorage: float64(*computeConfiguration.VolumeGb),
DiskType: wPod.RequestedDiskType,
NetworkType: wPod.RequestedNetworkType,
Price: float64(*computeConfiguration.Cost.PricePerUnit),
InstanceType: instanceType,
}
// 获取加权节点的中断率
interuptionRate, err := cs.GetInteruptionRateForWeightedNode(wNode)
if err != nil {
return nil, err
}
// 设置加权节点的中断率
wNode.InterruptionRate = *interuptionRate
// 获取加权节点的延迟率
latencyRate, err := cs.GetLatencyRateForWeightedNode(wNode)
if err != nil {
return nil, err
}
// 设置加权节点的延迟率
wNode.LatencyRate = *latencyRate
}
}
// 返回加权节点对象和错误
return wNode, nil
}
HTTP 处理程序
Ultron 内部的处理程序负责管理与 Kubernetes 基础设施集成的核心变异和验证操作。这些处理程序负责修改 pod 规范,或者确保在部署到节点前满足特定要求。详见 [internal/handlers](https://github.com/be-heroes/ultron/tree/main/internal/handlers)
。
mutation_handler.go
[MutationHandler](https://github.com/be-heroes/ultron/blob/a23d3c8487a05907c12325c0caea58c26da23425/internal/handlers/mutation_handler.go#L20)
会接收 Kubernetes pod 规格并根据预定义的规则对其进行修改。这可能包括注入环境变量、添加 sidecar 容器,或其他自动应用的修改。
func (mh *MutationHandler) HandleAdmissionReview(request *admissionv1.AdmissionRequest) (*admissionv1.AdmissionResponse, error) {
if request.Kind.Kind != "Pod" {
return &admissionv1.AdmissionResponse{
Allowed: true,
}, nil
}
var pod corev1.Pod
if err := json.Unmarshal(request.Object.Raw, &pod); err != nil {
return &admissionv1.AdmissionResponse{
Allowed: true,
}, err
}
wNode, err := mh.computeService.MatchPodSpec(&pod)
if err != nil {
return nil, err
}
if wNode == nil {
return &admissionv1.AdmissionResponse{
Allowed: true,
}, nil
}
pod.Spec.NodeSelector = wNode.Selector
patchBytes, err := json.Marshal([]map[string]interface{}{
{
"op": "add",
"path": "/spec/nodeSelector",
"value": pod.Spec.NodeSelector,
},
})
if err != nil {
return &admissionv1.AdmissionResponse{
Allowed: true,
}, err
}
return &admissionv1.AdmissionResponse{
Allowed: true,
Patch: patchBytes,
PatchType: func() *admissionv1.PatchType { pt := admissionv1.PatchTypeJSONPatch; return &pt }(),
}, nil
}
处理程序通过 [MatchPodSpec](https://github.com/be-heroes/ultron/blob/a23d3c8487a05907c12325c0caea58c26da23425/pkg/services/compute_service.go#L41)
操作利用 ComputeService
来修改 pod 规范。这种清晰的隔离确保了业务逻辑(在服务里)与 HTTP 处理代码分离,从而使系统更加模块化和易于维护。
validation_handler.go
同样,[ValidationHandler](https://github.com/be-heroes/ultron/blob/main/internal/handlers/validation_handler.go)
确保 Kubernetes Pod 规格在被集群接受之前符合某些验证规则。这对于防止无效或不安全的配置被部署到集群中至关重要。
func (vh *ValidationHandler) HandleAdmissionReview(request *admissionv1.AdmissionRequest) (*admissionv1.AdmissionResponse, error) {
// 如果请求的类型不是Pod,则返回允许的响应
if request.Kind.Kind != "Pod" {
return &admissionv1.AdmissionResponse{
Allowed: true,
}, nil
}
// 定义一个Pod对象
var pod corev1.Pod
// 解析请求中的Pod对象,如果解析失败则返回错误
if err := json.Unmarshal(request.Object.Raw, &pod); err != nil {
return &admissionv1.AdmissionResponse{
Allowed: true,
}, err
}
// 根据Pod对象匹配节点
wNode, err := vh.computeService.MatchPodSpec(&pod)
if err != nil {
return nil, err
}
// 如果节点为空且redisClient不为空,则发布Pod观察事件到redisClient
if wNode == nil && vh.redisClient != nil {
vh.redisClient.Publish(context.Background(), ultron.TopicPodObserve, pod)
} else if vh.redisClient != nil {
// 否则,发布节点观察事件到redisClient
vh.redisClient.Publish(context.Background(), ultron.TopicNodeObserve, wNode)
}
// 返回允许的响应
return &admissionv1.AdmissionResponse{
Allowed: true,
}, nil
}
ComputeService
用于验证 pod 规格。若发现任何验证错误,返回一个 400 Bad Request
错误给客户端。这样可以确保只有有效的 pod 才能进入 Kubernetes 集群,减少了配置错误的可能性。一旦验证通过,会向 Redis 服务器发送一条消息,以便其他组件开始监控集群内的资源,并反馈指标给 Ultron 处理,以判断优化是否达到预期效果,或者是否有进一步改进的可能通过重新调度工作负载。
Ultron 是一个开源应用程序,利用 Go 语言的优势来构建一个多云 Kubernetes 环境中工作负载部署的可扩展和安全的系统。服务和处理器之间职责的清晰划分、依赖注入的使用以及对可测试性的重视,使这个代码库易于理解和扩展。
乌隆特(Ultron)还有改进的空间,例如增加更细致的错误处理,对外部服务实现重试功能以及增强服务初始化时的日志记录。不过,乌隆特仍然是一个很好的例子,展示了如何构建一个与Kubernetes紧密结合的应用,提供了有关如何在大规模环境中管理Pod变异、验证和供应的宝贵经验。
共同学习,写下你的评论
评论加载中...
作者其他优质文章