Përvoja jonë me të dhënat në grupin e Kubernetes etcd drejtpërdrejt (pa K8s API)

Gjithnjë e më shumë, klientët po na kërkojnë të ofrojmë akses në grupin Kubernetes për të pasur akses në shërbimet brenda grupit: të mund të lidheni drejtpërdrejt me një bazë të dhënash ose shërbimi, të lidhni një aplikacion lokal me aplikacionet brenda grupit...

Përvoja jonë me të dhënat në grupin e Kubernetes etcd drejtpërdrejt (pa K8s API)

Për shembull, ekziston nevoja për t'u lidhur nga makina juaj lokale me një shërbim memcached.staging.svc.cluster.local. Ne e ofrojmë këtë aftësi duke përdorur një VPN brenda grupit me të cilin lidhet klienti. Për ta bërë këtë, ne shpallim nën-rrjetet e pods, shërbimeve dhe shtyjmë DNS-në e grupit tek klienti. Kështu, kur një klient përpiqet të lidhet me shërbimin memcached.staging.svc.cluster.local, kërkesa shkon te grupi DNS dhe si përgjigje merr adresën e këtij shërbimi nga rrjeti i shërbimit të grupit ose adresa e pod.

Ne konfigurojmë grupimet K8s duke përdorur kubeadm, ku është nënrrjeti i paracaktuar i shërbimit 192.168.0.0/16, dhe rrjeti i pods është 10.244.0.0/16. Zakonisht gjithçka funksionon mirë, por ka disa pika:

  • Nënrrjet 192.168.*.* përdoret shpesh në rrjetet e zyrave të klientëve dhe akoma më shpesh në rrjetet shtëpiake të zhvilluesve. Dhe më pas kemi konflikte: ruterat e shtëpisë punojnë në këtë nënrrjet dhe VPN i shtyn këto nënrrjeta nga grupi te klienti.
  • Ne kemi disa grupime (prodhimi, skena dhe/ose disa grupe dev). Më pas, si parazgjedhje, të gjithë do të kenë të njëjtat nënrrjeta për pods dhe shërbime, gjë që krijon vështirësi të mëdha për punën e njëkohshme me shërbime në disa grupime.

Ne kemi adoptuar kohë më parë praktikën e përdorimit të nën-rrjeteve të ndryshme për shërbime dhe pods brenda të njëjtit projekt - në përgjithësi, në mënyrë që të gjitha grupet të kenë rrjete të ndryshme. Sidoqoftë, ka një numër të madh grupesh në funksionim që nuk do të doja t'i ktheja nga e para, pasi ato drejtojnë shumë shërbime, aplikacione shtetërore, etj.

Dhe më pas pyetëm veten: si ta ndryshojmë nënrrjetin në një grup ekzistues?

Kërkoni zgjidhje

Praktika më e zakonshme është rikrijimi të gjithë shërbime me tip ClusterIP. Si opsion, mund të këshillojë dhe kjo:

Procesi i mëposhtëm ka një problem: pasi çdo gjë të konfigurohet, pod-et dalin me IP-në e vjetër si server emri DNS në /etc/resolv.conf.
Meqenëse ende nuk e gjeta zgjidhjen, më duhej të rivendosja të gjithë grupin me kubeadm reset dhe ta rifilloja përsëri.

Por kjo nuk është e përshtatshme për të gjithë... Këtu janë prezantimet më të detajuara për rastin tonë:

  • Përdoret fanellë;
  • Ka grupime si në retë ashtu edhe në harduer;
  • Do të doja të shmangja rivendosjen e të gjitha shërbimeve në grup;
  • Ekziston nevoja që në përgjithësi të bëhet gjithçka me një numër minimal problemesh;
  • Versioni i Kubernetes është 1.16.6 (megjithatë, hapat e mëtejshëm do të jenë të ngjashëm për versionet e tjera);
  • Detyra kryesore është të sigurohet që në një grup të vendoset duke përdorur kubeadm me një nënrrjet shërbimi 192.168.0.0/16, zëvendësojeni me 172.24.0.0/16.

Dhe ndodhi që prej kohësh ishim të interesuar të shihnim se çfarë dhe si ruhet në Kubernetes në etcd, çfarë mund të bëhet me të... Kështu menduam: "Pse jo thjesht të përditësoni të dhënat në etcd, duke zëvendësuar adresat e vjetra IP (nënnet) me të reja? "

