Az etcd Kubernetes-fürtben lévő adatokkal kapcsolatos tapasztalataink közvetlenül (K8s API nélkül)

Az ügyfelek egyre gyakrabban kérnek tőlünk, hogy biztosítsunk hozzáférést a Kubernetes-fürthöz, hogy hozzáférhessünk a fürtön belüli szolgáltatásokhoz: hogy közvetlenül kapcsolódhassunk valamilyen adatbázishoz vagy szolgáltatáshoz, hogy egy helyi alkalmazást kapcsolódjunk a fürtön belüli alkalmazásokhoz...

Az etcd Kubernetes-fürtben lévő adatokkal kapcsolatos tapasztalataink közvetlenül (K8s API nélkül)

Például a helyi gépről csatlakozni kell egy szolgáltatáshoz memcached.staging.svc.cluster.local. Ezt a lehetőséget egy VPN segítségével biztosítjuk azon a fürtön belül, amelyhez az ügyfél csatlakozik. Ennek érdekében bejelentjük a pod-ok, szolgáltatások alhálózatait és a push fürt DNS-t az ügyfélnek. Így amikor egy ügyfél megpróbál csatlakozni a szolgáltatáshoz memcached.staging.svc.cluster.local, a kérés a fürt DNS-hez érkezik, és válaszul megkapja ennek a szolgáltatásnak a címét a fürtszolgáltatási hálózattól vagy a podcímtől.

A K8s-fürtöket a kubeadm segítségével konfiguráljuk, ahol az alapértelmezett szolgáltatási alhálózat van 192.168.0.0/16, a hüvelyek hálózata pedig az 10.244.0.0/16. Általában minden jól működik, de van néhány pont:

  • Alhálózat 192.168.*.* gyakran használják a kliens irodai hálózatokban, és még gyakrabban a fejlesztői otthoni hálózatokban. És akkor ütközéseket kapunk: az otthoni útválasztók ezen az alhálózaton dolgoznak, és a VPN továbbítja ezeket az alhálózatokat a fürtből a kliensnek.
  • Számos klaszterünk van (gyártási, színpadi és/vagy több fejlesztői klaszter). Ekkor alapértelmezés szerint mindegyiknek ugyanaz az alhálózata lesz a podokhoz és szolgáltatásokhoz, ami nagy nehézségeket okoz a több fürtben lévő szolgáltatásokkal való egyidejű munka során.

Már régen átvettük azt a gyakorlatot, hogy ugyanazon projekten belül különböző alhálózatokat használunk szolgáltatásokhoz és podokhoz – általában úgy, hogy minden fürtnek más-más hálózata van. Viszont nagyon sok olyan klaszter működik, amiket nem szeretnék a semmiből átvinni, mivel sok szolgáltatást, állapottartó alkalmazást stb.

Aztán feltettük magunknak a kérdést: hogyan lehet megváltoztatni az alhálózatot egy meglévő fürtben?

Döntések keresése

A leggyakoribb gyakorlat az újraalkotás minden ClusterIP típusú szolgáltatások. Opcióként tanácsot adhat és ez:

A következő folyamattal van egy probléma: miután mindent beállítottunk, a pod-ok a régi IP-címet adják DNS névszerverként az /etc/resolv.conf fájlban.
Mivel továbbra sem találtam meg a megoldást, vissza kellett állítanom az egész fürtöt a kubeadm reset segítségével, és újra be kellett indítanom.

De ez nem mindenkinek való... Íme a részletesebb bevezető esetünkhöz:

  • Flanelt használnak;
  • A felhőkben és a hardveren is vannak klaszterek;
  • Szeretném elkerülni a fürt összes szolgáltatásának újratelepítését;
  • Általában mindent minimális számú probléma mellett kell megtenni;
  • A Kubernetes verziója 1.16.6 (a további lépések azonban hasonlóak lesznek a többi verziónál);
  • A fő feladat annak biztosítása, hogy a kubeadm használatával üzembe helyezett fürtben szolgáltatási alhálózattal 192.168.0.0/16, cserélje ki erre 172.24.0.0/16.

Történt pedig, hogy már régóta érdeklődtünk, hogy a Kubernetesben mit és hogyan tárolnak az etcd-ben, mit lehet vele kezdeni... Így gondoltuk: “Miért nem frissíti az adatokat az etcd-ben, lecserélve a régi IP-címeket (alhálózatot) újakra? "

Miután kész eszközöket kerestünk az adatokkal való munkavégzéshez etcd-ben, nem találtunk semmit, ami teljesen megoldotta volna a problémát. (Mellesleg, ha tud olyan segédprogramokról, amelyek segítségével közvetlenül az etcd-ben dolgozhat az adatokkal, szívesen fogadjuk a linkeket.) Azonban jó kiindulópont etcdhelper az OpenShiftből (köszönet a szerzőknek!).

Ez a segédprogram tanúsítványok segítségével csatlakozhat az etcd-hez, és parancsok segítségével kiolvashatja onnan az adatokat ls, get, dump.

Add hozzá az etcdhelpert

A következő gondolat logikus: "Mi akadályozza meg abban, hogy hozzáadja ezt a segédprogramot azáltal, hogy adatot írhat az etcd-be?"

Az etcdhelper módosított változata lett, két új funkcióval changeServiceCIDR и changePodCIDR. rajta láthatod a kódot itt.

Mit csinálnak az új funkciók? Algoritmus changeServiceCIDR:

  • hozzon létre egy deszerializálót;
  • reguláris kifejezés összeállítása a CIDR helyettesítésére;
  • a fürtben lévő összes ClusterIP típusú szolgáltatást végignézzük:
    • dekódolja az etcd értéket egy Go objektummá;
    • reguláris kifejezéssel lecseréljük a cím első két bájtját;
    • rendeljen a szolgáltatáshoz egy IP-címet az új alhálózatból;
    • hozzon létre egy szerializálót, konvertálja a Go objektumot protobuf-ba, írjon új adatokat az etcd-be.

Funkció changePodCIDR lényegében hasonló changeServiceCIDR - csak a szolgáltatás specifikáció szerkesztése helyett a csomópontra és a változtatásra csináljuk .spec.PodCIDR új alhálózatra.

Gyakorlat

Változtassa meg a CIDR szolgáltatást

A feladat végrehajtásának terve nagyon egyszerű, de leállással jár a fürt összes podjának újralétrehozásakor. A főbb lépések ismertetése után arról is megosztunk gondolatokat, hogy elméletileg hogyan lehet ezt az állásidőt minimalizálni.

Előkészületi lépések:

  • a szükséges szoftver telepítése és a javított etcdhelper összeállítása;
  • biztonsági mentés etcd és /etc/kubernetes.

Rövid cselekvési terv a szolgáltatásCIDR megváltoztatásához:

  • az apiserver és a controller-manager manifesztek megváltoztatása;
  • tanúsítványok újbóli kiadása;
  • ClusterIP szolgáltatások megváltoztatása az etcd-ben;
  • a fürt összes podjának újraindítása.

Az alábbiakban részletesen bemutatjuk a műveletek teljes sorozatát.

1. Telepítse az etcd-klienst az adatkiíratáshoz:

apt install etcd-client

2. Építsd meg az etcdhelpert:

  • A golang telepítése:
    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
  • Magunknak spórolunk etcdhelper.go, függőségek letöltése, gyűjtés:
    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. Készítsen biztonsági másolatot 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. Módosítsa a szolgáltatás alhálózatát a Kubernetes vezérlősík jegyzékeiben. Fájlokban /etc/kubernetes/manifests/kube-apiserver.yaml и /etc/kubernetes/manifests/kube-controller-manager.yaml módosítsa a paramétert --service-cluster-ip-range új alhálózatra: 172.24.0.0/16 helyett 192.168.0.0/16.

5. Mivel módosítjuk azt a szolgáltatási alhálózatot, amelyre a kubeadm tanúsítványokat állít ki az apiserverhez (beleértve), azokat újra ki kell adni:

  1. Nézzük meg, mely tartományokhoz és IP-címekhez lett kiállítva az aktuális tanúsítvány:
    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. Készítsünk egy minimális konfigurációt a kubeadm számára:
    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. Töröljük a régi crt-t és kulcsot, mert e nélkül nem kerül kiadásra az új tanúsítvány:
    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. Adjuk ki újra a tanúsítványokat az API-kiszolgálóhoz:
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. Ellenőrizzük, hogy a tanúsítványt az új alhálózathoz adták-e ki:
    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. Az API-kiszolgáló tanúsítványának újbóli kiadása után indítsa újra a tárolót:
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. Újra generáljuk a konfigurációt admin.conf:
    kubeadm alpha certs renew admin.conf
  8. Szerkesszük az adatokat az etcd-ben:
    ./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 

    Figyelem! Ebben a pillanatban a tartományfeloldás nem működik a fürtben, mivel a meglévő podokban /etc/resolv.conf a régi CoreDNS-cím (kube-dns) regisztrálva van, és a kube-proxy megváltoztatja az iptables-szabályokat a régi alhálózatról az újra. A cikk további részében az állásidő minimalizálásának lehetséges lehetőségeiről van szó.

  9. Javítsuk ki a ConfigMap-et a névtérben kube-system:
    kubectl -n kube-system edit cm kubelet-config-1.16

    - cserélje ki itt clusterDNS a kube-dns szolgáltatás új IP-címére: kubectl -n kube-system get svc kube-dns.

    kubectl -n kube-system edit cm kubeadm-config

    - megjavítjuk data.ClusterConfiguration.networking.serviceSubnet új alhálózatra.

  10. Mivel a kube-dns cím megváltozott, frissíteni kell a kubelet konfigurációt az összes csomóponton:
    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. Nincs más hátra, mint a fürt összes podjának újraindítása:
    kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(S+)s+(S+).*/kubectl --namespace 1 delete pod 2/e'

