4

kubernetes平台开发者小技巧

 3 years ago
source link: https://blog.happyhack.io/2020/10/30/kubernetes-develop-tips/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
Happy Hack Everday
kubernetes平台开发者小技巧
发表于2020-10-30|更新于2020-12-06

随着Cloud Native逐渐深入人心以及kubernetes的流行,国内外出现大量的kubernetes服务提供商,如红帽,阿里,腾讯等, 同时许多互联网公司也在定制kubernetes以满足自身需求,kubernetes平台开发者这个岗位的需求也逐渐增大, 那作为一名合格的kubernetes平台开发者其实需要具备一些特殊技能的。

在这个系列博文中,我将结合自身的开发经历给Kubernetes平台开发者分享一些开发小技巧,帮助kubernetes平台开发者少走一些弯路。

在你的项目使用依赖k8s.io/kubernetes主仓模块

Kubernetes提供了很多公共库供开发者使用, 比如client-goapimachinery,但是官方不推荐直接依赖主仓k8s.io/kubernetes,虽然其代码完全是开源的, 这样做最主要原因是直接依赖k8s.io/kubernetes会导致你的项目过大,包含太多不必要的文件。

但是除了公共库已经拆分的通用模块,主仓还有很多有意义的API接口(函数),比如包pkg/core/validationValidatePodCreate函数可以用来创建POD时, 做前校验处理(cli-runtime库定义了ContentValidator接口,建议使用该接口和dry-run机制),包pkg/apis/core/v1Convert_v1_Pod_To_Core_Pod函数可以用来将corev1.Pod转换为core.Pod等。 这些包目前还没有被抽离成单独模块。

如果我们直接go get k8s.io/[email protected]下载依赖,会出现以下错误:

➜  go-get-kubernetes go get k8s.io/kubernetes
go: k8s.io/kubernetes upgrade => v1.19.3
go get: k8s.io/[email protected] requires
k8s.io/[email protected]: reading k8s.io/api/go.mod at revision v0.0.0: unknown revision v0.0.0

错误的原因是在kubernetes主仓中,也使用了公共库,不过go.mod文件中所有公共库版本都指定为了v0.0.0(显然这个版本不存在), 然后通过Go Module的replace机制,将版本替换为子目录./staging/src/k8s.io对应的依赖。

module k8s.io/kubernetes
go 1.15
require (
...
k8s.io/api v0.0.0
k8s.io/apiextensions-apiserver v0.0.0
k8s.io/apimachinery v0.0.0
k8s.io/apiserver v0.0.0
k8s.io/cli-runtime v0.0.0
k8s.io/client-go v0.0.0
...
)

replace(
...
k8s.io/client-go => ./staging/src/k8s.io/client-go
k8s.io/cloud-provider => ./staging/src/k8s.io/cloud-provider
k8s.io/cluster-bootstrap => ./staging/src/k8s.io/cluster-bootstrap
k8s.io/code-generator => ./staging/src/k8s.io/code-generator
k8s.io/component-base => ./staging/src/k8s.io/component-base
...
)

那么如何解决呢,只需要复制保存以下脚本(来自社区相关Issue),在项目中执行以下脚本:bash hack/go-get-kubernetes.sh v1.19.2, 注意替换你需要的版本。这个脚本通过修改go.mod文件保证能够获取相关依赖。

#!/bin/sh
set -euo pipefail

