Čoraz častejšie sa na nás obracajú klienti s požiadavkou zabezpečiť prístup do Kubernetes klasteru, aby mohli komunikovať so službami v rámci klasteru: aby bolo možné priamo sa pripojiť k nejakej databáze alebo službe, pre spojenie lokálnej aplikácie s aplikáciami vo vnútri klasteru…

Napríklad sa objaví potreba pripojiť sa so svojho lokálneho počítača k službe memcached.staging.svc.cluster.local. Zabezpečujeme túto možnosť pomocou VPN v rámci klasteru, ku ktorému sa klient pripája. Na tento účel oznámime podsiete podov, služieb a posunieme klientovi klasterové DNS. Takže, keď sa klient pokúsi pripojiť k službe memcached.staging.svc.cluster.local, dopyt prechádza do DNS klasteru a v odpovedi dostáva adresu danej služby zo služobnej siete klasteru alebo adresu podu.
K8s klastry nastavujeme pomocou kubeadm, kde je predvolená služobná podsieť — 192.168.0.0/16, a sieť podov — 10.244.0.0/16. Zvyčajne všetko dobre funguje, ale sú tu niektoré momenty:
- Podsieť
192.168.*.*sa často používa v kancelárskych sieťach klientov, a ešte častejšie — v domácich sieťach vývojárov. A potom vznikajú konflikty: domáce routery fungujú v tejto podsieti a VPN posúva tieto podsiete z klasteru klientovi. - Máme niekoľko klastrov (produkčné, stage a/alebo niekoľko dev klastrov). Potom budú vo všetkých z nich predvolene rovnaké podsiete pre podov a služby, čo spôsobuje veľké ťažkosti pre súčasnú prácu so službami vo viacerých klastroch.
Už dlhší čas sme prijali prax používania rôznych podsietí pre služby a pod v rámci jedného projektu — aby mali všetky klastre rôzne siete. Avšak existuje veľké množstvo klastrov v prevádzke, ktoré by sme nechceli preinštalovať od nuly, pretože v nich beží množstvo služieb, stavové aplikácie a pod.
A tak sme si položili otázku: ako zmeniť podsieť v existujúcom klasteri?
Hľadanie riešení
Najbežnejšia prax — znovu vytvoriť všetky služby typu ClusterIP. Ako alternatívu, a aj toto:
Nasledujúci proces má problém: po nakonfigurovaní všetkého sa pady spúšťajú so starou IP ako DNS menný server v /etc/resolv.conf.
Keďže som ešte nenašiel riešenie, musel som resetovať celý klaster pomocou kubeadm reset a znova ho nastaviť.
Ale nie všetkým to vyhovuje… Tu sú podrobnejšie vstupy pre náš prípad:
- Používa sa Flannel;
- Existujú klastre ako v cloude, tak aj na železe;
- Chceli by sme sa vyhnúť opätovnému nasadeniu všetkých služieb v klustre;
- Existuje potreba spraviť všetko s minimálnym počtom problémov;
- Verzia Kubernetes — 1.16.6 (však, ďalšie kroky budú podobné aj pre iné verzie);
- Hlavná úloha spočíva v tom, aby sa v klustre, nasadenom pomocou kubeadm so servisnou podsieťou
192.168.0.0/16, nahradila na172.24.0.0/16.
A tak sa stalo, že nás už dlho zaujímalo, čo a ako sa v Kubernetes ukladá v etcd, čo s tým vôbec môžeme urobiť... Tak sme si povedali: „Prečo jednoducho neaktualizovať údaje v etcd, nahradením starých IP adries (podsieť) na nové?»
Hľadali sme hotové nástroje na prácu s údajmi v etcd, nič úplne riešiace danú úlohu sme nenašli. (Mimochodom, ak poznáte akékoľvek utilitky na prácu s údajmi priamo v etcd — budeme vďační za odkazy.) Avšak dobrým východiskovým bodom bol (ďakujeme jeho autorom!).
Tento nástroj dokáže pripojiť k etcd pomocou certifikátov a prečítať z neho údaje pomocou príkazov ls, get, dump.
Dopíšeme etcdhelper
Ďalšia myšlienka je logická: „Čo bráni dopísať tento nástroj, pridaním možnosti zápisu údajov do etcd?“
Bola realizovaná v upravenej verzii etcdhelper s dvoma novými funkciami changeServiceCIDR a changePodCIDR. Jej kód si môžete pozrieť .
Čo robia nové funkcie? Algoritmus changeServiceCIDR:
- vytvárame deserializátor;
- kompilujeme regulárny výraz na výmenu CIDR;
- prechádzame všetky služby s typom ClusterIP v klustre:
- dekódujeme hodnotu z etcd do Go-objektu;
- s pomocou regulárneho výrazu nahrádzame prvé dva bajty adresy;
- priraďujeme službe IP adresu z novej podsiete;
- vytvárame serializátor, prevádzame Go-objekt na protobuf, zapisujeme nové údaje do etcd.
Funkcia changePodCIDR v podstate je to podobné changeServiceCIDR — len namiesto úpravy špecifikácií služieb to robíme pre uzol a meníme .spec.PodCIDR na novú podsieť.
Praktika
Zmena serviceCIDR
Plán na realizáciu stanoveného cieľa je veľmi jednoduchý, ale predpokladá prestoje v okamihu opätovného vytvorenia všetkých podov v klustre. Po opise hlavných krokov sa tiež podelíme o myšlienky, ako teoreticky minimalizovať tento prestoj.
Prípravné kroky:
- inštalácia potrebného softvéru a zostavenie opraveného etcdhelper;
- záloha etcd a
/etc/kubernetes.
Stručný plán krokov na zmenu serviceCIDR:
- úprava manifestov apiserver'a a controller-manager'a;
- nové vydanie certifikátov;
- zmena ClusterIP služieb v etcd;
- reštart všetkých pod’ov v klasteri.
Nasleduje úplná postupnosť krokov v detailoch.
1. Nainštalujeme etcd-client pre dump dát:
apt install etcd-client2. Zostavíme etcdhelper:
- Nainštalujeme 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 - Uložíme si
etcdhelper.go, stiahneme závislosti, zostavíme: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. Urobíme zálohu etcd:
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. Zmienia sa sieťová podsieť služieb v manifestoch Kubernetes control plane. V súboroch /etc/kubernetes/manifests/kube-apiserver.yaml a /etc/kubernetes/manifests/kube-controller-manager.yaml meníme parameter --service-cluster-ip-range na novú podsieť: 172.24.0.0/16 namiesto 192.168.0.0/16.
5. Keďže meníme sieťovú podsieť, na ktorú kubeadm vydáva certifikáty pre apiserver (vrátane), musíme ich opätovne vydať:
- Pozrieme sa, na aké domény a IP adresy bol aktuálny certifikát vydaný:
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 - Pripravíme minimálny config 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 adresa master uzla - Odstránime staré crt a key, pretože bez toho nový certifikát nebude vydaný:
rm /etc/kubernetes/pki/apiserver.{key,crt} - Opätovne vydáme certifikáty pre API server:
kubeadm init phase certs apiserver --config=kubeadm-config.yaml - Skontrolujeme, č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 - Po opätovnom vydaní certifikátu API servera reštartujeme jeho kontajner:
docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart - Opätovne generujeme config pre
admin.conf:kubeadm alpha certs renew admin.conf - Upravíme dáta 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/16Pozor! V tejto chvíli v klastri prestáva fungovať resolvovanie domén, pretože v už existujúcich pod’och je
/etc/resolv.confzadaná stará adresa CoreDNS (kube-dns), a kube-proxy zmenil pravidlá iptables zo starej podsiete na novú. Ďalej v článku sú uvedené možnosti, ako minimalizovať prestoj. - Upravíme ConfigMapy v priestore názvov
kube-system:kubectl -n kube-system edit cm kubelet-config-1.16— tu nahradíme
clusterDNSnovou IP adresou služby kube-dns:kubectl -n kube-system get svc kube-dns.kubectl -n kube-system edit cm kubeadm-config— opravíme
data.ClusterConfiguration.networking.serviceSubnetna novú podsieť. - Keďže sa adresa kube-dns zmenila, je potrebné aktualizovať konfiguračný súbor kubelet na všetkých uzloch:
kubeadm upgrade node phase kubelet-config && systemctl restart kubelet - Zostáva reštartovať všetky pod’y v klastri:
kubectl get pods --no-headers=true --all-namespaces | sed -r 's\/(S+)s+(S+).*\/kubectl --namespace 1 delete pod 2\/e'
Minimalizácia prestoja
Myšlienky, ako minimalizovať downtime:
- Po zmenách manifestov control plane vytvorte novú službu kube-dns, napríklad s názvom
kube-dns-tmpa novou adresou172.24.0.10. - Urobiť
akv etcdhelper, ktorý nebude modifikovať službu kube-dns. - Nahradiť vo všetkých kubelet’och adresu
ClusterDNSnovou, pričom stará služba bude pokračovať v prevádzke súčasne s novou. - Čakať, kým sa pod’y s aplikáciami presunú buď samy prirodzene, alebo v dohodnutom čase.
- Odstrániť službu
kube-dns-tmpa zmeniťserviceSubnetCIDRpre službu kube-dns.
Tento plán umožní minimalizovať downtime na približne minútu — počas odstránenia služby kube-dns-tmp a zmeny podsiete pre službu Najzaujímavejšou a najnovšou vecou pre mňa bola sama príčina významného nárastu prevádzky DNS dopytov. O tom a o tom, čo s tým robiť, píšem v tomto príspevku..
Modifikácia podNetwork
Zároveň sme sa rozhodli pozrieť, ako modifikovať podNetwork pomocou získaného etcdhelpera. Postupnosť akcií je nasledujúca:
- opraviť konfigurácie v
kube-system; - opraviť manifest kube-controller-manager’a;
- zmeniť podCIDR priamo v etcd;
- reštartovať všetky uzly klastra.
Teraz podrobnejšie o týchto akciách:
1. Modifikujeme ConfigMapy v priestore názvov kube-system:
kubectl -n kube-system edit cm kubeadm-config — opravujeme data.ClusterConfiguration.networking.podSubnet na novú podsieť 10.55.0.0/16.
kubectl -n kube-system edit cm kube-proxy — opravujeme data.config.conf.clusterCIDR: 10.55.0.0/16.
2. Modifikujeme manifest controller-manager’a:
vim /etc/kubernetes/manifests/kube-controller-manager.yaml — opravujeme --cluster-cidr=10.55.0.0/16.
3. Pozrieme 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. Nahradíme podCIDR úpravou 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/165. Skontrolujeme, či sa podCIDR naozaj 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. Jednotlivo reštartujeme všetky uzly klastra.
7. Ak aspoň na jednom uzle zostane starý podCIDR, tak kube-controller-manager sa nebude môcť spustiť a pod'y v klastri nebudú naplánované.
V skutočnosti je možné zmeniť podCIDR aj jednoduchšie (napríklad, ). Ale chceli sme sa naučiť pracovať s etcd priamo, pretože existujú prípady, keď úprava objektov Kubernetes v etcd je jedinou možnou alternatívou. (Napríklad, nie je možné len tak bez prestojov zmeniť pole služby spec.clusterIP.)
Záver
V článku sa zaoberáme možnosťou práce s dátami v etcd priamo, teda mimo Kubernetes API. Niekedy tento prístup umožňuje robiť 'vychytralé veci'. Operácie uvedené v texte sme testovali na reálnych K8s klastra. Avšak ich stav pripravenosti na široké využitie je PoC (dôkaz konceptu). Preto, ak chcete používať modifikovanú verziu nástroja etcdhelper vo svojich klastroch, robte to na vlastné riziko.
P.S.
Prečítajte si tiež na našom blogu:
- «»;
- «»;
- «»;
- «».
Zdroj: habr.com
