不使用 K8s API,如何直接修改 etcd 数据?
K8S中文社区
国内 Kubernetes 技术爱好者聚集地,内容起于K8S而不止于K8S,涉及Docker、微服务、ServiceMesh、DevOps、虚拟化等云计算及云原生相关开源项目,分享技术、经验、资讯,坚持干货。
Official Account
本文探讨了不使用 Kubernetes API,直接在 etcd 中处理数据的可能性,并在真实的 K8s 集群上成功测试了所有步骤。
校对:星空下的文仔、bot,来源:K8sMeetup社区
大家是否曾经考虑过更改 Kubernetes 集群的 etcd 数据的“低级”方法?就是说在不使用任何通用的 Kubernetes 工具(例如 CLI 程序甚至 API)就更改 etcd 存储的数据。
一切从这开始
越来越多的客户(大多是开发人员)要求提供对 Kubernetes 集群的访问权限,以便与内部服务进行交互。他们希望能够直接连接到数据库或服务,将本地应用程序连接到集群中的其他应用程序等等。
memcached.staging.svc.cluster.local
service。我们可以通过客户端连接的集群内部 VPN 来实现。我们公开与 Pod 和 service 相关的子网,并将集群的 DNS 推送到客户端。结果,当客户端尝试连接到
memcached.staging.svc.cluster.local
service 时,请求转到了集群的 DNS,它从集群的服务网络或 Pod 的地址返回该 service 的地址。
kubeadm
配置 K8s 集群。在这种情况下,默认 service subnet(子网)是
192.168.0.0/16
,而 Pod 子网是
10.244.0.0/16
。此方法大部分时候效果很好,但是也有几点值得注意:
-
192.168.*.*
子网往往是在客户办公室中使用,甚至是开发商的家庭办公室。这就出现了问题:家用路由器会使用相同的地址空间,VPN 会将这些子网从集群推送到客户端。 -
有几个集群(production、stage、多个 dev 集群)的情况下,它们将默认全部具有与 Pod 和服务的相同子网,这使得同时使用多个集群中的 services 非常困难。
解决方案
最常见的方法是重新创建所有 ClusterIP 类型的 service。不过也有问题:
以下过程存在问题:配置完所有内容后,Pod 在 /etc/resolv.conf 中将旧 IP 用作 DNS nameserver。 由于仍然找不到解决方案,因此不得不使用 kubeadm reset 重置整个集群,再次将其初始化。
-
使用 Flannel。 -
既有裸机集群,也有 Kubernetes 云集群。 -
希望避免重新部署集群中的所有 service。 -
希望尽可能轻松地进行过渡。 -
该集群由 Kubernetes v1.16.6管理(但也适用于其他版本)。 -
目标是在使用 kubeadm
在部署的集群中将192.168.0.0/16
service subnet 替换为172.24.0.0/16
。
ls
、
get
、
dump
命令阅读 etcd 数据。
changeServiceCIDR
和
changePodCIDR
。其源代码可在此处获得:
https://github.com/flant/examples/tree/master/2020/04-etcdhelper
changeServiceCIDR
算法:
-
创建一个反序列化器(deserializer)。 -
编译正则表达式以替换 CIDR。 -
遍历集群中的 ClusterIP service 列表,并对每个 service 执行操作。
-
解码 etcd 值并将其放置在 Go 对象中。 -
使用正则表达式替换地址的前两个字节。 -
从新子网的地址范围为 service 分配 IP 地址。 -
创建一个序列化器,将 Go 对象转换为 protobuf,将新数据写入 etcd。
changePodCIDR
功能与 changeServiceCIDR
基本上相同,唯一的区别是我们编辑节点的规范时,用新的子网替换了 .spec.PodCIDR
的值,而不是 service。
用法
更换 serviceCIDR
-
安装必要的软件并构建补丁 etcdhelper
工具; -
备份 etcd 和 /etc/kubernetes
。
-
更改 apiserver 和控制器管理器清单。 -
重新颁发证书。 -
修改 etcd 中 services 的 ClusterIP 规范。 -
重新启动集群中的所有 Pod。
以下是这些步骤的详细说明:
etcd-client
用于转储数据:
etcdhelper
工具:
-
安装 golang
-
复制 etcdhelper.go
,下载依赖项,构建工具:
/etc/kubernetes/manifests/kube-apiserver.yaml
和
/etc/kubernetes/manifests/kube-controller-manager.yaml
中替换
--service-cluster-ip-range
值与新子网(
172.24.0.0/16
替代
192.168.0.0/16
)。
kubeadm
颁发 apiserver 证书(以及其他证书)的 service subnet 进行更改,因此我们需要重新颁发:
kubeadm
基本配置:
crt
和
key
旧文件(删除它们才能颁发新证书):
admin.conf
的证书 :
/etc/resolv.conf
中仍具有旧的 CoreDNS(kube-dns) 地址,而 kube-proxy 已经使用新子网,并更改了 iptables 规则。
kube-system
命名空间中编辑 ConfigMap:
ClusterDNS
为 kube-dns service 的新 IP 地址:
kubectl -n kube-system get svc kube-dns
。
data.ClusterConfiguration.networking.serviceSubnet
参数切换到新的子网。
-
编辑控制平面清单后,我们可以使用新名称(例如 kube-dns-tmp)和新地址(172.24.0.10)创建新的 kube-dns service。 -
我们在 etcdhelper
中插入if
条件,这能防止修改 kube-dns service。 -
将所有 kubelet 中的旧 ClusterDNS 地址替换为新的(旧 service 将继续与新 service 同时运行)。 -
等所有应用程序的 Pod 都在约定的时间重新部署。 -
删除 kube-dns-tmp
service 并编辑serviceSubnetCIDRkube-dns
service。
kube-dns-tmp
service 和切换
kube-dns
service 的子网所需时间。
etcdhelper
来修改 podNetwork。这是操作顺序:
-
在 kube-system
命名空间中编辑配置。 -
编辑 kube-controller-manager 的清单。 -
直接在 etcd 中编辑 podCIDR。 -
重新启动集群中的所有节点。
kube-system
命名空间中编辑 ConfigMap:
data.ClusterConfiguration.networking.podSubnet
为新的子网(
10.55.0.0/16
)。
data.config.conf.clusterCIDR: 10.55.0.0/16
。
.spec.podCIDR
、
.spec.podCIDRs
、
.InternalIP
、
.status.addresses
当前值:
podCIDR
:
podCIDR
是否已更改:
原文链接:https://medium.com/flant-com/modifying-kubernetes-etcd-data-ed3d4bb42379