Kubernetes ImagePolicyWebhook与ValidatingAdmissionWebhook【2】Image_Policy.go源码解析(2)

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
全局流量管理 GTM,标准版 1个月
简介: Kubernetes ImagePolicyWebhook与ValidatingAdmissionWebhook【2】Image_Policy.go源码解析(2)
splitDockerDomain(s)

splitDockerDomain(s)在第90行,通过字段其实大概就能明白它的意思。字段切分。具体怎么实现的呢?

1035234-20181020215539574-213176954.png

strings.IndexRune(name, '/')方法,可以参考go strings方法IndexRune返回字符/在字符串s中第一次出现的位置,如果找不到,则返回-1。domain就等于docker.io,在代码中已初始化好,name等于remainder

1035234-20181020215539574-213176954.png

如果镜像中有‘/’呢,例如:kainlite/kube-image-bouncer:latest,domain取kainlite,remainder取kube-image-bouncer:latest


假如domain等于index.docker.io,就重定义为docker.io


假如domain等于docker.io,并且再次确认remainder不包含‘/’,就将remainder再次重新定义 officialRepoName + "/" + remainder


splitDockerDomain(s)函数分析完毕。继续ParseNormalizedNamed(s string) (Named, error)的分析:


定义个remoteName


tagSep := strings.IndexRune(remainder, ‘:’),即确认:的位置,如果>-1,即如果存在,则

tagSep等于镜像的标签,否则,就等于镜像的名字


strings.ToLower将s中的所有字符修改为其小写格式,如果remotename存在大写的话则不符合仓库名字规范。

parse

Parse(domain + "/" + remainder)是什么意思呢?

1035234-20181020215539574-213176954.png

又是好大的一个函数。

那我们慢慢来分析吧

referenceRegexp.FindStringSubmatch(s)

referenceRegexp.FindStringSubmatch(s)是啥意思?翻译过来就是ReferenceRegexp是完全支持的引用格式。regexp被锚定,并具有名称、标记和摘要组件的捕获组。描述看不懂。还是具体代码逻辑吧

1035234-20181020215539574-213176954.png

anchored大体明白了,就是通过添加开始和结束分隔符锚定正则表达式并作为返回值。

1035234-20181020215539574-213176954.png

正则表达式字符的字符串转换字符串形式。

capture函数与anchored大同小异,只是将含有正则表达式字符的字符串转换数组形式并作为返回值。

1035234-20181020215539574-213176954.png

optional似乎是对字符串可有可无的一种设定,并且optional字面意思是可选的。

1035234-20181020215539574-213176954.png

1035234-20181020215539574-213176954.png

literal函数是什么意思?翻译是将文本编译为文本正则表达式,转义任何regexp保留字符。字面非常容易理解。

1035234-20181020215539574-213176954.png

  • QuoteMeta返回一个字符串,该字符串转义参数文本中的所有正则表达式元字符;返回的字符串是与文本匹配的正则表达式。
  • var match = regexp.MustCompile
  • re := regexp.MustCompile(正则字符串)
  • re就是单纯的正则表达式了。

1035234-20181020215539574-213176954.png

LiteralPrefix返回一个字面值字符串,该字符串必须以正则表达式re的任何匹配项开始。如果字面值字符串包含整个正则表达式,则返回布尔值true。

1035234-20181020215539574-213176954.png

后面的函数方法其实大同小异,这里不一一拆解。

回到函数ReferenceRegexp.FindStringSubmatch(s),FindStringSubmatch(s)是regexp的方法FindStringSubmatch返回一个字符串切片,其中包含正则表达式在s中最左匹配的文本,以及它的子表达式的匹配(如果有的话),如包注释中的’Submatch’描述中定义的那样。返回值为nil表示没有匹配。


ReferenceRegexp函数其实设定了一个正则表达式,使字符串s能够通过我们希望的分割的方式,形成一个切片。它的关键之处是获取s的正则表达式,融入到设定的规则之中。


