Vores erfaring med data i etcd Kubernetes cluster direkte (uden K8s API)

I stigende grad beder klienter os om at give adgang til Kubernetes-klyngen for at kunne få adgang til tjenester i klyngen: for at kunne oprette direkte forbindelse til en database eller tjeneste, for at forbinde en lokal applikation med applikationer i klyngen...

Vores erfaring med data i etcd Kubernetes cluster direkte (uden K8s API)

For eksempel er der behov for at oprette forbindelse fra din lokale maskine til en tjeneste memcached.staging.svc.cluster.local. Vi leverer denne mulighed ved hjælp af en VPN i den klynge, som klienten forbinder til. For at gøre dette annoncerer vi undernet af pods, tjenester og pusher klynge-DNS til klienten. Således, når en klient forsøger at oprette forbindelse til tjenesten memcached.staging.svc.cluster.local, går anmodningen til klynge-DNS og modtager som svar adressen på denne tjeneste fra klyngetjenestenetværket eller pod-adressen.

Vi konfigurerer K8s-klynger ved hjælp af kubeadm, hvor standardserviceundernet er 192.168.0.0/16, og netværket af pods er 10.244.0.0/16. Normalt fungerer alt godt, men der er et par punkter:

  • Undernet 192.168.*.* bruges ofte i klientkontornetværk og endnu oftere i udviklerhjemmenetværk. Og så får vi konflikter: hjemmeroutere arbejder på dette undernet, og VPN'en skubber disse undernet fra klyngen til klienten.
  • Vi har flere klynger (produktion, scene og/eller flere dev klynger). Så vil alle som standard have de samme undernet til pods og tjenester, hvilket skaber store vanskeligheder for samtidig arbejde med tjenester i flere klynger.

Vi har for længst indført praksis med at bruge forskellige undernet til tjenester og pods inden for et projekt – generelt, så alle klynger har forskellige netværk. Der er dog et stort antal klynger i drift, som jeg ikke kunne tænke mig at rulle over fra bunden, da de kører mange tjenester, stateful applikationer mv.

Og så spurgte vi os selv: hvordan ændrer man undernettet i en eksisterende klynge?

Søgning af beslutninger

Den mest almindelige praksis er at genskabe alle tjenester med typen ClusterIP. Som en mulighed, kan rådgive og dette:

Følgende proces har et problem: efter at alt er konfigureret, kommer pods med den gamle IP som en DNS-navneserver i /etc/resolv.conf.
Da jeg stadig ikke fandt løsningen, var jeg nødt til at nulstille hele klyngen med kubeadm reset og starte den igen.

Men dette er ikke egnet for alle... Her er mere detaljerede introduktioner til vores case:

  • Flanell bruges;
  • Der er klynger både i skyerne og på hardware;
  • Jeg vil gerne undgå at geninstallere alle tjenester i klyngen;
  • Der er behov for generelt at gøre alt med et minimum antal problemer;
  • Kubernetes version er 1.16.6 (yderligere trin vil dog være ens for andre versioner);
  • Hovedopgaven er at sikre, at der i en klynge implementeres ved hjælp af kubeadm med et serviceundernet 192.168.0.0/16, udskift den med 172.24.0.0/16.

Og det skete, at vi længe havde været interesseret i at se, hvad og hvordan i Kubernetes er gemt i etcd, hvad der kan gøres med det... Så vi tænkte: “Hvorfor ikke bare opdatere dataene i etcd, og erstatte de gamle IP-adresser (undernet) med nye? "

Efter at have søgt efter færdige værktøjer til at arbejde med data i etcd, fandt vi ikke noget, der helt løste problemet. (Hvis du i øvrigt kender til nogle værktøjer til at arbejde med data direkte i etcd, ville vi sætte pris på linksene.) Et godt udgangspunkt er dog etcdhjælper fra OpenShift (tak til forfatterne!).

Dette værktøj kan oprette forbindelse til etcd ved hjælp af certifikater og læse data derfra ved hjælp af kommandoer ls, get, dump.

Tilføj etcdhelper

Den næste tanke er logisk: "Hvad forhindrer dig i at tilføje dette værktøj ved at tilføje muligheden for at skrive data til etcd?"

Det blev til en modificeret version af etcdhelper med to nye funktioner changeServiceCIDR и changePodCIDR. på hende du kan se koden her.

Hvad gør de nye funktioner? Algoritme changeServiceCIDR:

  • oprette en deserializer;
  • kompiler et regulært udtryk for at erstatte CIDR;
  • vi gennemgår alle tjenester med ClusterIP-typen i klyngen:
    • afkode værdien fra etcd til et Go-objekt;
    • ved at bruge et regulært udtryk erstatter vi de første to bytes af adressen;
    • tildele tjenesten en IP-adresse fra det nye undernet;
    • vi opretter en serializer, konverterer Go-objektet til protobuf, skriver nye data til etcd.

Funktion changePodCIDR i det væsentlige ens changeServiceCIDR - kun i stedet for at redigere servicespecifikationen, gør vi det for noden og ændrer .spec.PodCIDR til et nyt undernet.

Praksis

Skift service CIDR

Planen for implementering af opgaven er meget enkel, men den involverer nedetid, mens alle pods i klyngen genskabes. Efter at have beskrevet hovedtrinene, vil vi også dele tanker om, hvordan denne nedetid i teorien kan minimeres.

Forberedende trin:

  • installation af den nødvendige software og samling af den patchede etcdhelper;
  • backup etcd og /etc/kubernetes.

Kort handlingsplan for ændring af serviceCIDR:

  • ændring af apiserver og controller-manager manifester;
  • genudstedelse af certifikater;
  • ændring af ClusterIP-tjenester i etcd;
  • genstart af alle pods i klyngen.

