本地调试kubernetes组件源码方法

安装etcd hack/install-etcd.sh export PATH="/home/blue/codes/kubernetes/third_party/etcd:${PATH}" 修改hack/local-up-cluster.sh,出以调试kube-apiserver为例 diff --git a/hack/local-up-cluster.sh b/hack/local-up-cluster.sh index e6195d73383..cfbabc65642 100755 --- a/hack/local-up-cluster.sh +++ b/hack/local-up-cluster.sh @@ -550,7 +550,7 @@ EOF APISERVER_LOG=${LOG_DIR}/kube-apiserver.log # shellcheck disable=SC2086 - ${CONTROLPLANE_SUDO} "${GO_OUT}/kube-apiserver" "${authorizer_arg}" "${priv_arg}" ${runtime_config} \ + ${CONTROLPLANE_SUDO} /opt/GoLand-2023.2.5/plugins/go-plugin/lib/dlv/linux/dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec -- "${GO_OUT}/kube-apiserver" "${authorizer_arg}" "${priv_arg}" ${runtime_config} \ ${cloud_config_arg} \ "${advertise_address}" \ "${node_port_range}" \ goland中添加golang远程调试配置。 启动本地集群 mkdir -p /var/run/kubernetes/ # 权限改成当前用户 chown -R blue:blue /var/run/kubernetes/ DBG=1 hack/local-up-cluster.sh 在出现这句提示时,点击启动调试按钮 此时等待集群启动完成,如果遇到不能启动,可查看/tmp/kube-apiserver.log找到具体原因。 kubectl --kubeconfig /var/run/kubernetes/admin.kubeconfig…

cgroup模式检测

cgroup有v1和v2版本,系统上对cgroupfs的挂载支持三种不同的模式: 统一(Unified) — 最简单的方式,只暴露纯粹的cgroup v2接口。在该模式下,/sys/fs/cgroup 是唯一挂载到主机上的文件系统,所有的控制器都通过它暴露。 兼容(Legacy) — 传统的cgroup v1模式,该模式下不同的控制器拥有自己挂载目录:/sys/fs/cgroup/<controller>/。在此基础之上,systemd拥有自己的cgroup层级来实现管理功能:/sys/fs/cgroup/systemd/。 混合(Hybrid) — 这是上面两种模式的结合形式。这种模式和兼容模式非常相似,但是会多挂载一个层级目录/sys/fs/cgroup/unified/,该目录下包含cgoup v2的接口(但是该目录下只是暴露cgroupfs层级树,不包含控制器功能,控制器都挂载到了兼容模式的单独目录下,/sys/fs/cgroup/unified/仅仅是纯粹的cgroupfs的v2的功能能力,无关资源管控)。在此种模式下,既能够兼容cgroup v1的功能,又能使用一些cgroup v2的特性。 对于不同的操作系统发行版,或者相同发行版的不同版本,挂载模式可能都不一样,因此要使用cgroup功能,需要使用者(如runc,新版jvm)能够检测当前的系统上使用的是何种模式,对于检测何种模式可以使用下列简单的方式: 在根命名空间中,可以使用statfs()获取/sys/fs/cgroup/这个文件系统的类型,如果.f_type是 CGROUP2_SUPER_MAGIC,则说明是统一模式。如果.f_type是TMPFS_MAGIC ,则可能是cgroup v1模式或者可能是混合模式,更进一步检查可通过statfs()获取/sys/fs/cgroup/unified/的文件系统类型,如果它的.f_type是CGROUP2_SUPER_MAGIC,则说明使用的是混合模式,否则就是cgroup v1模式。 下面是containerd中的实现: // github.com/containerd/cgroups/utils.go // Mode returns the cgroups mode running on the host func Mode() CGMode { checkMode.Do(func() { var st unix.Statfs_t if err := unix.Statfs(unifiedMountpoint, &st); err != nil { cgMode = Unavailable return } switch st.Type { case unix.CGROUP2_SUPER_MAGIC: cgMode = Unified default: cgMode = Legacy if err := unix.Statfs(filepath.Join(unifiedMountpoint,…

kube-prometheus问题小计

最近再Kubernetes集群上部署kube-prometheus套件遇到了一点小问题,再次记录一下。 按照官方的快速指引部署到集群中后,发现没有部署custom-metrics和external-metrics服务,而正好需要使用这两个功能做自动扩缩容,因此按照该文档进行自定义部署,但是这里遇到了一些小问题。 首先按照文档中的指引,安装jb,jsonnet和gojsontoyaml这几个命令: # 此处静态编译为了拿到任何地方都能直接用 yum install -y glibc-devel go install -a -ldflags='-linkmode external -extldflags -static' github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb@latest go install -a github.com/google/go-jsonnet/cmd/jsonnet@latest go install -a github.com/brancz/gojsontoyaml@latest mkdir bin/ cp ~/go/bin/{gojsontoyaml,jsonnet,jb} bin/ export PATH=`pwd`/bin:$PATH jb init # Creates the initial/empty `jsonnetfile.json` jb install github.com/prometheus-operator/kube-prometheus/jsonnet/kube-prometheus@release-0.9 # jb update # 下载对应版本的build.sh和example.jsonnet文件 $ wget https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/release-0.9/example.jsonnet -O example.jsonnet $ wget https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/release-0.9/build.sh -O build.sh # 编辑example.jsonnet,去掉被注释掉的custom metrics和external metrics部分 sh build.sh example.jsonnet # 上面命令会重新生成manifests目录 kubectl apply -f manifests/setup…

kubernetes api公约

api规范 前言 本问主要讲解整个kubernetes api的规范公约,本文译自kubernetes社区的本篇文档。译这篇文章是因为在与kubernetes打交道曾多次参考,非常有价值,可以帮助我们更好的理解kubernetes api。中文有的地方表达不是很完善,最好可以对照原文看。下面是部分译文。 本文档面向想深度理解kubernetes api结构,以及扩展kubernetes的开发人员。 目录 Types (Kinds) Resources Objects Metadata Spec and Status Typical status properties References to related objects Lists of named subobjects preferred over maps Primitive types Constants Unions Lists and Simple kinds Differing Representations Verbs on Resources PATCH operations Idempotency Optional vs. Required Defaulting Late Initialization Concurrency Control and Consistency Serialization Format Units Selecting Fields Object references HTTP Status codes Success codes Error codes…

external-dns介绍和基本使用

external-dns用来将集群内的pod,service,ingress等资源注册到外面的dns上,这样集群外的服务可通过统一的dns访问到集群内的服务,external-dns支持将域名注册到不同的域名服务,如aws,linode,或coredns,bind-dns等。external-dns支持众多kubernetes资源到外部域名服务的注册发布,具体支持的资源类型可进入source目录查看,同时也支持众多的外部域名服务支持,具体可进入provider目录查看。 项目主页:https://github.com/kubernetes-sigs/external-dns 本文主要使用bind作为外部dns服务进行演示测试,将集群内的service,ingress,和istio-gateway,istio-virtualservice注册到外面的dns上。 域名划分 首先我们需要对域名做一个划分: svc.mydomain.com kubernetes集群内服务域名,此处我们集群内外使用相同的域 hosts.mydomain.com 主机节点的dns解析域 mydomain.com 基础服务 部署bind bind的主配置文件修改了本地监听的ip地址,注释掉了ipv6的监听,使用tsig-keygen -a hmac-sha256 externaldns命令生成了认证密匙并配置到了配置文件中,加入forwarders转发配置,此处要求配置为客户基础环境中的。 [root@vm10-77-1-87 ~]# cat /etc/named.conf // // named.conf // // Provided by Red Hat bind package to configure the ISC BIND named(8) DNS // server as a caching only nameserver (as a localhost DNS resolver only). // // See /usr/share/doc/bind*/sample/ for example named configuration files. // // See the BIND Administrator's Reference Manual (ARM) for…

探索client-go中的exec和cp的原理

开发kubernetes控制器中可能涉及到进入特定的container中执行命令的操作,或者拷贝文件等操作,此时我们可能会借助client-go提供的这个工具去实现: "k8s.io/client-go/tools/remotecommand" // 构建请求 req := client.RESTClient().Post(). Resource("pods"). Name(podName). Namespace(namespace). SubResource("exec") req.VersionedParams(&v1.PodExecOptions{ Container: containerName, Command: cmd, Stdin: false, Stdout: true, Stderr: true, TTY: true, }, scheme.ParameterCodec) // 创建执行器 exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL()) // 执行命令 exec.Stream(remotecommand.StreamOptions{ Stdin: nil, Stdout: &buf, Stderr: &buf, Tty: true, }) 上面代码执行时会向apiserver发起一个请求,apiserver会通过代理机制将请求转发给相应节点上的kubelet服务,kubelet会通过cri接口调用runtime的接口发起流式接口中的Exec()接口进入到container执行。针对一般化的命令调用,输入参数和输出结果多数以文本为主,并不会占用带宽和apiserver的资源,但是当设计到文件拷贝的时候则会占用较多带宽,因此在实际使用时这种方式拷贝大文件来说可能并不是最优方案。 此处顺便描述一下如kubectl工具对cp命令的原理,其实也是调用的exec接口,然后执行tar命令进行文件的拷贝动作: # 从容器向外拷贝,通过tar命令压缩将输出重定向到标准输出 tar cf - <srcFile# 从外面向容器内拷贝,将标准输入数据通过tar解压写入到container内的文件目录 tar --no-same-permissions --no-same-owner -xmf - # 或 tar -xmf - 考虑到上面所说的带宽问题,在实际使用时也可向kubelet直接发起exec请求,只要通过client-go将pod所在节点实现查询一下即可,当然还会设计一些端口,证书问题,下面是一个直接向kubelet发起请求的示例代码。 package main import…

kubernetes基础 – 管理守护进程

damonset一般运行在集群的所有节点上,是一些常驻服务,通常可以用来收集日志,作为存储节点,运行监控进程等。 下面是一个日志收集的daemonset的定义: apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd-elasticsearch namespace: kube-system labels: k8s-app: fluentd-logging spec: selector: matchLabels: name: fluentd-elasticsearch updateStrategy: type: RollingUpdate rollingUpdate: maxUnavailable: 1 maxSurge: "100%" template: metadata: labels: name: fluentd-elasticsearch spec: # nodeSelector: # node-role.kubernetes.io/worker: "true" tolerations: - key: node-role.kubernetes.io/master operator: Exists effect: NoSchedule containers: - name: fluentd-elasticsearch image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2 resources: limits: memory: 200Mi requests: cpu: 100m memory: 200Mi volumeMounts: - name: varlog mountPath: /var/log - name: varlibdockercontainers…

kubernetes基础 – 管理有状态服务

statefulset区别于deployment有两个最重要的特性:有序性,固定性。 适用的场景 StatefulSets 对于需要满足以下一个或多个需求的应用程序很有价值: 稳定的、唯一的网络标识符 稳定的、持久的存储 有序的、优雅的部署和缩放 有序的、自动的滚动更新 限制 pod的持久化存储基于pvc和pv。 为保证数据安全,删除或者收缩statefulset并不会自动删除它关联的存储卷。 需要手动创建无头服务使pod的dns可解析。 删除 statefulset时,并不按照有序性执行,要求有序的话,可以在删除之前将 statefulset 缩放为 0。 默认pod管理策略(OrderedReady) 时使用滚动更新,有可能会有更新终止,需要人为修复的状况。 有序性: 每个pod都有一个序号 部署时和扩容时根据序号递增依次启动新pod 缩容时依次根据序号递减依次删除pod 固定标识 statefulset在创建pod的时候会为每个pod分配下面几个固定的标识。 固定网络标识 pod的名称和pod的主机名是根据statefulset的名称和当前pod的序号组成的:$(statefulset-name)-$(ordinal)。dns解析需要无头服务。 规则 Cluster Domain Service (ns/name) StatefulSet (ns/name) StatefulSet Domain Pod DNS Pod Hostname cluster.local default/nginx default/web nginx.default.svc.cluster.local web-{0..N-1}.nginx.default.svc.cluster.local web-{0..N-1} cluster.local foo/nginx foo/web nginx.foo.svc.cluster.local web-{0..N-1}.nginx.foo.svc.cluster.local web-{0..N-1} kube.local foo/nginx foo/web nginx.foo.svc.kube.local web-{0..N-1}.nginx.foo.svc.kube.local web-{0..N-1} 固定存储 pvc名称规则:$(tpl-metadata.name)-$(podname) pod标签 每个pod标签里会自动加一个 statefulset.kubernetes.io/pod-name 方便针对单个pod创建service。 pod管理策略 对于部署,扩缩容和更新时的并行度设置。 OrderedReady(依次) Parallel(并行,只影响扩缩操作,对更新策略不生效) 更新策略 手动(需要手动删除pod)…

kubernetes基础 – 管理无状态服务

考虑到性能和可用性,通常一个服务会有多个服务实例,在k8s中通过多个pod实现。 无状态服务是各个pod完全是一样,彼此可替代。 有状态服务是各个pod不完全一样,不可彼此替代,比如pod关联特定存储卷。 对于以下场景可以使用replicaset: 稳定的、唯一的网络标识符。 稳定的、持久的存储。 有序的、优雅的部署和缩放。 有序的、自动的滚动更新。 replicaset讲解 replicaset 的目的是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合。 因此,它通常用来保证给定数量的、完全相同的 Pod 的可用性。 replicaset通过pod的metadata.ownerReferences对应的replicaset。如果匹配的pod没有这个值扩不是控制器,那么replicaset将捕获纳管这个pod。 ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行。 然而,Deployment 是一个更高级的概念,它管理ReplicaSet,并向 Pod 提供声明式的更新以及许多其他有用的功能。 因此,我们建议使用 Deployment 而不是接使用 ReplicaSet,除非 你需要自定义更新业务流程或根本不需要更新。 示例replicaset: apiVersion: apps/v1 kind: ReplicaSet metadata: name: frontend labels: app: guestbook tier: frontend spec: # modify replicas according to your case replicas: 3 selector: matchLabels: tier: frontend template: metadata: labels: tier: frontend spec: containers: - name: php-redis image: gcr.io/google_samples/gb-frontend:v3 操作:…