Naše skúsenosti s údajmi priamo v klastri etcd Kubernetes (bez K8s API)

Čoraz častejšie nás klienti žiadajú o poskytnutie prístupu do klastra Kubernetes, aby mali prístup k službám v rámci klastra: aby sme sa mohli priamo pripojiť k nejakej databáze alebo službe, aby sme prepojili lokálnu aplikáciu s aplikáciami v rámci klastra...

Naše skúsenosti s údajmi priamo v klastri etcd Kubernetes (bez K8s API)

Napríklad je potrebné pripojiť sa z vášho lokálneho počítača k službe memcached.staging.svc.cluster.local. Túto schopnosť poskytujeme pomocou VPN v rámci klastra, ku ktorému sa klient pripája. Aby sme to dosiahli, oznamujeme podsiete podov, služieb a push cluster DNS klientovi. Teda, keď sa klient pokúša pripojiť k službe memcached.staging.svc.cluster.local, požiadavka prejde do klastrového DNS a ako odpoveď dostane adresu tejto služby zo siete klastrových služieb alebo pod adresu.

Klastre K8s konfigurujeme pomocou kubeadm, kde je predvolená podsieť služieb 192.168.0.0/16, a sieť podov je 10.244.0.0/16. Zvyčajne všetko funguje dobre, ale existuje niekoľko bodov:

  • Podsieť 192.168.*.* často používané v klientskych kancelárskych sieťach a ešte častejšie v domácich sieťach vývojárov. A potom dostaneme konflikty: domáce smerovače fungujú na tejto podsieti a VPN posúva tieto podsiete z klastra ku klientovi.
  • Máme niekoľko klastrov (produkčných, etapových a/alebo niekoľko vývojových klastrov). Potom budú mať štandardne všetky rovnaké podsiete pre moduly a služby, čo vytvára veľké ťažkosti pre súčasnú prácu so službami vo viacerých klastroch.

Už dávno sme prijali prax používania rôznych podsietí pre služby a moduly v rámci toho istého projektu – vo všeobecnosti tak, že všetky klastre majú rôzne siete. V prevádzke je však veľké množstvo klastrov, ktoré by som nerád prevalcoval od nuly, keďže na nich beží množstvo služieb, stavových aplikácií atď.

A potom sme si položili otázku: ako zmeniť podsieť v existujúcom klastri?

Hľadanie rozhodnutí

Najbežnejšou praxou je rekreácia všetko služby typu ClusterIP. Ako možnosť vie poradiť a to:

Nasledujúci proces má problém: po všetkom nakonfigurovaní pody prídu so starou IP ako DNS nameserver v /etc/resolv.conf.
Keďže som stále nenašiel riešenie, musel som resetovať celý klaster pomocou resetu kubeadm a znova ho spustiť.

Ale to nie je vhodné pre každého... Tu sú podrobnejšie úvody pre náš prípad:

  • Používa sa flanel;
  • Existujú klastre v oblakoch aj na hardvéri;
  • Chcel by som sa vyhnúť opätovnému nasadeniu všetkých služieb v klastri;
  • Vo všeobecnosti je potrebné robiť všetko s minimálnym počtom problémov;
  • Verzia Kubernetes je 1.16.6 (ďalšie kroky však budú podobné pre ostatné verzie);
  • Hlavnou úlohou je zabezpečiť, aby bol v klastri nasadený pomocou kubeadm so servisnou podsieťou 192.168.0.0/16, nahraďte ho 172.24.0.0/16.

A tak sa stalo, že nás už dlho zaujímalo, čo a ako je v Kubernetes uložené v etcd, čo sa s tým dá robiť... Tak sme si pomysleli: “Prečo neaktualizovať údaje v etcd, nahradiť staré IP adresy (podsiete) novými? "

Po hľadaní hotových nástrojov na prácu s údajmi v etcd sme nenašli nič, čo by problém úplne vyriešilo. (Mimochodom, ak viete o nejakých nástrojoch na prácu s údajmi priamo v etcd, ocenili by sme odkazy.) Dobrým východiskovým bodom však je etcdhelper z OpenShift (vďaka jeho autorom!).

