Eksperienca jonë me të dhënat në Kubernetes cluster etcd direkt (pa K8s API)

Shpesh po na drejtohen klientët me kërkesën për të siguruar qasje në Kubernetes cluster për mundësinë e qasjes në shërbimet brenda klasterit: që të mund të lidhen direkt me ndonjë bazë të dhënash ose shërbim, për lidhjen e aplikacionit lokal me aplikacione brenda klasterit...

Eksperienca jonë me të dhënat në Kubernetes cluster etcd direkt (pa K8s API)

Për shembull, lind nevoja për t'u lidhur nga makina juaj lokale me shërbimin memcached.staging.svc.cluster.local. Ne ofrojmë këtë mundësi përmes VPN brenda klasterit, të cilit i bashkohet klienti. Për këtë, ne shpallim subnet-et e podëve, shërbimeve dhe e dërgojmë DNS-in e klasterit tek klienti. Kështu, kur klienti përpiqet të lidhet me shërbimin memcached.staging.svc.cluster.local, kërkesa shkon në DNS-in e klasterit dhe në përgjigje merr adresën e këti shërbimi nga rrjeti i shërbimeve të klasterit ose adresën e pod-it.

Ne konfigurojmĂ« K8s-kat me kubeadm, ku rrjeti i shĂ«rbimeve pĂ«rveçse — 192.168.0.0/16, dhe rrjeti i podĂ«ve — 10.244.0.0/16. Zakonisht gjithçka funksionon mirĂ«, por ka disa momente:

  • Rrjeti 192.168.*.* pĂ«rdoret shpesh nĂ« rrjetet zyrtare tĂ« klientĂ«ve, dhe mĂ« shpesh — nĂ« rrjetet shtĂ«piake tĂ« zhvilluesve. Dhe kĂ«shtu, kemi pĂ«rplasje: routerĂ«t shtĂ«piakĂ« funksionojnĂ« nĂ« kĂ«tĂ« rrjet dhe VPN dĂ«rgon kĂ«to rrjete nga klasteri tek klienti.
  • Kemi disa klasterĂ« (klasterĂ« prodhimi, stage, dhe/ose disa klasterĂ« dev). AtĂ«herĂ« nĂ« tĂ« gjithĂ« ata do tĂ« ketĂ« rrjete tĂ« njĂ«jta pĂ«r podĂ«t dhe shĂ«rbimet, çka krijon vĂ«shtirĂ«si tĂ« mĂ«dha pĂ«r punĂ«n e pĂ«rbashkĂ«t me shĂ«rbimet nĂ« disa klasterĂ«.

Kemi pranuar praktikĂ«n pĂ«r pĂ«rdorimin e rretheve tĂ« ndryshme pĂ«r shĂ«rbimet dhe podĂ«t brenda njĂ« projekti — thjesht qĂ« tĂ« gjithĂ« klasterĂ«t tĂ« kenĂ« rrjete tĂ« ndryshme. MegjithatĂ«, ka shumĂ« klasterĂ« nĂ« punĂ« qĂ« nuk do tĂ« ishin dĂ«shirat pĂ«r t'i rikthyer nga e para, pasi aty janĂ« tĂ« nisura shumĂ« shĂ«rbime, aplikacione stateful, etj.

Dhe atëherë na erdhi mendja: si mund ta ndryshojmë subnet-in në një klaster ekzistues?

Kërkimi i zgjidhjeve

Praktika mĂ« e zakonshme — Ă«shtĂ« ri-krijimi i tĂ« gjithĂ« shĂ«rbimeve me tipin ClusterIP. Si alternativĂ«, mund tĂ« sugjerojnĂ« dhe kĂ«shtu:

Procesi në vijim ka një problem: pas konfigurimit të gjithçkaje, pod-et dalin me IP-në e vjetër si server DNS në /etc/resolv.conf.
Pasi akoma nuk e kam gjetur zgjidhjen, më duhej të riformatoja klasterin e gjithë duke përdorur kubeadm reset dhe ta init përsëri.

