Allt fler kunder vĂ€nder sig till oss med önskemĂ„l om att fĂ„ tillgĂ„ng till Kubernetes-klustret för att kunna nĂ„ tjĂ€nster inom klustret: sĂ„ att man direkt kan ansluta till en databas eller tjĂ€nst, för att koppla en lokal applikation till applikationer inom klustretâŠ

Till exempel uppstÄr behovet av att ansluta frÄn sin lokala maskin till tjÀnsten memcached.staging.svc.cluster.local. Vi erbjuder denna möjlighet via VPN inom klustret, som kunden ansluter till. För detta annonserar vi pod-subnÀt, tjÀnster och pushar kluster-DNS till kunden. PÄ sÄ sÀtt, nÀr kunden försöker ansluta till tjÀnsten memcached.staging.svc.cluster.local, skickas en begÀran till kluster-DNS och fÄr som svar adressen till denna tjÀnst frÄn tjÀnsternas nÀtverk eller adressen till pod'en.
K8s-kluster konfigurerar vi med kubeadm, dÀr standard tjÀnstenÀtverket Àr 192.168.0.0/16, och pod-nÀtverket Àr 10.244.0.0/16. Vanligtvis fungerar allt bra, men det finns ett par saker:
- SubnÀtverket
192.168.*.*anvÀnds ofta i kundernas kontorsnÀtverk, och Ànnu oftare i utvecklares hemmarnÀtverk. Och dÄ fÄr vi konflikter: hemmaroutrar arbetar i detta subnÀt och VPN pushar dessa subnÀt frÄn klustret till kunden. - Vi har flera kluster (produktionskluster, stage och/eller flera utvecklingskluster). DÄ kommer de alla att ha samma standard-subnÀt för poddar och tjÀnster, vilket skapar stora problem för samtidig anvÀndning av tjÀnster i flera kluster.
Vi har sedan lĂ€nge antagit en praxis att anvĂ€nda olika subnĂ€t för tjĂ€nster och poddar inom ett och samma projekt â för att alla kluster skall ha olika nĂ€tverk. Men det finns ett stort antal kluster i drift, som vi inte vill börja om frĂ„n grunden med, eftersom mĂ„nga tjĂ€nster, stateful-applikationer osv. Ă€r igĂ„ng dĂ€r.
Och dÄ stÀllde vi oss frÄgan: hur skulle man kunna Àndra subnÀtet i ett befintligt kluster?
Sök efter lösningar
Det vanligaste tillvÀgagÄngssÀttet Àr att Äterskapa alla tjÀnster med typ ClusterIP. Som ett alternativ kan och sÄ hÀr:
Den följande processen har ett problem: efter att allt Àr konfigurerat kommer poddarna upp med den gamla IP:n som DNS-nameserver i /etc/resolv.conf.
Eftersom jag fortfarande inte hittade lösningen, var jag tvungen att ÄterstÀlla hela klustret med kubeadm reset och initiera det igen.
Men inte alla passar för detta⊠HÀr Àr mer detaljerad information för vÄrt fall:
- Flannel anvÀnds;
- Det finns kluster bÄde i molnet och pÄ hÄrdvara;
- Vi vill undvika att behöva deploya alla tjÀnster i klustret igen;
- Det finns ett behov av att lösa allt med minimala problem;
- Kubernetes-versionen Àr 1.16.6 (övriga ÄtgÀrder kommer att vara desamma för andra versioner);
- Huvuduppgiften Àr att i klustret, distribuerat med kubeadm med service-subnÀtet,
192.168.0.0/16, ersÀtta det med172.24.0.0/16.
Och det rÄkar ocksÄ vara sÄ att vi lÀnge varit intresserade av att se vad och hur Kubernetes lagrar i etcd, vad som gÄr att göra med detta⊠SÄ vi tÀnkte: "Varför inte bara uppdatera uppgifterna i etcd genom att ersÀtta de gamla IP-adresserna (subnÀtet) med nya??»
Efter att ha letat efter fĂ€rdiga verktyg för att arbeta med data i etcd, fann vi inget som helt löste den stĂ€llda uppgiften. (Förresten, om ni kĂ€nner till nĂ„gra verktyg för att arbeta med data direkt i etcd â vi skulle uppskatta lĂ€nkar.) En bra utgĂ„ngspunkt blev (tack till dess skapare!).
Detta verktyg kan ansluta till etcd med certifikat och lÀsa data dÀrifrÄn med hjÀlp av kommandon. ls, hÀmta, dump.
Vi lÀgger till etcdhelper
Den nÀsta tanken Àr logisk: "Vad hindrar oss frÄn att utöka detta verktyg genom att lÀgga till möjlighet att skriva data i etcd?"
Detta blev en modifierad version av etcdhelper med tvÄ nya funktioner: changeServiceCIDR och changePodCIDR. Koden för den kan ses .
Vad gör de nya funktionerna? Algoritmen changeServiceCIDR:
- skapar en deserialiserare;
- kompilerar ett reguljÀrt uttryck för att ersÀtta CIDR;
- gÄr igenom alla tjÀnster av typen ClusterIP i klustret:
- avkodar vÀrdet frÄn etcd till ett Go-objekt;
- ersÀtter de första tvÄ bytes av adressen med hjÀlp av det reguljÀra uttrycket;
- tilldelar tjÀnsten en IP-adress frÄn det nya subnÀtet;
- skapar en serialiserare, omvandlar Go-objektet till protobuf, skriver de nya uppgifterna i etcd.
Funktionen changePodCIDR Ă€r i grunden liknande changeServiceCIDR â bara istĂ€llet för att redigera specifikationerna för tjĂ€nsterna gör vi detta för noden och Ă€ndrar .spec.PodCIDR till det nya subnĂ€tet.
Praxis
Ăndring av serviceCIDR
Planen för att genomföra den stÀllda uppgiften Àr mycket enkel, men innebÀr nedetid under ÄterstÀllandet av alla poddar i klustret. Efter att ha beskrivit de grundlÀggande stegen kommer vi ocksÄ att dela vÄra tankar om hur man i teorin kan minimera denna nedetid.
Förberedande ÄtgÀrder:
- installera nödvÀndig programvara och bygga det patchade etcdhelper;
- backup av etcd och
/etc/kubernetes.
Kort handlingsplan för att Àndra serviceCIDR:
- Àndra manifest för apiserver och controller-manager;
- omutfÀrda certifikat;
- Àndring av ClusterIP-tjÀnster i etcd;
- omstart av alla poddar i klustret.
HÀr presenteras hela sekvensen av ÄtgÀrder i detalj.
1. Installera etcd-klienten för att dumpa data:
apt install etcd-client2. Bygg etcdhelper:
- Installera 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 - Spara
etcdhelper.go, ladda ner beroenden, bygg: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. Skapa en backup av 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. Ăndra tjĂ€nstnĂ€tet i Kubernetes control plane-manifesten. I filerna /etc/kubernetes/manifests/kube-apiserver.yaml och /etc/kubernetes/manifests/kube-controller-manager.yaml Ă€ndra parameter --service-cluster-ip-range till det nya nĂ€tet: 172.24.0.0/16 istĂ€llet för 192.168.0.0/16.
5. Eftersom vi Àndrar tjÀnstnÀtet, för vilket kubeadm utfÀrdar certifikat för apiservern (bland annat), mÄste de utfÀrdas pÄ nytt:
- LÄt oss titta pÄ vilka domÀner och IP-adresser det nuvarande certifikatet har utfÀrdats för:
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 - Förbered en minimal konfiguration för 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-adress för master noden - Ta bort gamla crt och key, annars kommer det nya certifikatet inte att utfÀrdas:
rm \/etc\/kubernetes\/pki\/apiserver.{key,crt} - UtfÀrda certifikat pÄ nytt för API-servern:
kubeadm init phase certs apiserver --config=kubeadm-config.yaml - Kontrollera att certifikatet har utfÀrdats för det nya nÀtet:
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 - Efter att certifikatet för API-servern har utfÀrdats pÄ nytt, starta om dess container:
docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart - Regenerera konfigurationen för
admin.conf:kubeadm alpha certs renew admin.conf - Redigera data i 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\/16Varning! I detta ögonblick slutar domÀnupplösningen att fungera i klustret, eftersom de redan existerande poddarna har
/etc/resolv.confden gamla adressen för CoreDNS (kube-dns) instÀlld, och kube-proxy har Àndrat iptables-reglerna frÄn det gamla subnÀtet till det nya. Artikeln beskriver sedan möjliga alternativ för att minimera driftsstopp. - Vi justerar ConfigMap:ar i namnomrÄdet
kube-system:kubectl -n kube-system edit cm kubelet-config-1.16â hĂ€r kommer vi att byta ut
clusterDNSmot den nya IP-adressen för kube-dns-tjĂ€nsten:kubectl -n kube-system get svc kube-dns.kubectl -n kube-system edit cm kubeadm-configâ vi kommer att korrigera
data.ClusterConfiguration.networking.serviceSubnettill det nya subnÀtet. - Eftersom adressen för kube-dns har Àndrats Àr det nödvÀndigt att uppdatera kubelet-konfigurationen pÄ alla noder:
kubeadm upgrade node phase kubelet-config && systemctl restart kubelet - Det ÄterstÄr att starta om alla poddar i klustret:
kubectl get pods --no-headers=true --all-namespaces | sed -r 's\/(S+)s+(S+).*\/kubectl --namespace \1 delete pod \2\/e'
Minimera driftsstopp
Fundera pÄ hur man kan minimera nedetid:
- Efter förÀndringarna av kontrollplansmanifesten, skapa en ny kube-dns-tjÀnst, till exempel med namnet
kube-dns-tmpoch den nya adressen172.24.0.10. - Gör
ifi etcdhelper, som inte kommer att modifiera kube-dns-tjÀnsten. - Byt ut adressen i alla kubeletar
ClusterDNStill den nya, medan den gamla tjÀnsten fortsÀtter att fungera samtidigt som den nya. - VÀnta pÄ att poddar med ansökningar ska rullas ut antingen av sig sjÀlva av naturliga skÀl, eller vid en överenskommet tid.
- Ta bort tjÀnsten
kube-dns-tmpoch ÀndraserviceSubnetCIDRför kube-dns-tjÀnsten.
Denna plan kommer att minimera nedetiden till ~en minut â tiden det tar att ta bort tjĂ€nsten kube-dns-tmp och byta subnet för tjĂ€nsten Det mest intressanta och nya för mig var sjĂ€lva anledningen till den betydande ökningen av DNS-förfrĂ„gningar. Om detta och vad man ska göra Ă„t det handlar mitt inlĂ€gg..
Modifiering av podNetwork
Samtidigt har vi beslutat att se hur man modifierar podNetwork med hjÀlp av den resulterande etcdhelper. Stegen blir följande:
- Vi justerar konfigurationerna i
kube-system; - vi justerar kube-controller-manager-manifestet;
- vi Àndrar podCIDR direkt i etcd;
- vi startar om alla noder i klustret.
Nu mer detaljerat om dessa ÄtgÀrder:
1. Modifiera ConfigMap:ar i namnomrÄdet kube-system:
kubectl -n kube-system edit cm kubeadm-config â vi justerar data.ClusterConfiguration.networking.podSubnet till det nya subnĂ€tet 10.55.0.0/16.
kubectl -n kube-system edit cm kube-proxy â vi justerar data.config.conf.clusterCIDR: 10.55.0.0/16.
2. Modifiera controller-manager-manifestet:
vim /etc/kubernetes/manifests/kube-controller-manager.yaml â vi justerar --cluster-cidr=10.55.0.0/16.
3. Kolla aktuella vÀrden .spec.podCIDR, .spec.podCIDRs, .InternalIP, .status.addresses för alla noder i klustret:
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. Vi byter ut podCIDR genom att göra Àndringar direkt i 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. Vi kontrollerar att podCIDR verkligen har Àndrats:
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. Vi startar om alla noder i klustret en i taget.
7. Om ens en nod lÀmnas med den gamla podCIDR, kan kube-controller-manager inte startas, vilket innebÀr att poddar i klustret inte kommer att schemalÀggas.
Ăndringen av podCIDR kan faktiskt göras enklare (till exempel, ). Men vi ville ju lĂ€ra oss att arbeta direkt med etcd, för det finns tillfĂ€llen nĂ€r det kan vara nödvĂ€ndigt att redigera Kubernetes-objekt i etcd â den enda en möjlig lösning. (Till exempel kan man inte bara Ă€ndra ett Service-fĂ€lt utan att fĂ„ nedtid, spec.clusterIP.)
Resultat
Denna artikel undersöker möjligheten att arbeta med data direkt i etcd, det vill sĂ€ga utan Kubernetes API. Ibland gör detta tillvĂ€gagĂ„ngssĂ€tt det möjligt att göra "smartare grejer". De operationer som presenteras har testats pĂ„ verkliga K8s-kluster. Deras status för bred anvĂ€ndning Ă€r â PoC (proof of concept). DĂ€rför, om du vill anvĂ€nda en modifierad version av verktyget etcdhelper pĂ„ dina kluster, gör det pĂ„ egen risk.
P.S.
LÀs Àven i vÄr blogg:
- «»;
- «»;
- «»;
- «».
KĂ€lla: habr.com
