Naše izkušnje s podatki v gruči etcd Kubernetes neposredno (brez API-ja K8s)

Vse pogosteje nas naročniki prosijo, da jim omogočimo dostop do gruče Kubernetes, da lahko dostopamo do storitev znotraj gruče: da se lahko neposredno povežemo z neko bazo ali storitvijo, da povežemo lokalno aplikacijo z aplikacijami znotraj gruče ...

Naše izkušnje s podatki v gruči etcd Kubernetes neposredno (brez API-ja K8s)

Na primer, obstaja potreba po povezavi z vašega lokalnega računalnika na storitev memcached.staging.svc.cluster.local. To možnost zagotavljamo z uporabo VPN znotraj gruče, na katero se odjemalec poveže. Da bi to naredili, odjemalcu objavimo podomrežja podov, storitev in DNS potisne gruče. Torej, ko se odjemalec poskuša povezati s storitvijo memcached.staging.svc.cluster.local, gre zahteva v DNS gruče in kot odgovor prejme naslov te storitve iz omrežja storitev gruče ali naslov pod.

Konfiguriramo gruče K8s z uporabo kubeadm, kjer je privzeto servisno podomrežje 192.168.0.0/16, mreža pods pa je 10.244.0.0/16. Ponavadi vse deluje dobro, vendar obstaja nekaj točk:

  • Podomrežje 192.168.*.* pogosto uporablja v pisarniških omrežjih strank in še pogosteje v domačih omrežjih razvijalcev. In potem pride do konfliktov: domači usmerjevalniki delujejo v tem podomrežju in VPN potisne ta podomrežja iz gruče v odjemalca.
  • Imamo več grozdov (production, stage in/ali več dev grozdov). Potem bodo privzeto vsi imeli enaka podomrežja za pode in storitve, kar ustvarja velike težave pri hkratnem delu s storitvami v več grozdih.

Že zdavnaj smo sprejeli prakso uporabe različnih podomrežij za storitve in pode znotraj istega projekta – na splošno tako, da imajo vsi grozdi različna omrežja. Vendar pa deluje veliko število gruč, ki jih ne bi želel prenoviti iz nič, saj izvajajo številne storitve, aplikacije s stanjem itd.

In potem smo se vprašali: kako spremeniti podomrežje v obstoječi gruči?

Iskanje odločitev

Najpogostejša praksa je poustvarjanje Vsi storitev tipa ClusterIP. Kot možnost, lahko svetuje in to:

Naslednji postopek ima težavo: ko je vse konfigurirano, pods prikažejo stari IP kot imenski strežnik DNS v /etc/resolv.conf.
Ker še vedno nisem našel rešitve, sem moral ponastaviti celotno gručo s kubeadm reset in jo znova zagnati.

Vendar to ni primerno za vsakogar ... Tukaj je podrobnejši uvod za naš primer:

  • Uporablja se flanel;
  • Grozdi so tako v oblakih kot na strojni opremi;
  • Rad bi se izognil ponovni umestitvi vseh storitev v gruči;
  • Na splošno je treba narediti vse z minimalnim številom težav;
  • Različica Kubernetes je 1.16.6 (vendar bodo nadaljnji koraki podobni za druge različice);
  • Glavna naloga je zagotoviti, da je v gruči, razporejeni z uporabo kubeadm, s servisnim podomrežjem 192.168.0.0/16, ga nadomestite z 172.24.0.0/16.

In zgodilo se je, da nas je že dolgo zanimalo, kaj in kako je v Kubernetesu shranjeno v etcd, kaj je mogoče narediti s tem ... Pa smo pomislili: “Zakaj ne bi preprosto posodobili podatkov v etcd in zamenjali stare naslove IP (podomrežje) z novimi? "

Ko smo iskali že pripravljena orodja za delo s podatki v etcd, nismo našli ničesar, kar bi popolnoma rešilo težavo. (Mimogrede, če poznate kakšne pripomočke za delo s podatki neposredno v etcd, bomo cenili povezave.) Vendar pa je dobro izhodišče etcdhelper iz OpenShift (hvala avtorjem!).

Ta pripomoček se lahko poveže z etcd z uporabo potrdil in bere podatke od tam z uporabo ukazov ls, get, dump.

Dodaj etcdhelper

Naslednja misel je logična: "Kaj vam preprečuje, da dodate ta pripomoček tako, da dodate možnost zapisovanja podatkov v etcd?"

Postal je spremenjena različica etcdhelperja z dvema novima funkcijama changeServiceCIDR и changePodCIDR. na njej si lahko ogledate kodo tukaj.

Kaj počnejo nove funkcije? Algoritem changeServiceCIDR:

  • ustvarite deserializator;
  • prevedite regularni izraz za zamenjavo CIDR;
  • gremo skozi vse storitve s tipom ClusterIP v gruči:
    • dekodirajte vrednost iz etcd v objekt Go;
    • z uporabo regularnega izraza zamenjamo prva dva bajta naslova;
    • storitvi dodeli naslov IP iz novega podomrežja;
    • ustvarite serializator, pretvorite objekt Go v protobuf, zapišite nove podatke v itd.

Funkcija changePodCIDR v bistvu podobni changeServiceCIDR - le da namesto urejanja specifikacije storitve to naredimo za vozlišče in spremembo .spec.PodCIDR v novo podomrežje.

Practice

Spremenite storitev CIDR

Načrt za izvedbo naloge je zelo preprost, vendar vključuje izpade v času ponovne izdelave vseh podov v gruči. Po opisu glavnih korakov bomo delili tudi misli o tem, kako je teoretično mogoče te izpade zmanjšati.

Pripravljalni koraki:

  • namestitev potrebne programske opreme in sestavljanje popravljenega etcdhelperja;
  • varnostno kopiranje itd. in /etc/kubernetes.

Kratek akcijski načrt za spremembo storitve CIDR:

  • spreminjanje manifestov apiserver in controller-manager;
  • ponovna izdaja certifikatov;
  • spreminjanje storitev ClusterIP v etcd;
  • ponovni zagon vseh podov v gruči.

Sledi podrobno celotno zaporedje dejanj.

1. Namestite etcd-client za izpis podatkov:

apt install etcd-client

2. Zgradite etcdhelper:

  • Namestite 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
  • Varčujemo zase etcdhelper.go, prenesite odvisnosti, zberite:
    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. Naredite varnostno kopijo 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. Spremenite storitveno podomrežje v manifestih nadzorne ravnine Kubernetes. V datotekah /etc/kubernetes/manifests/kube-apiserver.yaml и /etc/kubernetes/manifests/kube-controller-manager.yaml spremenite parameter --service-cluster-ip-range v novo podomrežje: 172.24.0.0/16 namesto 192.168.0.0/16.

5. Ker spreminjamo storitveno podomrežje, kateremu kubeadm izdaja potrdila za apiserver (vključno), jih je treba ponovno izdati:

  1. Poglejmo, za katere domene in naslove IP je bil 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. 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-адрес мастер узла
  3. Zbrišemo stari crt in ključ, saj brez tega ne bo izdano novo potrdilo:
    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. Ponovno izdajmo potrdila za strežnik API:
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. Preverimo, ali 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 ponovni izdaji potrdila strežnika API znova zaženite njegov vsebnik:
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. Ponovno ustvarimo 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 

    Opozorilo! V tem trenutku razrešitev domene preneha delovati v gruči, saj v obstoječih sklopih /etc/resolv.conf stari naslov CoreDNS (kube-dns) je registriran, kube-proxy pa spremeni pravila iptables iz starega podomrežja v novo. Nadalje v članku je napisano o možnih možnostih za zmanjšanje izpadov.

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

    - zamenjajte tukaj clusterDNS na nov naslov IP storitve kube-dns: kubectl -n kube-system get svc kube-dns.

    kubectl -n kube-system edit cm kubeadm-config

    - bomo popravili data.ClusterConfiguration.networking.serviceSubnet v novo podomrežje.

  10. Ker se je naslov kube-dns spremenil, je treba posodobiti konfiguracijo kubeleta na vseh vozliščih:
    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. Vse, kar ostane, je, da znova zaženete vse pode v gruči:
    kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(S+)s+(S+).*/kubectl --namespace 1 delete pod 2/e'

