k8s系列 – client-go安装原理与基本使用
发现网上关于k8s client-go的用法基本没有,所以特意把基本的安装与使用步骤以及原理记录下来,帮助大家理解整个过程。
client-go项目地址
https://github.com/kubernetes/client-go
用go客户端访问k8s必然是最靠谱的,我们 要做的就是在k8s集群外访问k8s apiserver。
包管理工具问题
golang的包管理方案有好几个,client-go支持了glide、godep这两款。
glide项目说自己未来会停止维护,建议大家用godep;而godep项目说自己未来会停止维护,建议大家用dep;而client-go说自己还没支持dep。
综合看下来,用godep是目前最靠谱的选择。
用包管理工具的前提是知道为什么要用包管理工具。
我们知道go get下载一个项目的时候,它会先下载整个项目到磁盘上,golang认为这是一个go的package,它会找到里面每个.go文件,分析它import了什么包,然后去递归下载它们,这就是下载依赖,当然依赖的依赖都会被下载。
问题就出在这里,go get下载依赖的时候,总是下载它们的master代码,如果依赖的master代码有不兼容的升级,我们的项目就编译不成功了。显然,我们想要的效果是,下载的依赖应该是我们开发项目时用的那个版本,而不是最新master代码。
所以包管理工具就出现了,它们可以帮你记录下你当前使用的依赖是master分支的哪一次git提交,这些信息可以上传到项目git里。下次go get项目之后,我们可以用包管理工具复原到当时的依赖版本,就可以顺利编译了。
实际上,godep更牛逼,它不仅记录当前依赖的版本,还会分析我们项目的代码引入了哪些依赖,然后会去GOPATH下面把所以依赖都拷贝到我们项目的vendor目录下,这样我们项目依赖的包以及二级依赖的包都可以在vendor找到(golang的vendor机制你应该了解一下),完全不会再去GOPATH下寻找了。vendor可以直接上传到项目git里,下次go get项目就不会再去下载依赖了,因为都在vendor里可以找到。
安装client-go
1,找到一台墙外的服务器
因为我们要下载的client-go是托管在google的git仓库里的,所以go get的时候就会被墙。
解决方法有2种:
- 你有一台美国的服务器,那么去服务器上go get之后再拷贝回来就好。
- 使用shadowsocks+cow的组合,后者提供http协议代理并基于socks5协议转发给本机的1080端口(也就是ss),从而提供了http协议的翻墙,然后就可以配置git客户端走本机cow的http代理了。
大家自己克服吧!
2,创建一个空的gopath目录
比如,我建立了一个目录:
1 |
mkdir /Users/liangdong/Documents/github/golang-k8s-client-go |
然后导出一下GOPATH:
1 |
export GOPATH=/Users/liangdong/Documents/github/golang-k8s-client-go |
现在进入这个目录。
3,安装godep包管理工具
执行:
1 |
go get github.com/tools/godep |
生成的二进制程序在$GOPATH/bin目录下。
4,下载client-go
执行:
1 |
go get k8s.io/client-go/... |
/后面紧接着…是啥意思?
go get在git clone下载了源码后,只会扫描第一级目录中的.go文件,并递归下载它们的依赖。
而client-go项目呢,在第一级目录下没有go文件,都放在子目录里了,所以…的意思就是递归扫描所有层级的目录中的.go文件,下载它们的依赖以及依赖的依赖,就这么个意思。
大家可以看一下client-go项目的外层目录是不是这样:https://github.com/kubernetes/client-go
5,godep恢复依赖
client-go项目使用godep保存了开发时的依赖,放在它的vendor目录下,大家可以去client-go目录下看一下vendor目录。
当我们的项目依赖client-go的时候,client-go则会在自己的vendor下找到自己的依赖,并不会往GOPATH中去查找。
client-go官方给了一点指导建议,就是担心出现这么一种情况:我们在GOPATH下面,下载了一个依赖库A,然而client-go的vendor中也有一个库A,恰好2个库A的版本还不一样。 这种情况下,非client-go包下面的代码就会编译GOPATH下面的A,而client-go包下面的代码会编译vendor下面的A,最后导致编译出的二进制存在问题。
解决方案,就是把client-go的vendor通过godep释放到GOPATH下面覆盖已有的库,这样client-go继续使用vendor中的依赖与其他库使用GOPATH中的依赖是没有区别的了,也就是打平了依赖。
所以我们进入client-go:
1 |
cd $GOPATH/src/k8s.io/client-go/ |
执行godep restore释放vendor目录到GOPATH下:
1 |
../../../bin/godep restore ./... |
这里…的意思是所有子包的vendor都释放,但其实只有client-go目录有vendor,子目录并没有。
6,下载自己的项目
我们创建一个空的github项目,然后go get下来即可,比如我的项目是:github.com/owenliang/k8s-client-go。
我要在这个项目中使用client-go来访问k8s apiserver。
首先我把k8s master上面的/etc/kubernetes/admin.conf文件拷贝到项目下,里面包含了k8s集群的地址以及认证密钥,client-go就可以成功访问到apiserver了。
我们先实现InitClient方法,建立到K8s的连接,代码在https://github.com/owenliang/k8s-client-go/tree/master/common:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
package common import ( "io/ioutil" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" ) // 初始化k8s客户端 func InitClient() (clientset *kubernetes.Clientset, err error) { var ( kubeconfig []byte restConf *rest.Config ) // 读kubeconfig文件 if kubeconfig, err = ioutil.ReadFile("./admin.conf"); err != nil { goto END } // 生成rest client配置 if restConf, err = clientcmd.RESTConfigFromKubeConfig(kubeconfig); err != nil { goto END } // 生成clientset配置 if clientset, err = kubernetes.NewForConfig(restConf); err != nil { goto END } END: return } |
然后建立一个demo1目录,写一段测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
package main import ( "fmt" "k8s.io/client-go/kubernetes" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" core_v1 "k8s.io/api/core/v1" "github.com/owenliang/k8s-client-go/common" ) func main() { var ( clientset *kubernetes.Clientset podsList *core_v1.PodList err error ) // 初始化k8s客户端 if clientset, err = common.InitClient(); err != nil { goto FAIL } // 获取default命名空间下的所有POD if podsList, err = clientset.CoreV1().Pods("").List(meta_v1.ListOptions{}); err != nil { goto FAIL } fmt.Println(*podsList) return FAIL: fmt.Println(err) return } |
这段代码调用core/v1的API,获取了default命名空间下面的pods列表。
7,godep保存依赖
现在,我们要把自己的项目的依赖保存到vendor目录下,然后一起上传到github。
这样的话,以后要下载与编译我们的项目,只需要go get我们的项目即可,所有依赖都可以在vendor下找到,所以go get就不会递归去下载依赖了,也就不存在被墙的问题了。
进入我的项目:
1 |
cd $GOPATH/src/github.com/owenliang/k8s-client-go |
然后执行:
1 |
../../../../bin/godep save ./... |
这里…意思就是递归分析整个k8s-client-go项目的所有依赖,然后copy到当前目录的vendor目录中。
1 2 3 4 5 6 7 8 9 10 |
liangdongs-MacBook-Pro:k8s-client-go liangdong$ pwd /Users/liangdong/Documents/github/golang-k8s-client-go/src/github.com/owenliang/k8s-client-go liangdongs-MacBook-Pro:k8s-client-go liangdong$ ll total 24 drwxr-xr-x 4 liangdong staff 128 12 12 11:13 Godeps -rw-r--r-- 1 liangdong staff 62 12 12 11:12 README.md -rw-r--r-- 1 liangdong staff 5447 12 12 11:24 admin.conf drwxr-xr-x 3 liangdong staff 96 12 12 13:01 common drwxr-xr-x 3 liangdong staff 96 12 12 13:02 demo1 drwxr-xr-x 7 liangdong staff 224 12 12 11:38 vendors |
其实,只有我们引入的包才会被copy到vendors中,所以vendors目录并不大。
比如我们import了这个包:
1 |
k8s.io/apimachinery/pkg/apis/meta/v1 |
实际上只有这个包被copy到vendor,而k8s.io/apimachinery中其他的包是没有copy进来的。
这也意味着,如果以后我们的项目Import了其他client-go的子包,得重新save一次提交到github才能保证是依赖完备的。
现在,我们把整个项目推到github保存,包括vendor目录以及Godeps目录,就是你看到的这个项目了:https://github.com/owenliang/k8s-client-go
8,验证项目
我们新建一个GOPATH目录,然后go get github.com/owenliang/k8s-client-go,应该可以顺利的完成下载,并不会再去墙外下载k8s依赖了,这是因为在k8s-client-go一级目录下没有任何.go文件,所以go get无法分析到任何依赖,如果用go get github.com/owenliang/k8s-client-go/…的话,它就会找到k8s的依赖去下载,还是会被墙,也就是说go get的时候vendor目录是不会被考虑的。
然后进入k8s-client-go目录,进入demo1直接go build就可以成功,因为k8s-client-go目录下有vendor,包含了所有项目依赖:
1 2 3 4 5 6 7 8 9 10 |
liangdongs-MacBook-Pro:k8s-client-go liangdong$ cd demo1/ liangdongs-MacBook-Pro:demo1 liangdong$ go build liangdongs-MacBook-Pro:demo1 liangdong$ ll .. total 24 drwxr-xr-x 4 liangdong staff 128 12 12 13:27 Godeps -rw-r--r-- 1 liangdong staff 62 12 12 13:27 README.md -rw-r--r-- 1 liangdong staff 5447 12 12 13:27 admin.conf drwxr-xr-x 3 liangdong staff 96 12 12 13:27 common drwxr-xr-x 4 liangdong staff 128 12 12 13:31 demo1 drwxr-xr-x 7 liangdong staff 224 12 12 13:27 vendor |
完结
后续会继续在这个项目下补充各种demo代码,欢迎star。
如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~