Pasi kërkuam mjete të gatshme për të punuar me të dhëna në etcd, nuk gjetëm asgjë që e zgjidhte plotësisht problemin. (Meqë ra fjala, nëse dini për ndonjë mjet për të punuar me të dhëna direkt në etcd, ne do t'i vlerësonim lidhjet.) Megjithatë, një pikënisje e mirë është ndihmës etj nga OpenShift (faleminderit autoreve te saj!).

Ky mjet mund të lidhet me etcd duke përdorur certifikata dhe të lexojë të dhëna nga atje duke përdorur komanda ls, get, dump.

Shto etcdhelper

Mendimi tjetër është logjik: "Çfarë po ju pengon të shtoni këtë mjet duke shtuar aftësinë për të shkruar të dhëna në etcd?"

Ai u bë një version i modifikuar i etcdhelper me dy funksione të reja changeServiceCIDR и changePodCIDR. Tek ajo ju mund të shihni kodin këtu.

Çfarë bëjnë veçoritë e reja? Algoritmi changeServiceCIDR:

  • krijoni një deserializues;
  • përpiloni një shprehje të rregullt për të zëvendësuar CIDR;
  • ne kalojmë nëpër të gjitha shërbimet me llojin ClusterIP në grup:
    • deshifroni vlerën nga etcd në një objekt Go;
    • duke përdorur një shprehje të rregullt zëvendësojmë dy bajtët e parë të adresës;
    • caktoni shërbimit një adresë IP nga nënrrjeti i ri;
    • krijoni një serializues, shndërroni objektin Go në protobuf, shkruani të dhëna të reja në etcd.

Funksion changePodCIDR në thelb të ngjashme changeServiceCIDR - vetëm në vend që të modifikojmë specifikimin e shërbimit, ne e bëjmë atë për nyjen dhe ndryshojmë .spec.PodCIDR në një nënrrjet të ri.

Praktikë

Ndryshoni shërbimin CIDR

Plani për zbatimin e detyrës është shumë i thjeshtë, por përfshin kohë joproduktive në kohën e rikrijimit të të gjitha podeve në grup. Pas përshkrimit të hapave kryesorë, ne do të ndajmë gjithashtu mendime se si, në teori, kjo kohë joproduktive mund të minimizohet.

Hapat përgatitor:

  • instalimi i softuerit të nevojshëm dhe montimi i etjdhelper-it të arnuar;
  • backup etjd dhe /etc/kubernetes.

Plani i shkurtër i veprimit për ndryshimin e shërbimitCIDR:

  • ndryshimi i manifestit apiserver dhe kontrollues-menaxher;
  • rilëshimi i certifikatave;
  • ndryshimi i shërbimeve ClusterIP në etjd;
  • rinisni të gjitha pods në grup.

Më poshtë është një sekuencë e plotë veprimesh në detaje.

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

apt install etcd-client

2. Ndërtoni 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
  • Ne kursejmë për veten tonë etcdhelper.go, shkarkoni varësitë, mblidhni:
    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ë kopje rezervë etj.

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. Ndryshoni nënrrjetin e shërbimit në manifestimet e planit të kontrollit Kubernetes. Në skedarë /etc/kubernetes/manifests/kube-apiserver.yaml и /etc/kubernetes/manifests/kube-controller-manager.yaml ndryshoni parametrin --service-cluster-ip-range në një nënrrjet të ri: 172.24.0.0/16 në vend të 192.168.0.0/16.

5. Meqenëse po ndryshojmë nënrrjetin e shërbimit në të cilin kubeadm lëshon certifikata për apiserver (përfshirë), ato duhet të ribotohen:

  1. Le të shohim se për cilat domene dhe adresa IP është lëshuar certifikata aktuale:
    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. Le 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-адрес мастер узла
  3. Le të fshijmë crt dhe çelësin e vjetër, pasi pa këtë certifikata e re nuk do të lëshohet:
    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. Le të ribotojmë certifikatat për serverin API:
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. Le të kontrollojmë nëse certifikata është lëshuar për nënrrjetin 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 rilëshimit të certifikatës së serverit API, rinisni kontejnerin e tij:
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. Le të rigjenerojmë konfigurimin për admin.conf:
    kubeadm alpha certs renew admin.conf
  8. Le të 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, rezolucioni i domenit ndalon së punuari në grup, pasi në podet ekzistuese /etc/resolv.conf adresa e vjetër CoreDNS (kube-dns) regjistrohet dhe kube-proxy ndryshon rregullat iptables nga nënrrjeti i vjetër në atë të ri. Më tej në artikull shkruhet për opsionet e mundshme për të minimizuar kohën e ndërprerjes.

  9. Le të rregullojmë ConfigMap në hapësirën e emrave kube-system:
    kubectl -n kube-system edit cm kubelet-config-1.16

    - zëvendëso këtu clusterDNS në 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 ta rregullojmë data.ClusterConfiguration.networking.serviceSubnet në një nënrrjet të ri.

  10. Meqenëse adresa kube-dns ka ndryshuar, është e nevojshme të përditësohet konfigurimi i kubelet në të gjitha nyjet:
    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. Gjithçka që mbetet është të rinisni të gjitha podet në grup:
    kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(S+)s+(S+).*/kubectl --namespace 1 delete pod 2/e'

Minimizoni kohën e pushimit

Mendime se si të minimizoni kohën e ndërprerjes:

  1. Pas ndryshimit të manifestimit të planit të kontrollit, krijoni një shërbim të ri kube-dns, për shembull, me emrin kube-dns-tmp dhe adresën e re 172.24.0.10.
  2. bëj if në etcdhelper, i cili nuk do të modifikojë shërbimin kube-dns.
  3. Zëvendësoni adresën në të gjitha kubelet ClusterDNS në një të ri, ndërsa shërbimi i vjetër do të vazhdojë të funksionojë njëkohësisht me të riun.
  4. Prisni derisa bishtajat me aplikacione të rrokullisen ose vetë për arsye natyrore ose në një kohë të rënë dakord.
  5. Fshi shërbimin kube-dns-tmp dhe ndryshim serviceSubnetCIDR për shërbimin kube-dns.

Ky plan do t'ju lejojë të minimizoni kohën e ndërprerjes në ~ një minutë - për kohëzgjatjen e heqjes së shërbimit kube-dns-tmp dhe ndryshimi i nënrrjetit për shërbimin kube-dns.

Modifikimi podNetwork

Në të njëjtën kohë, ne vendosëm të shikojmë se si të modifikojmë podNetwork duke përdorur etcdhelper-in që rezulton. Sekuenca e veprimeve është si më poshtë:

  • rregullimi i konfigurimeve në kube-system;
  • rregullimi i manifestit kube-controller-manager;
  • ndryshoni podCIDR direkt në etcd;
  • rinisni të gjitha nyjet e grupimit.

Tani më shumë rreth këtyre veprimeve:

1. Ndryshoni ConfigMap's në hapësirën e emrave kube-system:

kubectl -n kube-system edit cm kubeadm-config

- korrigjimi data.ClusterConfiguration.networking.podSubnet në një nënrrjet të ri 10.55.0.0/16.

kubectl -n kube-system edit cm kube-proxy

- korrigjimi data.config.conf.clusterCIDR: 10.55.0.0/16.

2. Ndryshoni manifestin e menaxherit-kontrollues:

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

- korrigjimi --cluster-cidr=10.55.0.0/16.

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

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ësoni 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. Le të kontrollojmë që podCIDR ka ndryshuar vërtet:

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. Le të rinisim të gjitha nyjet e grupimit një nga një.

7. Nëse lini të paktën një nyje podCIDR e vjetër, atëherë kube-controller-manager nuk do të jetë në gjendje të fillojë dhe podet në grup nuk do të planifikohen.

Në fakt, ndryshimi i podCIDR mund të bëhet edhe më i thjeshtë (për shembull, kështu). Por ne donim të mësonim se si të punonim drejtpërdrejt me etcd, sepse ka raste kur redaktoni objekte Kubernetes në etcd - единственный variant i mundshëm. (Për shembull, nuk mund ta ndryshoni vetëm fushën e Shërbimit pa ndërprerje spec.clusterIP.)

Total

Artikulli diskuton mundësinë e punës me të dhëna në etjd drejtpërdrejt, d.m.th. duke anashkaluar API-në e Kubernetes. Ndonjëherë kjo qasje ju lejon të bëni "gjëra të ndërlikuara". Ne testuam operacionet e dhëna në tekst në grupe reale K8. Megjithatë, statusi i tyre i gatishmërisë për përdorim të gjerë është PoC (prova e konceptit). Prandaj, nëse dëshironi të përdorni një version të modifikuar të mjetit etcdhelper në grupimet tuaja, bëjeni këtë me rrezikun tuaj.

PS

Lexoni edhe në blogun tonë:

Burimi: www.habr.com

Shto një koment