介绍

通过 k8s 源码运行一个集群的操作在 github 上有对应的文档,我这里主要记录一下过程中遇到的坑。

安装步骤

开发环境准备文档: https://github.com/kubernetes/community/blob/master/contributors/devel/development.md#preparing-your-local-operating-system

构建源码指引:https://github.com/kubernetes/community/blob/master/contributors/devel/development.md#preparing-your-local-operating-system

遇到的问题

运行环境问题

运行环境只能是 linux, 之前我看 Docker Desktop 里面可以在 mac 直接启动 k8s 集群,还以为官方提供的脚本也可以,配置好了环境后以为好了,运行一个 demo:

./cluster/kubectl.sh run my-nginx --image=nginx --port=80

查看 pod 详情

./cluster/kubectl.sh describe pod my-nginx

失败了

image-20220731104548346

报错:no nodes available to schedule pods

查看一下 node

./cluster/kubectl.sh get nodes

No resources found

仔细观察 /hack/local-up-cluster.sh 脚本的输出

kubelet is not currently supported in darwin, kubelet aborted.
kubelet is not currently supported in darwin, kube-proxy aborted.

查了一下,https://github.com/kubernetes/kubernetes/issues/62940 这个脚本确实不能在 mac 上运行 kubelet 和 kube-proxy。

那我只能去 找一个 linux 环境了。

构建源码时报错 execvp: /usr/bin/env: Argument list too long

这个报错是在准备好 debian 的 k8s 开发环境后,运行 make WHAT=cmd/kubectl 构建时遇到的

image-20220731110110031

这个报错是在 debian 系统报错的,报错原因看着是 shell 脚本传递的参数太多了,相同的源码,在 mac 上没报错。运行 git status显示本地文件没有更改。

运行 getconf ARG_MAX命令,查看参数长度限制

Mac 是 1048576 ,debian 是 2097152,dibian 比 mac 长,但是mac 构建成功了,debian 却失败了?

我决定查一下是哪个命令报错的,给 make 命令加上 -d 选项,并且设置 DBG_MAKEFILE 变量,打印处理详细的执行信息

make -d  DBG_MAKEFILE=1

输出

// 忽略无关内容

Reading makefile '.make/go-pkgdeps.mk' (search path) (no ~ expansion)...
Makefile.generated_files:109: ***** finding all *.go dirs
make[1]: execvp: /usr/bin/env: Argument list too long

发现第一次报错是在 Makefile.generated_files:109 后面,看了一下上下文脚本,这里是把项目里面所所有 go 文件的文件名保存到了.make/all_go_dirs.mk,然后下面的命令还出现了把文件内容作为参数传入命令行的操作,初步怀疑是这里超长了。

随便看了一下,发现有文件名重复了,有很多文件出现了两次,有一次多了个前缀 kubernetes, 一看根目录,确实有一个 kubernates 目录,里面是另一份源码。删除源码后,再次 make就成功了。

这个问题是多个因素导致的,刚开始,我没有把 k8s 源码放在 $GOPATH/src/k8s.io里面,操作完回想了一下,老版本的 k8s 源码基于 GOPATH, 位置不对现在的版本代码运行正常,但是切换到老版本就运行不了了。

于是我直接运行 mv kubernetes $GOPATH/src/k8s.io/kubernetes,把clone 好的文件夹移动过去了,然后到了新文件夹下 git status后,没有更改,就以为移动成功了。

我运行的 mv 命令,如果 $GOPATH/src/k8s.io 目录下不存在 kubernetes 文件,那么就会把文件夹移动到 $GOPATH/src/k8s.io 下,如果已经有一个 $GOPATH/src/k8s.io/kubernetes 目录了,就会放在这个目录下面。所以我 mv 的代码实际去到了 $GOPATH/src/k8s.io/kubernetes/kubernetes 目录下。

那为什么 git status 看不出来文件夹里面多了一个文件夹呢?看了一下 .gitignore, 里面确实把根目录下的 kubernetes 文件夹加进去了。

 cat .gitignore| grep kubernetes
/kubernetes/
# Downloaded kubernetes binary release tar ball
kubernetes.tar.gz

到这里这个问题就清楚了,前几天我已经放了一份源码到这个 debian 电脑了,但是忘记了,重新 clone 一份后 mv , 因为已经有一个 kubernetes 文件夹了,所以新源码被放到了根目录。然后刚好 k8s 的 .gitignore 把 kubernetes 文件夹加进去了,git 命令看着没有任何文件。构建的时候,脚本收集了项目的所有文件名,并且作为参数传给其他 shell 命令,两份项目的文件名超过了系统参数长度限制。

Go 版本

最新版 k8s 要求 18.2 , 我的版本不够,升级一下。

wget https://go.dev/dl/go1.18.4.linux-amd64.tar.gz
tar -zxvf go1.18.4.linux-amd64.tar.gz

# 可能你的go位置和我的不一样,使用 which go 查看
sudo mv /usr/local/lib/go /usr/local/lib/go.bak
sudo mv go  /usr/local/lib/

APIServer 启动失败

脚本需要用 root 权限运行

忽略构建

每次启动构建没必要,可以先 make all,然后启动集群的时候使用 sudo ./hack/local-up-cluster.sh -O

sudo ./hack/local-up-cluster.sh -O

安装了 etcd ,但是运行集群找不到 etcd,etcd must be in your PATH

首先我已经按照文档安装了etcd, https://github.com/kubernetes/community/blob/master/contributors/devel/development.md#etcd

运行命令如下

sudo ./hack/local-up-cluster.sh -O

然后确认 bash zsh 打开新窗口都能找到 etcd 了,但是运行的时候就是报 etcd must be in your PATH

搜索内容,发现是 hack/lib/etcd.sh:31 这个地方报出来的,启动脚本 这个地方调用了验证,hack/local-up-cluster.sh:1137 。

在调用前打印一下环境变量

echo `env`

发现 path 没了,又在脚本开头确认了一下,还是没有 path

检查了一下

sudo visudo

发现内容里面有Defaults env_reset,这里设置成了 sudo 的时候不继承环境变量了。

可以改成Defaults !env_reset,或者在暂时在 sudo 后加 env PATH=$PATH

新的运行命令

sudo env PATH=$PATH hack/local-up-cluster.sh -O

这次可以找到了

unknown service runtime.v1alpha2.RuntimeService

集群终于起来了, node 也 ok 了

 ./cluster/kubectl.sh get nodes
NAME        STATUS   ROLES    AGE     VERSION
127.0.0.1   Ready    <none>   3h18m   v1.25.0-alpha.3.129+12b22ede416177-dirty

运行了一个 pod, ./cluster/kubectl.sh run my-nginx --image=nginx --port=80

查看情况,./cluster/kubectl.sh describe pod my-nginx,发现报错了 unknown service runtime.v1alpha2.RuntimeService

找到了这个 issue https://github.com/containerd/containerd/issues/4581 ,跟着一通配置也不行,后面看https://github.com/kubernetes/kubernetes/issues/73189,需要重新安装一下containerd cri,https://github.com/containerd/containerd,

wget https://github.com/containerd/containerd/releases/download/v1.5.11/containerd-1.5.11-linux-amd64.tar.gz
sudo tar -C / -xzf cri-containerd-cni-1.5.11-linux-amd64.tar.gz 

containerd config default > /etc/containerd/config.toml
systemctl enable containerd --now
systemctl restart containerd

我是在这里下载的containerd https://github.com/containerd/containerd/releases/tag/v1.5.11

保险起见,重启 docker

sudo service docker restart
# 发现启动失败了
systemctl status docker.service
# Failed to start docker.service: Unit docker.service is masked.

解决

systemctl unmask docker.service
systemctl unmask docker.socket
systemctl start docker.service

然后再尝试,报错变了

附录

  1. 前台启动 docker 并且输出 debug 日志: sudo dockerd --debug
  2. Docke 在 debian 的日志位置: /var/log/daemon.log ,参考:https://blog.csdn.net/warrior_0319/article/details/79713155

Error response from daemon: Get "https://k8s.gcr.io/v2/": dial tcp 142.250.157.82:443: connect: connection timed out

这个就是镜像被墙了,需要配置代理或者镜像,这里需要注意的是,我给 docker 配置好镜像源后, docker pull k8s.gcr.io/pause:3.5,没问题了,k8s 启动还是会报错,这里网上的资料基本是给 docker 配置后就可以了,最新版还不行。

后面才知道 还要给 containerd 配置一下,配置后还是报错,failed to do request: Head "https://k8s.gcr.io/v2/pause/manifests/3.5": dial tcp 142.250.157.82:443: connect: connection timed out

直接给 containerd 配置代理,问题解决。

参考:https://segmentfault.com/a/1190000020363043

Error response from daemon: OCI runtime create failed: unable to retrieve OCI runtime error

再次尝试 启动 pod , 发现 报错。

unable to retrieve OCI runtime error xxx/log.json: no such file or directory

看了Shashank V的回答https://stackoverflow.com/questions/59544107/docker-error-response-from-daemon-oci-runtime-create-failed-unable-to-retriev,试了一下 docker run hello-world,也在报错,那应该是 docker 的问题。

再找了一下找到这个 issue https://github.com/moby/moby/issues/35906

是缺少 libseccomp 库

下载地址: https://packages.debian.org/zh-cn/sid/amd64/libseccomp2/download

wget http://ftp.us.debian.org/debian/pool/main/libs/libseccomp/libseccomp2_2.5.4-1+b1_s390x.deb
sudo dpkg -i libseccomp2_2.5.4-1+b1_s390x.deb

安装后 docker run hello-world,正常了。

Apt 报错Unsupported proxy configured:

下载某些文件的时候再终端设置了 http 代理,运行 apt 会报错,把代理 unset 掉后不报错了。

运行成功

最终,通过源码构建一个集群并且运行一个 pod 成功

image-20220731125002465

参考资料

https://github.com/kubernetes/community/blob/master/contributors/devel/development.md

https://github.com/kubernetes/community/blob/master/contributors/devel/running-locally.md

https://blog.csdn.net/yj1499945/article/details/80944203

https://mdnice.com/writing/3e3ec25bfa464049ae173c31a6d98cf8

https://blog.csdn.net/u011403655/article/details/50524071

https://blog.csdn.net/warrior_0319/article/details/79713155

https://segmentfault.com/a/1190000020363043

https://github.com/moby/moby/issues/35906

https://github.com/containerd/containerd/issues/4581

https://github.com/kubernetes/kubernetes/issues/73189

https://stackoverflow.com/questions/59544107/docker-error-response-from-daemon-oci-runtime-create-failed-unable-to-retriev