假如matches为nil,报错

假如matches[1]长度>255,也会报错

nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1])

这段代码其实是对domain的再度切片,如果它较多的递级目录,那我们就要对目录与仓库名称做出区分。

这里定义了一个关于镜像仓库名与标签的结构体,这是非常重要的一步。

ref := reference{
  namedRepository: repo,
  tag:             matches[2],
}

matches[3]是什么? matches[2]是镜像的版本标签,在这之后,又是通过@分割当然是一个哈希字符串的内容,是可有可无的。所以有下面的一个判断。

if matches[3] != "" {
  var err error
  ref.digest, err = digest.Parse(matches[3])
  if err != nil {
    return nil, err
  }
}

digest包正是处理哈希字符串的。

1035234-20181020215539574-213176954.png

1035234-20181020215539574-213176954.png

对包含镜像的仓库、标签、哈希值的ref结构体再次检查判断,有什么输出什么。并重构还有该特性的结构体。一共有三类结构体。如下:

1035234-20181020215539574-213176954.png

到这里,关于parse的函数分析已经结束了,这一路下来学到了不少方法,不能说全盘了解,但调用的机理已经摸透。

named, isNamed := ref.(Named)是个非常有趣的值得摸索记住的。我不懂,结构体跟点跟括号。后续研究。,但根据下面的代码逻辑推理,可能:

  r.Name() + ":" + r.tag + "@" + r.digest.String()

Named是管道,ref是结构体reference结构体的定义,那么自然会承接Reference管道中的refenceString()

1035234-20181020215539574-213176954.png

1035234-20181020215539574-213176954.png

1035234-20181020215539574-213176954.png

1035234-20181020215539574-213176954.png

1035234-20181020215539574-213176954.png

剩下要做的就是看看这个parse函数返回值被如何用了,自然可以推理出来,如下

1035234-20181020215539574-213176954.png

strings.HasSuffix判断字符串s是否以某个字符串结尾,

1035234-20181020215539574-213176954.png

TagNameOnly函数很好理解,就是判断镜像有没有标签,如果没有标签就添加默认"latest"。

那我们来看看他怎么实现的吧。

IsNameOnly函数在helpers.go

1035234-20181020215539574-213176954.png

来到这里我们又遇到了ref.(NamedTagged),看到这里,也许有一丝明白过来,这个对ref的结构体属性的判断,根据结构体中的属性是否包含值,通过接口组合成一个判断类型。之前,named, isNamed := ref.(Named)代表返回一个完整的镜像+标签的内容,并判断是否正常返回,这里代表是否只返回标签,也就是只判断是否有标签。下面的ref.(Canonical)则是判断标签是否有哈希值。

1035234-20181020215539574-213176954.png

1035234-20181020215539574-213176954.png

最后,如果没有任何标签,即为true,继续执行namedTagged, err := WithTag(ref, defaultTag)

1035234-20181020215539574-213176954.png

withtag函数传递两个函数,获取的镜像的信息,和latest标签。

1035234-20181020215539574-213176954.png

这个对已经获取的Named的对象重新进行定义,目的是为了把默认没有标签的镜像打上latest标签。


当withtag函数执行结束,TagNameOnly(named)也就返回新的镜像结构体,然后通过String()方法,字符串化,Strings.HasSuffix方法判断这个字符串是否以:latest结尾。根据正确与否返回true或false。


IsUsingLatestTag函数的逻辑终于也就结束了。


回到我们的image_policy代码中来。


下面就是根据判断是否有latest做出终端日志输出判断,并且打个是否allow的标签。


我们完成了哪些部分的代码分析呢?真的是九牛一毛。

1035234-20181020215539574-213176954.png

4. echo包

下面只需要分析明白如下内容。

1035234-20181020215539574-213176954.png

echo web框架是go语言开发的一种高性能,可扩展,轻量级的web框架。

echo框架真的非常简单,几行代码就可以启动一个高性能的http服务端。

echo.Context表示当前 HTTP 请求的上下文。它保存请求和响应引用、路径、路径参数、数据、注册处理程序和 API 以读取请求和写入响应。由于 Context 是一个接口,因此很容易使用自定义 API 对其进行扩展。

handlerFunc定义http请求,匿名函数像变量一样返回给echo.HandlerFunc

1035234-20181020215539574-213176954.png

c.bind(&imageReview)意思是通过将请求参数绑定到一个名叫imageReview的struct对象的方式获取数据。这种方式获取请求参数支持json、xml、k/v键值对等多种方式。


该函数最终返回一个json格式的pod拉去一个镜像的属性信息,并伴随http请求状态。


分析到这里,我们完成了对Image_Policy.go的步步分析,也深刻的体会到读源码的重要性。

5. 总结

我对go有了以下感悟:


go的logo是一只土拨鼠,土拨鼠的习性是挖地洞,因此,我们在学习go的时候要有土拨鼠的挖洞精神,在每个包、每个函数、每个方法、每个接口、每个结构体找到它最真实的面孔。

echo web框架的使用,请参考这篇文章

匿名函数作为返回值的使用

匿名函数由一个不带函数名的函数声明和函数体组成。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。这是它最大的特点。这里将一个函数当做一个变量一样的操作作为函数的返回值输出给echo.HandlerFunc


依赖包的结构体具体特性进行变量声明,方便简化代码的逻辑。例如:var imageReview v1alpha1.ImageReview

谁在调用image_policy.go ,是main.go,在下一篇接文章,我们慢慢分析它的逻辑是什么。


相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
8天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
28 2
|
8天前
|
存储 安全 Linux
Golang的GMP调度模型与源码解析
【11月更文挑战第11天】GMP 调度模型是 Go 语言运行时系统的核心部分,用于高效管理和调度大量协程(goroutine)。它通过少量的操作系统线程(M)和逻辑处理器(P)来调度大量的轻量级协程(G),从而实现高性能的并发处理。GMP 模型通过本地队列和全局队列来减少锁竞争,提高调度效率。在 Go 源码中,`runtime.h` 文件定义了关键数据结构,`schedule()` 和 `findrunnable()` 函数实现了核心调度逻辑。通过深入研究 GMP 模型,可以更好地理解 Go 语言的并发机制。
|
14天前
|
运维 Kubernetes Cloud Native
Kubernetes云原生架构深度解析与实践指南####
本文深入探讨了Kubernetes作为领先的云原生应用编排平台,其设计理念、核心组件及高级特性。通过剖析Kubernetes的工作原理,结合具体案例分析,为读者呈现如何在实际项目中高效部署、管理和扩展容器化应用的策略与技巧。文章还涵盖了服务发现、负载均衡、配置管理、自动化伸缩等关键议题,旨在帮助开发者和运维人员掌握利用Kubernetes构建健壮、可伸缩的云原生生态系统的能力。 ####
|
12天前
|
存储 Kubernetes 调度
深度解析Kubernetes中的Pod生命周期管理
深度解析Kubernetes中的Pod生命周期管理
|
15天前
|
安全 测试技术 Go
Go语言中的并发编程模型解析####
在当今的软件开发领域,高效的并发处理能力是提升系统性能的关键。本文深入探讨了Go语言独特的并发编程模型——goroutines和channels,通过实例解析其工作原理、优势及最佳实践,旨在为开发者提供实用的Go语言并发编程指南。 ####
|
20天前
|
Go
|
1月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
68 0
|
1月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
57 0
|
1月前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
62 0
|
1月前
|
安全 Java 程序员
Collection-Stack&Queue源码解析
Collection-Stack&Queue源码解析
83 0

推荐镜像

更多
下一篇
无影云桌面