Det følgende er en komplet rækkefølge af handlinger i detaljer.

1. Installer etcd-klient til datadump:

apt install etcd-client

2. Byg etcdhelper:

  • Installer 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
  • Vi sparer til os selv etcdhelper.go, download afhængigheder, indsaml:
    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. Lav en sikkerhedskopi 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. Skift serviceundernet i Kubernetes kontrolplanmanifester. I filer /etc/kubernetes/manifests/kube-apiserver.yaml и /etc/kubernetes/manifests/kube-controller-manager.yaml ændre parameteren --service-cluster-ip-range til et nyt undernet: 172.24.0.0/16 i stedet for 192.168.0.0/16.

5. Da vi ændrer det serviceundernet, hvortil kubeadm udsteder certifikater til apiserver (inklusive), skal de genudstedes:

  1. Lad os se, hvilke domæner og IP-adresser det aktuelle certifikat er blevet udstedt til:
    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. Lad os forberede en minimal konfiguration for 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. Lad os slette den gamle crt og nøgle, da uden dette vil det nye certifikat ikke blive udstedt:
    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. Lad os genudstede certifikater til API-serveren:
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. Lad os kontrollere, at certifikatet blev udstedt til det nye undernet:
    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. Efter genudstedelse af API-servercertifikatet, genstart dens container:
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. Lad os genskabe konfigurationen for admin.conf:
    kubeadm alpha certs renew admin.conf
  8. Lad os redigere dataene i 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 

    Advarsel! I dette øjeblik holder domæneopløsningen op med at fungere i klyngen, da i eksisterende pods i /etc/resolv.conf den gamle CoreDNS-adresse (kube-dns) er registreret, og kube-proxy ændrer iptables-reglerne fra det gamle undernet til det nye. Længere i artiklen er der skrevet om mulige muligheder for at minimere nedetid.

  9. Lad os rette ConfigMap's i navnerummet kube-system:
    kubectl -n kube-system edit cm kubelet-config-1.16

    - udskift her clusterDNS til den nye IP-adresse for kube-dns-tjenesten: kubectl -n kube-system get svc kube-dns.

    kubectl -n kube-system edit cm kubeadm-config

    - vi ordner det data.ClusterConfiguration.networking.serviceSubnet til et nyt undernet.

  10. Da kube-dns-adressen er ændret, er det nødvendigt at opdatere kubelet-konfigurationen på alle noder:
    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. Det eneste, der er tilbage, er at genstarte alle pods i klyngen:
    kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(S+)s+(S+).*/kubectl --namespace 1 delete pod 2/e'

Minimer nedetid

Tanker om, hvordan man minimerer nedetid:

  1. Efter at have ændret kontrolplanmanifesterne, skal du oprette en ny kube-dns-tjeneste, for eksempel med navnet kube-dns-tmp og ny adresse 172.24.0.10.
  2. lave if i etcdhelper, som ikke vil ændre kube-dns-tjenesten.
  3. Erstat adressen i alle kubelets ClusterDNS til en ny, mens den gamle service vil fortsætte med at arbejde samtidig med den nye.
  4. Vent til bælgerne med applikationer ruller over enten af ​​sig selv af naturlige årsager eller på et aftalt tidspunkt.
  5. Slet tjeneste kube-dns-tmp og ændre serviceSubnetCIDR for kube-dns-tjenesten.

Denne plan giver dig mulighed for at minimere nedetiden til ~et minut - i varigheden af ​​servicefjernelsen kube-dns-tmp og ændring af undernet for tjenesten kube-dns.

Modifikation podNetwork

Samtidig besluttede vi at se på, hvordan man ændrer podNetwork ved hjælp af den resulterende etcdhelper. Rækkefølgen af ​​handlinger er som følger:

  • rette konfigurationer i kube-system;
  • fiksering af kube-controller-manager-manifestet;
  • ændre podCIDR direkte i etcd;
  • genstart alle klynge noder.

Nu mere om disse handlinger:

1. Rediger ConfigMaps i navneområdet kube-system:

kubectl -n kube-system edit cm kubeadm-config

- korrigere data.ClusterConfiguration.networking.podSubnet til et nyt undernet 10.55.0.0/16.

kubectl -n kube-system edit cm kube-proxy

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

2. Rediger controller-manager-manifestet:

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

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

3. Se på de aktuelle værdier .spec.podCIDR, .spec.podCIDRs, .InternalIP, .status.addresses for alle klynge noder:

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. Erstat podCIDR ved at foretage ændringer direkte til 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. Lad os tjekke, at podCIDR virkelig har ændret sig:

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. Lad os genstarte alle klynge noder én efter én.

7. Hvis du forlader mindst én node gammel podCIDR, så vil kube-controller-manager ikke kunne starte, og pods i klyngen vil ikke blive planlagt.

Faktisk kan ændring af podCIDR gøres endnu enklere (f.eks. ). Men vi ville lære at arbejde med etcd direkte, fordi der er tilfælde, når man redigerer Kubernetes-objekter i etcd - kun mulig variant. (Du kan for eksempel ikke bare ændre feltet Service uden nedetid spec.clusterIP.)

Total

Artiklen diskuterer muligheden for at arbejde med data i etcd direkte, dvs. omgå Kubernetes API. Nogle gange giver denne tilgang dig mulighed for at gøre "vanskelige ting". Vi testede operationerne i teksten på rigtige K8s-klynger. Men deres status som klar til udbredt brug er PoC (proof of concept). Derfor, hvis du ønsker at bruge en ændret version af etcdhelper-værktøjet på dine klynger, skal du gøre det på egen risiko.

PS

Læs også på vores blog:

Kilde: www.habr.com

Tilføj en kommentar