Naše iskustvo s podacima u etcd Kubernetes klasteru izravno (bez K8s API-ja)

Sve češće klijenti od nas traže da omogućimo pristup Kubernetes klasteru kako bi mogli pristupiti uslugama unutar klastera: kako bi se mogli izravno povezati s nekom bazom podataka ili servisom, kako bi povezali lokalnu aplikaciju s aplikacijama unutar klastera...

Naše iskustvo s podacima u etcd Kubernetes klasteru izravno (bez K8s API-ja)

Na primjer, postoji potreba za povezivanjem s vašeg lokalnog računala na uslugu memcached.staging.svc.cluster.local. Ovu mogućnost pružamo pomoću VPN-a unutar klastera na koji se klijent povezuje. Da bismo to učinili, klijentu najavljujemo podmreže podova, usluge i DNS klastera. Dakle, kada se klijent pokuša spojiti na uslugu memcached.staging.svc.cluster.local, zahtjev ide u DNS klastera i kao odgovor prima adresu ove usluge iz mreže servisa klastera ili adresu pod-a.

Konfiguriramo K8s klastere koristeći kubeadm, gdje je zadana servisna podmreža 192.168.0.0/16, a mreža mahuna je 10.244.0.0/16. Obično sve radi dobro, ali postoji nekoliko točaka:

  • Podmreža 192.168.*.* često se koristi u mrežama ureda klijenata, a još češće u kućnim mrežama programera. I onda dobijemo sukobe: kućni usmjerivači rade na ovoj podmreži, a VPN gura te podmreže iz klastera u klijenta.
  • Imamo nekoliko klastera (produkcija, faza i/ili nekoliko dev klastera). Tada će svi oni prema zadanim postavkama imati iste podmreže za podove i servise, što stvara velike poteškoće za istovremeni rad sa servisima u nekoliko klastera.

Odavno smo usvojili praksu korištenja različitih podmreža za usluge i podove unutar jednog projekta – općenito, tako da svi klasteri imaju različite mreže. Međutim, postoji velik broj klastera u funkciji koje ne bih želio ispočetka mijenjati, budući da pokreću mnoge usluge, aplikacije sa statusom itd.

I onda smo se zapitali: kako promijeniti podmrežu u postojećem klasteru?

Traženje odluka

Najčešća praksa je ponovno stvaranje sve usluge tipa ClusterIP. Kao opciju, može savjetovati i to:

Sljedeći proces ima problem: nakon što je sve konfigurirano, moduli dolaze sa starim IP-om kao DNS poslužiteljem imena u /etc/resolv.conf.
Budući da još uvijek nisam pronašao rješenje, morao sam resetirati cijeli klaster pomoću kubeadm reset i ponovno ga pokrenuti.

Ali ovo nije prikladno za svakoga... Evo detaljnijih uvoda za naš slučaj:

  • Koristi se flanel;
  • Postoje klasteri iu oblacima i na hardveru;
  • Želio bih izbjeći ponovnu implementaciju svih usluga u klasteru;
  • Općenito je potrebno učiniti sve s minimalnim brojem problema;
  • Verzija Kubernetesa je 1.16.6 (međutim, daljnji koraci bit će slični za druge verzije);
  • Glavni zadatak je osigurati da u klasteru koji se koristi kubeadm s servisnom podmrežom 192.168.0.0/16, zamijenite ga s 172.24.0.0/16.

I slučajno se dogodilo da nas je dugo zanimalo što i kako se u Kubernetesu pohranjuje u etcd, što se s tim može učiniti... Pa smo pomislili: “Zašto jednostavno ne ažurirati podatke u etcd, zamjenjujući stare IP adrese (subnet) novima? "

Nakon što smo tražili gotove alate za rad s podacima u itd., nismo pronašli ništa što bi u potpunosti riješilo problem. (Usput, ako znate za bilo kakve pomoćne programe za rad s podacima izravno u itd., cijenili bismo veze.) Međutim, dobro polazište je etcdhelper iz OpenShift-a (hvala njegovim autorima!).

