我们在etcd Kubernetes-cluster中直接处理数据的经验(不使用K8s API)

客户越来越多地向我们请求提供对Kubernetes集群的访问权,以访问集群内的服务:为了能够直接连接到某些数据库或服务,将本地应用程序与集群内的应用程序连接起来……



例如,需要进行连接从您的本地机器到服务memcached.staging.svc.cluster.local。我们为这个机会提供了客户端连接到的群集内部的VPN。为此,我们宣布了Pod,服务的子网,并将群集DNS推送到客户端。因此,当客户端尝试连接到服务时memcached.staging.svc.cluster.local,请求将转到群集的DNS,并作为响应从群集服务网络接收该服务的地址或Pod地址。

我们使用kubeadm配置K8s集群,其中服务子网默认192.168.0.0/16为,吊舱网络为10.244.0.0/16通常,一切正常,但有两点:

  • 192.168.*.*网通常用于客户端的办公网络,甚至更经常用于开发人员的家庭网络。然后我们遇到了冲突:家用路由器在该子网上工作,VPN将这些子网从群集推送到客户端。
  • 我们有几个集群(生产,阶段和/或几个开发集群)。然后,默认情况下,所有这些容器中的pod和服务都将具有相同的子网,这给同时使用多个群集中的服务带来了很大的困难。

现在,在相当长的一段时间内,我们已经采用了在一个项目的框架内对服务和Pod使用不同子网的做法-通常,以便所有群集都具有不同的网络。但是,我不想从头开始运行大量群集,因为它们运行许多服务,有状态应用程序等。

然后我们问自己:如何更改现有群集中的子网?

搜寻决策


最常见的做法是使用ClusterIP类型重新创建所有服务。或者,他们也可以建议

以下过程存在问题:配置完所有内容后,pod在/etc/resolv.conf中将旧IP用作DNS名称服务器。
由于仍然找不到解决方案,因此我不得不使用kubeadm reset重置整个集群,然后再次将其初始化。

但这并不适合每个人...以下是针对我们案例的更详细的入门说明:

  • 被法兰绒使用;
  • 云层和铁块上都有团簇;
  • 我想避免在集群中重复部署所有服务;
  • 需要以最小的问题来做所有事情;
  • Kubernetes版本为1.16.6(但是,其他版本的其他操作将类似);
  • 主要任务是将其192.168.0.0/16替换为使用带有服务子网的kubeadm部署的群集172.24.0.0/16

碰巧的是,很长一段时间以来,我们很感兴趣地看到它存储在etcd中的方式以及如何在Kubernetes中存储,根本可以用它来完成...因此我们想到:“ 为什么不通过替换旧的IP地址(子网)来更新etcd中的数据换新的?”

在寻找用于在etcd中处理数据的现成工具时,我们没有找到可以完全解决任务的任何东西。(顺便说一句,如果您知道任何直接在etcd中处理数据的实用程序,我们将非常感谢您提供的链接。)但是,OpenShift etcdhelper 成为了一个很好的起点(感谢其作者!)

该实用程序能够连接使用证书ETCD使用这些命令上读出的数据lsgetdump

添加etcdhelper


以下想法是合乎逻辑的:“是什么阻碍了添加此实用程序,增加了向etcd写入数据的功能?”

它已被翻译成etcdhelper修改后的版本有两个新的changeServiceCIDR功能changePodCIDR可以在这里看到她的代码

新功能有什么作用?算法changeServiceCIDR

  • 创建一个反序列化器;
  • 编译正则表达式以替换CIDR;
  • 我们通过集群中所有具有ClusterIP类型的服务:

    • 将etcd中的值解码为Go对象;
    • 使用正则表达式替换地址的前两个字节;
    • 从新子网为服务分配IP地址;
    • 创建一个序列化器,将Go对象转换为protobuf,将新数据写入etcd。

功能changePodCIDR本质上是相同的changeServiceCIDR-只是不对服务规范进行编辑,我们对节点进行了处理并将其更改.spec.PodCIDR为新的子网。

实践


变更服务CIDR


任务的执行计划非常简单,但是在重新创建集群中的所有Pod时都会涉及停机时间。在描述了主要步骤之后,我们还将分享我们的想法,即从理论上如何最小化这一简单步骤。

准备行动:

  • 安装必要的软件并组装修补的etcdhelper;
  • 备份etcd和/etc/kubernetes

更改服务的短期行动计划CIDR:

  • 修改apiserver和控制器管理器清单
  • 重新签发证书;
  • etcd中的ClusterIP服务发生了变化;
  • 重新启动集群中的所有Pod。

以下是详细的完整动作序列。

1.安装etcd-client进行数据转储:

apt install etcd-client

2.我们收集etcdhelper:

  • 我们把golang:

    GOPATH=/root/golang
    mkdir -p $GOPATH/local
    curl -sSL https://dl.google.com/go/go1.14.1.linux-amd64.tar.gz | tar -xzvC $GOPATH/local
    echo "export GOPATH=\"$GOPATH\"" >> ~/.bashrc
    echo 'export GOROOT="$GOPATH/local/go"' >> ~/.bashrc
    echo 'export PATH="$PATH:$GOPATH/local/go/bin"' >> ~/.bashrc
  • 我们保存自己etcdhelper.go,加载依赖项,收集:

    wget https://raw.githubusercontent.com/flant/examples/master/2020/04-etcdhelper/etcdhelper.go
    go get go.etcd.io/etcd/clientv3 k8s.io/kubectl/pkg/scheme k8s.io/apimachinery/pkg/runtime
    go build -o etcdhelper etcdhelper.go

3.备份etcd:

backup_dir=/root/backup
mkdir ${backup_dir}
cp -rL /etc/kubernetes ${backup_dir}
ETCDCTL_API=3 etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt --key=/etc/kubernetes/pki/etcd/server.key --cert=/etc/kubernetes/pki/etcd/server.crt --endpoints https://192.168.199.100:2379 snapshot save ${backup_dir}/etcd.snapshot

4.在Kubernetes控制平面清单中更改服务子网。在文件中/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

5.由于我们正在更改kubeadm为其颁发apiserver证书(包括)的服务子网,因此必须重新发布:

  1. 让我们看一下当前证书的颁发域和IP地址:

    openssl x509 -noout -ext subjectAltName </etc/kubernetes/pki/apiserver.crt
    X509v3 Subject Alternative Name:
        DNS:dev-1-master, DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, DNS:apiserver, IP Address:192.168.0.1, IP Address:10.0.0.163, IP Address:192.168.199.100
  2. 准备kubeadm的最低配置:

    cat kubeadm-config.yaml
    apiVersion: kubeadm.k8s.io/v1beta1
    kind: ClusterConfiguration
    networking:
      podSubnet: "10.244.0.0/16"
      serviceSubnet: "172.24.0.0/16"
    apiServer:
      certSANs:
      - "192.168.199.100" # IP-  
  3. 让我们删除旧的crt和密钥,因为没有它,将不会颁发新证书:

    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. 重新颁发API服务器的证书:

    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. , :

    openssl x509 -noout -ext subjectAltName </etc/kubernetes/pki/apiserver.crt
    X509v3 Subject Alternative Name:
        DNS:kube-2-master, DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, IP Address:172.24.0.1, IP Address:10.0.0.163, IP Address:192.168.199.100
  6. API- :

    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. admin.conf:

    kubeadm alpha certs renew admin.conf
  8. etcd:

    ./etcdhelper -cacert /etc/kubernetes/pki/etcd/ca.crt -cert /etc/kubernetes/pki/etcd/server.crt -key /etc/kubernetes/pki/etcd/server.key -endpoint https://127.0.0.1:2379 change-service-cidr 172.24.0.0/16 

    ! , pod' /etc/resolv.conf CoreDNS (kube-dns), kube-proxy iptables . .
  9. ConfigMap' kube-system:

    kubectl -n kube-system edit cm kubelet-config-1.16

    clusterDNS IP- kube-dns: kubectl -n kube-system get svc kube-dns.

    kubectl -n kube-system edit cm kubeadm-config

    data.ClusterConfiguration.networking.serviceSubnet .
  10. kube-dns, kubelet :

    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. 仍然可以重新启动集群中的所有Pod:

    kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(\S+)\s+(\S+).*/kubectl --namespace \1 delete pod \2/e'

停机时间最少


关于如何最大程度地减少停机时间的想法:

  1. 更改控制平面的表示后,例如,使用名称kube-dns-tmp和新地址创建一个新的kube-dns服务172.24.0.10
  2. if在etcdhelper,这不会修改KUBE-DNS服务。
  3. ClusterDNS新的kubelet替换所有kubelet中的地址,而旧的服务将继续与新的kubelet 同时工作。
  4. 等待带有应用程序的pod出于自然原因自己或在约定的时间滚动。
  5. 删除服务kube-dns-tmp并将其更改serviceSubnetCIDR为kube-dns服务。

该计划将kube-dns-tmp在关闭服务和更换服务的子网之前,将停机时间最小化到一分钟左右kube-dns

修改podNetwork


同时,我们决定看看如何使用生成的etcdhelper修改podNetwork。动作顺序如下:

  • 我们修复了配置kube-system;
  • 我们修复了kube-controller-manager的清单;
  • 我们直接在etcd中更改podCIDR;
  • 重新启动群集的所有节点。

现在,更多有关这些操作的信息:

1.在名称空间中修改ConfigMap kube-system

kubectl -n kube-system edit cm kubeadm-config

-固定data.ClusterConfiguration.networking.podSubnet在新的子网中10.55.0.0/16

kubectl -n kube-system edit cm kube-proxy

-我们纠正了data.config.conf.clusterCIDR: 10.55.0.0/16

2.修改控制器管理员的清单:

vim /etc/kubernetes/manifests/kube-controller-manager.yaml

-我们纠正了--cluster-cidr=10.55.0.0/16

3.查看当前值.spec.podCIDR.spec.podCIDRs.InternalIP.status.addresses对于集群中的所有节点:

kubectl get no -o json | jq '[.items[] | {"name": .metadata.name, "podCIDR": .spec.podCIDR, "podCIDRs": .spec.podCIDRs, "InternalIP": (.status.addresses[] | select(.type == "InternalIP") | .address)}]'

[
  {
    "name": "kube-2-master",
    "podCIDR": "10.244.0.0/24",
    "podCIDRs": [
      "10.244.0.0/24"
    ],
    "InternalIP": "192.168.199.2"
  },
  {
    "name": "kube-2-master",
    "podCIDR": "10.244.0.0/24",
    "podCIDRs": [
      "10.244.0.0/24"
    ],
    "InternalIP": "10.0.1.239"
  },
  {
    "name": "kube-2-worker-01f438cf-579f9fd987-5l657",
    "podCIDR": "10.244.1.0/24",
    "podCIDRs": [
      "10.244.1.0/24"
    ],
    "InternalIP": "192.168.199.222"
  },
  {
    "name": "kube-2-worker-01f438cf-579f9fd987-5l657",
    "podCIDR": "10.244.1.0/24",
    "podCIDRs": [
      "10.244.1.0/24"
    ],
    "InternalIP": "10.0.4.73"
  }
]

4.通过直接对etcd进行更改来替换podCIDR:

./etcdhelper -cacert /etc/kubernetes/pki/etcd/ca.crt -cert /etc/kubernetes/pki/etcd/server.crt -key /etc/kubernetes/pki/etcd/server.key -endpoint https://127.0.0.1:2379 change-pod-cidr 10.55.0.0/16

5.检查podCIDR是否确实已更改:

kubectl get no -o json | jq '[.items[] | {"name": .metadata.name, "podCIDR": .spec.podCIDR, "podCIDRs": .spec.podCIDRs, "InternalIP": (.status.addresses[] | select(.type == "InternalIP") | .address)}]'

[
  {
    "name": "kube-2-master",
    "podCIDR": "10.55.0.0/24",
    "podCIDRs": [
      "10.55.0.0/24"
    ],
    "InternalIP": "192.168.199.2"
  },
  {
    "name": "kube-2-master",
    "podCIDR": "10.55.0.0/24",
    "podCIDRs": [
      "10.55.0.0/24"
    ],
    "InternalIP": "10.0.1.239"
  },
  {
    "name": "kube-2-worker-01f438cf-579f9fd987-5l657",
    "podCIDR": "10.55.1.0/24",
    "podCIDRs": [
      "10.55.1.0/24"
    ],
    "InternalIP": "192.168.199.222"
  },
  {
    "name": "kube-2-worker-01f438cf-579f9fd987-5l657",
    "podCIDR": "10.55.1.0/24",
    "podCIDRs": [
      "10.55.1.0/24"
    ],
    "InternalIP": "10.0.4.73"
  }
]

6.反过来,我们将重新引导集群的所有节点。

7.如果至少一个节点离开了旧的podCIDR,那么kube-controller-manager将无法启动,并且群集中的Pod也不会被计划。

实际上,更改podCIDR可以变得更加容易(例如,像这样)。但是我们想学习如何直接使用etcd,因为在某些情况下,在etcd中编辑Kubernetes对象是唯一可能的选择。(例如,您不能在没有停机的情况下更改服务范围spec.clusterIP。)


本文考虑了直接在etcd中处理数据的可能性,即 绕过Kubernetes API。有时,这种方法使您可以做“棘手的事情”。本文中描述的操作已在真实的K8s集群上进行了测试。但是,它们准备广泛使用的状态是PoC(概念证明)因此,如果要在群集上使用etcdhelper实用程序的修改版,则后果自负,并承担风险。

聚苯乙烯


另请参阅我们的博客:


All Articles