golang & k8s学习笔记
学习笔记
1、k8s概念图
2、In Kubernetes, namespaces provides a mechanism for isolating groups of resources within a single cluster. 在一个k8s集群中,命名空间提供一种资源组隔离的机制。
3、凡是调度、网络、存储,以及安全相关的属性,基本上是 Pod 级别的。凡是跟容器的 Linux Namespace 相关的属性,也一定是 Pod 级别的。
4、这些特殊 Volume 的作用,是为容器提供预先定义好的数据。所以,从容器的角度来看,这些 Volume 里的信息就是仿佛是被 Kubernetes“投射”(Project)进入容器当中的。到目前为止,Kubernetes 支持的 Projected Volume 一共有四种:Secret;ConfigMap;Downward API;ServiceAccountToken。
5、关于golang中切片作为函数参数:
因为切片中的底层数组部分是通过隐式指针传递(指针本身依然是传值的,但是指针指向的却是同一份的数据),所以被调用函数是可以通过指针修改掉调用参数切片中的数据。除了数据之外,切片结构还包含了切片长度和切片容量信息,这2个信息也是传值的。如果被调用函数中修改了Len
或Cap
信息的话,就无法反映到调用参数的切片中,这时候我们一般会通过返回修改后的切片来更新之前的切片。这也是为何内置的append
必须要返回一个切片的原因。
6、在Go1.4以前,Go的动态栈采用的是分段式的动态栈,通俗地说就是采用一个链表来实现动态栈,每个链表的节点内存位置不会发生变化。但是链表实现的动态栈对某些导致跨越链表不同节点的热点调用的性能影响较大,因为相邻的链表节点它们在内存位置一般不是相邻的,这会增加CPU高速缓存命中失败的几率。为了解决热点调用的CPU缓存命中率问题,Go1.4之后改用连续的动态栈实现,也就是采用一个类似动态数组的结构来表示栈。不过连续动态栈也带来了新的问题:当连续栈动态增长时,需要将之前的数据移动到新的内存空间,这会导致之前栈中全部变量的地址发生变化。虽然Go语言运行时会自动更新引用了地址变化的栈变量的指针,但最重要的一点是要明白Go语言中指针不再是固定不变的了(因此不能随意将指针保持到数值变量中,Go语言的地址也不能随意保存到不在GC控制的环境中,因此使用CGO时不能在C语言中长期持有Go语言对象的地址)。
7、在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。
在鸭子类型中,关注点在于对象的行为,能作什么;而不是关注对象所属的类型。Go语言中的面向对象就是如此,如果一个对象只要看起来像是某种接口类型的实现,那么它就可以作为该接口类型使用。这种设计可以让你创建一个新的接口类型满足已经存在的具体类型却不用去破坏这些类型原有的定义;当我们使用的类型来自于不受我们控制的包时这种设计尤其灵活有用。Go语言的接口类型是延迟绑定,可以实现类似虚函数的多态功能。
8、Go语言是基于消息并发模型的集大成者,它将基于CSP(Communicating Sequential Process)模型的并发编程内置到了语言中,通过一个go关键字就可以轻易地启动一个Goroutine,与Erlang不同的是Go语言的Goroutine之间是共享内存的。
9、对比系统线程,goroutine的优势点:
1)调整了栈分配策略,使用动态扩展栈,最小2kb,最大可大1G。
2)goroutine切换只保存极少的寄存器,切换代价更低。
10、Each controller focuses on one root Kind, but may interact with other Kinds.
11、What is Workload?
官网的解释:A workload is an application running on Kubernetes. Whether your workload is a single component or several that work together, on Kubernetes you run it inside a set of pods.
... However, to make life considerably easier, you don't need to manage each Pod
directly. Instead, you can use workload resources that manage a set of pods on your behalf. These resources configure controllers that make sure the right number of the right kind of pod are running, to match the state you specified。
一言以蔽之:workload是运行在pod之上的k8s对象,通过它来管理pod的生命周期,以达到期望状态。
12、Pods are only scheduled once in their lifetime. Once a Pod is scheduled (assigned) to a Node, the Pod runs on that Node until it stops or is terminated. Pod一经被调度,就无法被修改。那如何保证我们的应用一直运行呢?通过workload resource。
13、实际上go的GMP模型,只能减少活跃线程切换的数量,如果在一个系统中,阻塞的线程或goroutine固定,活跃的线程或goroutine<= procs,那么这个系统无论是用多线程还是使用goroutine,没有没太大的区别。
14、抢占式和协作式:抢占式是指当前执行程序被动放弃cpu资源,协作式是当前执行程序执行完成了,释放cpu资源,其他执行程序才能得到cpu资源进行执行。goroutine是半抢占式的,指goroutine在10ms前是协作式的,超过10ms后,会被动让出cpu资源,防止其他goroutine被饿死。
15、Golang中一个函数内局部变量,不管是不是动态new出来的,它会被分配在堆还是栈,是由编译器做逃逸分析之后做出的决定。
16、三色标记法和写屏障:所谓三色,是指在垃圾回收的时候,在并发标记,可达性分析一些列过程中的一种方法;所谓写屏障,是指在并发情况下,为了达到标记的一致性,所遵循的规则,如黑色节点不允许连接白色节点。参考:golang/5、Golang三色标记+混合写屏障GC模式全分析.md at main · aceld/golang · GitHub
17、golang 中,panic仅有最后一个可以被revover捕获。
18、golang中,在函数有多个返回值时,只要有一个返回值有指定命名,其他的也必须有命名。 如果返回值有有多个返回值必须加上括号; 如果只有一个返回值并且有命名也需要加上括号。
19、只有相同类型的结构体才可以比较,结构体是否相同不但与属性类型个数有关,还与属性顺序相关。两个结构体即使成员相同,定义的顺序不同,编译器也会把它们识别为两个不同的结构体。
20、golang的map跟java和python的map不一样,golang的map对象是个变量,访问其元素返回的是元素值本身(也就是说在golang的map中,元素本身没有“变量”这个概念在map中,来指定元素),因此,不能通过访问map元素来给元素的成员赋值,也不能获取map元素的地址。
21、golang中,使用range遍历list或map,遍历值是一个临时变量,每次循环通过值拷贝给这个临时变量,因此,整个遍历过程中,这个值变量只有一个,因此地址也只有一个,在使用循环赋值这个值变量的地址的时候特别注意。
22、golang中,interface类型,就是指针类型。interface{}可以类比c/c++中的void *。
23、golang中的interface关键字,类比c++中的抽象类:相当于golang在语言层面支持了抽象类,类似于java中interface的关键字。实际上golang将类型进行归类,即:struct、map、slice、interface等,通过这些关键字进行归类是区别于其他语言的一种特性。对于基础类型,单独归为一类。例如int,被归类为int。看看下面代码:
type Student struct {
Name string
Age int
}
func (s *Student) Speak(data string) string {
fmt.Println("Say: ", data)
return data
}
type People interface {
Speak(string) string
}
type myS string
func main() {
var p People = &Student{}
s := Student{}
m := myS("ddd")
k := 12
fmt.Println(reflect.TypeOf(p).Kind())
fmt.Println(reflect.TypeOf(p))
fmt.Println(reflect.TypeOf(s).Kind())
fmt.Println(reflect.TypeOf(s))
fmt.Println(reflect.TypeOf(m).Kind())
fmt.Println(reflect.TypeOf(m))
fmt.Println(reflect.TypeOf(k).Kind())
fmt.Println(reflect.TypeOf(k))
}
输出:
ptr
*main.Student
struct
main.Student
string
main.myS
int
int
《张磊讲k8s》
24、“敏捷”和“高性能”是容器相较于虚拟机最大的优势,也是它能够在 PaaS 这种更细粒度的资源管理平台上大行其道的重要原因。
25、容器技术跟kvm技术的区别:
资源占用:容器使用的是linux的namespace技术隔离进程,对于宿主机来说,容器进程只是加了特定namespace参数的进程,与一般进程无异,因此性能损耗几乎可忽略不计;kvm运行整个模拟操作系统,即使系统不跑任何应用,也会占用资源(100M~200M),并且任何系统调用,都会经过一层hook,也增加了性能消耗。
隔离性:容器,并不是所有东西都可以用namespace进行隔离,比如系统时间,而且容器与宿主机公用Linux系统内核;而kvm模拟了整个操作系统。
安全性:由于容器存隔离不足,相对于kvm,暴露给外面的攻击面比较大。因此,生产环境不应该直接把容器的服务暴露到公网。
26、Linux Cgroups 就是 Linux 内核中用来为进程设置资源限制的一个重要功能。
27、Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。
28、Linux Cgroups 的设计还是比较易用的,简单粗暴地理解呢,它就是一个子系统目录加上一组资源限制文件的组合。
29、实际上,Mount Namespace 正是基于对 chroot 的不断改良才被发明出来的,它也是 Linux 操作系统里的第一个 Namespace。
30、而这个挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统,就是所谓的“容器镜像”。它还有一个更为专业的名字,叫作:rootfs(根文件系统)。
31、思考:docker exec 命令,实际上并不是真的“进入”了一个容器的东西,而是通过chroot命令,改变了要执行进程的rootfs,即根文件系统。
32、docker镜像实际就是一个完整文件系统的压缩包,启动容器的时候,1号进程被mount namespace到这个文件系统上。
33、需要明确的是,rootfs 只是一个操作系统所包含的文件、配置和目录,并不包括操作系统内核。在 Linux 操作系统中,这两部分是分开存放的,操作系统只有在开机启动时才会加载指定版本的内核镜像。
更多推荐
所有评论(0)