Ovaj se uslužni program može spojiti na etcd pomoću certifikata i čitati podatke odatle pomoću naredbi ls, get, dump.

Dodaj etcdhelper

Sljedeća misao je logična: "Što vas sprječava da dodate ovaj uslužni program dodavanjem mogućnosti pisanja podataka u etcd?"

Postao je modificirana verzija etcdhelpera s dvije nove funkcije changeServiceCIDR и changePodCIDR. na njoj možete vidjeti kod здесь.

Što rade nove značajke? Algoritam changeServiceCIDR:

  • stvoriti deserializator;
  • sastaviti regularni izraz za zamjenu CIDR-a;
  • prolazimo kroz sve usluge s tipom ClusterIP u klasteru:
    • dekodirati vrijednost iz etcd u Go objekt;
    • korištenjem regularnog izraza zamjenjujemo prva dva bajta adrese;
    • dodijelite servisu IP adresu iz nove podmreže;
    • stvoriti serijalizator, pretvoriti Go objekt u protobuf, napisati nove podatke u itd.

Funkcija changePodCIDR bitno slični changeServiceCIDR - samo umjesto uređivanja specifikacije usluge, mi to radimo za čvor i mijenjamo .spec.PodCIDR na novu podmrežu.

Praksa

Promjena usluge CIDR

Plan za provedbu zadatka je vrlo jednostavan, ali uključuje prekid rada dok se sve jedinice u klasteru ponovno kreiraju. Nakon opisa glavnih koraka, također ćemo podijeliti razmišljanja o tome kako se, u teoriji, ovaj zastoj može svesti na minimum.

Pripremni koraci:

  • instaliranje potrebnog softvera i sastavljanje zakrpanog etcdhelpera;
  • sigurnosna kopija itd. i /etc/kubernetes.

Kratki akcijski plan za promjenu serviceCIDR-a:

  • mijenjanje manifesta apiservera i kontrolera-upravitelja;
  • ponovno izdavanje certifikata;
  • mijenjanje ClusterIP usluga u etcd;
  • ponovno pokretanje svih mahuna u klasteru.

Slijedi detaljan cjelovit slijed radnji.

1. Instalirajte etcd-client za ispis podataka:

apt install etcd-client

2. Izgradite etcdhelper:

  • Instalirajte 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
  • Štedimo za sebe etcdhelper.go, preuzimanje ovisnosti, prikupljanje:
    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. Napravite sigurnosnu kopiju itd.:

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. Promijenite servisnu podmrežu u manifestima kontrolne ravnine Kubernetes. U datotekama /etc/kubernetes/manifests/kube-apiserver.yaml и /etc/kubernetes/manifests/kube-controller-manager.yaml promijeniti parametar --service-cluster-ip-range na novu podmrežu: 172.24.0.0/16 umjesto 192.168.0.0/16.

5. Budući da mijenjamo servisnu podmrežu na koju kubeadm izdaje certifikate za apiserver (uključujući), potrebno ih je ponovno izdati:

  1. Pogledajmo za koje domene i IP adrese je izdan trenutni certifikat:
    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. Pripremimo minimalnu konfiguraciju 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-адрес мастер узла
  3. Idemo izbrisati stari crt i ključ, jer bez toga novi certifikat neće biti izdan:
    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. Ponovno izdajmo certifikate za API poslužitelj:
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. Provjerimo je li certifikat izdan za novu podmrežu:
    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. Nakon ponovnog izdavanja certifikata API poslužitelja, ponovno pokrenite njegov spremnik:
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. Idemo ponovno generirati konfiguraciju za admin.conf:
    kubeadm alpha certs renew admin.conf
  8. Uredimo podatke 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-service-cidr 172.24.0.0/16 

    Upozorenje! U ovom trenutku razlučivost domene prestaje raditi u klasteru, jer u postojećim podovima /etc/resolv.conf registrirana je stara CoreDNS adresa (kube-dns), a kube-proxy mijenja iptables pravila sa stare podmreže na novu. Dalje u članku piše se o mogućim opcijama za smanjenje vremena zastoja.

  9. Popravimo ConfigMap u prostoru imena kube-system:
    kubectl -n kube-system edit cm kubelet-config-1.16

    - zamijenite ovdje clusterDNS na novu IP adresu usluge kube-dns: kubectl -n kube-system get svc kube-dns.

    kubectl -n kube-system edit cm kubeadm-config

    - mi ćemo to popraviti data.ClusterConfiguration.networking.serviceSubnet na novu podmrežu.

  10. Budući da se kube-dns adresa promijenila, potrebno je ažurirati kubelet konfiguraciju na svim čvorovima:
    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. Sve što preostaje je ponovno pokrenuti sve mahune u klasteru:
    kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(S+)s+(S+).*/kubectl --namespace 1 delete pod 2/e'

