Meie kogemus andmete haldamisel etcd Kubernetes-klastri kaudu otse (ilma K8s API-ta).

Üha enam pöörduvad meie kliendid meie poole sooviga tagada juurdepääs Kubernetes-klastrile, et saaks suhelda klastrisiseste teenustega: näiteks ühiselt ühenduda mõne andmebaasi või teenusega, et siduda kohaliku rakenduse ja klastris olevate rakenduste vahel…

Meie kogemus andmete haldamisel etcd Kubernetes-klastri kaudu otse (ilma K8s API-ta).

Näiteks tekib vajadus Ühenduda oma kohalikult masinalt teenusega memcached.staging.svc.cluster.local. Me pakume selleks võimalust VPN-i abil klastris, millega klient ühendub. Selleks kuulutame välja podide, teenuste alamvõrgud ning pushime kliendile klastrilise DNS-i. Nii, kui klient püüab teenusele ühendust luua, memcached.staging.svc.cluster.local, läheb päring klastrilise DNS-i ja vastuseks saab ta selle teenuse aadressi teenuste võrgust või podi aadressi.

K8s-klastrid seadistame kubeadm'i abil, kus vaikimisi teenuse alamvõrk on 192.168.0.0/16, ja podide võrk on 10.244.0.0/16. Tavaline on see, et kõik töötab hästi, kuid on mõned punktid:

  • Alamvõrk 192.168.*.* on sageli kasutusel kliendi kontorivõrkudes ning veelgi sagedamini arendajate koduvõrkudes. Siis tekivad meil konfliktid: kodused ruuterid töötavad selles alamvõrgus ja VPN push’ib need alamvõrgud kliendile.
  • Meil on mitu klastrit (tootmis-, etapi- ja /või mitmed arendusklastrid). Seega on kõigis vaikimisi sama alamvõrk pod'ide ja teenuste jaoks, mis tekitab suuri raskusi teenuste samaaegsel kasutamisel mitmes klastris.

Meile on juba üsna kaua olnud praktika kasutada erinevaid alamvõrke teenuste ja pod'ide jaoks ühe projekti raames — põhimõtteliselt, et kõik klastrid oleksid erinevate võrkudega. Siiski on palju klastreid, mis on tööprotsessis ja mida ei tahaks nullist üle viia, kuna nendes on käimas paljusid teenuseid, stateful-rakendusi jne.

Ja siis küsisime endalt: kuidas saaks olemasoleva klastris alamvõrku muuta?

Lahenduste otsing

Levinum praktika on uuesti luua kõik teenused, mille tüüp on ClusterIP. Alternatiivina, võidakse soovitada ka järgmist:

Järgmine protsess omab probleemi: pärast kõike konfigureerimist käivituvad pod'id vana IP-ga DNS nimiserverina /etc/resolv.conf.
Kuna ma ikka ei leidnud lahendust, pidin ma kogu klastrit resettima ja selle uuesti algatama kubeadm reset abil.

Kuid see ei sobi kõigile... Siin on meie juhtumi jaoks rohkem detaile:

  • Kasutatakse Flannelit;
  • On klastreid nii pilvedes kui rauas;
  • Soovime vältida kõigi klastrite teenuste uuesti juurutamist;
  • On vajadus teha kõik minimaalsete probleemidega;
  • Kubernetes versioon — 1.16.6 (kuid edasi minekud on sarnased ka muude versioonide jaoks);
  • Peamine ülesanne on see, et klastris, mis on juurutatud kubeadm-iga teenuse alamvõrguga, 192.168.0.0/16asendada see 172.24.0.0/16.

Ja nii on juhtunud, et oleme juba ammu tahtnud vaadata, kuidas ja mis Kuberneteses etcd-s talletatakse, ning mida selle kõigega teha… Mõtlesime: „Miks mitte lihtsalt uuendada andmeid etcd-s, asendades vanad IP-aadressid (alamvõrk) uusidega?

Otsides valmis tööriistu andmete töötlemiseks etcd-s, ei leidnud me midagi, mis täielikult lahendaks seatud ülesande. (Ütlen muide, kui teate mingeid utiliite andmete otse töötlemiseks etcd-s — oleme tänulikud linkide eest.) Kuid hea lähtepunkt oli etcdhelper OpenShift-ist (tänud autoritele!).

See tööriist oskab etcd-sse ühineda sertifikaatide abil ja lugeda sealt andmeid käskude abil ls, get, dump.

Lisa etcdhelper

Järgmine mõte on mõistetav: „Mis takistab selle utiliidi täiustamist, lisades andmete kirjutamise võimaluse etcd-sse?“

See on kujutatud muudetud versioonis etcdhelper koos kahe uue funktsiooniga changeServiceCIDR ja changePodCIDR. Selle koodi saab vaadata siit.

Mida teevad uued funktsioonid? Algoritm changeServiceCIDR:

  • loome deserialisaatori;
  • kompileerime regulaaravaldisi CIDRi vahetamiseks;
  • läbime kõik ClusterIP tüüpi teenused klastris:
    • dekodeerime väärtuse etcd-st Go-objektiks;
    • kasutades regulaaravaldist, vahetame kahe esimese baiti aadressi;
    • omistame teenusele IP-aadressi uuest alamvõrgust;
    • loome serialiseerija, muudame Go-objekti protobuf-iks ja kirjutame uued andmed etcd-sse.

Function changePodCIDR on põhimõtteliselt analoogne changeServiceCIDR — ainult nimede teenuste spetsifikatsiooni redigeerimise asemel teeme seda sõlme jaoks ja muudame .spec.PodCIDR uuest alamvõrgust.

Praktika

ServiceCIDRi vahetamine

Tehtud ülesande täitmise kava on väga lihtne, kuid eeldab seisakut, kui kõik pod'id klastris uuesti luuakse. Peale põhietappide kirjeldamist jagame ka mõtteid selle kohta, kuidas teoreetiliselt seda seisakut minimeerida.

Ettevalmistavad toimingud:

  • vajaliku tarkvara installimine ja patcheeritud etcdhelperi koostamine;
  • etcd varundamine ja /etc/kubernetes.

Lühikava serviceCIDRi vahetamiseks:

  • apiserver'i ja controller-manager'i manifestide muutmine;
  • sertifikaatide uuesti väljastamine;
  • ClusterIP teenuste muutmine etcd-s;
  • kogu pod'ide restartimine кластерis.

Edasi on esitatud täielik tegevusjärg üksikasjalikult.

1. Paigaldame etcd-client andmete varundamiseks:

apt install etcd-client

2. Koostame etcdhelper’i:

  • Paigaldame golangi:
    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
  • Salvestame endale etcdhelper.go, laadime sõltuvused, koostame:
    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. Teeme etcd varukoopia:

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. Muudame Kubernetes control plane'i manifestides teenuse alamvõrgu. Failides /etc/kubernetes/manifests/kube-apiserver.yaml ja /etc/kubernetes/manifests/kube-controller-manager.yaml muudame parameetrit --service-cluster-ip-range uus alamvõrk: 172.24.0.0/16 asetatakse 192.168.0.0/16.

5. Kuna me muudame teenuse alamvõrku, millele kubeadm väljastab sertifikaadid apiserver'ile (sealhulgas), tuleb need uuesti väljastada:

  1. Vaadake, milliste domeenide ja IP-aadresside jaoks on praegune sertifikaat väljastatud:
    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. Valmistame ette minimaalse kubeadm konfiguratsiooni:
    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" # Meistriklindi IP-aadress
  3. Kustutame vanad crt ja key, sest nende puudumisel ei saa uut sertifikaati väljastada:
    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. Väljastame uuesti API-serveri sertifikaadid:
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. Kontrollime, kas sertifikaat on uue alamvõrgu jaoks väljastatud:
    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. Pärast API-serveri sertifikaadi uuesti väljastamist taaskäivitame selle konteineri:
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. Genereerime konfiguratsiooni uuesti admin.conf:
    kubeadm alpha certs renew admin.conf
  8. Redigeerime andmeid etcd-s:
    ./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 

    Tähelepanu! Sel hetkel lakkab klastris domeenide lahendamine töötamast, kuna eksisteerivates pod'ides on /etc/resolv.conf kirjutatud vana aadress CoreDNS (kube-dns), samal ajal kui kube-proxy muutis iptables'i reegleid vanast alamvõrgust uuele. Edasiartiklis arutatakse võimalusi seisaku vähendamiseks.

  9. Parandame ConfigMap'id nimede ruumis kube-system:
    kubectl -n kube-system edit cm kubelet-config-1.16

    — siin asendame clusterDNS uuesti kube-dns teenuse uue IP-aadressiga: kubectl -n kube-system get svc kube-dns.

    kubectl -n kube-system edit cm kubeadm-config

    — parandame data.ClusterConfiguration.networking.serviceSubnet uuest alamvõrgust.

  10. Kuna kube-dns aadress on muutunud, tuleb kõigis sõlmedes kubeleti konfiguratsioon uuendada:
    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. Jäänud on taaskäivitada kõik pod'id klastris:
    kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(S+)s+(S+).*/kubectl --namespace 1 delete pod 2/e'

Seisaku vähendamine

Mõtted, kuidas vähendada seisakut:

  1. Pärast control plane'i manifestide muutmist luua uus kube-dns teenus, näiteks nimega kube-dns-tmp ja uue aadressiga 172.24.0.10.
  2. Teha if etcdhelper'is, mis ei modifitseeri teenust kube-dns.
  3. Asendada kõigis kubelet'ides aadress ClusterDNS uuega, samal ajal jätkab vana teenus töötamist koos uuega.
  4. Oodata, kuni rakenduste pod'id kas automaatselt voolavad või kokkulepitud ajal.
  5. Kustuta teenus kube-dns-tmp ja asenda serviceSubnetCIDR kube-dns teenuse jaoks.

See plaan võimaldab minimeerida seisakuid kuni ~ minutini — teenuse kustutamise ajal kube-dns-tmp ja teenuse kube-dns.

alavõrgu asendamisel.

PodNetwork'i muutmine

  • Samuti otsustasime vaadata, kuidas muuta podNetwork'i saadud etcdhelper'i abil. Järgnevad toimingud: kube-system;
  • parandame konfiguratsioonid
  • parandame kube-controller-manager'i manifesti;
  • muudame podCIDR'i otse etcd-s;

taaskäivitame kõik klastrisõlmed.

Nüüd vaatame neid toiminguid lähemalt: kube-system:

kubectl -n kube-system edit cm kubeadm-config

1. Muudame ConfigMap'e nimede ruumis — muutke data.ClusterConfiguration.networking.podSubnet 10.55.0.0/16.

uue alavõrku

1. Muudame ConfigMap'e nimede ruumis kubectl -n kube-system edit cm kube-proxy.

data.config.conf.clusterCIDR: 10.55.0.0/16

2. Muudame controller-manager'i manifesti:

1. Muudame ConfigMap'e nimede ruumis vim /etc/kubernetes/manifests/kube-controller-manager.yaml.

--cluster-cidr=10.55.0.0/16 3. Vaatame hetke väärtusi, .spec.podCIDR, .spec.podCIDRs, .InternalIP .status.addresses

kogu klastrisõlmed jaoks:

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

4. Muudame podCIDR, tehes otseseid muudatusi etcd-s:

./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. Kontrollime, et podCIDR tõepoolest muutus:

kogu klastrisõlmed jaoks:

[
  {
    "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. Taaskäivitame järk-järgult kõik klastri sõlmed.

7. Kui vähemalt ühes sõlmes jääb vana podCIDR, siis kube-controller-manager ei saa käivituda ja pod'id klastris ei saa olema planeeritud.

Tegelikult võib podCIDR-i muutmine toimuda ka lihtsamalt (näiteks, nii). Kuid me soovisime õppida töötama otse etcd-ga, kuna on olukordi, kus Kubernetes'i objektide redigeerimine etcd-s on ainus võimalik variant. (Näiteks, ei saa lihtsalt nii katkestamata muuta Service väljal spec.clusterIP..)

Kokkuvõte

Artiklis käsitletakse võimalust töötada andmetega otse etcd-s, s.t. mööda Kubernetes API-d. Mõnikord võimaldab see lähenemine teha "nutikaid trikke". Tekstis toodud operatsioone oleme testinud päris K8s klastrites. Kuid nende valmidus laialdaseks kasutamiseks on PoC (proof of concept). Seetõttu, kui soovite kasutada muudetud versiooni utiliidist etcdhelper oma klastrites, tehke seda oma riski ja ohu peale.

P.S.

Lugege ka meie blogist:

Allikas: habr.com

Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster