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

Po na drejtohen gjithnjë e më shpesh klientët me kërkesën për të siguruar akses në klasterin Kubernetes për të pasur mundësi për të kontaktuar shërbimet brenda klasterit: për t'u lidhur direkt me ndonjë bazë të dhënash ose shërbim, për lidhjen e aplikacioneve lokale me aplikacionet brenda klasterit


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

Për shembull, krijohet nevoja për t'u lidhur nga makina juaj lokale me shërbimin memcached.staging.svc.cluster.local. Ne ofrojmë një mundësi të tillë përmes VPN brenda klasterit, me të cilin lidhet klienti. Për këtë, njoftojmë subnetet e pod-ëve, shërbimeve dhe dërgojmë DNS-in e klasterit te 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ëtij shërbimi nga rrjeti shërbimesh të klasterit ose adresën e pod-it.

Ne konfigurojmë klasterët K8s me kubeadm, ku nënkuptohet që subneti i shërbimit është 192.168.0.0/16, dhe rrjeti i pod-ëve është 10.244.0.0/16. Zakonisht gjithçka funksionon mirë, por ka disa momente:

  • Subneta 192.168.*.* shpĂ«rdoret shpesh nĂ« rrjetet e zyrave tĂ« klientĂ«ve, dhe mĂ« shpesh ende — nĂ« rrjetet shtĂ«piake tĂ« zhvilluesve. Dhe kĂ«shtu kemi konflikte: routerat shtĂ«piakĂ« punojnĂ« nĂ« kĂ«tĂ« nĂ«nrrjetĂ« dhe VPN e shtyn kĂ«to nĂ«nrrjeta nga klasteri te klienti.
  • Kemi disa klasterĂ« (klasterĂ« production, stage dhe/ose disa klasterĂ« dev). AtĂ«herĂ« nĂ« tĂ« gjithĂ« klasterĂ«t do tĂ« kenĂ« nĂ«nrrjeta tĂ« njĂ«jta pĂ«r podĂ«t dhe shĂ«rbimet, gjĂ« qĂ« krijon vĂ«shtirĂ«si tĂ« mĂ«dha pĂ«r tĂ« punuar njĂ«kohĂ«sisht me shĂ«rbimet nĂ« disa klasterĂ«.

Qysh prej njĂ« kohe tĂ« gjatĂ« kemi pranuar praktikĂ«n e pĂ«rdorimit tĂ« nĂ«nrrjetave tĂ« ndryshme pĂ«r shĂ«rbimet dhe podĂ«t brenda njĂ« projekti — nĂ« pĂ«rgjithĂ«si, pĂ«r tĂ« siguruar qĂ« tĂ« gjithĂ« klasterĂ«t tĂ« kenĂ« rrjete tĂ« ndryshme. MegjithatĂ«, ka njĂ« numĂ«r tĂ« madh klasterĂ«sh nĂ« punĂ«, tĂ« cilĂ«t nuk do tĂ« dĂ«shironim t'i rikthinim nga e para, pasi nĂ« to janĂ« aktivizuar shumĂ« shĂ«rbime, aplikacione stateful, etj.

Dhe kështu na erdhi në mendje pyetja: si ta ndryshojmë nënrrjetën në një klaster ekzistues?

Kërkimi i zgjidhjeve

Praktika mĂ« e zakonshme — pĂ«r ta krijuar pĂ«rsĂ«ri tĂ« gjitha shĂ«rbimet me tipin ClusterIP. Si njĂ« mundĂ«si, mund tĂ« kĂ«shillojnĂ« dhe diçka tĂ« tillĂ«:

Proçesi në vazhdim ka një problem: pas konfigurimit të gjithçkaje, podët dalin me IP-në e vjetër si një server DNS në /etc/resolv.conf.
Deri sa nuk e gjeta zgjidhjen, më duhej të rivendosja tërë klasterin me kubeadm reset dhe ta filloja atë përsëri.

Por, nuk është e përshtatshme për të gjithë... Këtu janë disa informacione më të detajuara për rastin tonë:

  • PĂ«rdoret Flannel;
  • Ka klastera si nĂ« re ashtu edhe nĂ« hardware;
  • Do tĂ« doja tĂ« evitonim ri-deploy tĂ« tĂ« gjitha shĂ«rbimeve nĂ« klaster;
  • Ka njĂ« nevojĂ« pĂ«r tĂ« bĂ«rĂ« gjithçka me sa mĂ« pak probleme tĂ« jetĂ« e mundur;
  • Versioni i Kubernetes Ă«shtĂ« 1.16.6 (megjithatĂ«, veprimet e mĂ«tejshme do tĂ« jenĂ« tĂ« ngjashme edhe pĂ«r versione tĂ« tjera);
  • Detyra kryesore pĂ«rfshin qĂ« nĂ« klasterin e ndĂ«rtuar me kubeadm me nĂ«nrrjetĂ« shĂ«rbimi 192.168.0.0/16, ta zĂ«vendĂ«sojmĂ« atĂ« me 172.24.0.0/16.

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