Smanjite vrijeme zastoja

Razmišljanja o tome kako minimizirati vrijeme zastoja:

  1. Nakon promjene manifesta kontrolne ravnine, stvorite novu kube-dns uslugu, na primjer, s imenom kube-dns-tmp i nova adresa 172.24.0.10.
  2. napraviti if u etcdhelperu, koji neće modificirati uslugu kube-dns.
  3. Zamijenite adresu u svim kubeletima ClusterDNS na novu, dok će stara usluga nastaviti raditi istovremeno s novom.
  4. Pričekajte dok se kapsule s aplikacijama ne prevrnu same od sebe iz prirodnih razloga ili u dogovoreno vrijeme.
  5. Izbriši uslugu kube-dns-tmp i promijeniti serviceSubnetCIDR za uslugu kube-dns.

Ovaj plan će vam omogućiti da minimizirate vrijeme prekida rada na ~ minutu - za vrijeme trajanja uklanjanja usluge kube-dns-tmp i mijenjanje podmreže za uslugu kube-dns.

Modifikacija podNetwork

U isto vrijeme, odlučili smo pogledati kako modificirati podNetwork pomoću rezultirajućeg etcdhelpera. Slijed radnji je sljedeći:

  • popravljanje konfiguracija kube-system;
  • popravljanje manifesta kube-controller-manager;
  • promijenite podCIDR izravno u etcd;
  • ponovno pokrenite sve čvorove klastera.

Sada više o ovim akcijama:

1. Izmijenite ConfigMaps u prostoru naziva kube-system:

kubectl -n kube-system edit cm kubeadm-config

- ispravljanje data.ClusterConfiguration.networking.podSubnet na novu podmrežu 10.55.0.0/16.

kubectl -n kube-system edit cm kube-proxy

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

2. Izmijenite manifest kontrolera-upravitelja:

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

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

3. Pogledajte trenutne vrijednosti .spec.podCIDR, .spec.podCIDRs, .InternalIP, .status.addresses za sve čvorove klastera:

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. Zamijenite podCIDR unošenjem promjena izravno 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 se podCIDR stvarno promijenio:

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. Ponovno pokrenimo sve čvorove klastera jedan po jedan.

7. Ako napustite barem jedan čvor stari podCIDR, tada se kube-controller-manager neće moći pokrenuti, a moduli u klasteru neće biti zakazani.

Zapravo, mijenjanje podCIDR-a može se učiniti još jednostavnije (npr. tako). Ali željeli smo naučiti kako izravno raditi s etcd-om, jer postoje slučajevi kada se Kubernetes objekti uređuju u etcd-u - jedini moguća varijanta. (Na primjer, ne možete samo promijeniti polje usluge bez prekida rada spec.clusterIP.)

Ukupan

U članku se govori o mogućnosti izravnog rada s podacima u etcd-u, tj. zaobilazeći Kubernetes API. Ponekad vam ovaj pristup omogućuje da radite "škakljive stvari". Operacije navedene u tekstu testirali smo na stvarnim klasterima K8s. Međutim, njihov status spremnosti za široku upotrebu jest PoC (dokaz koncepta). Stoga, ako želite koristiti modificiranu verziju uslužnog programa etcdhelper na svojim klasterima, učinite to na vlastitu odgovornost.

PS

Pročitajte i na našem blogu:

Izvor: www.habr.com

Dodajte komentar