Naše zkušenosti s daty přímo v clusteru etcd Kubernetes (bez K8s API)

Stále častěji nás klienti žádají o poskytnutí přístupu ke clusteru Kubernetes, aby měli přístup ke službám v rámci clusteru: abychom se mohli přímo připojit k nějaké databázi nebo službě, abychom propojili lokální aplikaci s aplikacemi v rámci clusteru...

Naše zkušenosti s daty přímo v clusteru etcd Kubernetes (bez K8s API)

Například je potřeba se z místního počítače připojit ke službě memcached.staging.svc.cluster.local. Tuto možnost poskytujeme pomocí VPN v rámci clusteru, ke kterému se klient připojuje. K tomu klientovi oznamujeme podsítě podů, služeb a push clusteru DNS. Tedy, když se klient pokusí připojit ke službě memcached.staging.svc.cluster.local, požadavek přejde do clusteru DNS a jako odpověď obdrží adresu této služby ze sítě clusterových služeb nebo adresy pod.

Klastry K8s konfigurujeme pomocí kubeadm, kde je výchozí podsíť služeb 192.168.0.0/16, a síť podů je 10.244.0.0/16. Obvykle vše funguje dobře, ale existuje několik bodů:

  • Podsíť 192.168.*.* často používané v sítích klientských kanceláří a ještě častěji v domácích sítích vývojářů. A pak se dostáváme ke konfliktům: domácí routery fungují na této podsíti a VPN tyto podsítě tlačí z clusteru ke klientovi.
  • Máme několik clusterů (produkční, etapový a/nebo několik vývojových clusterů). Ve výchozím nastavení pak všechny budou mít stejné podsítě pro pody a služby, což vytváří velké potíže pro současnou práci se službami v několika clusterech.

Již dávno jsme přijali praxi používání různých podsítí pro služby a moduly v rámci stejného projektu – obecně tak, že všechny clustery mají různé sítě. V provozu je však velké množství clusterů, které bych nerad převaloval od nuly, protože na nich běží mnoho služeb, stavových aplikací atd.

A pak jsme si položili otázku: jak změnit podsíť ve stávajícím clusteru?

Hledejte řešení

Nejběžnější praxí je rekreace vše služby typu ClusterIP. Jako možnost může poradit a tohle:

Následující proces má problém: poté, co vše nakonfigurujete, pody přijdou se starou IP jako DNS nameserver v /etc/resolv.conf.
Protože jsem stále nenašel řešení, musel jsem resetovat celý cluster pomocí resetu kubeadm a znovu jej spustit.

To ale není vhodné pro každého... Zde jsou podrobnější úvody pro náš případ:

  • Používá se flanel;
  • Existují clustery jak v cloudech, tak na hardwaru;
  • Rád bych se vyhnul opětovnému nasazení všech služeb v clusteru;
  • Všeobecně je potřeba dělat vše s minimálním počtem problémů;
  • Verze Kubernetes je 1.16.6 (další kroky však budou pro ostatní verze podobné);
  • Hlavním úkolem je zajistit, aby v clusteru nasazeném pomocí kubeadm byla podsíť služeb 192.168.0.0/16, nahraďte jej 172.24.0.0/16.

A tak se stalo, že nás dlouho zajímalo, co a jak je v Kubernetes uloženo v etcd, co se s tím dá dělat... Tak jsme si řekli: “Proč prostě neaktualizovat data v etcd a nahradit staré IP adresy (podsítě) novými? "

Po hledání hotových nástrojů pro práci s daty v etcd jsme nenašli nic, co by problém úplně vyřešilo. (Mimochodem, pokud víte o nějakých utilitách pro práci s daty přímo v etcd, budeme rádi za odkazy.) Nicméně, dobrý výchozí bod je etcdhelper z OpenShift (díky jejím autorům!).

Tento nástroj se může připojit k etcd pomocí certifikátů a číst data odtud pomocí příkazů ls, get, dump.

Přidejte etcdhelper

Další myšlenka je logická: "Co vám brání přidat tento nástroj přidáním možnosti zapisovat data do etcd?"

Stala se upravenou verzí etcdhelper se dvěma novými funkcemi changeServiceCIDR и changePodCIDR. na ní můžete vidět kód zde.

Co dělají nové funkce? Algoritmus changeServiceCIDR:

  • vytvořit deserializátor;
  • zkompilovat regulární výraz, který nahradí CIDR;
  • procházíme všechny služby s typem ClusterIP v clusteru:
    • dekódovat hodnotu z etcd do objektu Go;
    • pomocí regulárního výrazu nahradíme první dva bajty adresy;
    • přiřadit službě IP adresu z nové podsítě;
    • vytvořit serializátor, převést objekt Go na protobuf, zapsat nová data do etcd.

Funkce changePodCIDR v podstatě podobný changeServiceCIDR - pouze místo úpravy specifikace služby to uděláme pro uzel a změnu .spec.PodCIDR do nové podsítě.

Praxe

Změna služby CIDR

Plán implementace úlohy je velmi jednoduchý, ale zahrnuje prostoje v době opětovného vytvoření všech modulů v clusteru. Po popisu hlavních kroků se také podělíme o myšlenky, jak lze teoreticky tyto prostoje minimalizovat.

Přípravné kroky:

  • instalace potřebného softwaru a sestavení opraveného etcdhelper;
  • zálohování atdd a /etc/kubernetes.

Stručný akční plán pro změnu serviceCIDR:

  • změna manifestů apiserver a controller-manager;
  • opětovné vydání certifikátů;
  • změna služeb ClusterIP v etcd;
  • restartování všech modulů v clusteru.

Následuje podrobný úplný sled akcí.

1. Nainstalujte etcd-client pro výpis dat:

apt install etcd-client

2. Sestavení etcdhelper:

  • Nainstalujte 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
  • Šetříme pro sebe etcdhelper.go, stáhnout závislosti, shromáždit:
    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. Vytvořte zálohu atd.

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. Změňte podsíť služeb v manifestech řídicí roviny Kubernetes. V souborech /etc/kubernetes/manifests/kube-apiserver.yaml и /etc/kubernetes/manifests/kube-controller-manager.yaml změnit parametr --service-cluster-ip-range do nové podsítě: 172.24.0.0/16 místo 192.168.0.0/16.

5. Protože měníme podsíť služeb, do které kubeadm vydává certifikáty pro apiserver (včetně), je třeba je znovu vydat:

  1. Podívejme se, pro které domény a IP adresy byl vydán aktuální 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. Připravíme si minimální konfiguraci pro 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. Smažte starý crt a klíč, protože bez toho nebude nový certifikát vydán:
    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. Pojďme znovu vystavit certifikáty pro server API:
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. Zkontrolujeme, zda byl certifikát vydán pro novou podsíť:
    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ětovném vydání certifikátu serveru API restartujte jeho kontejner:
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. Pojďme znovu vygenerovat konfiguraci pro admin.conf:
    kubeadm alpha certs renew admin.conf
  8. Upravme data 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 

    Varování! V tuto chvíli přestává v clusteru fungovat rozlišení domény, protože ve stávajících podech /etc/resolv.conf stará adresa CoreDNS (kube-dns) je zaregistrována a kube-proxy změní pravidla iptables ze staré podsítě na novou. Dále se v článku píše o možných možnostech minimalizace prostojů.

  9. Opravme ConfigMap ve jmenném prostoru kube-system:
    kubectl -n kube-system edit cm kubelet-config-1.16

    - vyměňte zde clusterDNS na novou 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 nové podsítě.

  10. Protože se adresa kube-dns změnila, je nutné aktualizovat konfiguraci kubelet na všech uzlech:
    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. Zbývá pouze restartovat všechny moduly v clusteru:
    kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(S+)s+(S+).*/kubectl --namespace 1 delete pod 2/e'

Minimalizujte prostoje

Nápady, jak minimalizovat prostoje:

  1. Po změně manifestů řídicí roviny vytvořte novou službu kube-dns, například s názvem kube-dns-tmp a novou adresu 172.24.0.10.
  2. Udělat if v etcdhelper, který nezmění službu kube-dns.
  3. Nahraďte adresu ve všech kubeletech ClusterDNS na novou, přičemž stará služba bude nadále fungovat současně s novou.
  4. Počkejte, až se tobolky s aplikacemi převalí buď samy od sebe z přirozených důvodů, nebo v dohodnutou dobu.
  5. Smazat službu kube-dns-tmp a změnit serviceSubnetCIDR pro službu kube-dns.

Tento plán vám umožní minimalizovat prostoje na ~ minutu - po dobu odstranění služby kube-dns-tmp a změna podsítě pro službu kube-dns.

Modifikace podNetwork

Zároveň jsme se rozhodli podívat se na to, jak upravit podNetwork pomocí výsledného etcdhelper. Posloupnost akcí je následující:

  • oprava konfigurací v kube-system;
  • oprava manifestu kube-controller-manager;
  • změnit podCIDR přímo v etcd;
  • restartujte všechny uzly clusteru.

Nyní více o těchto akcích:

1. Upravte ConfigMap ve jmenném prostoru kube-system:

kubectl -n kube-system edit cm kubeadm-config

- opravování data.ClusterConfiguration.networking.podSubnet do nové podsítě 10.55.0.0/16.

kubectl -n kube-system edit cm kube-proxy

- opravování data.config.conf.clusterCIDR: 10.55.0.0/16.

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

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

- opravování --cluster-cidr=10.55.0.0/16.

3. Podívejte se na aktuální hodnoty .spec.podCIDR, .spec.podCIDRs, .InternalIP, .status.addresses pro všechny uzly clusteru:

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 provedením změn přímo 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. Zkontrolujte, zda se podCIDR skutečně změnil:

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. Restartujme všechny uzly clusteru jeden po druhém.

7. Pokud ponecháte alespoň jeden uzel starý podCIDR, pak se kube-controller-manager nebude moci spustit a pody v clusteru nebudou naplánovány.

Ve skutečnosti lze změnu podCIDR provést ještě jednodušeji (např. tak). Chtěli jsme se ale naučit pracovat s etcd přímo, protože existují případy, kdy editujete Kubernetes objekty v etcd - jediný možná varianta. (Například nemůžete jen změnit pole Služba bez výpadku spec.clusterIP.)

Celkový

Článek pojednává o možnosti práce s daty v etcd přímo, tzn. obcházení Kubernetes API. Někdy vám tento přístup umožňuje dělat „ošidné věci“. Operace uvedené v textu jsme testovali na skutečných clusterech K8s. Jejich stav připravenosti k širokému použití je však takový PoC (proof of concept). Pokud tedy chcete na svých clusterech používat upravenou verzi utility etcdhelper, činíte tak na vlastní nebezpečí.

PS

Přečtěte si také na našem blogu:

Zdroj: www.habr.com

Přidat komentář