Minimalizálja az állásidőt

Gondolatok az állásidő minimalizálására:

  1. A vezérlősík jegyzékeinek módosítása után hozzon létre egy új kube-dns szolgáltatást, például a névvel kube-dns-tmp és új címet 172.24.0.10.
  2. csinál if az etcdhelperben, amely nem módosítja a kube-dns szolgáltatást.
  3. Cserélje ki a címet az összes kubeletben ClusterDNS egy újra, míg a régi szolgáltatás az újjal egyidejűleg működik tovább.
  4. Várja meg, amíg a kijuttatott hüvelyek természetes okokból vagy egy egyeztetett időpontban maguktól felborulnak.
  5. Szolgáltatás törlése kube-dns-tmp és változtass serviceSubnetCIDR a kube-dns szolgáltatáshoz.

Ez a terv lehetővé teszi, hogy az állásidőt ~ egy percre minimalizálja a szolgáltatás eltávolításának idejére kube-dns-tmp és módosítja a szolgáltatás alhálózatát kube-dns.

Módosítás podNetwork

Ugyanakkor úgy döntöttünk, hogy megvizsgáljuk, hogyan módosítható a podNetwork a kapott etcdhelper segítségével. A műveletek sorrendje a következő:

  • konfigurációk rögzítése kube-system;
  • a kube-controller-manager jegyzék javítása;
  • módosítsa a podCIDR-t közvetlenül az etcd-ben;
  • indítsa újra az összes fürtcsomópontot.

Most többet ezekről a műveletekről:

1. Módosítsa a ConfigMap-et a névtérben kube-system:

kubectl -n kube-system edit cm kubeadm-config

- javítani data.ClusterConfiguration.networking.podSubnet új alhálózatra 10.55.0.0/16.

kubectl -n kube-system edit cm kube-proxy

- javítani data.config.conf.clusterCIDR: 10.55.0.0/16.

2. Módosítsa a vezérlő-kezelő jegyzékét:

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

- javítani --cluster-cidr=10.55.0.0/16.

3. Tekintse meg az aktuális értékeket .spec.podCIDR, .spec.podCIDRs, .InternalIP, .status.addresses az összes fürt csomóponthoz:

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. Cserélje le a podCIDR-t az etcd módosításával:

./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. Ellenőrizzük, hogy a podCIDR valóban megváltozott-e:

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. Egyenként indítsuk újra az összes fürtcsomópontot.

7. Ha legalább egy csomópontot elhagy régi podCIDR, akkor a kube-controller-manager nem tud elindulni, és a fürtben lévő pod-ok nem lesznek ütemezve.

Valójában a podCIDR megváltoztatása még egyszerűbben is elvégezhető (pl. így). De meg akartuk tanulni, hogyan kell közvetlenül dolgozni az etcd-vel, mert vannak esetek, amikor Kubernetes objektumokat szerkesztünk etcd-ben - az egyetlen lehetséges változata. (Például nem módosíthatja egyszerűen a Szolgáltatás mezőt állásidő nélkül spec.clusterIP.)

Teljes

A cikk az etcd-ben lévő adatokkal való közvetlen munka lehetőségét tárgyalja, pl. megkerülve a Kubernetes API-t. Néha ez a megközelítés lehetővé teszi „trükkös dolgok” elvégzését. A szövegben megadott műveleteket valódi K8s klasztereken teszteltük. Széles körű felhasználásra kész állapotuk azonban az PoC (proof of concept). Ezért, ha az etcdhelper segédprogram módosított verzióját szeretné használni a fürtökön, ezt saját felelősségére tegye.

PS

Olvassa el blogunkon is:

Forrás: will.com

Hozzászólás