Pasi kĂ«rkuam mjete tĂ« gatshme pĂ«r tĂ« punuar me tĂ« dhĂ«nat nĂ« etcd, nuk gjetĂ«m asgjĂ« qĂ« tĂ« zgjidhte plotĂ«sisht detyrĂ«n. (P.S. nĂ«se dini pĂ«r ndonjĂ« utilitare pĂ«r tĂ« punuar drejtpĂ«rdrejt me tĂ« dhĂ«nat nĂ« etcd — do jemi mirĂ«njohĂ«s pĂ«r lidhjet.) MegjithatĂ«, njĂ« pikĂ« e mirĂ« prej nga filluam ishte etcdhelper nga OpenShift (faleminderit autorĂ«ve tĂ« tij!).

Ky utilitar ka aftësinë të lidhë me etcd përmes certifikateve dhe të lexojë të dhëna nga aty me anë të komandave ls, merr, dump.

Shtojmë etcdhelper

Mendimi tjetĂ«r Ă«shtĂ« i dukshĂ«m: «ÇfarĂ« e pengon tĂ« shtojmĂ« kĂ«tĂ« utilitar duke shtuar mundĂ«sinĂ« pĂ«r tĂ« shkruar tĂ« dhĂ«na nĂ« etcd?»

Ajo është realizuar në një version të modifikuar të etcdhelper me dy funksione të reja changeServiceCIDR dhe changePodCIDR. Në kodin e saj mund të shihni këtu.

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

  • krijon njĂ« deserializues;
  • kompilon njĂ« shprehje tĂ« rregullt pĂ«r tĂ« zĂ«vendĂ«suar CIDR;
  • kalon nĂ«pĂ«r tĂ« gjitha shĂ«rbimet me llojin ClusterIP nĂ« klaster:
    • dekodifikon vlerĂ«n nga etcd nĂ« objektin Go;
    • me anĂ« tĂ« shprehjes sĂ« rregullt zĂ«vendĂ«son dy bajtat e para tĂ« adresĂ«s;
    • i jep shĂ«rbimit njĂ« adresĂ« IP nga subneti i ri;
    • krijon njĂ« serializues, transformon objektin Go nĂ« protobuf, shkruan tĂ« dhĂ«nat e reja nĂ« etcd.

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

Praktika

Ndryshimi i serviceCIDR

Plani pĂ«r realizimin e detyrĂ«s sĂ« caktuar Ă«shtĂ« shumĂ« i thjeshtĂ«, por pĂ«rfshin ndalesa gjatĂ« ripĂ«rtĂ«ritjes sĂ« tĂ« gjithĂ« pod’ave nĂ« klaster. Pas pĂ«rshkrimit tĂ« hapat kryesorĂ«, do tĂ« ndajmĂ« gjithashtu mendimet tona se si, nĂ« teori, mund tĂ« minimalizohet kjo ndalesĂ«.

Veprimet përgatitore:

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

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

  • ndryshimi i manifestĂ«ve tĂ« apiserver-it dhe controller-manager-it;
  • rishpĂ«rndarja e certifikatave;
  • ndryshimi i ClusterIP tĂ« shĂ«rbimeve nĂ« etcd;
  • ri-ngritja e tĂ« gjithĂ« pod’ave nĂ« klaster.

Më poshtë është e paraqitur sekuenca e plotë e veprimeve në detaje.

1. Instaloni etcd-client për dump të të dhënave:

apt install etcd-client

2. Ndërtojmë etcdhelper:

  • Instaloni 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
  • Ruani etcdhelper.go, shkarkoni varĂ«sitĂ«, ndĂ«rtoni:
    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ëni një 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ë subnetin e shërbimeve në manifestet e Kubernetes control plane. Në skedarët /etc/kubernetes/manifests/kube-apiserver.yaml dhe /etc/kubernetes/manifests/kube-controller-manager.yaml ndryshojmë parametrin --service-cluster-ip-range në subnetin e ri: 172.24.0.0/16 në vend të 192.168.0.0/16.

