Naše iskustvo sa podacima u etcd Kubernetes klasteru direktno (bez K8s API-ja)

Sve češće klijenti traže od nas da omogućimo pristup Kubernetes klasteru kako bismo mogli pristupiti uslugama unutar klastera: da bismo se mogli direktno povezati na neku bazu podataka ili servis, povezati lokalnu aplikaciju sa aplikacijama unutar klastera...

Naše iskustvo sa podacima u etcd Kubernetes klasteru direktno (bez K8s API-ja)

Na primjer, postoji potreba za povezivanjem s vašeg lokalnog stroja na uslugu memcached.staging.svc.cluster.local. Ovu mogućnost pružamo koristeći VPN unutar klastera na koji se klijent povezuje. Da bismo to učinili, najavljujemo podmreže podova, servisa i guramo DNS klastera klijentu. Dakle, kada se klijent pokuša povezati na uslugu memcached.staging.svc.cluster.local, zahtjev ide do DNS-a klastera i kao odgovor prima adresu ove usluge iz mreže servisa klastera ili pod adresu.

Konfigurišemo K8s klastere koristeći kubeadm, gde je podrazumevana servisna podmreža 192.168.0.0/16, a mreža mahuna je 10.244.0.0/16. Obično sve radi dobro, ali postoji nekoliko tačaka:

  • Podmreža 192.168.*.* često se koristi u mrežama klijentskih ureda, a još češće u kućnim mrežama programera. A onda dobijamo konflikte: kućni ruteri rade na ovoj podmreži i VPN gura ove podmreže iz klastera do klijenta.
  • Imamo nekoliko klastera (proizvodni, pozornički i/ili nekoliko dev klastera). Tada će po defaultu svi imati iste podmreže za podove i servise, što stvara velike poteškoće za istovremeni rad sa servisima u nekoliko klastera.

Odavno smo usvojili praksu korištenja različitih podmreža za usluge i podove u okviru istog projekta – općenito, tako da svi klasteri imaju različite mreže. Međutim, postoji veliki broj klastera u radu koje ne bih želio preokrenuti od nule, jer pokreću mnoge servise, aplikacije za praćenje stanja itd.

A onda smo se zapitali: kako promijeniti podmrežu u postojećem klasteru?

Traži rješenja

Najčešća praksa je rekreacija sve usluge tipa ClusterIP. kao opcija, mogu savjetovati i to:

Sljedeći proces ima problem: nakon što je sve konfigurirano, podovi dolaze sa starom IP-om kao DNS serverom imena u /etc/resolv.conf.
Pošto još uvek nisam našao rešenje, morao sam da resetujem ceo klaster sa kubeadm resetovanjem i ponovo ga pokrenem.

Ali ovo nije pogodno za svakoga... Evo detaljnijih uvoda za naš slučaj:

  • Koristi se flanel;
  • Postoje klasteri i u oblacima i na hardveru;
  • Želio bih izbjeći ponovno postavljanje svih usluga u klasteru;
  • Postoji potreba da se generalno sve radi sa minimalnim brojem problema;
  • Verzija Kubernetesa je 1.16.6 (međutim, dalji koraci će biti slični za druge verzije);
  • Glavni zadatak je osigurati da je u klasteru raspoređenom koristeći kubeadm sa uslužnom podmrežom 192.168.0.0/16, zamijenite ga sa 172.24.0.0/16.

I desilo se da smo dugo bili zainteresovani da vidimo šta je i kako u Kubernetesu pohranjeno u etcd-u, šta se s tim može uraditi... Pa smo pomislili: “Zašto jednostavno ne ažurirate podatke u etcd-u, zamjenjujući stare IP adrese (podmreže) novima?

Tragajući za gotovim alatima za rad sa podacima u etcd-u, nismo pronašli ništa što bi u potpunosti riješilo problem. (Usput, ako znate za bilo kakve uslužne programe za rad s podacima direktno u etcd-u, bili bismo zahvalni na linkovima.) Međutim, dobra polazna tačka je etcdhelper iz OpenShift (hvala njegovim autorima!).