Zmanjšajte izpade

Razmišljanja o tem, kako zmanjšati čas nedelovanja:

  1. Ko spremenite manifeste nadzorne ravnine, ustvarite novo storitev kube-dns, na primer z imenom kube-dns-tmp in nov naslov 172.24.0.10.
  2. Naredi if v etcdhelperju, ki ne bo spremenil storitve kube-dns.
  3. Zamenjajte naslov v vseh kubeletih ClusterDNS na novo, medtem ko bo stara storitev delovala sočasno z novo.
  4. Počakajte, da se stroki z aplikacijami prevrnejo sami iz naravnih razlogov ali ob dogovorjenem času.
  5. Izbriši storitev kube-dns-tmp in spremeniti serviceSubnetCIDR za storitev kube-dns.

Ta načrt vam bo omogočil, da zmanjšate čas nedelovanja na ~ minuto - za čas odstranitve storitve kube-dns-tmp in spreminjanje podomrežja za storitev kube-dns.

Sprememba podNetwork

Hkrati smo se odločili pogledati, kako spremeniti podNetwork z uporabo nastalega etcdhelperja. Zaporedje dejanj je naslednje:

  • popravljanje konfiguracij kube-system;
  • popravljanje manifesta kube-controller-manager;
  • spremenite podCIDR neposredno v etcd;
  • znova zaženite vsa vozlišča gruče.

Zdaj pa več o teh dejanjih:

1. Spremenite ConfigMap v imenskem prostoru kube-system:

kubectl -n kube-system edit cm kubeadm-config

- popravljanje data.ClusterConfiguration.networking.podSubnet v novo podomrežje 10.55.0.0/16.

kubectl -n kube-system edit cm kube-proxy

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

2. Spremenite manifest krmilnika-upravitelja:

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

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

3. Poglejte trenutne vrednosti .spec.podCIDR, .spec.podCIDRs, .InternalIP, .status.addresses za vsa vozlišča gruče:

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. Zamenjajte podCIDR tako, da spremenite neposredno 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-pod-cidr 10.55.0.0/16

5. Preverimo, ali se je podCIDR res spremenil:

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 zaženimo vsa vozlišča gruče enega za drugim.

7. Če zapustite vsaj eno vozlišče stari podCIDR, potem se kube-controller-manager ne bo mogel zagnati in podi v gruči ne bodo načrtovani.

Pravzaprav je spreminjanje podCIDR mogoče narediti celo preprosteje (npr. Tako). Želeli pa smo se naučiti, kako neposredno delati z etcd, ker obstajajo primeri, ko urejamo predmete Kubernetes v etcd - edini možna varianta. (Na primer, ne morete samo spremeniti polja storitve brez izpadov spec.clusterIP.)

Skupaj

Članek obravnava možnost neposrednega dela s podatki v etcd, tj. mimo API-ja Kubernetes. Včasih vam ta pristop omogoča "zapletene stvari". Operacije, navedene v besedilu, smo preizkusili na realnih gručah K8s. Vendar pa je njihov status pripravljenosti za široko uporabo PoC (dokaz koncepta). Zato, če želite uporabiti spremenjeno različico pripomočka etcdhelper na svojih gručah, to storite na lastno odgovornost.

PS

Preberite tudi na našem blogu:

Vir: www.habr.com

Dodaj komentar