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

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
云解析 DNS,旗舰版 1个月
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 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搭建和管理企业级网站应用
相关文章
|
14天前
|
存储 缓存 Java
什么是线程池?从底层源码入手,深度解析线程池的工作原理
本文从底层源码入手,深度解析ThreadPoolExecutor底层源码,包括其核心字段、内部类和重要方法,另外对Executors工具类下的四种自带线程池源码进行解释。 阅读本文后,可以对线程池的工作原理、七大参数、生命周期、拒绝策略等内容拥有更深入的认识。
什么是线程池?从底层源码入手,深度解析线程池的工作原理
|
18天前
|
开发工具
Flutter-AnimatedWidget组件源码解析
Flutter-AnimatedWidget组件源码解析
|
14天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
157 37
|
6天前
|
编解码 开发工具 UED
QT Widgets模块源码解析与实践
【9月更文挑战第20天】Qt Widgets 模块是 Qt 开发中至关重要的部分,提供了丰富的 GUI 组件,如按钮、文本框等,并支持布局管理、事件处理和窗口管理。这些组件基于信号与槽机制,实现灵活交互。通过对源码的解析及实践应用,可深入了解其类结构、布局管理和事件处理机制,掌握创建复杂 UI 界面的方法,提升开发效率和用户体验。
47 12
|
29天前
|
监控 网络协议 Java
Tomcat源码解析】整体架构组成及核心组件
Tomcat,原名Catalina,是一款优雅轻盈的Web服务器,自4.x版本起扩展了JSP、EL等功能,超越了单纯的Servlet容器范畴。Servlet是Sun公司为Java编程Web应用制定的规范,Tomcat作为Servlet容器,负责构建Request与Response对象,并执行业务逻辑。
Tomcat源码解析】整体架构组成及核心组件
|
1月前
|
存储 NoSQL Redis
redis 6源码解析之 object
redis 6源码解析之 object
56 6
|
1月前
|
测试技术 Python
python自动化测试中装饰器@ddt与@data源码深入解析
综上所述,使用 `@ddt`和 `@data`可以大大简化写作测试用例的过程,让我们能专注于测试逻辑的本身,而无需编写重复的测试方法。通过讲解了 `@ddt`和 `@data`源码的关键部分,我们可以更深入地理解其背后的工作原理。
28 1
|
1月前
|
开发者 Python
深入解析Python `httpx`源码,探索现代HTTP客户端的秘密!
深入解析Python `httpx`源码,探索现代HTTP客户端的秘密!
71 1
|
1月前
|
开发者 Python
深入解析Python `requests`库源码,揭开HTTP请求的神秘面纱!
深入解析Python `requests`库源码,揭开HTTP请求的神秘面纱!
128 1
|
2月前
|
负载均衡 Java Spring
@EnableFeignClients注解源码解析
@EnableFeignClients注解源码解析
64 14

热门文章

最新文章