kubernetes 开发环境搭建与社区贡献

一、go 环境搭建

1.22.1 升级日志 更新来看,使用了 Golang 1.16.7 的环境。

1.1 备份当前的 go 环境

先确认系统路径PATH 有没有包含 goroot,没有的话加上。一般如果已经存在了都会有的:

image-20210831104549671

image-20210831104135117

可以看到我这里系统路径已经包含了goroot和gopath的路径。

主要思路是把 goroot / gopath 做备份,保留环境变量不变,将它们文件和文件夹重命名加个后缀版本号,再在用软链接 ln -s 指向它们。

image-20210831104344545

1.2 安装 Golang 1.16.7

我是 debian 9 x86 环境。

# 也可以直接访问 https://golang.org/dl/ 手动下载
wget https://golang.org/dl/go1.16.7.linux-amd64.tar.gz   

tar zxvf go1.16.7.linux-amd64.tar.gz
mv go /var/local/go1.16.7    # 我习惯使用/var/local保存自己安装的软件

# 该整的软链接整一下
rm /var/local/go /home/kelu/Workspace/go
ln -s /var/local/go1.16.7 /var/local/go
ls -s /home/kelu/Workspace/gopath/go1.16.7 /home/kelu/Workspace/go

image-20210831104344545

确认安装ok

go version

二、kubernetes 源码编译

官方开发参考文档: https://github.com/kubernetes/community/blob/master/contributors/devel/development.md

2.1 下载源码

直奔 https://github.com/kubernetes/kubernetes/releases/tag/v1.22.1

2.2 其它环境准备

  • 系统配置,准备好 8G内存和50G存储。
  • GNU development tools:
sudo apt update
sudo apt install build-essential
  • docker
  • rsync, 文件同步,一般都装了的。
  • jq, JSON 处理包。apt-get install jq. 官方文档
  • gcloud,如果构建 e2e 测试,需要安装GCP的 CLI
  • go
  • pyyaml,某些测试用,pip install pyyaml 官方文档
  • etcd,这个版本是 3.5.0,新版本改进了安全性、性能、监控和开发人员体验。./hack/install-etcd.sh

2.3 尝试编译

使用 kubernetes自带的 Makefile,使用make即可编译。可以通过查看Makefile文件代码,查看编译执行脚本。

也可以对不同的模块可以进行单独的编译。

2.3.1 round 1

在docker中执行跨平台编译出二进制文件。

./build/run.sh make

image-20210831113539036

发现 docker pull 阶段没法拉镜像,需要添加代理:

systemctl cat docker

# /lib/systemd/system/docker.service

修改此文件: vi /lib/systemd/system/docker.service

[Service]
Environment="HTTP_PROXY=http://proxy.example.com:8080/"
Environment="HTTPS_PROXY=http://proxy.example.com:8080/"
Environment="NO_PROXY=localhost,127.0.0.1,.example.com"

如果是 sock5 代理,把 http:// 改成 socks5:// 即可.

重启docker:

docker pull k8s.gcr.io/v2/build-image/kube-cross/manifests/v1.16.7-1

image-20210831115325630

下载有点久阿,要有亿点耐心。

image-20210831120049440

2.3.2 round 2

继续上路:

./build/run.sh make

image-20210831121901677

编译完成的二进制文件在/_output目录下。

image-20210831125906228

2.3.3 round 3 构建单个/跨平台构建

除了使用上边的 ./build/run.sh make,还可以直接使用make命令进行编译,编译出来的目录稍有不同:

image-20210910144957207

image-20210910145024523

make WHAT=cmd/kubectl
make all     # 编译所有
make cross   # 跨平台编译
make cross KUBE_BUILD_PLATFORMS=windows/amd64 # 特定平台编译
make help # 编译帮助

# 如果需要使用dlv进行远程调试,make需要添加一些参数,使得我们可以dlv attach进来:
make WHAT=cmd/kube-apiserver GOGCFLAGS="-N -l" GOLDFLAGS=""

image-20210831142728820

image-20210831145559472

2.3.4 构建镜像
KUBE_BUILD_PLATFORMS=linux/amd64 KUBE_BUILD_CONFORMANCE=n KUBE_BUILD_HYPERKUBE=n make release-images GOFLAGS=-v GOGCFLAGS="-N -l"
  • UBE_BUILD_CONFORMANCE=nKUBE_BUILD_HYPERKUBE=n 参数配置是否构建 hyperkube-amd64conformance-amd64 镜像,默认是 y 构建,设置为 n 不需要构建。
  • make release-images 表示执行编译并生成镜像 tar 包。

编译的 kubernetes 组件 docker 镜像以 tar 包的形式发布在 kubernetes/_output/release-images/amd64 目录中。

image-20210909181021179

image-20210909181143418

三、kubernetes 开发

3.1 github开发流

https://github.com/kubernetes/community/blob/master/contributors/guide/github-workflow.md

git_workflow.jpg

3.2 开发环境搭建

我使用 vscode 作为 ide

# 注意本地环境要做好国外代理,有时候证书工具下载不下来。
./hack/install-etcd.sh
./hack/local-up-cluster.sh

image-20210923143956075

# 打开新的terminal
cd $GOPATH/src/k8s.io/kubernetes
export KUBECONFIG=/var/run/kubernetes/admin.kubeconfig

# 使用kubectl
cluster/kubectl.sh get cs
cluster/kubectl.sh get ns
cluster/kubectl.sh get nodes
cluster/kubectl.sh run nginx --image=nginx
cluster/kubectl.sh get po -A

image-20210923143911863

这样一个简易的本地环境就起来了。

image-20210924111215107

一共运行了 7 个进程:

  • kube-apiserver
  • kube-controller-manager
  • kube-scheduler
  • sudo kubelet
  • kubelet
  • sudo kube-proxy
  • kube-proxy

image-20210923151337473

下面以调试 apiserver 作为例子:

# kill 掉 apiserver, 注意保存apiserver的启动命令。
ps aux | grep apiserver
kill -9 xxx

# 运行命令备忘:
/var/local/go/src/k8s.io/kubernetes/_output/local/bin/linux/amd64/kube-apiserver --authorization-mode=Node,RBAC  --cloud-provider= --cloud-config=   --v=3 --vmodule= --audit-policy-file=/tmp/kube-audit-policy-file --audit-log-path=/tmp/kube-apiserver-audit.log --authorization-webhook-config-file= --authentication-token-webhook-config-file= --cert-dir=/var/run/kubernetes --egress-selector-config-file=/tmp/kube_egress_selector_configuration.yaml --client-ca-file=/var/run/kubernetes/client-ca.crt --kubelet-client-certificate=/var/run/kubernetes/client-kube-apiserver.crt --kubelet-client-key=/var/run/kubernetes/client-kube-apiserver.key --service-account-key-file=/tmp/kube-serviceaccount.key --service-account-lookup=true --service-account-issuer=https://kubernetes.default.svc --service-account-jwks-uri=https://kubernetes.default.svc/openid/v1/jwks --service-account-signing-key-file=/tmp/kube-serviceaccount.key --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,Priority,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota --disable-admission-plugins= --admission-control-config-file= --bind-address=0.0.0.0 --secure-port=6443 --tls-cert-file=/var/run/kubernetes/serving-kube-apiserver.crt --tls-private-key-file=/var/run/kubernetes/serving-kube-apiserver.key --storage-backend=etcd3 --storage-media-type=application/vnd.kubernetes.protobuf --etcd-servers=http://127.0.0.1:2379 --service-cluster-ip-range=10.0.0.0/24 --feature-gates=AllAlpha=false --external-hostname=localhost --requestheader-username-headers=X-Remote-User --requestheader-group-headers=X-Remote-Group --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-client-ca-file=/var/run/kubernetes/request-header-ca.crt --requestheader-allowed-names=system:auth-proxy --proxy-client-cert-file=/var/run/kubernetes/client-auth-proxy.crt --proxy-client-key-file=/var/run/kubernetes/client-auth-proxy.key --cors-allowed-origins="/127.0.0.1(:[0-9]+)?$,/localhost(:[0-9]+)?$"

编译apiserver:

make WHAT=cmd/kube-apiserver GOGCFLAGS="-N -l" GOLDFLAGS=""

可以看到是刚刚编译的apiserver,时间稍微落后一点:

image-20210923152019828

运行命令:

dlv exec --headless --listen=:2345 --api-version=2 /var/local/go/src/k8s.io/kubernetes/_output/local/bin/linux/amd64/kube-apiserver -- --authorization-mode=Node,RBAC  --cloud-provider= --cloud-config=   --v=3 --vmodule= --audit-policy-file=/tmp/kube-audit-policy-file --audit-log-path=/tmp/kube-apiserver-audit.log --authorization-webhook-config-file= --authentication-token-webhook-config-file= --cert-dir=/var/run/kubernetes --egress-selector-config-file=/tmp/kube_egress_selector_configuration.yaml --client-ca-file=/var/run/kubernetes/client-ca.crt --kubelet-client-certificate=/var/run/kubernetes/client-kube-apiserver.crt --kubelet-client-key=/var/run/kubernetes/client-kube-apiserver.key --service-account-key-file=/tmp/kube-serviceaccount.key --service-account-lookup=true --service-account-issuer=https://kubernetes.default.svc --service-account-jwks-uri=https://kubernetes.default.svc/openid/v1/jwks --service-account-signing-key-file=/tmp/kube-serviceaccount.key --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,Priority,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota --disable-admission-plugins= --admission-control-config-file= --bind-address=0.0.0.0 --secure-port=6443 --tls-cert-file=/var/run/kubernetes/serving-kube-apiserver.crt --tls-private-key-file=/var/run/kubernetes/serving-kube-apiserver.key --storage-backend=etcd3 --storage-media-type=application/vnd.kubernetes.protobuf --etcd-servers=http://127.0.0.1:2379 --service-cluster-ip-range=10.0.0.0/24 --feature-gates=AllAlpha=false --external-hostname=localhost --requestheader-username-headers=X-Remote-User --requestheader-group-headers=X-Remote-Group --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-client-ca-file=/var/run/kubernetes/request-header-ca.crt --requestheader-allowed-names=system:auth-proxy --proxy-client-cert-file=/var/run/kubernetes/client-auth-proxy.crt --proxy-client-key-file=/var/run/kubernetes/client-auth-proxy.key --cors-allowed-origins="/127.0.0.1(:[0-9]+)?$,/localhost(:[0-9]+)?$"

