Nia sperto kun datumoj en ktpd Kubernetes-grupo rekte (sen K8s API)

Ĉiam pli, klientoj petas nin havigi aliron al la Kubernetes-grupo por povi aliri servojn ene de la areto: por ke ili povu rekte konektiĝi al iu datumbazo aŭ servo, por konekti lokan aplikaĵon kun aplikaĵoj ene de la areto...

Nia sperto kun datumoj en ktpd Kubernetes-grupo rekte (sen K8s API)

Ekzemple, necesas konekti de via loka maŝino al servo memcached.staging.svc.cluster.local. Ni provizas ĉi tiun kapablon uzante VPN ene de la areto al kiu la kliento konektas. Por fari tion, ni anoncas subretojn de podoj, servoj kaj push cluster DNS al la kliento. Tiel, kiam kliento provas konekti al la servo memcached.staging.svc.cluster.local, la peto iras al la cluster DNS kaj en respondo ricevas la adreson de ĉi tiu servo de la cluster-serva reto aŭ la pod-adreso.

Ni agordas K8s-aretojn per kubeadm, kie estas la defaŭlta servo-subreto 192.168.0.0/16, kaj la reto de balgoj estas 10.244.0.0/16. Kutime ĉio funkcias bone, sed estas kelkaj punktoj:

  • Subreto 192.168.*.* ofte uzata en klientoficejaj retoj, kaj eĉ pli ofte en programistaj hejmaj retoj. Kaj tiam ni ricevas konfliktojn: hejmaj enkursigiloj funkcias sur ĉi tiu subreto kaj la VPN puŝas ĉi tiujn subretojn de la areto al la kliento.
  • Ni havas plurajn aretojn (produktado, scenejo kaj/aŭ pluraj dev-grupoj). Tiam, defaŭlte, ĉiuj el ili havos la samajn subretojn por podoj kaj servoj, kio kreas grandajn malfacilaĵojn por samtempa laboro kun servoj en pluraj aretoj.

Ni antaŭ longe adoptis la praktikon uzi malsamajn subretojn por servoj kaj podoj ene de la sama projekto - ĝenerale, tiel ke ĉiuj aretoj havas malsamajn retojn. Tamen, ekzistas granda nombro da aretoj en funkciado, kiujn mi ne ŝatus renversi de nulo, ĉar ili funkcias multajn servojn, ŝtatajn aplikojn ktp.

Kaj tiam ni demandis nin: kiel ŝanĝi la subreton en ekzistanta areto?

Serĉado de decidoj

La plej ofta praktiko estas rekrei ĉiuj servoj kun tipo ClusterIP. Kiel opcio, povas konsili kaj ĉi tio:

La sekva procezo havas problemon: post ĉio agordita, la podoj venas kun la malnova IP kiel DNS-nomservilo en /etc/resolv.conf.
Ĉar mi ankoraŭ ne trovis la solvon, mi devis restarigi la tutan areton per kubeadm reset kaj rekomenci ĝin.

Sed ĉi tio ne taŭgas por ĉiuj... Jen pli detalaj enkondukoj por nia kazo:

  • Flanelo estas uzata;
  • Estas aretoj kaj en la nuboj kaj sur aparataro;
  • Mi ŝatus eviti redeploji ĉiujn servojn en la areto;
  • Necesas ĝenerale fari ĉion kun minimuma nombro da problemoj;
  • Kubernetes-versio estas 1.16.6 (tamen, pliaj paŝoj estos similaj por aliaj versioj);
  • La ĉefa tasko estas certigi ke en grapolo deplojita uzante kubeadm kun servo subreto 192.168.0.0/16, anstataŭigu ĝin per 172.24.0.0/16.

Kaj okazis, ke ni delonge interesiĝis pri tio, kio kaj kiel en Kubernetes estas konservita en etcd, kion oni povas fari per ĝi... Do ni pensis: “Kial ne simple ĝisdatigi la datumojn en etcd, anstataŭigante la malnovajn IP-adresojn (subreto) per novaj? »

Serĉinte pretajn ilojn por labori kun datumoj en etcd, ni trovis nenion, kiu tute solvis la problemon. (Cetere, se vi scias pri iuj utilecoj por labori kun datumoj rekte en etcd, ni dankus la ligilojn.) Tamen, bona deirpunkto estas etcdhelper de OpenShift (dankon al ĝiaj aŭtoroj!).

Ĉi tiu ilo povas konektiĝi al etcd per atestiloj kaj legi datumojn de tie per komandoj ls, get, dump.

Aldonu etcdhelper

La sekva penso estas logika: "Kio malhelpas vin aldoni ĉi tiun utilecon aldonante la kapablon skribi datumojn al etcd?"

Ĝi fariĝis modifita versio de etcdhelper kun du novaj funkcioj changeServiceCIDR и changePodCIDR. sur ŝi vi povas vidi la kodon tie.

Kion faras la novaj funkcioj? Algoritmo changeServiceCIDR:

  • krei deserialigilon;
  • kompili regulan esprimon por anstataŭigi CIDR;
  • ni ekzamenas ĉiujn servojn kun la ClusterIP-tipo en la areto:
    • malkodi la valoron de etcd en Go-objekton;
    • uzante regulan esprimon ni anstataŭigas la unuajn du bajtojn de la adreso;
    • atribui al la servo IP-adreson de la nova subreto;
    • kreu seriigilon, konvertu la objekton Go en protobuf, skribu novajn datumojn al ktpd.

funkcio changePodCIDR esence similaj changeServiceCIDR - nur anstataŭ redakti la servospecifon, ni faras ĝin por la nodo kaj ŝanĝas .spec.PodCIDR al nova subreto.

Praktiko

Ŝanĝi servon CIDR

La plano por efektivigi la taskon estas tre simpla, sed ĝi implikas malfunkcion en la momento de rekreado de ĉiuj balgoj en la areto. Post priskribi la ĉefajn paŝojn, ni ankaŭ dividos pensojn pri kiel, teorie, ĉi tiu malfunkcio povas esti minimumigita.

Preparaj paŝoj:

  • instali la necesan programaron kaj kunmeti la flikitan etcdhelper;
  • rezerva ktpd kaj /etc/kubernetes.

Mallonga agadplano por ŝanĝi servoCIDR:

  • ŝanĝante la manifestojn apiserver kaj regilo-manaĝero;
  • reeldono de atestiloj;
  • ŝanĝante ClusterIP-servojn en etcd;
  • rekomenco de ĉiuj balgoj en la areto.

La sekvanta estas kompleta sekvenco de agoj en detalo.

1. Instalu etcd-client por datumdump:

apt install etcd-client

2. Konstruu etcdhelper:

  • Instalu 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
  • Ni ŝparas por ni mem etcdhelper.go, elŝutu dependecojn, kolektu:
    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. Faru rezervan ktpd:

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. Ŝanĝu la servan subreton en la manifestoj de la kontrolaviadiloj de Kubernetes. En dosieroj /etc/kubernetes/manifests/kube-apiserver.yaml и /etc/kubernetes/manifests/kube-controller-manager.yaml ŝanĝi la parametron --service-cluster-ip-range al nova subreto: 172.24.0.0/16 anstataŭ 192.168.0.0/16.

5. Ĉar ni ŝanĝas la servosubreton al kiu kubeadm eldonas atestojn por apiserver (inkluzive), ili devas esti reeldonitaj:

  1. Ni vidu por kiuj domajnoj kaj IP-adresoj la nuna atestilo estis eldonita:
    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. Ni preparu minimuman agordon por 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. Ni forigu la malnovajn crt kaj ŝlosilon, ĉar sen tio la nova atestilo ne estos elsendita:
    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. Ni reeldonu atestilojn por la API-servilo:
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. Ni kontrolu, ke la atestilo estis eldonita por la nova subreto:
    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. Post reeldonado de la API-servila atestilo, rekomencu ĝian ujon:
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. Ni regeneru la agordon por admin.conf:
    kubeadm alpha certs renew admin.conf
  8. Ni redaktu la datumojn en 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 

    Singardemo En ĉi tiu momento, domajna rezolucio ĉesas funkcii en la grapolo, ekde en ekzistantaj podoj /etc/resolv.conf la malnova CoreDNS-adreso (kube-dns) estas registrita, kaj kube-proxy ŝanĝas la iptables-regulojn de la malnova subreto al la nova. Plue en la artikolo estas skribita pri eblaj opcioj por minimumigi malfunkcion.

  9. Ni riparu ConfigMap-ojn en la nomspaco kube-system:
    kubectl -n kube-system edit cm kubelet-config-1.16

    - anstataŭigu ĉi tie clusterDNS al la nova IP-adreso de la servo kube-dns: kubectl -n kube-system get svc kube-dns.

    kubectl -n kube-system edit cm kubeadm-config

    - ni riparos ĝin data.ClusterConfiguration.networking.serviceSubnet al nova subreto.

  10. Ĉar la kube-dns-adreso ŝanĝiĝis, necesas ĝisdatigi la kubelet-agordon ĉe ĉiuj nodoj:
    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. Restas nur rekomenci ĉiujn podojn en la areto:
    kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(S+)s+(S+).*/kubectl --namespace 1 delete pod 2/e'

