Naša izkušnja z delom s podatki v etcd Kubernetes klasterju neposredno (brez K8s API)

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ša izkušnja z delom s podatki v etcd Kubernetes klasterju neposredno (brez K8s API)

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, lahko svetujejo 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 sa 172.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 etcdhelper od OpenShift-a (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 ovde.

Š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-client

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

  1. 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
  2. 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
  3. Izbrišemo stara crt in key, saj brez tega novega potrdila ne bomo izdali:
    rm \/etc\/kubernetes\/pki\/apiserver.{key,crt}
  4. Ponovno izdamo potrdila za API-server:
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. 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
  6. Po ponovnem izdaji potrdila API-serverja znova zagnamo njegov kontejner:
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. Ponovno generiramo konfiguracijo za admin.conf:
    kubeadm alpha certs renew admin.conf
  8. 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\/16 

    Pozor! V tem trenutku se v klastru preneha izvajati razreševanje domen, saj je v obstoječih podih /etc/resolv.conf naveden 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.

  9. Popravimo ConfigMap-e v prostoru imen kube-system:
    kubectl -n kube-system edit cm kubelet-config-1.16

    — tukaj zamenjamo clusterDNS z 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.serviceSubnet na novu podmrežu.

  10. 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
  11. 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:

  1. Po spremembi manifestov nadzorne ravni ustvarite novo storitev kube-dns, na primer, z imenom kube-dns-tmp in novim naslovom 172.24.0.10.
  2. Ustvarite if v etcdhelperju, ki ne bo spremenil storitve kube-dns.
  3. Zamenjajte naslov ClusterDNS z novim, pri čemer stara storitev še naprej deluje hkrati z novo.
  4. Počakajte, da se podi z aplikacijami sami posodobijo bodisi naravno ali v dogovorjenem času.
  5. Izbrišite storitev kube-dns-tmp in spremenite serviceSubnetCIDR za 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/16

5. 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, tako). 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

Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki 🔥 Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki | ProHoster