image-20210923153123713

settings.json 配置如下:

{
    "go.delveConfig": {
        "debugAdapter": "legacy",
    }
}

调试配置如下:

image-20210923153256597

此时可以看到,dlv 开始刷日志了,我们连上了!

image-20210923153436186

尝试暂停debug,看看左侧堆栈:

image-20210923153626580

尝试打个断点,成功!

image-20210923154058644

3.3 golang相关能力与代码规范

四、kubernetes 测试

4.1 验证

verify 很烧 cpu,注意自己的机器性能,请酌情验证,我机器已经死机好几次了,16c16g的机器。

image-20210831160623377

4.2 单元测试

todo

4.3 集成测试

todo

4.4 e2e测试

todo

五、kubernetes 贡献

5.1 签贡献者协议(Contributor License Agreement)

https://github.com/kubernetes/community/blob/master/CLA.md#the-contributor-license-agreement

  • 验证邮箱(该邮箱要跟GitHub账户邮箱一致)
  • 重设密码
  • 电子签署SLA文件

image-20210831164732222

linux基金会个人账号信息:https://identity.linuxfoundation.org/user

5.2 选择一个issue/todo

在 Kubernetes issue 列表,用标签过滤问题列表,例如 “good first issue”,“help wanted”,这些标签表明这个问题对新手友好。

image-20210901115818775

也可以搜索代码库里的TODO。

这里有两位大佬的first blood:

5.3 处理issue流程

  • 先熟读当前issue上下文或者pr,理解问题的背景和要解决的难题。
    • 如果它是一个 bug,就要验证你是否能复现这个 bug。请注意这可能需要投入大量时间.
  • 在 Slack 上联系问题(issue)的创建者来验证你的想法。
    • 一周之内没有收到反馈,直接提交 PR 。
  • 开发,coding
  • 本地单元测试/集成测试(最好做一下)
    • 跑通make verify(可能需要 30-40 分钟)
    • 跑通 make test
    • 跑通 make test-integration
  • pr
    • 至少两周内提交 PR 或者提供状态更新。
  • 在相关的sig Slack 频道找 Kubernetes Github 组织的成员给pr打标签 /ok-to-test。

5.4 贡献者相关链接

参考资料:

六、社区其它内容

6.1 社区行为准则

https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/zh.md

Kubernetes 社区行为准则遵循 CNCF的行为准则,CNCF的行为准则也受 Linux 基金会行为准则约束。

CNCF 不可接受的参与者行为(v1.0):

  • 使用性语言或图像
  • 人身攻击
  • 挑衅、侮辱或贬低性评论
  • 公开或私下骚扰
  • 未经明确许可,发布他人的私人信息,比如地址或电子邮箱
  • 其它不道德或不专业的行为

Linux 基金会活动是旨在用于开源社区内的专业网络和协作的工作会议。它们的存在是为了鼓励思想和表达的开放交流,并需要一个承认每个人和团体的内在价值的环境。

不可接受的行为:

  • 骚扰
    • 基于性别、性别认同和表达、性取向、残疾、外貌、体型、种族、年龄、宗教或任何其他受举办会议或法律保护的内容
    • 使用辱骂性、冒犯性或有辱人格的语言
    • 恐吓、跟踪、骚扰性的摄影或录音
    • 不当的身体接触
    • 性图像、不受欢迎的性挑逗或性要求
  • 参展商
    • 不应在其展位中使用色情图片、活动或其他材料
    • 不得使用色情服装、制服、服装或以其他方式营造色情环境。
    • 演讲者不应在其演讲中使用性语言、图像或任何会构成上述定义的骚扰的语言或图像。

6.2 社区价值观

  • 分布式优于集中
  • 社区胜过产品或公司
  • 流程自动化
  • 包容胜于独占
  • 进化胜于停滞

6.3 社区期望

https://github.com/kubernetes/community/blob/master/contributors/guide/expectations.md

  • 必须 code review
  • Reviewer 与提交者交流要注意社区形象

6.4 社区成员与职责

https://github.com/kubernetes/community/blob/master/community-membership.md

  • Member
  • Reviewer
  • Approver
  • Subproject owner

我常用的 vscode 快捷键 复杂世界的认知方式 —— 为什么应对比预测重要 - 重阳投资