Tento nástroj sa môže pripojiť k etcd pomocou certifikátov a čítať dáta odtiaľ pomocou príkazov ls, get, dump.

Pridajte etcdhelper

Ďalšia myšlienka je logická: „Čo vám bráni pridať tento nástroj pridaním možnosti zapisovať údaje do etcd?“

Stala sa upravenou verziou etcdhelper s dvoma novými funkciami changeServiceCIDR и changePodCIDR. na nej môžete vidieť kód tu.

Čo robia nové funkcie? Algoritmus changeServiceCIDR:

  • vytvorte deserializátor;
  • zostaviť regulárny výraz, ktorý nahradí CIDR;
  • prechádzame všetkými službami s typom ClusterIP v klastri:
    • dekódovať hodnotu z etcd do objektu Go;
    • pomocou regulárneho výrazu nahradíme prvé dva bajty adresy;
    • priradiť službe IP adresu z novej podsiete;
    • vytvoríme serializátor, prevedieme objekt Go na protobuf, zapíšeme nové dáta do etcd.

Funkcia changePodCIDR v podstate podobné changeServiceCIDR - len namiesto úpravy špecifikácie služby to robíme pre uzol a zmenu .spec.PodCIDR do novej podsiete.

Prax

Zmeniť službu CIDR

Plán implementácie úlohy je veľmi jednoduchý, ale zahŕňa prestoje v čase opätovného vytvárania všetkých modulov v klastri. Po opísaní hlavných krokov sa podelíme aj o myšlienky, ako teoreticky možno tieto prestoje minimalizovať.

Prípravné kroky:

  • inštalácia potrebného softvéru a zostavenie opraveného etcdhelper;
  • zálohovanie atď /etc/kubernetes.

Krátky akčný plán na zmenu serviceCIDR:

  • zmena manifestov apiserver a controller-manažér;
  • opätovné vydanie certifikátov;
  • zmena služieb ClusterIP v etcd;
  • reštartujte všetky moduly v klastri.

Nasleduje podrobný úplný sled akcií.

1. Nainštalujte etcd-client pre výpis údajov:

apt install etcd-client

2. Zostavte pomocníka etcd:

  • Nainštalujte 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
  • Šetríme pre seba etcdhelper.go, stiahnuť závislosti, zbierať:
    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. Urobte zálohu atď.

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. Zmeňte podsieť služby v manifestoch riadiacej roviny Kubernetes. V súboroch /etc/kubernetes/manifests/kube-apiserver.yaml и /etc/kubernetes/manifests/kube-controller-manager.yaml zmeniť parameter --service-cluster-ip-range do novej podsiete: 172.24.0.0/16 namiesto 192.168.0.0/16.

5. Keďže meníme servisnú podsieť, do ktorej kubeadm vydáva certifikáty pre apiserver (vrátane), je potrebné ich znova vydať:

  1. Pozrime sa, pre ktoré domény a IP adresy bol vydaný aktuálny certifikát:
    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. Pripravme si minimálnu konfiguráciu pre 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. Vymažte starý crt a kľúč, pretože bez toho nebude nový certifikát vydaný:
    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. Znovu vystavme certifikáty pre server API:
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. Skontrolujte, či bol certifikát vydaný pre novú podsieť:
    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. Po opätovnom vydaní certifikátu servera API reštartujte jeho kontajner:
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. Poďme znova vygenerovať konfiguráciu pre admin.conf:
    kubeadm alpha certs renew admin.conf
  8. Upravme údaje v 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 

    Varovanie! V tomto momente prestáva v klastri fungovať rozlíšenie domény, pretože v existujúcich moduloch /etc/resolv.conf stará adresa CoreDNS (kube-dns) je zaregistrovaná a kube-proxy zmení pravidlá iptables zo starej podsiete na novú. Ďalej v článku sa píše o možných možnostiach minimalizácie prestojov.

  9. Opravme ConfigMap v mennom priestore kube-system:
    kubectl -n kube-system edit cm kubelet-config-1.16

    - nahradiť tu clusterDNS na novú IP adresu služby kube-dns: kubectl -n kube-system get svc kube-dns.

    kubectl -n kube-system edit cm kubeadm-config

    - opravíme to data.ClusterConfiguration.networking.serviceSubnet do novej podsiete.

  10. Keďže sa adresa kube-dns zmenila, je potrebné aktualizovať konfiguráciu kubelet na všetkých uzloch:
    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. Zostáva len reštartovať všetky moduly v klastri:
    kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(S+)s+(S+).*/kubectl --namespace 1 delete pod 2/e'

Minimalizujte prestoje

Myšlienky, ako minimalizovať prestoje:

  1. Po zmene manifestov riadiacej roviny vytvorte novú službu kube-dns, napríklad s názvom kube-dns-tmp a nová adresa 172.24.0.10.
  2. činiť if v etcdhelper, ktorý nebude upravovať službu kube-dns.
  3. Nahraďte adresu vo všetkých kubeletoch ClusterDNS na novú, pričom stará služba bude naďalej fungovať súčasne s novou.
  4. Počkajte, kým sa tobolky s aplikáciami prevrátia buď samy od seba z prirodzených dôvodov alebo v dohodnutom čase.
  5. Odstrániť službu kube-dns-tmp a zmeniť serviceSubnetCIDR pre službu kube-dns.

Tento plán vám umožní minimalizovať prestoje na ~ minútu - počas trvania odstránenia služby kube-dns-tmp a zmena podsiete pre službu kube-dns.

Modifikácia podNetwork

Zároveň sme sa rozhodli pozrieť sa na to, ako upraviť podNetwork pomocou výsledného etcdhelper. Postupnosť akcií je nasledovná:

  • oprava konfigurácií v kube-system;
  • oprava manifestu kube-controller-manager;
  • zmeniť podCIDR priamo v etcd;
  • reštartujte všetky uzly klastra.

Teraz viac o týchto akciách:

1. Upravte ConfigMap v mennom priestore kube-system:

kubectl -n kube-system edit cm kubeadm-config

- opravovanie data.ClusterConfiguration.networking.podSubnet do novej podsiete 10.55.0.0/16.

kubectl -n kube-system edit cm kube-proxy

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

2. Upravte manifest správcu-správcu:

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

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

3. Pozrite sa na aktuálne hodnoty .spec.podCIDR, .spec.podCIDRs, .InternalIP, .status.addresses pre všetky uzly klastra:

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. Nahraďte podCIDR vykonaním zmien priamo v 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. Skontrolujte, či sa podCIDR skutočne zmenil:

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. Reštartujme všetky uzly klastra jeden po druhom.

7. Ak necháte aspoň jeden uzol starý podCIDR, potom sa kube-controller-manager nebude môcť spustiť a moduly v klastri nebudú naplánované.

V skutočnosti je možné zmeniť podCIDR ešte jednoduchšie (napr. tak). Chceli sme sa však naučiť pracovať s etcd priamo, pretože existujú prípady, keď upravujete objekty Kubernetes v etcd - iba možný variant. (Napríklad nemôžete zmeniť pole Service bez prestojov spec.clusterIP.)

Celkový

Článok pojednáva o možnosti pracovať s dátami v etcd priamo, t.j. obchádzanie Kubernetes API. Niekedy vám tento prístup umožňuje robiť „zložité veci“. Operácie uvedené v texte sme testovali na skutočných klastroch K8s. Ich stav pripravenosti na široké použitie je však taký PoC (proof of concept). Ak teda chcete na svojich klastroch použiť upravenú verziu pomôcky etcdhelper, robíte tak na vlastné riziko.

PS

Prečítajte si aj na našom blogu:

Zdroj: hab.com

Pridať komentár