Por kjo nuk i përshtatet të gjithëve
 Këtu janë disa hyrje më të detajuar për rastin tonë:

  • PĂ«rdoret Flannel;
  • EkzistojnĂ« klastera si nĂ« re ashtu edhe nĂ« harduer;
  • Do tĂ« doja tĂ« shmang ndĂ«rrimin e pĂ«rsĂ«ritur tĂ« tĂ« gjitha shĂ«rbimeve nĂ« klaster;
  • Ka nevojĂ« pĂ«r tĂ« bĂ«rĂ« gjithçka me sa mĂ« pak probleme tĂ« jetĂ« e mundur;
  • Versions Kubernetes - 1.16.6 (sidoqoftĂ«, veprimet e mĂ«tejshme do tĂ« jenĂ« tĂ« ngjashme edhe pĂ«r versione tĂ« tjera);
  • Detyra kryesore pĂ«rfshin qĂ« nĂ« klasterin qĂ« Ă«shtĂ« krijuar me kubeadm me subnet shĂ«rbimi 192.168.0.0/16, ta zĂ«vendĂ«sojmĂ« atĂ« me 172.24.0.0/16.

Dhe ndodhi që na kishte interesuar për një kohë të gjatë të shihnim se çfarë dhe si ruhet në Kubernetes në etcd, çfarë mund të bëhet me të... Pra, menduam: "Pse të mos përditësojmë thjesht të dhënat në etcd, duke zëvendësuar adresat e vjetra IP (subnet) me të rejat?»

Pas kërkimit të mjeteve të gatshme për punë me të dhënat në etcd, nuk gjetëm asgjë që të zgjidhte plotësisht problemin e ngritur. (P.S. nëse dini për ndonjë utilitar për të punuar drejtpërdrejt me të dhënat në etcd - do të ishim mirënjohës për lidhjet.) Megjithatë, një pikë e mirë fillestare ishte etcdhelper nga OpenShift (faleminderit autores së tij!).

Ky utilitar mund të lidhet me etcd nëpërmjet certifikatave dhe të lexojë të dhëna atje duke përdorur komandat ls, merr, dump.

Shtojmë etcdhelper

Mendimi i ardhshĂ«m Ă«shtĂ« i natyrshĂ«m: "ÇfarĂ« pengon tĂ« shkruajmĂ« kĂ«tĂ« utilitar duke i shtuar mundĂ«sinĂ« pĂ«r tĂ« shkruar tĂ« dhĂ«na nĂ« etcd?"

Ai u realizua në një version të modifikuar të etcdhelper me dy funksione të reja changeServiceCIDR dhe changePodCIDR. Mund të shihni për kodin e saj këtu.

ÇfarĂ« bĂ«jnĂ« funksionet e reja? Algoritmi changeServiceCIDR:

  • krijon njĂ« deserializues;
  • kompilon njĂ« shprehje tĂ« rregullt pĂ«r zĂ«vendosjen e CIDR;
  • kalon pĂ«rmes tĂ« gjitha shĂ«rbimeve me llojin ClusterIP nĂ« klaster:
    • dekodosh vlerĂ«n nga etcd nĂ« njĂ« objekt nĂ« Go;
    • pĂ«rdor njĂ« shprehje tĂ« rregullt pĂ«r tĂ« zĂ«vendĂ«suar dy bajtat e parĂ« tĂ« adresĂ«s;
    • i cakton shĂ«rbimit njĂ« adresĂ« IP nga subneti i ri;
    • krijon njĂ« serializues, e kthen objektin Go nĂ« protobuf, shkruan tĂ« dhĂ«nat e reja nĂ« etcd.

Funksioni changePodCIDR esencialisht Ă«shtĂ« e ngjashme changeServiceCIDR — vetĂ«m nĂ« vend tĂ« redaktimit tĂ« specifikimeve tĂ« shĂ«rbimeve ne e bĂ«jmĂ« kĂ«tĂ« pĂ«r nodin dhe ndryshojmĂ« .spec.PodCIDR nĂ« subnetin e ri.

Praktika

Ndryshimi i serviceCIDR

Plani pĂ«r realizimin e problemit tĂ« ngritur - Ă«shtĂ« shumĂ« i thjeshtĂ«, por nĂ«nkupton ndĂ«rrimin gjatĂ« kohĂ«s sĂ« krijimit tĂ« tĂ« gjitha pod’ave nĂ« klaster. Pas pĂ«rshkrimit tĂ« hapave kryesorĂ« do tĂ« ndajmĂ« gjithashtu mendimet se si teorikisht mund ta minimizojmĂ« kĂ«tĂ« thjesht.

Veprime përgatitore:

  • instalimi i softuerit tĂ« nevojshĂ«m dhe ndĂ«rtimi i etcdhelper tĂ« propatuar;
  • backup i etcd dhe /etc/kubernetes.

Një plan i shkurtër veprimesh për ndryshimin e serviceCIDR:

  • ndryshimi i manifestĂ«ve tĂ« apiserver dhe controller-manager;
  • ri-lĂ«shimi i certifikatave;
  • ndryshimi i shĂ«rbimeve ClusterIP nĂ« etcd;
  • rindĂ«rtojmĂ« tĂ« gjitha pod-et nĂ« klaster.

Më poshtë paraqitet sekvenca e plotë e hapat në detaje.

1. Instalojmë etdc-client për dump të të dhënave:

apt install etcd-client

2. Krijojmë etcdhelper:

  • InstalojmĂ« 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
  • RuajmĂ« etcdhelper.go, shkarkojmĂ« varĂ«sitĂ«, krijojmĂ«:
    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. Bëjmë backup të 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. Ndryshojmë subnet-in e shërbimeve në manifestët e planeve të kontrollit të Kubernetes. Në skedarët /etc/kubernetes/manifests/kube-apiserver.yaml dhe /etc/kubernetes/manifests/kube-controller-manager.yaml ndryshojmë parametrin --service-cluster-ip-range në subnet-in e ri: 172.24.0.0/16 në vend të 192.168.0.0/16.

5. Pasi ndryshojmë subnet-in e shërbimeve, për të cilin kubeadm lëshon certifikata për apiserver (përfshirë), është e nevojshme të ri-lëshojmë ato:

  1. Shikojmë për cilat domene dhe adresa IP është lëshuar aktualisht certifikata:
    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. Të përgatisim një konfigurim minimal pë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" # Adresa IP e nodit kryesor
  3. Të heqim certifikat e vjetra crt dhe key, sepse pa këtë certifikata e re nuk do të lëshohet:
    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. Rialësojmë certifikatat për API-serverin:
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. Kontrollojmë nëse certifikata është lëshuar për subnet-in e ri:
    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. Pas rialëshimit të certifikatës së API-serverit, rindërtojmë containerin e tij:
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. Rikrijojmë konfigurimin për admin.conf:
    kubeadm alpha certs renew admin.conf
  8. Redaktojmë të dhënat në 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 

    Kujdes! NĂ« kĂ«tĂ« moment, rezolvimi i domeneve ndalon nĂ« klaster, pasi nĂ« pod’ët ekzistues Ă«shtĂ« /etc/resolv.conf shĂ«nuar adresa e vjetĂ«r CoreDNS (kube-dns), ndĂ«rsa kube-proxy ka ndryshuar rregullat e iptables nga subneti i vjetĂ«r nĂ« tĂ« riun. MĂ« pas nĂ« artikull do tĂ« flitet pĂ«r mundĂ«sitĂ« pĂ«r tĂ« minimizuar kohĂ«n e pezullimit.

  9. Do tĂ« korrigjojmĂ« ConfigMap’ët nĂ« hapĂ«sirĂ«n emĂ«rorĂ« kube-system:
    kubectl -n kube-system edit cm kubelet-config-1.16

    — kĂ«tu do tĂ« zĂ«vendosim clusterDNS me adresĂ«n e re IP tĂ« shĂ«rbimit kube-dns: kubectl -n kube-system get svc kube-dns.

    kubectl -n kube-system edit cm kubeadm-config

    — do tĂ« korrigjojmĂ« data.ClusterConfiguration.networking.serviceSubnet nĂ« subnetin e ri.

  10. Duke qenë se adresa kube-dns ka ndryshuar, është e nevojshme të përditësojmë konfigurimin e kubelet në të gjitha nyjet:
    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. Kjo mbetet pĂ«r tĂ« rinisur tĂ« gjitha pod’ët nĂ« klaster:
    kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(S+)s+(S+).*/kubectl --namespace 1 delete pod 2/e'

Minimizimi i pezullimeve

Mendime për si të minimizohet kohën e pezullimit:

  1. Pas ndryshimeve të manifestëve të planeve kontrolluese, krijoni një shërbim të ri kube-dns, p.sh., me emrin kube-dns-tmp dhe adresën e re 172.24.0.10.
  2. Bëni nëse në etcdhelper, i cili nuk do të modifikojë shërbimin kube-dns.
  3. ZĂ«vendĂ«soni nĂ« tĂ« gjithĂ« kubelet’ët adresĂ«n ClusterDNS me tĂ« rejĂ«n, ndĂ«rsa shĂ«rbimi i vjetĂ«r do tĂ« vazhdojĂ« tĂ« funksionojĂ« paralelisht me tĂ« riun.
  4. Prisni derisa pod’ët me aplikacione tĂ« kalojnĂ« ose pĂ«r shkak tĂ« arsyeve natyrore, ose nĂ« njĂ« kohĂ« tĂ« caktuar.
  5. Fshini shërbimin kube-dns-tmp dhe ndryshoni serviceSubnetCIDR për shërbimin kube-dns.

Ky plan do tĂ« lejojĂ« minimizimin e kohĂ«s sĂ« pezullimit deri nĂ« ~minuta — nĂ« kohĂ«n e fshirjes sĂ« shĂ«rbimit kube-dns-tmp dhe zĂ«vendĂ«simit tĂ« subnetit pĂ«r shĂ«rbimin kube-dns.

Modifikimi i podNetwork

NĂ« tĂ« njĂ«jtĂ«n kohĂ«, ne vendosĂ«m tĂ« shohim se si tĂ« modifikojmĂ« podNetwork me ndihmĂ«n e etcdhelper’it qĂ« Ă«shtĂ« krijuar. Sequenta e veprimeve Ă«shtĂ« si mĂ« poshtĂ«:

  • korrigjojmĂ« konfigurimet nĂ« kube-system;
  • korrigjojmĂ« manifestin e kube-controller-manager’it;
  • ndryshojmĂ« podCIDR direkt nĂ« etcd;
  • Rinisim tĂ« gjitha nyjet e klasterit.

Tani më shumë për këto veprime:

1. ModifikojmĂ« ConfigMap’ët nĂ« hapĂ«sirĂ«n emĂ«rorĂ« kube-system:

kubectl -n kube-system edit cm kubeadm-config

— korrigjojmĂ« data.ClusterConfiguration.networking.podSubnet me subnetin e ri 10.55.0.0/16.

kubectl -n kube-system edit cm kube-proxy

— korrigjojmĂ« data.config.conf.clusterCIDR: 10.55.0.0/16.

2. ModifikojmĂ« manifestin e controller-manager’it:

vim /etc/kubernetes/manifests/kube-controller-manager.yaml

— korrigjojmĂ« --cluster-cidr=10.55.0.0/16.

3. Shikoni vlerat aktuale .spec.podCIDR, .spec.podCIDRs, .InternalIP, .status.addresses për të gjitha nyjet e klasterit:

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. Do të zëvendësojmë podCIDR duke bërë ndryshime direkt në 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. Do të kontrollojmë nëse podCIDR në të vërtetë është ndryshuar:

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. Gradualisht do të rinisim të gjitha nyjat e klasterit.

7. Nëse të paktën një nyje ruan podCIDR-in e vjetër, atëherë kube-controller-manager nuk do të mund të nisë, dhe pod-et në klaster nuk do të planifikohen.

NĂ« tĂ« vĂ«rtetĂ«, ndryshimi i podCIDR mund tĂ« bĂ«het edhe mĂ« thjeshtĂ« (p.sh. ashtu). Por ne do tĂ« donim tĂ« mĂ«sonim tĂ« punojmĂ« direkt me etcd, sepse ka rastet kur redaktimi i objekteve Kubernetes nĂ« etcd — Ă«shtĂ« opsioni i vetĂ«m mĂ« i mundshĂ«m. (P.sh., nuk mund tĂ« ndryshoni thjesht fushĂ«n spec.clusterIP.)

Përfundimi

Ky artikull shqyrton mundĂ«sinĂ« e punĂ«s me tĂ« dhĂ«nat nĂ« etcd direkt, duke anashkaluar Kubernetes API. NdonjĂ«herĂ« ky qasje lejon tĂ« bĂ«ni “truke tĂ« zgjuara”. Operacionet e paraqitura nĂ« tekst ne i kemi testuar nĂ« klasterĂ«t e vĂ«rtetĂ« K8s. MegjithatĂ«, statusi i tyre i gatshmĂ«risĂ« pĂ«r pĂ«rdorim tĂ« gjerĂ« — PoC (provĂ« e konceptit). Prandaj, nĂ«se doni tĂ« pĂ«rdorni njĂ« version tĂ« modifikuar tĂ« utilitarit etcdhelper nĂ« klasterĂ«t tuaj, bĂ«jeni kĂ«tĂ« me rrezik.

P.S.

Lexoni gjithashtu në blogun tonë:

Burimi: habr.com

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster