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...

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 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 jej172.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 (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 .
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-client2. 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:
- 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 - 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-адрес мастер узла - Smažte starý crt a klíč, protože bez toho nebude nový certifikát vydán:
rm /etc/kubernetes/pki/apiserver.{key,crt} - Pojďme znovu vystavit certifikáty pro server API:
kubeadm init phase certs apiserver --config=kubeadm-config.yaml - 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 - 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 - Pojďme znovu vygenerovat konfiguraci pro
admin.conf:kubeadm alpha certs renew admin.conf - 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/16Varová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.confstará 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ů. - Opravme ConfigMap ve jmenném prostoru
kube-system:kubectl -n kube-system edit cm kubelet-config-1.16- vyměňte zde
clusterDNSna 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.serviceSubnetdo nové podsítě. - 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 - 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:
- Po změně manifestů řídicí roviny vytvořte novou službu kube-dns, například s názvem
kube-dns-tmpa novou adresu172.24.0.10. - Udělat
ifv etcdhelper, který nezmění službu kube-dns. - Nahraďte adresu ve všech kubeletech
ClusterDNSna novou, přičemž stará služba bude nadále fungovat současně s novou. - Počkejte, až se tobolky s aplikacemi převalí buď samy od sebe z přirozených důvodů, nebo v dohodnutou dobu.
- Smazat službu
kube-dns-tmpa změnitserviceSubnetCIDRpro 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/165. 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ř. ). 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