Ovaj uslužni program se može povezati na etcd koristeći certifikate i čitati podatke odatle pomoću naredbi ls, get, dump.

Dodajte etcdhelper

Sljedeća pomisao je logična: „Šta vas sprečava da dodate ovaj uslužni program dodavanjem mogućnosti pisanja podataka u etcd?“

Postao je modificirana verzija etcdhelpera sa dvije nove funkcije changeServiceCIDR и changePodCIDR. Na njoj možete vidjeti kod ovdje.

Šta rade nove funkcije? Algoritam changeServiceCIDR:

  • kreirati deserijalizator;
  • kompajlirati regularni izraz za zamjenu CIDR-a;
  • prolazimo kroz sve servise sa tipom ClusterIP u klasteru:
    • dekodirajte vrijednost iz etcd u Go objekt;
    • pomoću regularnog izraza zamjenjujemo prva dva bajta adrese;
    • dodelite servisu IP adresu iz nove podmreže;
    • kreiramo serijalizator, pretvaramo Go objekat u protobuf, upisujemo nove podatke u etcd.

funkcija changePodCIDR suštinski slični changeServiceCIDR - samo umjesto da uređujemo specifikaciju usluge, mi to radimo za čvor i mijenjamo .spec.PodCIDR na novu podmrežu.

Praksa

Promijenite uslugu CIDR

Plan implementacije zadatka je vrlo jednostavan, ali uključuje zastoje u vrijeme ponovnog kreiranja svih podova u klasteru. Nakon što opišemo glavne korake, podijelit ćemo i razmišljanja o tome kako, u teoriji, ovo vrijeme zastoja može biti svedeno na minimum.

Pripremni koraci:

  • instaliranje potrebnog softvera i sklapanje zakrpljenog etcdhelpera;
  • backup etcd and /etc/kubernetes.

Kratak akcioni plan za promjenu usluge CIDR:

  • promjena manifesta apiservera i kontrolora-menadžera;
  • ponovno izdavanje sertifikata;
  • promjena ClusterIP usluga u etcd-u;
  • ponovno pokretanje svih podova u klasteru.

U nastavku je detaljan kompletan slijed radnji.

1. Instalirajte etcd-client za dump podataka:

apt install etcd-client

2. Napravi etcdhelper:

  • Instalirajte 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
  • Štedimo za sebe etcdhelper.go, preuzimanje ovisnosti, prikupljanje:
    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. Napravite sigurnosnu kopiju itd.:

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. Promenite podmrežu usluge u manifestima Kubernetes kontrolne ravni. U fajlovima /etc/kubernetes/manifests/kube-apiserver.yaml и /etc/kubernetes/manifests/kube-controller-manager.yaml promijenite parametar --service-cluster-ip-range na novu podmrezu: 172.24.0.0/16 umjesto 192.168.0.0/16.

5. Budući da mijenjamo servisnu podmrežu kojoj kubeadm izdaje certifikate za apiserver (uključujući), potrebno ih je ponovo izdati:

  1. Pogledajmo za koje domene i IP adrese je izdat trenutni certifikat:
    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. Hajde da pripremimo minimalnu konfiguraciju za 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. Izbrišemo stari crt i ključ, jer bez toga novi certifikat neće biti izdat:
    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. Hajde da ponovo izdamo sertifikate za API server:
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. Provjerimo da li je certifikat izdat za novu podmrežu:
    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. Nakon ponovnog izdavanja certifikata API servera, ponovo pokrenite njegov spremnik:
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. Hajde da regenerišemo konfiguraciju za admin.conf:
    kubeadm alpha certs renew admin.conf
  8. Uredimo podatke u 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 

    Oprez U ovom trenutku, rezolucija domena prestaje da radi u klasteru, jer u postojećim podovima /etc/resolv.conf stara CoreDNS adresa (kube-dns) je registrovana, a kube-proxy menja iptables pravila sa stare podmreže na novu. Dalje u članku je napisano o mogućim opcijama za minimiziranje zastoja.

  9. Popravimo ConfigMap u imenskom prostoru kube-system:
    kubectl -n kube-system edit cm kubelet-config-1.16

    - zamijenite ovdje clusterDNS na novu IP adresu kube-dns servisa: kubectl -n kube-system get svc kube-dns.

    kubectl -n kube-system edit cm kubeadm-config

    - Popravićemo to data.ClusterConfiguration.networking.serviceSubnet na novu podmrežu.

  10. Pošto je kube-dns adresa promijenjena, potrebno je ažurirati kubelet konfiguraciju na svim čvorovima:
    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. Sve što ostaje je da ponovo pokrenete sve podove u klasteru:
    kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(S+)s+(S+).*/kubectl --namespace 1 delete pod 2/e'