5. Pasi po ndryshojmĂ« subnetin e shĂ«rbimeve, pĂ«r tĂ« cilin kubeadm lĂ«shon certifikatat pĂ«r apiserver’in (pĂ«rfshirĂ«), Ă«shtĂ« e nevojshme tĂ« ripublikojmĂ«:

  1. Le të shikojmë për çfarë domenesh dhe IP adresash është lëshuar certifikati aktual:
    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" # IP adresa e nodit master
  3. Do të fshijmë crt dhe key-të e vjetra, pasi pa këtë certifikati i ri nuk do të lëshohet:
    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. Do të ripublikojmë certifikatat për API-serverin:
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. Do të kontrollojmë që certifikati është lëshuar për subnetin 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 rivendosjes së certifikatës së API-serverit, do të rindiznim kontejnerin e tij:
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. Rregullojmë konfigurimin për admin.conf:
    kubeadm alpha certs renew admin.conf
  8. Modifikojmë 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 domain-eve në klaster pushon së funksionuari, pasi në pod-at ekzistues ka ende adresën e vjetër të CoreDNS (kube-dns), ndërsa kube-proxy e ka ndryshuar rregulloren e iptables nga subneti i vjetër në të riun. Më tej në artikull diskutohet për opsionet për të minimizuar pezullimin. /etc/resolv.conf Korrigjojmë ConfigMap-at në hapësirën emri

  9. kube-system kubectl -n kube-system edit cm kubelet-config-1.16:
    — kĂ«tu do tĂ« zĂ«vendĂ«sojmĂ«

    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 Duke qenë se adresa e kube-dns ndryshoi, është e nevojshme të përditësojmë konfigurimin e kubelet në të gjithë nyjet: në subnetin e ri.

  10. kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. Përfundoni ripërshtimin e të gjitha pod-eve 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 kohës së ndalimit

Mendoni se si mund të minimizoni kohën e ndalimit:

  1. Pas ndryshimeve në manifestet e kontrollit, krijoni një shërbim të ri kube-dns, për shembull me emrin kube-dns-tmp dhe një adresë të 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ë gjitha kubelet-at adresën ClusterDNS me të re, ndërsa shërbimi i vjetër do të vazhdojë të funksionojë njëkohësisht me të riun.
  4. Prisni deri sa pod-et me aplikacione të kalojnë ose vetë për arsye 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Ă« ndalimit deri nĂ« ~minuta — pĂ«r kohĂ«n e fshirjes sĂ« shĂ«rbimit kube-dns-tmp dhe zĂ«vendĂ«simin e subnetit pĂ«r shĂ«rbimin kube-dns.

Modifikimi i podNetwork

Për njëherë, ne vendosëm të shihnim se si të modifikojmë podNetwork me ndihmën e etcdhelper-it të krijuar. Seanca e veprimeve është si më poshtë:

  • rregulloni konfigurimet nĂ« kubectl -n kube-system edit cm kubelet-config-1.16;
  • rregulloni manifestin e kube-controller-manager-it;
  • ndryshoni podCIDR drejtpĂ«rdrejt nĂ« etcd;
  • rindizni tĂ« gjithĂ« nodet e klasterit.

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

1. Modifikojmë ConfigMap të në hapësirën e emrave kubectl -n kube-system edit cm kubelet-config-1.16:

— do tĂ« korrigjojmĂ«

— rregullojmĂ« data.ClusterConfiguration.networking.podSubnet nĂ« maskĂ« tĂ« re 10.55.0.0/16.

kubectl -n kube-system edit cm kube-proxy

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

2. Modifikojmë manifestin e menaxherit të controller-it:

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

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

3. Shohim vlerat aktuale .spec.podCIDR, .spec.podCIDRs, .InternalIP, .status.addresses për të gjithë nodet 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. Zëvendësojmë podCIDR, duke bërë rregullime drejtpërdrejt 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 me 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. Ne do të rindezim një nga një të gjithë nyjet e klasterit.

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

Në të vërtetë, mund të bëhet dhe më lehtë (p.sh., kështu). Por ne dëshironim të mësoheshim të punonim me etcd drejtpërdrejt, sepse ka raste kur modifikimi i objekteve Kubernetes në etcd është i vetmi opsion i mundshëm. (P.sh., nuk mund ta ndryshosh në mënyrë të thjeshtë fushën spec.clusterIP.)

Përfundimi

Artikulli shqyrton mundĂ«sinĂ« e punĂ«s me tĂ« dhĂ«nat nĂ« etcd drejtpĂ«rdrejt, pra, duke e anashkaluar Kubernetes API. NdonjĂ«herĂ«, ky qasje lejon tĂ« bĂ«hen 'trikĂ« tĂ« zgjuara'. Operacionet e paraqitura nĂ« tekst i kemi testuar nĂ« klastera tĂ« vĂ«rtetĂ« K8s. MegjithatĂ«, statusi i tyre i gatishmĂ«risĂ« pĂ«r pĂ«rdorim tĂ« gjerĂ« Ă«shtĂ« — PoC (provĂ« e konceptit). Prandaj, nĂ«se dĂ«shironi tĂ« pĂ«rdorni versionin e modifikuar tĂ« utilitetit etcdhelper nĂ« klasterĂ«t tuaj, bĂ«jeni kĂ«tĂ« me rrezikun tuaj.

P.S.

Lexoni gjithashtu në blogun tonë:

Burimi: habr.com

Bli njĂ« hosting tĂ« besueshĂ«m pĂ«r faqet me mbrojtje DDoS, VPS VDS serverĂ« đŸ”„ Bli njĂ« hosting tĂ« besueshĂ«m pĂ«r faqet me mbrojtje DDoS, VPS VDS serverĂ« | ProHoster