基于Goland和dlv远程调试Kubernetes组件

简介: 基于Goland和dlv远程调试Kubernetes组件

一个正常运行的 Kubernetes 集群包含以下的各种组件。

通常开发者日常编码都基于Windows/Mac上的IDE(VsCode/Goland),编码完成后再部署到远端Linux机器运行。因此,我们就需要一种基于IDE和dlv远程调试Kubernetes组件的方式,而go-delve正是一个不错的选择。

delve调试包括附加到进程调试和远程调试。其实附加到本地进程和远程调试原理是一样的,待调试的进程是通过delve启动的,delve会启动进程,并立即附加到进程,开启一个debug session。并且启动一个debug server,暴露某个端口,客户端IDE可以通过该端口连接到debug server进行调试。

远程Linux服务器准备工作

Go安装

wget安装包
$ wget https://dl.google.com/go/go1.17.8.linux-amd64.tar.gz
解压并配置GOROOT、GOPATH和PATH
# 解压GO安装包
$ tar -zxvf go1.17.8.linux-amd64.tar.gz -C /usr/local/
# 编辑配置文件  vim ~/.bashrc
$ export GOROOT=/usr/local/go #GOROOT是系统上安装Go软件包的位置。
$ export GOPATH=/go #GOPATH是工作目录的位置。这个是自己创建的,想放在哪都行
$ export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
$ export GOPROXY="https://goproxy.cn,https://mirrors.aliyun.com/goproxy,direct"
# 更新配置文件
$ source ~/.bashrc
验证
# 有输出表示安装成功
go env

go-delve安装

目前 Go 语言支持 GDB、LLDB 和 Delve 几种调试器。其中 GDB 是最早支持的调试工具,LLDB 是 macOS 系统推荐的标准调试工具。但是 GDB 和 LLDB 对 Go 语言的专有特性都缺乏很大支持,而只有 Delve 是专门为 Go 语言设计开发的调试工具。而且 Delve 本身也是采用 Go 语言开发,对 Windows 平台也提供了一样的支持。

以下指令适用于 Linux、macOS、Windows 和 FreeBSD。

方式一: 克隆 git 仓库并构建:
$ git clone https://github.com/go-delve/delve
$ cd delve
$ go install github.com/go-delve/delve/cmd/dlv
方式二: 在 Go 版本 1.16 或更高版本上:
# Install the latest release:
$ go install github.com/go-delve/delve/cmd/dlv@latest
# Install at tree head:
$ go install github.com/go-delve/delve/cmd/dlv@master
# Install at a specific version or pseudo-version:
$ go install github.com/go-delve/delve/cmd/dlv@v1.7.3
$ go install github.com/go-delve/delve/cmd/dlv@v1.7.4-0.20211208103735-2f13672765fe

有关go-delve版本信息,请参阅https://go.dev/ref/mod#versions

验证
# 有输出表示安装成功
dlv

Kubernetes编译打包

下载
$ mkdir -p $GOPATH/src/github.com/kubernetes
$ cd $GOPATH/src/github.com/kubernetes
$ git clone https://github.com/kubernetes/kubernetes.git
$ git check v1.18
编译

-s disable symbol table 禁用符号表

-w disable DWARF generation 禁用调试信息;

更多编译参数帮助信息查看:go tool link

# Kubernetes v1.18在k8s.io/kubernetes/hack/lib/golang.sh中设置了-s -w选项来禁用符号表以及debug信息,因此在编译Kubernetes组件进行远程调试时需要去掉这两个限制,如下:
-    goldflags="${GOLDFLAGS=-s -w} $(kube::version::ldflags)"
+    #goldflags="${GOLDFLAGS=-s -w} $(kube::version::ldflags)"
+    goldflags="${GOLDFLAGS:-} $(kube::version::ldflags)"
# 编译单个组建:
sudo make WHAT="cmd/kube-apiserver" GOGCFLAGS="-N -l" GOLDFLAGS=""  
# 编译所有组件:
sudo make all GOGCFLAGS="-N -l" GOLDFLAGS=""

Kubernetes static pod组件 调试

本文以kube-apiserver为例,其他kube-controller-managerkube-scheduler等以static pod部署的组件,调试方法类似。

除了“Goland配置”,以下操作都是在远程Linux服务器中进行。

编译kube-apiserver组件

重编译的输出,在当前位置的_output/bin/目录下;

sudo make WHAT="cmd/kube-apiserver" GOGCFLAGS="-N -l" GOLDFLAGS=""  
# 执行过程
[root@gv187 kubernetes]# make WHAT="cmd/kube-apiserver" GOGCFLAGS="-N -l" GOLDFLAGS=""
+++ [1004 20:26:13] Building go targets for linux/amd64:
    ./vendor/k8s.io/code-generator/cmd/deepcopy-gen
warning: ignoring symlink /go/src/github.com/kubernetes/kubernetes/_output/local/go/src/k8s.io/kubernetes
go: warning: "k8s.io/kubernetes/vendor/github.com/go-bindata/go-bindata/..." matched no packages
+++ [1004 20:26:25] Building go targets for linux/amd64:
    cmd/kube-apiserver

查找kube-apiserver配置信息

[root@gv187 kubernetes]# ps -ef | grep kube-apiserver
root       421 29137  0 20:27 pts/1    00:00:00 grep --color=auto kube-apiserver
root     34900 34776  6 9月27 ?       11:00:53 kube-apiserver --advertise-address=10.0.35.187 --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/etcd/pki/ca.pem --etcd-certfile=/etc/etcd/pki/client.pem --etcd-keyfile=/etc/etcd/pki/client-key.pem --etcd-servers=https://10.0.35.187: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/12 --tls-cert-file=/etc/kubernetes/pki/apiserver.crt --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
组装dlv debug命令
dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec 编译生成的组件 -- 组件配置参数
# 示例
dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec /go/src/github.com/kubernetes/kubernetes/_output/local/bin/linux/amd64/kube-apiserver -- --advertise-address=10.0.35.187 --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/etcd/pki/ca.pem --etcd-certfile=/etc/etcd/pki/client.pem --etcd-keyfile=/etc/etcd/pki/client-key.pem --etcd-servers=https://10.0.35.187: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/12 --tls-cert-file=/etc/kubernetes/pki/apiserver.crt --tls-private-key-file=/etc/kubernetes/pki/apiserver.key

停止kube-apiserver的static pod

$ mv /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/

只需要把manifest目录下的配置文件移动到别的地方即可,kubelet会直接停止不在manifest目录下的static pod。

通过ps -ef | grep kube-apiserver验证进程是否存在,如果依然存在,可以通过终止进程方式。

dlv 启动kube-apiserver

dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec /go/src/github.com/kubernetes/kubernetes/_output/local/bin/linux/amd64/kube-apiserver -- --advertise-address=10.0.35.187 --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/etcd/pki/ca.pem --etcd-certfile=/etc/etcd/pki/client.pem --etcd-keyfile=/etc/etcd/pki/client-key.pem --etcd-servers=https://10.0.35.187: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/12 --tls-cert-file=/etc/kubernetes/pki/apiserver.crt --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
# 提示监听在2345端口
API server listening at: [::]:2345
2022-10-04T20:34:58+08:00 warning layer=rpc Listening for remote connections (connections are not authenticated nor encrypted)

本地Goland配置

首先安装Go,下载对应版本的Kubernetes代码

GoLand IDE界面Run=>Debug=>Edit Configurations新增Go Remote debug条目,同时配置相关Host以及Port

调试效果

还原kube-apiserver的manifest文件

mv /etc/kubernetes/kube-apiserver.yaml /etc/kubernetes/manifests/

Kubernetes daemonset组件调试

本文以kube-proxy为例,其他daemonset组件调试类似。

除了“Goland配置”,以下操作都是在远程Linux服务器中进行。

kube-proxy的启动方式不是static pod方式;是以daemonset+configmap配置文件方式启动服务的;

编译kube-proxy组件

重编译的输出,在当前位置的_output/bin/目录下;

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

查找kube-proxy配置

先看看kube-proxy相关启动参数:

启动命令参数看daemonset中的command部分,配置文件看configmap中的config.conf和kubeconfig.conf

# daemonset/kube-proxy    
      ...
      spec:
        containers:
        - command:
          - /usr/local/bin/kube-proxy
          - --config=/var/lib/kube-proxy/config.conf
          - --hostname-override=$(NODE_NAME)
          volumeMounts:
          - mountPath: /var/lib/kube-proxy
            name: kube-proxy
          - mountPath: /run/xtables.lock
            name: xtables-lock
          - mountPath: /lib/modules
            name: lib-modules
            readOnly: true
        ...    
        volumes:
        - configMap:
            defaultMode: 420
            name: kube-proxy
          name: kube-proxy
        - hostPath:
            path: /run/xtables.lock
            type: FileOrCreate
          name: xtables-lock
        - hostPath:
            path: /lib/modules
            type: ""
          name: lib-modules
        ...   
  # configmap/kube-proxy
  apiVersion: v1
  data:
    config.conf: |-
      ...
    kubeconfig.conf: |-
      ...
  kind: ConfigMap
  ...

kube-proxy configmap中主要包含两部分:config.conf以及kubeconfig.conf,这里可以将config.conf的内容存放到单独的一个文件config.conf中,而kubeconfig.conf的内容则可以直接用$HOME/.kube/config进行替代

停止kube-proxy

这里为了不影响其它母机上的kube-proxy,可以通过设置node标签以及nodeSelector的方式将某一个节点的kube-proxy停止:

# 方式一:设置node标签
kubectl label nodes <node-name> <label-key>=<label-value>
# 方式一:修改nodeSelector,让node的标签匹配不上
kubectl -n kube-system edit daemonsets.kube-proxy nodeSelector:beta.kubernetes.io/os:linux2

dlv启动kube-proxy

# 注意nodeName替换成实际节点名称
$dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec /go/src/github.com/kubernetes/kubernetes/_output/local/bin/linux/amd64/kube-proxy -- \
--config=./config.conf \
--hostname-override=nodeName

然后,Goland设置kubelet代码断点并调试

Kubernetes 二进制组件调试

kubelet是以二进制方式运行在宿主机上,是通过systemd管理的。

本文以kubelet为例,其他二进制组件调试类似。

除了“Goland配置”,以下操作都是在远程Linux服务器中进行。

编译kubelet组件

重编译的输出,在当前位置的_output/bin/目录下;

sudo make WHAT="cmd/kubelet" GOGCFLAGS="-N -l" GOLDFLAGS=""

查找kubelet组件配置

[root@gv187 ~]# systemctl status -l kubelet 
● kubelet.service - kubelet: The Kubernetes Node Agent
   Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
  Drop-In: /usr/lib/systemd/system/kubelet.service.d
           └─10-kubeadm.conf
   Active: active (running) since 一 2022-09-26 21:12:13 CST; 1 weeks 1 days ago
     Docs: https://kubernetes.io/docs/
 Main PID: 20478 (kubelet)
    Tasks: 74
   Memory: 86.0M
   CGroup: /system.slice/kubelet.service
           └─20478 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --cgroup-driver=systemd --network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.2
# 其中配置信息就是
--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --cgroup-driver=systemd --network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.2

停止kubelet组件

$ systemctl stop kubelet.service

dlv启动kubelet

$ dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec /go/src/github.com/kubernetes/kubernetes/_output/local/bin/linux/amd64/kubelet -- --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --cgroup-driver=systemd --network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.2

然后,Goland设置kubelet代码断点并调试

参考

https://github.com/go-delve/delve/tree/master/Documentation/installation

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务&nbsp;ACK 容器服务&nbsp;Kubernetes&nbsp;版(简称&nbsp;ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
目录
相关文章
|
1月前
|
存储 Kubernetes 负载均衡
Kubernetes的“厨房”:架构是菜谱,组件是厨具,资源对象是食材(下)
本文深入探讨了Kubernetes(K8s)的架构、核心组件以及资源对象。Kubernetes作为一个开源的容器编排系统,通过其独特的架构设计和丰富的组件,实现了对容器化应用程序的高效管理和扩展。通过本文的介绍,读者可以深入了解Kubernetes的架构、核心组件以及资源对象,从而更好地应用和管理容器化应用程序。Kubernetes的灵活性和可扩展性使得它成为容器编排领域的领先者,为企业提供了强大的容器运行环境。
|
3月前
|
存储 Kubernetes 监控
K8S核心组件介绍
K8S核心组件介绍
|
6月前
|
Kubernetes 容器
使用Kubeadm部署K8s集群获取kube-scheduler和kube-controller-manager组件状态异常问题
使用Kubeadm部署K8s集群获取kube-scheduler和kube-controller-manager组件状态异常问题
|
6月前
|
Prometheus Kubernetes 监控
prometheus operator监控k8s集群之外的haproxy组件
prometheus operator监控k8s集群之外的haproxy组件
|
6月前
|
存储 Kubernetes Cloud Native
【云原生】k8s组件&架构介绍与K8s最新版部署
【云原生】k8s组件&架构介绍与K8s最新版部署
184 0
|
15天前
|
JSON Kubernetes 网络架构
Kubernetes CNI 网络模型及常见开源组件
【4月更文挑战第13天】目前主流的容器网络模型是CoreOS 公司推出的 Container Network Interface(CNI)模型
|
5月前
|
Linux Go 网络安全
goland 远程调试 remote debug
goland 远程调试 remote debug
96 0
|
1月前
|
Kubernetes API 调度
Kubernetes的“厨房”:架构是菜谱,组件是厨具,资源对象是食材(上)
本文深入探讨了Kubernetes(K8s)的架构、核心组件以及资源对象。Kubernetes作为一个开源的容器编排系统,通过其独特的架构设计和丰富的组件,实现了对容器化应用程序的高效管理和扩展。通过本文的介绍,读者可以深入了解Kubernetes的架构、核心组件以及资源对象,从而更好地应用和管理容器化应用程序。Kubernetes的灵活性和可扩展性使得它成为容器编排领域的领先者,为企业提供了强大的容器运行环境。
|
6月前
|
Kubernetes 负载均衡 调度
kubernetes概述-介绍、组件、架构
kubernetes概述-介绍、组件、架构
kubernetes概述-介绍、组件、架构
|
8月前
|
容器
阿里云最新产品手册——云基础产品与基础设施——计算——弹性容器实例——通用部署ACK虚拟节点组件创建ECI Pot——ECI Pot——特殊实例
阿里云最新产品手册——云基础产品与基础设施——计算——弹性容器实例——通用部署ACK虚拟节点组件创建ECI Pot——ECI Pot——特殊实例自制脑图
355 4