Minimizirajte zastoje

Razmišljanja o tome kako minimizirati zastoje:

  1. Nakon promjene manifesta kontrolne ravni, kreirajte novu kube-dns uslugu, na primjer, s imenom kube-dns-tmp i novu adresu 172.24.0.10.
  2. Napravi if u etcdhelper, koji neće modificirati kube-dns uslugu.
  3. Zamijenite adresu u svim kubeletima ClusterDNS na novu, dok će stari servis nastaviti da radi istovremeno sa novim.
  4. Pričekajte da se mahune sa aplikacijama prevrnu ili same iz prirodnih razloga ili u dogovoreno vrijeme.
  5. Izbriši uslugu kube-dns-tmp i promenite serviceSubnetCIDR za kube-dns uslugu.

Ovaj plan će vam omogućiti da minimizirate zastoje na ~ minutu - za vrijeme trajanja uklanjanja usluge kube-dns-tmp i promjenu podmreže za uslugu kube-dns.

Modifikacija podNetwork

U isto vrijeme, odlučili smo pogledati kako modificirati podNetwork koristeći rezultirajući etcdhelper. Redoslijed radnji je sljedeći:

  • popravljanje konfiguracija u kube-system;
  • popravljanje manifesta kube-controller-manager;
  • promijenite podCIDR direktno u etcd;
  • ponovo pokrenite sve čvorove klastera.

Sada više o ovim akcijama:

1. Izmijenite ConfigMap u imenskom prostoru kube-system:

kubectl -n kube-system edit cm kubeadm-config

- ispravljanje data.ClusterConfiguration.networking.podSubnet na novu podmrežu 10.55.0.0/16.

kubectl -n kube-system edit cm kube-proxy

- ispravljanje data.config.conf.clusterCIDR: 10.55.0.0/16.

2. Izmijenite manifest kontrolora-menadžera:

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

- ispravljanje --cluster-cidr=10.55.0.0/16.

3. Pogledajte trenutne vrijednosti .spec.podCIDR, .spec.podCIDRs, .InternalIP, .status.addresses za sve čvorove klastera:

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. Zamijenite podCIDR unošenjem promjena direktno u 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-pod-cidr 10.55.0.0/16

5. Provjerimo da li se podCIDR zaista promijenio:

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. Ponovo pokrenimo sve čvorove klastera jedan po jedan.

7. Ako ostavite barem jedan čvor stari podCIDR, tada kube-controller-manager neće moći da se pokrene, a podovi u klasteru neće biti zakazani.

U stvari, promjena podCIDR-a može biti još jednostavnija (npr. tako). Ali htjeli smo naučiti kako raditi s etcd-om direktno, jer postoje slučajevi kada se Kubernetes objekti uređuju u etcd-u - jedini moguća varijanta. (Na primjer, ne možete samo promijeniti polje usluge bez prekida rada spec.clusterIP.)

Rezultat

U članku se govori o mogućnosti direktnog rada sa podacima u etcd-u, tj. zaobilazeći Kubernetes API. Ponekad vam ovaj pristup omogućava da uradite "škakljive stvari". Testirali smo operacije date u tekstu na stvarnim K8s klasterima. Međutim, njihov status spremnosti za široku upotrebu je PoC (dokaz koncepta). Stoga, ako želite koristiti modificiranu verziju uslužnog programa etcdhelper na svojim klasterima, učinite to na vlastitu odgovornost.

PS

Pročitajte i na našem blogu:

izvor: www.habr.com

Dodajte komentar