Minimumu malfunkcion

Pensoj pri kiel minimumigi malfunkcion:

  1. Post ŝanĝado de la kontrolebenaj manifestoj, kreu novan kube-dns-servon, ekzemple, kun la nomo kube-dns-tmp kaj nova adreso 172.24.0.10.
  2. Fari if en etcdhelper, kiu ne modifos la servon kube-dns.
  3. Anstataŭigu la adreson en ĉiuj kubeletoj ClusterDNS al nova, dum la malnova servo daŭre funkcios samtempe kun la nova.
  4. Atendu ĝis la balgoj kun aplikoj ruliĝas aŭ per si mem pro naturaj kialoj aŭ je interkonsentita tempo.
  5. Forigi servon kube-dns-tmp kaj ŝanĝi serviceSubnetCIDR por la servo kube-dns.

Ĉi tiu plano permesos al vi minimumigi malfunkcion al ~minuto - dum la daŭro de la forigo de la servo kube-dns-tmp kaj ŝanĝante la subreton por la servo kube-dns.

Modifo podReto

Samtempe, ni decidis rigardi kiel modifi podReton uzante la rezultan etcdhelper. La sekvenco de agoj estas kiel sekvas:

  • riparante agordojn en kube-system;
  • ripari la manifeston kube-controller-manager;
  • ŝanĝi podCIDR rekte en etcd;
  • rekomencu ĉiujn grapolnodojn.

Nun pli pri ĉi tiuj agoj:

1. Modifi ConfigMap-ojn en la nomspaco kube-system:

kubectl -n kube-system edit cm kubeadm-config

- korektante data.ClusterConfiguration.networking.podSubnet al nova subreto 10.55.0.0/16.

kubectl -n kube-system edit cm kube-proxy

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

2. Modifi la manifeston de regilo-administranto:

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

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

3. Rigardu la nunajn valorojn .spec.podCIDR, .spec.podCIDRs, .InternalIP, .status.addresses por ĉiuj clusternodoj:

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. Anstataŭigu podCIDR farante ŝanĝojn rekte al 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. Ni kontrolu, ke podCIDR vere ŝanĝiĝis:

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. Ni rekomencu ĉiujn grapolnodojn unu post la alia.

7. Se vi forlasas almenaŭ unu nodon malnova podCIDR, tiam kube-controller-manager ne povos komenci, kaj podoj en la areto ne estos planitaj.

Fakte, ŝanĝi podCIDR povas esti farita eĉ pli simple (ekzemple, tiel). Sed ni volis lerni kiel labori kun etcd rekte, ĉar estas kazoj kiam redaktas Kubernetes-objektojn en etcd - la sola ebla varianto. (Ekzemple, vi ne povas simple ŝanĝi la Servan kampon sen malfunkcio spec.clusterIP.)

La rezulto

La artikolo diskutas la eblecon labori kun datumoj en etcd rekte, t.e. preterirante la Kubernetes API. Kelkfoje ĉi tiu aliro permesas vin fari "malfacilajn aferojn". Ni testis la operaciojn donitajn en la teksto pri realaj K8s-aretoj. Tamen, ilia statuso de preteco por ĝeneraligita uzo estas PoC (pruvo de koncepto). Sekve, se vi volas uzi modifitan version de la utileco etcdhelper sur viaj aretoj, faru tion je via propra risko.

PS

Legu ankaŭ en nia blogo:

fonto: www.habr.com

Aldoni komenton