如何优化K8s容器检查代码?复用同逻辑不同类型函数
合并同逻辑不同参数类型Go函数的实现方案
问题描述
现有Go代码中存在fnc1、fnc2两个函数,二者核心逻辑完全一致,仅接收的容器参数类型分别为v1.Container和v1.EphemeralContainer。为减少代码重复,希望将这两个函数合并为单个函数,可通过泛型或接口适配等方式实现。
解决方案
方案一:使用Go泛型(Go 1.18+)
利用Go的泛型特性,定义包含所需字段的类型约束,让单个函数支持两种容器类型:
import ( "context" "fmt" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/api/core/v1" ) // 定义类型约束,匹配拥有Name和SecurityContext字段的结构 type ContainerLike interface { ~struct { Name string SecurityContext *v1.SecurityContext } } // 泛型函数,处理两种容器类型的逻辑 func checkContainer[T ContainerLike](container T, pod v1.Pod, containerType string) { sc := container.SecurityContext if sc.AllowPrivilegeEscalation != nil && !*sc.AllowPrivilegeEscalation { fmt.Printf("Pod %s has escalatable %s %s\n", pod.Name, containerType, container.Name) } if sc.RunAsNonRoot != nil && *sc.RunAsNonRoot == false { fmt.Printf("Pod %s has %s %s running as root\n", pod.Name, containerType, container.Name) } } func main() { pods, err := clientset.CoreV1().Pods("").List(context.Background(), metav1.ListOptions{}) if err != nil { panic(err) } for _, pod := range pods.Items { // 处理普通容器 for _, container := range pod.Spec.Containers { if container.SecurityContext != nil { checkContainer(container, pod, "container") } } // 处理初始化容器 for _, container := range pod.Spec.InitContainers { if container.SecurityContext != nil { checkContainer(container, pod, "container") } } // 处理临时容器 for _, container := range pod.Spec.EphemeralContainers { if container.SecurityContext != nil { checkContainer(container, pod, "ephemeralContainer") } } } }
方案二:使用接口适配
定义统一接口,为两种容器类型实现接口方法,通过接口抽象实现逻辑复用:
import ( "context" "fmt" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/api/core/v1" ) // 定义容器接口,包含业务逻辑所需的方法 type Container interface { GetName() string GetSecurityContext() *v1.SecurityContext } // 为v1.Container实现Container接口 func (c v1.Container) GetName() string { return c.Name } func (c v1.Container) GetSecurityContext() *v1.SecurityContext { return c.SecurityContext } // 为v1.EphemeralContainer实现Container接口 func (c v1.EphemeralContainer) GetName() string { return c.Name } func (c v1.EphemeralContainer) GetSecurityContext() *v1.SecurityContext { return c.SecurityContext } // 统一处理函数,接收Container接口类型参数 func checkContainer(container Container, pod v1.Pod, containerType string) { sc := container.GetSecurityContext() if sc.AllowPrivilegeEscalation != nil && !*sc.AllowPrivilegeEscalation { fmt.Printf("Pod %s has escalatable %s %s\n", pod.Name, containerType, container.GetName()) } if sc.RunAsNonRoot != nil && *sc.RunAsNonRoot == false { fmt.Printf("Pod %s has %s %s running as root\n", pod.Name, containerType, container.GetName()) } } func main() { pods, err := clientset.CoreV1().Pods("").List(context.Background(), metav1.ListOptions{}) if err != nil { panic(err) } for _, pod := range pods.Items { for _, container := range pod.Spec.Containers { if container.SecurityContext != nil { checkContainer(container, pod, "container") } } for _, container := range pod.Spec.InitContainers { if container.SecurityContext != nil { checkContainer(container, pod, "container") } } for _, container := range pod.Spec.EphemeralContainers { if container.SecurityContext != nil { checkContainer(container, pod, "ephemeralContainer") } } } }
方案对比
- 泛型方案:代码更简洁,无需额外编写接口实现,直接利用类型约束复用逻辑,适合Go 1.18及以上版本。
- 接口方案:兼容性更强,支持Go 1.18之前的版本,符合Go语言"面向接口编程"的设计理念,扩展性更好。
内容的提问来源于stack exchange,提问作者Jenney
相关产品推荐
相关产品推荐