VERSION=${1#"v"}
if [ -z "$VERSION" ]; then
echo "Must specify version!"
exit 1
fi
MODS=($(
curl -sS https://raw.githubusercontent.com/kubernetes/kubernetes/v${VERSION}/go.mod |
sed -n 's|.*k8s.io/\(.*\) => ./staging/src/k8s.io/.*|k8s.io/\1|p'
))
for MOD in "${MODS[@]}"; do
V=$(
go mod download -json "${MOD}@kubernetes-${VERSION}" |
sed -n 's|.*"Version": "\(.*\)".*|\1|p'
)
go mod edit "-replace=${MOD}=${MOD}@${V}"
done
go get "k8s.io/kubernetes@v${VERSION}"

不过建议大家不要直接依赖主仓

Goland如何调试Kubernetes相关组件

学会调试kubernetes,对于我们学习kubernetes源码及定制化kubernetes十分有帮助,其实刚开始接触kubernetes项目,我和许多开发者一样, 面对kubernetes这一复杂庞大的项目,不知道从何看起,也不知道如何调试它(当然Kubectl除外),其实kubernetes的本地调试并没有想象中的复杂。

首先假设你已经在虚拟机通过kubeadm安装了一套kubernetes集群,克隆了kubernetes代码仓到本地和虚拟机上。 这里我以APIServer组件为例,其他组件类似。

首先,查看安装Kubernetes集群的版本,并在虚机上checkout对应版本的代码仓分支,然后编译Kubernetes相关组件, 编译时需要打开调试选项(参照Makefile的说明),这个编译时间可能有点长,对应的二进制产物在_output/bin目录中,

# 编译
➜ kubernetes git:(release-1.18) ✗ make all GOGCFLAGS=”-N -l”
➜ kubernetes git:(release-1.18) ✗ cd _output/bin
➜ bin git:(release-1.18) ✗ ll
总用量 1.8G
-rwxr-xr-x 1 root root 65M 9月 11 11:20 apiextensions-apiserver
-rwxr-xr-x 1 root root 6.0M 9月 10 16:56 conversion-gen
-rwxr-xr-x 1 root root 6.0M 9月 10 16:56 deepcopy-gen
-rwxr-xr-x 1 root root 6.0M 9月 10 16:56 defaulter-gen
-rwxr-xr-x 1 root root 172M 9月 11 11:21 e2e_node.test
-rwxr-xr-x 1 root root 157M 9月 11 11:21 e2e.test
-rwxr-xr-x 1 root root 59M 9月 11 11:21 gendocs
-rwxr-xr-x 1 root root 192M 9月 11 11:21 genkubedocs
-rwxr-xr-x 1 root root 200M 9月 11 11:21 genman
-rwxr-xr-x 1 root root 9.4M 9月 11 11:21 genswaggertypedocs
-rwxr-xr-x 1 root root 59M 9月 11 11:21 genyaml
-rwxr-xr-x 1 root root 11M 9月 11 11:21 ginkgo
-rwxr-xr-x 1 root root 3.6M 9月 10 16:07 go2make
-rwxr-xr-x 1 root root 2.0M 9月 10 16:57 go-bindata
-rwxr-xr-x 1 root root 2.8M 9月 11 11:21 go-runner
-rwxr-xr-x 1 root root 55M 9月 11 11:20 kubeadm
-rwxr-xr-x 1 root root 149M 9月 11 11:20 kube-apiserver
-rwxr-xr-x 1 root root 141M 9月 11 11:20 kube-controller-manager
-rwxr-xr-x 1 root root 60M 9月 11 11:20 kubectl
-rwxr-xr-x 1 root root 142M 9月 11 11:21 kubelet
-rwxr-xr-x 1 root root 139M 9月 11 11:21 kubemark
-rwxr-xr-x 1 root root 52M 9月 11 11:20 kube-proxy
-rwxr-xr-x 1 root root 59M 9月 11 11:20 kube-scheduler
-rwxr-xr-x 1 root root 7.2M 9月 11 11:21 linkcheck
-rwxr-xr-x 1 root root 2.3M 9月 11 11:20 mounter
-rwxr-xr-x 1 root root 9.9M 9月 10 16:56 openapi-gen
-rwxr-xr-x 1 root root 5.7M 9月 10 16:07 prerelease-lifecycle-gen

调试需要使用到Go调试工具delve,在kubernetes集群的控制节点上安装delve, 这里使用go get的方式安装。

# 在Module目录外执行,并将GOBIN目录添加环境变量PATH中
➜ ~ go get github.com/go-delve/delve/cmd/dlv
➜ bin git:(release-1.18) ✗ dlv -h
Delve is a source level debugger for Go programs.

Delve enables you to interact with your program by controlling the execution of the process,
evaluating variables, and providing information of thread / goroutine state, CPU register state and more.

The goal of this tool is to provide a simple yet powerful interface for debugging Go programs.

Pass flags to the program you are debugging using `--`, for example:

`dlv exec ./hello -- server --config conf/config.toml`

通过Kubeadm安装的集群,kubernetes控制平面的组件是以Static pod形式运行的, 对应的yaml文件保存在/etc/kubernetes/manifests,查看APIServer对应的配置文件如下,我们需要拷贝APIServer的启动参数。 接下来,我们重命名/etc/kubernetes/manifests/kube-apiserver.yamlkube-apiserver.yaml.old,观察容器列表, 等待APIServer对应的容器停止,通过delve启动APIServer进行调试,注意相关参数配置。

dlv exec _output/bin/kube-apiserver --headless -l 192.168.5.82:2345 --api-version=2 \\
--advertise-address=192.168.5.82 \\
--allow-privileged=true \\
--authorization-mode=Node,RBAC\\
--client-ca-file=/etc/kubernetes/pki/ca.crt\\
--enable-admission-plugins=NodeRestriction\\
--enable-bootstrap-token-auth=true\\
--etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt\\
--etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt\\
--etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key\\
--etcd-servers=https://127.0.0.1:2379\\
--insecure-port=0\\
--kubelet-client-certificate=/etc/kubernetes/pki/apiserver- kubelet-client.crt\\
--kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet- client.key\\
--kubelet-preferred-address-types=InternalIP,ExternalIP, Hostname\\
--proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client. crt\\
--proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client. key\\
--requestheader-allowed-names=front-proxy-client\\
--requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy- ca.crt\\
--requestheader-extra-headers-prefix=X-Remote-Extra-\\
--requestheader-group-headers=X-Remote-Group\\
--requestheader-username-headers=X-Remote-User\\
--secure-port=6443\\
--service-account-key-file=/etc/kubernetes/pki/sa.pub\\
--service-cluster-ip-range=10.96.0.0/16\\
--tls-cert-file=/etc/kubernetes/pki/apiserver.crt\\
--tls-private-key-file=/etc/kubernetes/pki/apiserver.key
server listening at: 192.168.5.82:2345

在本地开发环境也切到与虚机对应的kubernetes分支,然后添加一个远程调试的Configuration,配置对应的主机和端口,并在相关位置打上断点,开始调试。

2020-10-30-16-23-53.png

2020-10-30-16-23-37.png

到这里,就已经成功对Kubernetes的APIServer进行调试啦。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK