2025-04-25 00:09:35
由于客户机器禁用了root密码登陆,想从web页面添加worker节点时就有点尴尬了,因为输入框已直接被 disabled 焊死,想要修改默认值root用户为普通用户,就得动点小心思了,F12打开浏览器调试工具,先将 disabled 全去掉,此时输入框变成可编辑了,但是高兴得有点早,一点击页面span又自动加上next-disabled,再次无法编辑。
看来没这么简单,只能实行 B 计划了,通过id获取元素value值强行更改,点击下一步顺利通过了~
2025-04-21 05:50:45
最近在 Kubernetes 使用中,有个 Pod 一直处于 Terminating
状态,通常原因是 Pod 占用的某些资源未被正确释放(如 Finalizers、Volume 挂载、网络资源、节点状态为NotReady等),强制删除也一直卡住,尝试了各种姿势,最后不得不去 ETCD 删除 Pod 数据解决,mark一下。
Finalizers 是 Kubernetes 中用于控制资源删除、防止资源被意外删除的保护机制。如果 Pod 的 metadata.finalizers
字段不为空,Kubernetes 会等待这些 Finalizers 被清除后才能删除 Pod。
手动编辑 Pod,移除 Finalizers:
kubectl edit pod <pod-name> -n <namespace>
找到 metadata.finalizers
字段,将其设置为空数组 []
,然后保存退出。
或者使用 patch
命令直接移除 Finalizers:
# 查看 Pod 的 Finalizers kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.metadata.finalizers}' # 移除 Pod 的 Finalizers kubectl patch pod <pod-name> -n <namespace> -p '{"metadata":{"finalizers":[]}}' --type=merge
如果 Pod 所在的节点(Node)出现问题(如节点宕机或网络断开),Pod 可能会一直卡在 Terminating
状态。
检查节点状态:
kubectl get nodes
如果节点状态为 NotReady
,尝试重启节点或修复节点问题,通常包括。
检查节点硬件资源,确保资源充足。
检查节点网络状态,确保节点能够正常通信。
检查节点上的容器运行状态,确保容器正常运行。
如果 Pod 使用了持久卷(Persistent Volume,PV),并且 PV 无法卸载,可能会导致 Pod 卡在 Terminating
状态。
检查 PV 和 PVC 的状态:
kubectl get pv kubectl get pvc -n <namespace>
如果 PV 或 PVC 处于异常状态,尝试手动修复或删除它们。
如果问题依然存在,可能与节点上的 Kubelet 有关,可以查看异常Pod 所在节点 Kubelet日志并尝试重启 Kubelet:
# 查看 kubelet 日志 journalctl -u kubelet -f # 重启 kubelet systemctl restart kubelet
如果问题仍然存在,可以检查 Kubernetes API Server 的日志,查看是否有相关错误信息。
查看 API Server 日志:
kubectl logs -n kube-system kube-apiserver-<node-name> kubectl logs -n kube-system -l <label-name>=kube-apiserver
如果 Finalizers 已经移除,但 Pod 仍然卡在 Terminating
状态,可以尝试强制删除。
使用 kubectl delete
的 --force --grace-period=0
参数:
kubectl delete pod <pod-name> -n <namespace> --force --grace-period=0
这会立即强制删除 Pod,但可能会留下一些未清理的资源。如果还是hang住无法删除,可以尝试直接删除 ETCD 中 Pod 记录。
在 Kubernetes 中,etcdctl
是一个用于直接与 ETCD 交互的命令行工具。ETCD 是 Kubernetes 的后端存储,所有资源(如 Pod、Service、Deployment 等)都存储在 ETCD 中。如果以上方法都无效,可以尝试直接删除 ETCD 中该 Pod 的记录。注意:直接操作 ETCD 可能会破坏 Kubernetes 集群的状态,建议仅在万不得已时使用,请谨慎执行。
1、在操作 ETCD 之前,建议先备份 ETCD 数据:
# 备份 ETCD 数据 etcdctl snapshot save snapshot.db # 验证 ETCD 快照 etcdctl snapshot status snapshot.db # 恢复 ETCD 数据 etcdctl snapshot restore snapshot.db --data-dir /var/lib/etcd
2、查看 Pod 的 ETCD 记录:
Kubernetes 资源在 ETCD 中的存储路径遵循以下格式:/registry/<资源类型>/<namespace>/<资源名称>
例如:
Pod:/registry/pods/default/my-pod
Deployment:/registry/deployments/default/my-deploy
Service:/registry/services/default/my-svc
Pod 的路径通常为:/registry/pods/<namespace>/<pod-name>
# 查看某个 Pod 的详细信息 etcdctl get /registry/pods/<namespace>/<pod-name> # 列出所有 Pod 的键 etcdctl get /registry/pods --prefix --keys-only
3、删除 Pod 的 ETCD 记录:
# 使用 etcdctl del 命令删除 Pod 的记录 etcdctl del /registry/pods/<namespace>/<pod-name>
4、验证删除 Pod 的 ETCD 记录:
# 删除后,可以通过以下命令验证 Pod 是否已从 ETCD 中移除 etcdctl get /registry/pods/<namespace>/<pod-name>
如果返回为空,说明 Pod 已成功删除。
5、K8s资源 ETCD 增删改查操作(可选):
# 列出所有 Pod 的键 etcdctl get /registry/pods --prefix --keys-only # 列出所有资源键 etcdctl get / --prefix --keys-only | grep "/registry/" # 修改资源(Update),导出资源为 JSON etcdctl get /registry/pods/default/my-pod --print-value-only > pod-data.json # 使用文本编辑器修改字段(如调整副本数、修复状态),重新写入 ETCD etcdctl put /registry/pods/default/my-pod < pod-data.json # 插入资源(Create),将 Kubernetes 资源 YAML 转换为 JSON,并确保符合 ETCD 存储格式 etcdctl put /registry/pods/default/new-pod < new-pod.json # 删除某个命名空间下的所有 Pod etcdctl del /registry/pods/<namespace> --prefix # 删除所有命名空间下的所有 Pod etcdctl del /registry/pods --prefix # 解码 Protobuf 数据,Kubernetes 默认使用 Protobuf 编码存储数据,可以通过 hexdump 或工具解码 etcdctl get /registry/pods/default/my-pod --print-value-only | hexdump -C
参考:
2025-04-17 19:32:44
杰夫·阿特伍德(Jeff Atwood)说过这么一句话:“Code Tells You How, Comments Tell You Why”。我把其扩展一下:
代 码 => What, How & Details
文档 / 书 => What, How & Why
可见,代码并不会告诉你 Why,看代码只能靠猜测或推导来估计 Why,是揣测,不准确,所以会有很多误解。而且,我们每个人都知道,Why 是能让人一通百通的东西,也是能让人醍醐灌顶的东西。
但是,代码会告诉你细节,这是书和文档不能给你的。细节是魔鬼,细节决定成败。这样的话我们不但听过很多,我们做技术的也应该体会过很多。当然,我们也要承认,这些代码细节给人带来的快感毕竟不如知道 Why 后的快感大(至少对我是这样的)。
书和文档是人对人说的话,代码是人对机器说的话(注:代码中有一部份逻辑是控制流程的逻辑,不是业务逻辑)。所以,
如果你想知道人为什么要这么搞,那么应该去看书(像 Effective C++、Code Complete、Design Pattern、Thinking in Java 等),看文档。
如果你要知道让机器干了什么?那你应该看代码!(就像 Linus 去看 zlib 的代码来找性能问题。)
因此,我认为都比较重要,关键看你的目的是什么了。
如果你想了解一种思想,一种方法,一种原理,一种思路,一种经验,恐怕,读书和读文档会更有效率一些,因为其中会有作者的思路描述。像 Effective C++ 之类的书,里面有很多对不同用法和设计的推敲,TCP/IP 详解里面也会有对 TCP 算法好坏的比较……这些思维方式能让你对技术的把握力更强,而光看代码很难达到这种级别。(现在你知道什么样的书是好书了吧 ;-))
如果你想了解的就是具体细节,比如某协程的实现,某个模块的性能,某个算法的实现,那么你还是要去读代码的,因为代码中会有更具体的处理(尤其是对于一些 edge case 或是代码技巧方面的内容)。
另外,看看下面的几个现象,你可以自己比较一下。
很多时候,我们去读代码,那是因为没有文档,或是文档写得太差。
很多时候,在 Google、Stack Overflow、GitHub 过后,你会发现,你掌握的知识就是一块一块的碎片,既不系统,也不结构化,更别说融汇贯通了。你会觉得自己需要好好地读一本书,系统地掌握知识。你的这种感觉一定很强烈吧。
很多时候,在读别人代码的时候,你会因为基础知识或是原理不懂,或是你在不知道为什么的情况下,要么完全读不懂代码,要么会误解代码。比如,如果你没有 C 语言和 TCP 原理方面的基础知识,就根本读不懂 Linux 下 TCP 的相关代码。我们因为误解代码用意而去修改代码造成的故障还少吗?
很多时候,看到一个算法或是一个设计时,比如 Paxos,你是不是会想去看一下这个算法的实现代码是什么样的?思考一下如何才能实现得好?(但是如果你没看过 Paxos 的算法思想,我不认为你光看代码实现,就能收获 Paxos 的思想。)
很多时候,当你写代码的时候,你能感觉得到自己写的代码有点别扭,怎么写都别扭,这个时候,你也会有想去看别人的代码是怎么实现的冲动。
类似的情况还有很多,但从代码中收获大,还是从书中收获大,在不同的场景、不同的目的下,会有不同的答案。这里,谈一谈人的学习过程吧。从学习的过程中,我们来分析一下看代码和看书这两个活动。人对新事物的学习过程基本都是从“感性认识”到“理性认识”的。
如果你是个新手,那应该多读代码,多动手写代码,因为你需要的是“感性认识”,这个时候“理性认识”你体会不到。一是因为,你没有切身的感受,即便告诉你 Why 你也体会不到。另一方面,这个阶段,你要的不是做漂亮,而是做出来。所以,在新手阶段,你会喜欢 GitHub 这样的东西。
如果你是个老手,你有多年的“感性认识”了,那么你的成长需要更多的“理性认识”。因为这个阶段,一方面,你会不满足于做出来,你会想去做更牛更漂亮的东西;另一方面,你知道的越多,你的问题也越多,你迫切地需要知道 Why!这时,你需要大量地找牛人交流(读牛人的书,是一种特殊的人与人的交流),所以,这个阶段,你会喜欢读好的书和文章。
然而,对于计算机行业这个技术创新能力超强、技术种类繁多的行业来说,我们每个人都既是新手,也是老手。
很多人问过我,如何读代码。因为我在外企里工作的时间较长,所以,我经常接手一些国外团队写的代码。我发现,虽然老外写的代码比国人好一点儿(有 Code Review),但依然有文档缺失、代码注释不清、代码风格混乱等一些问题,这些都是阅读代码的障碍。这里,我把我的一些阅读源代码的经验分享给你,希望对你有用。
首先,在阅读代码之前,我建议你需要有下面的这些前提再去阅读代码,这样你读起代码来会很顺畅。
基础知识。相关的语言和基础技术的知识。
软件功能。你先要知道这个软件完成的是什么样的功能,有哪些特性,哪些配置项。你先要读一遍用户手册,然后让软件跑起来,自己先用一下感受一下。
相关文档。读一下相关的内部文档,Readme 也好,Release Notes 也好,Design 也好,Wiki 也好,这些文档可以让你明白整个软件的方方面面。如果你的软件没有文档,那么,你只能指望这个软件的原作者还在,而且他还乐于交流。
代码的组织结构。也就是代码目录中每个目录是什么样的功能,每个文档是干什么的。如果你要读的程序是在某种标准的框架下组织的,比如:Java 的 Spring 框架,那么恭喜你,这些代码不难读了。
接下来,你要了解这个软件的代码是由哪些部分构成的,我在这里给你一个列表,供你参考。
接口抽象定义。任何代码都会有很多接口或抽象定义,其描述了代码需要处理的数据结构或者业务实体,以及它们之间的关系,理清楚这些关系是非常重要的。
模块粘合层。我们的代码有很多都是用来粘合代码的,比如中间件(middleware)、Promises 模式、回调(Callback)、代理委托、依赖注入等。这些代码模块间的粘合技术是非常重要的,因为它们会把本来平铺直述的代码给分裂开来,让你不容易看明白它们的关系。
业务流程。这是代码运行的过程。一开始,我们不要进入细节,但需要在高层搞清楚整个业务的流程是什么样的,在这个流程中,数据是怎么被传递和处理的。一般来说,我们需要画程序流程图或者时序处理图。
具体实现。了解上述的三个方面的内容,相信你对整个代码的框架和逻辑已经有了总体认识。这个时候,你就可以深入细节,开始阅读具体实现的代码了。对于代码的具体实现,一般来说,你需要知道下面一些事实,这样有助于你在阅读代码时找到重点。
代码逻辑。代码有两种逻辑,一种是业务逻辑,这种逻辑是真正的业务处理逻辑;另一种是控制逻辑,这种逻辑只是用控制程序流转的,不是业务逻辑。比如:flag 之类的控制变量,多线程处理的代码,异步控制的代码,远程通讯的代码,对象序列化反序列化的代码等。这两种逻辑你要分开,很多代码之所以混乱就是把这两种逻辑混在一起了(详情参看《编程范式游记》)。
出错处理。根据 2:8 原则,20% 的代码是正常的逻辑,80% 的代码是在处理各种错误,所以,你在读代码的时候,完全可以把处理错误的代码全部删除掉,这样就会留下比较干净和简单的正常逻辑的代码。排除干扰因素,可以更高效地读代码。
数据处理。只要你认真观察,就会发现,我们好多代码就是在那里倒腾数据。比如 DAO、DTO,比如 JSON、XML,这些代码冗长无聊,不是主要逻辑,可以不理。
重要的算法。一般来说,我们的代码里会有很多重要的算法,我说的并不一定是什么排序或是搜索算法,可能会是一些其它的核心算法,比如一些索引表的算法,全局唯一 ID 的算法,信息推荐的算法、统计算法、通读算法(如 Gossip)等。这些比较核心的算法可能会非常难读,但它们往往是最有技术含量的部分。
底层交互。有一些代码是和底层系统的交互,一般来说是和操作系统或是 JVM 的交互。因此,读这些代码通常需要一定的底层技术知识,不然,很难读懂。
运行时调试。很多时候,代码只有运行起来了,才能知道具体发生了什么事,所以,我们让代码运行进来,然后用日志也好,debug 设置断点跟踪也好。实际看一下代码的运行过程,是了解代码的一种很好的方式。
总结一下,阅读代码的方法如下。
一般采用自顶向下,从总体到细节的“剥洋葱皮”的读法。
画图是必要的,程序流程图,调用时序图,模块组织图……
代码逻辑归一下类,排除杂音,主要逻辑才会更清楚。
debug 跟踪一下代码是了解代码在执行中发生了什么的最好方式。
对了,阅读代码你需要一个很好的 IDE。我记得以前读 C 和 C++ 代码时,有一个叫 source insight 的工具就大大提高了我的代码阅读效率。说白了就是可以查看代码间相互的调用 reference 的工具,这方面 Visual Studio 做得是非常好的。
总结一下今天的内容。我先跟你探讨了“是读文档,还是读代码”,分析对比了从文档和代码中各自能收获到哪些东西,然后给出建议,如果想了解思想、方法和原理,读书和读文档会更有效率;如果想知道具体细节,还是应该读代码。随后分享了一些我阅读代码和源代码时候的方法和技巧。希望对你有启发。
下篇文章是《高效学习》系列的最后一篇,我将分享一下面对枯燥和量大的知识时,我们该怎样做。
来源:《左耳听风专栏:高效学习》
2025-04-14 22:32:09
修改 settings.json ,Settings > User > multiCursorModifier must be set to alt (default),editor.gotoLocation.multipleDefinitions
and change its value from peek
to goto
{ "editor.multiCursorModifier": "alt", "editor.gotoLocation.multipleDefinitions": "goto" }
再执行以下命令:
go mod vendor
2025-04-09 18:01:46
k8s集群中 ETCD 一般以 static pod方式部署在 master 0/1/2 节点上,路径一般为 /etc/kubernetes/manifests/etcd.yaml ,需要针对k8s集群中已经在运行的 ETCD 3 副本进行端口切换变更,从 2379 端口变更到 2378,2380 保持不变。
apiVersion: v1 kind: Pod metadata: namespace: kube-system name: etcd labels: component: etcd tier: control-plane spec: containers: - name: etcd image: xxx/etcd:v3.5.4-amd64 command: - etcd - --cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 env: - name: ETCD_NAME value: kube-etcd2 - name: ETCD_INITIAL_ADVERTISE_PEER_URLS value: https://10.0.1.6:2380 - name: ETCD_LISTEN_PEER_URLS value: https://10.0.1.6:2380 - name: ETCD_LISTEN_CLIENT_URLS value: https://10.0.1.6:2379,https://127.0.0.1:2379 - name: ETCD_ADVERTISE_CLIENT_URLS value: https://10.0.1.6:2379 - name: ETCD_INITIAL_CLUSTER_TOKEN value: xxx-k8s - name: ETCD_INITIAL_CLUSTER value: kube-etcd1=https://10.0.1.8:2380,kube-etcd2=https://10.0.1.6:2380,kube-etcd3=https://10.0.1.7:2380 - name: ETCD_INITIAL_CLUSTER_STATE value: new - name: ETCD_EXPERIMENTAL_BACKEND_BBOLT_FREELIST_TYPE value: "map" - name: ETCD_AUTO_COMPACTION_RETENTION value: "5m" - name: ETCD_SNAPSHOT_COUNT value: "10000" - name: ETCD_MAX_SNAPSHOTS value: "5" - name: ETCD_MAX_WALS value: "5" - name: ETCD_HEARTBEAT_INTERVAL value: "1000" - name: ETCD_ELECTION_TIMEOUT value: "10000" - name: ETCD_QUOTA_BACKEND_BYTES value: "100000000000" - name: ETCD_BACKEND_BATCH_LIMIT value: "1000" - name: ETCD_BACKEND_BATCH_INTERVAL value: "10ms" - name: ETCD_CLIENT_CERT_AUTH value: "true" - name: ETCD_TRUSTED_CA_FILE value: /etc/kubernetes/pki/etcd/ca.crt - name: ETCD_CERT_FILE value: /etc/kubernetes/pki/etcd/server.crt - name: ETCD_KEY_FILE value: /etc/kubernetes/pki/etcd/server.key - name: ETCD_PEER_CLIENT_CERT_AUTH value: "true" - name: ETCD_PEER_TRUSTED_CA_FILE value: /etc/kubernetes/pki/etcd/ca.crt - name: ETCD_PEER_CERT_FILE value: /etc/kubernetes/pki/etcd/peer.crt - name: ETCD_PEER_KEY_FILE value: /etc/kubernetes/pki/etcd/peer.key - name: ETCD_DATA_DIR value: /var/lib/etcd/data - name: ETCD_LOG_LEVEL value: "info" - name: ETCD_LOG_OUTPUTS value: /var/lib/etcd/logs/etcd.log - name: ETCD_ENABLE_LOG_ROTATION value: "true" - name: ETCD_LOG_ROTATION_CONFIG_JSON value: "{\"maxsize\": 1024, \"maxage\": 30, \"maxbackups\": 5, \"localtime\": false, \"compress\": false}" livenessProbe: exec: command: - /bin/sh - -ec - ETCDCTL_API=3 etcdctl --endpoints=127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd/peer.key get test failureThreshold: 8 initialDelaySeconds: 15 timeoutSeconds: 15 resources: requests: cpu: 2000m memory: 2Gi limits: cpu: 4000m memory: 8Gi volumeMounts: - name: etcd-data mountPath: /var/lib/etcd/data - name: etcd-certs mountPath: /etc/kubernetes/pki/etcd - name: etcd-log mountPath: /var/lib/etcd/logs hostNetwork: true volumes: - name: etcd-certs hostPath: path: /etc/kubernetes/pki/etcd type: Directory - name: etcd-data hostPath: path: /home/t4/etcd/data type: DirectoryOrCreate - name: etcd-log hostPath: path: /home/t4/sigma-master/logs/etcd type: DirectoryOrCreate
参数项 | 样例 | 说明 |
---|---|---|
ETCD_INITIAL_ADVERTISE_PEER_URLS | https://10.0.1.6:2380 | List of this member’s peer URLs to advertise to the rest of the cluster. These addresses are used for communicating etcd data around the cluster. At least one must be routable to all cluster members. These URLs can contain domain names. |
ETCD_LISTEN_PEER_URLS | https://10.0.1.6:2380 |
List of URLs to listen on for peer traffic. This flag tells the etcd to accept incoming requests from its peers on the specified scheme://IP:port combinations. Scheme can be http or https . Alternatively, use unix:// or unixs:// for unix sockets. If 0.0.0.0 is specified as the IP, etcd listens to the given port on all interfaces. If an IP address is given as well as a port, etcd will listen on the given port and interface. Multiple URLs may be used to specify a number of addresses and ports to listen on. The etcd will respond to requests from any of the listed addresses and ports.
|
ETCD_LISTEN_CLIENT_URLS | https://10.0.1.6:2379,https://127.0.0.1:2379 |
List of URLs to listen on for client traffic. This flag tells the etcd to accept incoming requests from the clients on the specified scheme://IP:port combinations as long as --listen-client-http-urls is not specified. Scheme can be either http or https . Alternatively, use unix:// or unixs:// for unix sockets. If 0.0.0.0 is specified as the IP, etcd listens to the given port on all interfaces. If an IP address is given as well as a port, etcd will listen on the given port and interface. Multiple URLs may be used to specify a number of addresses and ports to listen on. The etcd will respond to requests from any of the listed addresses and ports.
|
ETCD_ADVERTISE_CLIENT_URLS | https://10.0.1.6:2379 | List of this member’s client URLs to advertise to the rest of the cluster. These URLs can contain domain names. |
ETCD_INITIAL_CLUSTER_TOKEN | xxx-k8s | Initial cluster token for the etcd cluster during bootstrap |
ETCD_INITIAL_CLUSTER | kube-etcd1=https://10.0.1.8:2380,kube-etcd2=https://10.0.1.6:2380,kube-etcd3=https://10.0.1.7:2380 | Initial cluster configuration for bootstrapping |
ETCD_INITIAL_CLUSTER_STATE | new |
Initial cluster state (“new” or “existing”). Set to new for all members present during initial static or DNS bootstrapping. If this option is set to existing , etcd will attempt to join the existing cluster. If the wrong value is set, etcd will attempt to start but fail safely
|
ETCD_EXPERIMENTAL_BACKEND_BBOLT_FREELIST_TYPE | "map" | The freelist type that etcd backend(bboltdb) uses (array and map are supported types) |
ETCD_AUTO_COMPACTION_RETENTION | "5m" | Auto compaction retention for mvcc key value store in hour. 0 means disable auto compaction |
ETCD_SNAPSHOT_COUNT | "10000" | Number of committed transactions to trigger a snapshot to disk |
ETCD_MAX_SNAPSHOTS | "5" | Maximum number of snapshot files to retain (0 is unlimited) |
ETCD_MAX_WALS | "5" | Maximum number of wal files to retain (0 is unlimited) |
ETCD_HEARTBEAT_INTERVAL | "1000" | Time (in milliseconds) of a heartbeat interval |
ETCD_ELECTION_TIMEOUT | "10000" | Time (in milliseconds) for an election to timeout |
ETCD_QUOTA_BACKEND_BYTES | "100000000000" | Raise alarms when backend size exceeds the given quota (0 defaults to low space quota) |
ETCD_BACKEND_BATCH_LIMIT | "1000" | BackendBatchLimit is the maximum operations before commit the backend transaction |
ETCD_BACKEND_BATCH_INTERVAL | "10ms" | BackendBatchInterval is the maximum time before commit the backend transaction |
ETCD_CLIENT_CERT_AUTH | "true" | Enable client cert authentication |
ETCD_TRUSTED_CA_FILE | /etc/kubernetes/pki/etcd/server.crt | Path to the client server TLS trusted CA cert file |
ETCD_KEY_FILE | /etc/kubernetes/pki/etcd/server.key | Path to the client server TLS key file |
ETCD_PEER_CLIENT_CERT_AUTH | "true" | Enable peer client cert authentication |
ETCD_PEER_TRUSTED_CA_FILE | /etc/kubernetes/pki/etcd/ca.crt | Path to the peer server TLS trusted CA file |
ETCD_PEER_CERT_FILE | /etc/kubernetes/pki/etcd/peer.crt | Path to the peer server TLS cert file. This is the cert for peer-to-peer traffic, used both for server and client |
ETCD_PEER_KEY_FILE | /etc/kubernetes/pki/etcd/peer.key | Path to the peer server TLS key file. This is the key for peer-to-peer traffic, used both for server and client |
ETCD_DATA_DIR | /var/lib/etcd/data | Path to the data directory |
ETCD_LOG_LEVEL | "info" | Configures log level. Only supports debug, info, warn, error, panic, or fatal |
ETCD_LOG_OUTPUTS | /var/lib/etcd/logs/etcd.log | Specify ‘stdout’ or ‘stderr’ to skip journald logging even when running under systemd, or list of comma separated output targets |
ETCD_ENABLE_LOG_ROTATION | "true" | |
ETCD_LOG_ROTATION_CONFIG_JSON | "{"maxsize": 1024, "maxage": 30, "maxbackups": 5, "localtime": false, "compress": false}" |
客户端/API Server访问端口(2379): +-------------------+ +-------------------+ +-------------------+ | ETCD 0 | | ETCD 1 | | ETCD 2 | | (master 0) |<---->| (master 1) |<----->| (master 2) | | IP: 10.0.1.6 | | IP: 10.0.1.7 | | IP: 10.0.1.8 | +-------------------+ +-------------------+ +-------------------+ ^ 客户端请求 (2379) ^ 客户端请求 (2379) ^ 客户端请求 (2379) | | | v v v +----------------------------------------------------------------------------+ | 客户端/API Server访问端口(读写键值数据) | +----------------------------------------------------------------------------+ 集群内部通信端口(2380): +-------------------+ +-------------------+ +-------------------+ | ETCD 0 |<--->| ETCD 1 |<--->| ETCD 2 | | (master 0) | | (master 1) | | (master 2) | | IP: 10.0.1.6 | | IP: 10.0.1.7 | | IP: 10.0.1.8 | | 2380 (集群) | | 2380 (集群) | | 2380 (集群) | +-------------------+ +-------------------+ +-------------------+ - 客户端通过 2379 端口与任意节点通信(读/写请求)。 - 节点间通过 2380 端口进行 Leader 选举、心跳检测、日志复制(Raft 协议)。
查看ETCD集群信息:
ETCDCTL_API=3 etcdctl --endpoints=10.0.1.6:2379,10.0.1.7:2379,10.0.1.8:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd/peer.key endpoint status -w table ETCDCTL_API=3 etcdctl --endpoints=10.0.1.6:2379,10.0.1.7:2379,10.0.1.8:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd/peer.key endpoint health -w table
备份ETCD数据(Lead节点):
ETCDCTL_API=3 etcdctl --endpoints=10.0.1.8:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd/peer.key snapshot save /root/etcd_backup/etcd-backup-20250307.db 验证快照命令 etcdctl snapshot status /root/etcd_backup/etcd-backup-20250307.db -w table 14c436f9, 93609, 2535, 29 MB
修改/etc/kubernetes/manifests/etcd.yaml
ETCD_LISTEN_CLIENT_URLS 2379 → 2378
ETCD_ADVERTISE_CLIENT_URLS 2379 → 2378
livenessProbe --endpoints 2379 → 2378
修改后重启 ETCD 0, 检查 pod 是否正常运行,如果修改后一直没有看到etcd pod,可以重启 kubelet 观察。
# 变更后检察etcd状态: kubectl get pods -n kube-system -l component=etcd # 查看 etcd 日志: kubectl logs -n kube-system -l component=etcd
apiVersion: v1 kind: Pod metadata: namespace: kube-system name: kube-apiserver labels: component: kube-apiserver tier: control-plane spec: containers: - name: kube-apiserver image: xxx/kube-apiserver-amd64:v1.22.x command: - kube-apiserver - --advertise-address=10.0.1.6 - --secure-port=6443 - --insecure-port=0 - --client-ca-file=/etc/kubernetes/pki/ca.crt - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key - --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt - --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key - --enable-bootstrap-token-auth=true - --authorization-mode=Node,RBAC - --feature-gates=RotateKubeletServerCertificate=true - --etcd-servers=https://10.0.1.8:2379,https://10.0.1.6:2379,https://10.0.1.7:2379 - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt - --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt - --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key - --allow-privileged=true - --apiserver-count=3 - --requestheader-username-headers=X-Remote-User - --requestheader-group-headers=X-Remote-Group - --requestheader-allowed-names=front-proxy-client,aggregator - --requestheader-extra-headers-prefix=X-Remote-Extra- - --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt - --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt - --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key - --service-cluster-ip-range=192.16.0.0/16 - --service-node-port-range=30000-32000 - --service-account-key-file=/etc/kubernetes/pki/sa.pub - --service-account-signing-key-file=/etc/kubernetes/pki/sa.key - --service-account-issuer=https://kubernetes.default.svc.cluster.local - --log-dir=/logs - --logtostderr=false ......
修改 /etc/kubernetes/manifests/kube-apiserver.yaml 中 - --etcd-servers 的 master 0 etcd 配置 2379 → 2378,重启 api server 0, 检查其 pod 是否正常运行
kubectl get po -n kube-system -l component=kube-apiserver kubectl delete pod -n kube-system apiserver-name kubectl logs -n kube-system -l component=kube-apiserver
没有问题的话接下来就是一台台替换master 1/2上etcd 2379端口地址,重复上述操作 master 0/1/2 apiserver替换etcd端口操作,需检察替换过程中etcd集群和apiserver集群都无异常再进行下一步变更。
ETCDCTL_API=3 etcdctl --endpoints=10.0.1.6:2379,10.0.1.7:2379,10.0.1.8:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd/peer.key endpoint status -w table
参考: