一、工程概述
- 本项目主要基于Kubernetes集群开展,针对开源项目进行功能扩展。要求基于已有的Kubernetes集群和Prometheus 监控系统进行扩展开发。
- K8s是由Google开发,并使用go语言进行开发的。
二、源码准备
1.系统环境:
- 操作系统:我们使用Linux作为k8s源码分析和调试环境,fedora、centos、ubuntu都行,我这里使用fedora;
- golang相关:
GOROOT=/usr/local/lib/golang
GOPATH=/root/go
go version go1.10.3 linux/amd64
2.源码下载
mkdir -p /root/go/src/k8s.io
cd /root/go/src/k8s.io/
git clone https://github.com/kubernetes/kubernetes.git
-
目录展示:
-
主要目录:
目录名 | 功能 |
---|---|
cmd | 每个组件代码入口(main函数) |
pkg | 各个组件的具体功能实现 |
staging | 已经分库的项目 |
vendor | 依赖 |
3.IDE
- 通过学校邮箱申请JetBrains的教育账号,通过Goland看代码:
三、go语言特点及命名规范
1.go语言特点
GO语言的关键特性主要包括以下几方面:
- 并发与协程
- 基于消息传递的通信方式
- 丰富实用的内置数据类型
- 函数多返回值
- defer机制
- 反射(reflect)
- 高性能HTTP Server
- 工程管理
- 编程规范
2.相关规范
-
package名字
保持package的名字和目录保持一致,尽量采取有意义的包名,简短,有意义,尽量和标准库不要冲突。 -
import 规范
import在多行的情况下,自动工具会自动帮你格式化,但是我们这里还是规范一下import的一些规范,如果你在一个文件里面引入了一个package,还是建议采用如下格式:
import (
"fmt"
)
如果你的包引入了三种类型的包,标准库包,程序内部包,第三方包,建议采用如下方式进行组织你的包:
import (
"strings"
"myproject/models"
"myproject/controller"
"github.com/mysql"
)
有顺序的引入包,不同的类型采用空格分离,第一种实标准库,第二是项目包,第三是第三方包。在项目中不要使用相对路径引入包:
// 这是不好的导入
import “../pkg”
// 这是正确的做法
import “github.com/tx23/pkg”
- 变量申明
变量名采用驼峰标准,不要使用_来命名变量名,多个变量申明放在一起
在函数外部申明必须使用var,不要采用:=,容易踩到变量的作用域的问题。
var (
Found bool
count int
)
- 自定义类型的string循环问题
如果自定义的类型定义了String方法,那么在打印的时候会产生隐藏的一些bug。
type MyInt int
func (m MyInt) String() string {
return fmt.Sprint(m) //BUG:死循环
}
func(m MyInt) String() string {
return fmt.Sprint(int(m)) //这是安全的,因为我们内部进行了类型转换
}
- 避免返回命名的参数
如果你的函数很短小,少于10行代码,那么可以使用,不然请直接使用类型,因为如果使用命名变量很容易引起隐藏的bug。
func Foo(a int, b int) (string, ok){
}
当然如果是有多个相同类型的参数返回,那么命名参数可能更清晰。
func (f *Foo) Location() (float64, float64, error)
-
错误处理
错误处理的原则就是不能丢弃任何有返回err的调用,不要采用_丢弃,必须全部处理。接收到错误,要么返回err,要么实在不行就panic,或者使用log记录下来,error的信息不要采用大写字母,尽量保持你的错误简短,但是要足够表达你的错误的意思。 -
注意闭包的调用
在循环中调用函数或者goroutine方法,一定要采用显示的变量调用,不要再闭包函数里面调用循环的参数
fori:=0;i<limit;i++{
go func(){ DoSomething(i) }() //错误的做法
go func(i int){ DoSomething(i) }(i)//正确的做法
}
-
在逻辑处理中禁用panic
在main包中只有当实在不可运行的情况采用panic,例如文件无法打开,数据库无法连接导致程序无法正常运行,但是对于其他的package对外的接口不能有panic,只能在包内采用。强烈建议在main包中使用log.Fatal来记录错误,这样就可以由log来结束程序。 -
struct规范
struct申明和初始化格式采用多行:
定义如下:
type User struct{
Username string
Email string
}
初始化如下:
u := User{
Username: "astaxie",
Email: "astaxie@gmail.com",
}
- recieved是值类型还是指针类型
到底是采用值类型还是指针类型主要参考如下原则:
func(w Win) Tally(playerPlayer)int //w不会有任何改变
func(w *Win) Tally(playerPlayer)int //w会改变数据
更多的请参考:
https://code.google.com/p/go-wiki/wiki/CodeReviewComments#Receiver_Type
- 带mutex的struct必须是指针receivers
如果你定义的struct中带有mutex,那么你的receivers必须是指针
参考资料:
https://code.google.com/p/go-wiki/wiki/CodeReviewComments
http://golang.org/doc/effective_go.html