Vse bolj se obrnejo na nas stranke z zahtevo, da omogočimo dostop do Kubernetes klastera za možnost dostopa do storitev znotraj klasterja: da bi se lahko neposredno povezali z neko bazo podatkov ali storitvijo, za povezavo lokalne aplikacije z aplikacijami znotraj klasterja…

Na primer, pojavi se potreba po povezavi iz svoje lokalne naprave do storitve memcached.staging.svc.cluster.local. To možnost zagotavljamo s pomočjo VPN znotraj klasterja, s katerim se povezuje stranka. Zato oglašujemo podomrežja podov, storitev in potisnemo DNS klasterja stranki. Tako, ko se stranka poskuša povezati s storitvijo memcached.staging.svc.cluster.local, zahteva gre v DNS klasterja in v odgovor prejme naslov te storitve iz storitvene mreže klasterja ali naslov poda.
K8s klastre nastavljamo s pomočjo kubeadm, kjer je privzeto storitvena podmreža — 192.168.0.0/16, podmreža podov pa — 10.244.0.0/16. Običajno vse dobro deluje, vendar obstaja nekaj točk:
- Podmreža
192.168.*.*se pogosto uporablja v pisarniških omrežjih strank, še pogosteje pa v domačih omrežjih razvijalcev. Takrat se nam pojavijo konflikti: domači usmerjevalniki delujejo v tej podmreži in VPN potiska te podmreže iz klasterja stranki. - Imamo nekaj klasterjev (klastre produkcije, testne in/ali več dev klasterjev). Takrat bodo v vseh njih privzeto enake podmreže za pode in storitve, kar predstavlja velike težave za istočasno delo s storitvami v več klasterjih.
Že kar nekaj časa sprejemamo prakso uporabe različnih podmrež za storitve in pode v okviru enega projekta — na splošno, da so vsi klasterji z različnimi omrežji. Vendar je veliko število klasterjev v uporabi, ki jih ne bi radi preoblikovali od začetka, saj v njih delujejo številne storitve, stateful aplikacije itd.
In takrat smo si zastavili vprašanje: kako spremeniti podmreže v obstoječem klasterju?
Iskanje rešitev
Najpogostejša praksa je, da se ponovno ustvarijo vse storitev z vrsto ClusterIP. Kot alternativa, tudi to:
Postopek ima težavo: ko je vse konfigurirano, se podi zaženejo z starim IP-jem kot DNS strežnikom v /etc/resolv.conf.
Ker še vedno nisem našel rešitve, sem moral ponastaviti celoten klaster s kubeadm reset in ga ponovno nastaviti.
Toda to ne ustreza vsem… Tu so bolj podrobne informacije za naš primer:
- Uporablja se Flannel;
- Obstajajo klasterji tako v oblakih kot na strojni opremi;
- Želeli bismo se izogniti ponovnom deployu svih usluga u klasteru;
- Postoji potreba da se sve uradi s minimalnim brojem problema;
- Verzija Kubernetes-a je 1.16.6 (međutim, dalji postupci će biti slični i za druge verzije);
- Osnovni zadatak se svodi na to da se u klasteru, koji je postavljen putem kubeadm s servisnom podmrežom
192.168.0.0/16, zameni sa172.24.0.0/16.
I tako se desilo da smo već dugo želeli da vidimo šta i kako se u Kubernetes-u čuva u etcd, i šta se uopšte može učiniti s tim... Pa smo pomislili: „Zašto jednostavno ne bismo ažurirali podatke u etcd, zamenjujući stare IP adrese (podmrežu) novim?»
Tražeći gotove alate za rad sa podacima u etcd, nismo našli ništa što bi u potpunosti rešilo dati zadatak. (Usput, ako znate za bilo koje alate za rad sa podacima direktno u etcd — bili bismo zahvalni za linkove.) Međutim, dobra polazišna tačka bila je (hvala njegovim autorima!).
Ovaj alat može da se poveže na etcd pomoću sertifikata i čita podatke sa njim koristeći komande ls, pridobi, dump.
Dopisujući etcdhelper
Sledeća misao je logična: „Šta sprečava da dopišemo ovaj alat, dodajući mogućnost pisanja podataka u etcd?“
Ona se realizovala u modifikovanoj verziji etcdhelper-a s dve nove funkcije changeServiceCIDR in changePodCIDR. Njegov kod može se pogledati .
Šta rade nove funkcije? Algoritam changeServiceCIDR:
- pravi deserializator;
- kompajlira regularni izraz za zamenu CIDR;
- prolazi kroz sve servise tipa ClusterIP u klasteru:
- dekodira vrednost iz etcd u Go objekat;
- pomoću regularnog izraza zamenjuje prva dva bajta adrese;
- dodeljuje servisu IP adresu iz nove podmreže;
- pravi serializer, pretvara Go objekat u protobuf, upisuje nove podatke u etcd.
Funkcija changePodCIDR suštinski je slična changeServiceCIDR — samo umesto uređivanja specifikacija servisa, to radimo za čvor i menjamo .spec.PodCIDR na novu podmrežu.
Praktika
Promena serviceCIDR
Plan za implementaciju datog zadatka je veoma jednostavan, ali podrazumeva downtime u trenutku ponovnog kreiranja svih pod-ova u klasteru. Nakon opisivanja osnovnih koraka, takođe ćemo podeliti misli o tome kako se u teoriji može minimalizovati ovo kašnjenje.
Pripremne radnje:
- instalacija potrebnog softvera i pravljenje ispravljenog etcdhelper-a;
- backup etcd i
/etc/kubernetes.
Kratak plan akcije za promenu serviceCIDR:
- izmena manifestacija apiserver-a i controller-manager-a;
- ponovno izdavanje sertifikata;
- sprememba ClusterIP storitev v etcd;
- ponovni zagon vseh podov v grozdu.
Spodaj je prikazana celotna zaporedje dejanj v podrobnostih.
1. Namestimo etcd-client za izvoz podatkov:
apt install etcd-client2. Zgradimo etcdhelper:
- Namestimo 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 - Shranjeno:
etcdhelper.go, prenesemo odvisnosti, zgradimo:wget https:\/\/raw.githubusercontent.com\/flant\/examples\/master\/2020\/04-etcdhelper\/etcdhelper.go\n go get go.etcd.io\/etcd\/clientv3 k8s.io\/kubectl\/pkg\/scheme k8s.io\/apimachinery\/pkg\/runtime\ngo build -o etcdhelper etcdhelper.go
3. Naredimo varnostno kopijo etcd:
backup_dir=\/root\/backup\nmkdir ${backup_dir}\ncp -rL \/etc\/kubernetes ${backup_dir}\nETCDCTL_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. Spremenimo omrežno podomrežje storitev v manifestih Kubernetes control plane. V datotekah /etc/kubernetes/manifests/kube-apiserver.yaml in /etc/kubernetes/manifests/kube-controller-manager.yaml spremenimo parameter --service-cluster-ip-range na novo podomrežje: 172.24.0.0/16 namesto 192.168.0.0/16.
5. Ker spreminjamo storitveno podomrežje, za katerega kubeadm izdaja potrdila za apiserver (vključno), jih je potrebno ponovno izdati:
- Poglejmo, na katere domene in IP-naslove je izdano trenutno potrdilo:
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 - Pripravimo minimalno konfiguracijo 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-naslov master vozlišča - Izbrišemo stara crt in key, saj brez tega novega potrdila ne bomo izdali:
rm \/etc\/kubernetes\/pki\/apiserver.{key,crt} - Ponovno izdamo potrdila za API-server:
kubeadm init phase certs apiserver --config=kubeadm-config.yaml - Preverimo, da je bilo potrdilo izdano za novo podomrežje:
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 ponovnem izdaji potrdila API-serverja znova zagnamo njegov kontejner:
docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart - Ponovno generiramo konfiguracijo za
admin.conf:kubeadm alpha certs renew admin.conf - Uredimo podatke 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 tem trenutku se v klastru preneha izvajati razreševanje domen, saj je v obstoječih podih
/etc/resolv.confnaveden stari naslov CoreDNS (kube-dns), medtem ko je kube-proxy spremenil pravila iptables iz stare podsätte na novo. V nadaljevanju članka so opisane možnosti za zmanjšanje nedelovanja. - Popravimo ConfigMap-e v prostoru imen
kube-system:kubectl -n kube-system edit cm kubelet-config-1.16— tukaj zamenjamo
clusterDNSz novim IP-naslovom storitve kube-dns:kubectl -n kube-system get svc kube-dns.kubectl -n kube-system edit cm kubeadm-config— popravimo
data.ClusterConfiguration.networking.serviceSubnetna novu podmrežu. - Ker se je naslov kube-dns spremenil, je potrebno posodobiti konfiguracijo kubeleta na vseh vozliščih:
kubeadm upgrade node phase kubelet-config && systemctl restart kubelet - Preostane še ponovni zagon vseh podov v klastru:
kubectl get pods --no-headers=true --all-namespaces | sed -r 's\/(S+)s+(S+).*\/kubectl --namespace 1 delete pod 2\/e'
Zmanjšanje nedelovanja
Razmišljanja o tem, kako znižati nedelovanje:
- Po spremembi manifestov nadzorne ravni ustvarite novo storitev kube-dns, na primer, z imenom
kube-dns-tmpin novim naslovom172.24.0.10. - Ustvarite
ifv etcdhelperju, ki ne bo spremenil storitve kube-dns. - Zamenjajte naslov
ClusterDNSz novim, pri čemer stara storitev še naprej deluje hkrati z novo. - Počakajte, da se podi z aplikacijami sami posodobijo bodisi naravno ali v dogovorjenem času.
- Izbrišite storitev
kube-dns-tmpin spremeniteserviceSubnetCIDRza storitev kube-dns.
Ta načrt bo omogočil zmanjšanje nedelovanja na približno minuto — med odstranjevanjem storitve kube-dns-tmp in zamenjavo podsätte za storitev Najinteresantniji i najsvježiji dio koji sam otkrio je sama priroda značajnog povećanja prometa DNS upita. O tome i o tome što s tim učiniti, pišem u ovom postu..
Modifikacija podNetwork
Obenem smo se odločili, da si ogledamo, kako modificirati podNetwork s pomočjo pridobljenega etcdhelperja. Zaporedje dejanj je naslednje:
- popravimo konfiguracije v
kube-system; - popravimo manifest kube-controller-managerja;
- spreminjamo podCIDR neposredno v etcd;
- ponovno zaženemo vsa vozlišča klastr.
Zdaj podrobneje o teh dejanjih:
1. Modificiramo ConfigMap-e v prostoru imen kube-system:
kubectl -n kube-system edit cm kubeadm-config — popravimo data.ClusterConfiguration.networking.podSubnet z novo podsättjo 10.55.0.0/16.
kubectl -n kube-system edit cm kube-proxy — popravimo data.config.conf.clusterCIDR: 10.55.0.0/16.
2. Modificiramo manifest controller-managerja:
vim /etc/kubernetes/manifests/kube-controller-manager.yaml — popravimo --cluster-cidr=10.55.0.0/16.
3. Oglejmo si trenutne vrednosti .spec.podCIDR, .spec.podCIDRs, .InternalIP, .status.addresses za vsa vozlišča klastr:
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. Zamenimo podCIDR, unesimo promjene 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/165. Provjerimo da li je podCIDR zaista promijenjen:
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. Redom najprije restartujemo sve čvorove klastera.
7. Ako barem jedan čvor ostavi stari podCIDR, kube-controller-manager se neće moći pokrenuti, a podovi u klasteru neće biti raspoređeni.
U stvari, promjenu podCIDR-a je moguće izvršiti i jednostavnije (na primjer, ). Ali željeli smo naučiti raditi sa etcd direktno, jer postoje slučajevi kada je izmjena objekata Kubernetes u etcd — jedina moguća opcija. (Na primjer, ne može se jednostavno promijeniti polje kod Servisa spec.clusterIP.)
Zaključek
U članku se razmatra mogućnost rada s podacima u etcd direktno, tj. zaobilazeći Kubernetes API. Ponekad takav pristup omogućava izvođenje 'spretnijih stvari'. Operacije navedene u tekstu testirali smo na stvarnim K8s klasterima. Međutim, njihov status spremnosti za široku primjenu — PoC (dokaz koncepta). Stoga, ako želite koristiti modificiranu verziju alata etcdhelper na svojim klasterima, radite to na svoju odgovornost.
P.S.
Preberite tudi na našem blogu:
- «»;
- «»;
- «»;
- «».
Izvor: habr.com
