TL;DR
本文主要介绍在本机IED中如何远程调试位于k8s中的knative程序。
目标
由于knative组件运行在k8s中,当发生错误的时候,在对代码不是特别熟悉的情况下,单步调试程序能够观察程序运行的函数,以及运行过程中的上下文,对排查问题非常方便。实际knative程序允许你在k8s外运行服务组件,通过环境变量或者命令行参数指定kubeconfig和server参数即可。
但是本文主要介绍另外一种思路,不是所有程序都能方便的运行在本地的。所以对于运行在k8s中的任意knative程序包括proxy进行调试就是本文的目标。
步骤
镜像
knative 镜像制作:https://www.likakuli.com/posts/knative-build/
首先要创建一个镜像,编译的二进制和启动命令都会有所不同。通过查看knative组件
由于knative使用ko来进行镜像的制作和推送。我简单的看了一下,发现了解这个可能会给我带来一定的时间成本。所以我直接按照自己最舒服的方式自己写了一下Makefile和Dockerfile。
REGCFLAGS = -gcflags "all=-N -l"
SRC_FOLDER := $(shell ls cmd)
prepare:
if [ ! -d "./bin/" ]; then \
mkdir bin; \
fi
default:
@for dir in ${SRC_FOLDER}; do \
go build $(REGCFLAGS) -mod vendor -o bin/$$dir ./cmd/$$dir ; \
done
remote: prepare default
docker: remote
@for dir in ${SRC_FOLDER}; do \
docker build --build-arg BIN=$$dir -t docker4zc/$$dir . ; docker push docker4zc/$$dir ; \
done
docker-local: remote
@for dir in ${SRC_FOLDER}; do \
docker build --build-arg BIN=$$dir -t docker4zc/$$dir . ; \
done
FROM golang:latest AS golang
ENV GOPROXY=https://goproxy.cn,direct
RUN CGO_ENABLED=0 go get -ldflags '-s -w -extldflags -static' github.com/go-delve/delve/cmd/dlv
#FROM gcr.oneitfarm.com/distroless/static:noroot
FROM ubuntu
ARG BIN
WORKDIR /
COPY bin/${BIN} /execbin
COPY --from=golang /go/bin/dlv /
CMD ["/dlv", "--listen=:2345", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/execbin"]
首先你需要在运行命令的地方登陆自己的dockerhub账号,并且将我的dockerhub账号docker4zc
换成你自己的账号,这样你就可以把镜像推送到自己的仓库。然后你在项目主目录下运行make docker
即可。
然后你需要在这个网址https://github.com/knative/serving/releases/download/v0.26.0/serving-core.yaml
(将v0.26.0替换成你需要的版本)下载安装knative serving的yaml文件,并将你想要调试的组件镜像替换,如果是webhook
组件,那么就是将gcr.io/knative-releases/knative.dev/serving/cmd/webhook@sha256:d512342e1a1ec454ceade96923e21c24ec0f2cb780e86ced8e66eb62033c74b5
格式的镜像替换成docker.io/{your dockerhub account}/webhook:latest
。
另外由于我将基础镜像由gcr.oneitfarm.com/distroless/static:noroot
替换成了ubuntu
,所以你同时需要将yaml文件中每个deployment下runAsNonRoot: true
去掉。
接下来你就可以kubectl apply -f serving-core.yaml
将其部署到k8s中。
端口转发
转发一个本地端口到 Pod 端口
以下命令将activator的2345端口转发到本地12345端口
kubectl port-forward -n knative-serving webhook-7b9b84596d-245rh 12345:2345
这相当于
kubectl port-forward -n knative-serving pods/webhook-7b9b84596d-245rh 12345:2345
或者
kubectl port-forward -n knative-serving deployment/webhook 12345:2345
如果是在minikube中运行,那么你就是在minikube所在机器运行以上命令。并通过机器ip+12345端口进行连接。如果是在k8s中运行,那么你可以在本地将kubectl设置对应的kubeconfig后,通过127.0.0.1+12345端口进行连接。
Goland IDE远程调试
VS code和goland都具有此功能,这里以goland为例。在创建时选择go remote类型,设置对应的host和port即可:
注意事项
使用私有镜像仓库
如果你在调试过程中发现
Unable to fetch image...x509: certificate signed by unknown authority
,你可以考虑是否由以下原因造成。
如果你的服务使用的是私有的镜像仓库,你需要设置跳过tag resolving。如果你的私有仓库为harbor.test.com
,你可以通过以下命令设置:
kubectl patch configmap -n knative-serving config-deployment -p "{\"data\": {\"registriesSkippingTagResolving\": \"harbor.test.com\"}}"
k8s探活
由于部分knative组件配置了k8s probe探针,所以你在调试过程中由于执行太慢,发现有时候pod会被重启。所以当遇到这种情况的时候将livenessProbe
和readinessProbe
部分去掉即可。部署之前可以将yaml下载到本地,然后删掉这部分内容之后再apply。如果已经部署完成,以autoscaler
为例可以通过kubectl edit deploy -n knative-serving autoscaler
编辑对应的yaml文件删除。
【注意】:此更改应该仅用于测试。
其他参考:
- /dlv
- --listen=:40000
- --accept-multiclient
- --headless=true
- --log
- --api-version=2
- exec
- /daprd
- --