Нашето искуство со работа со податоци во etcd Kubernetes кластер директно (без K8s API)

Сè почесто клиентите бараат од нас да обезбедиме пристап до кластерот Kubernetes за да можат да пристапат до услугите во кластерот: да можат директно да се поврзат со некоја база на податоци или услуга, да поврзат локална апликација со апликации во кластерот...

Нашето искуство со работа со податоци во etcd Kubernetes кластер директно (без K8s API)

На пример, има потреба да се поврзете од вашата локална машина на услуга memcached.staging.svc.cluster.local. Ние ја обезбедуваме оваа можност користејќи VPN во кластерот на кој се поврзува клиентот. За да го направите ова, објавуваме подмрежи од подмрежи, услуги и туркаме кластер DNS на клиентот. Така, кога клиентот се обидува да се поврзе со услугата memcached.staging.svc.cluster.local, барањето оди до кластерот DNS и како одговор ја добива адресата на оваа услуга од мрежата за услуги на кластерот или адресата на подлогата.

Ние ги конфигурираме кластерите K8s користејќи kubeadm, каде што е стандардната подмрежа на услугата 192.168.0.0/16, а мрежата на мешунки е 10.244.0.0/16. Обично сè работи добро, но има неколку точки:

  • Подмрежа 192.168.*.* често се користи во канцелариски мрежи на клиенти, а уште почесто во домашни мрежи на програмери. И тогаш добиваме конфликти: домашните рутери работат на оваа подмрежа и VPN ги турка овие подмрежи од кластерот до клиентот.
  • Имаме неколку кластери (продукција, сцена и/или неколку дев-кластери). Потоа, стандардно, сите ќе имаат исти подмрежи за подмрежи и услуги, што создава големи тешкотии за истовремена работа со услуги во неколку кластери.

Одамна ја усвоивме практиката да користиме различни подмрежи за услуги и подови во рамките на истиот проект - генерално, така што сите кластери имаат различни мрежи. Сепак, постојат голем број кластери во работа кои не би сакал да ги превртам од нула, бидејќи тие работат многу услуги, државни апликации итн.

И тогаш се запрашавме: како да ја смениме подмрежата во постоечки кластер?

Пребарување на одлуки

Најчеста практика е да се рекреира сите услуги со тип ClusterIP. Како опција, може да советува и ова:

Следниот процес има проблем: по сè што е конфигурирано, подовите доаѓаат со старата IP адреса како сервер за имиња на DNS во /etc/resolv.conf.
Бидејќи сè уште не го најдов решението, морав да го ресетирам целиот кластер со reset на kubeadm и повторно да го иницирам.

Но, ова не е погодно за секого... Еве подетални воведи за нашиот случај:

  • Се користи фланелен;
  • Има кластери и во облаците и на хардверот;
  • Би сакал да избегнам повторно распоредување на сите услуги во кластерот;
  • Постои потреба генерално да се прави сè со минимален број проблеми;
  • Верзијата на Kubernetes е 1.16.6 (сепак, понатамошните чекори ќе бидат слични за другите верзии);
  • Главната задача е да се осигура дека во кластер е распореден со користење на kubeadm со сервисна подмрежа 192.168.0.0/16, заменете го со 172.24.0.0/16.

И така се случи што долго време бевме заинтересирани да видиме што и како во Kubernetes се чува во etcd, што може да се направи со него... Така си помисливме:Зошто не само ажурирање на податоците во etcd, заменувајќи ги старите IP адреси (подмрежа) со нови? "

Откако баравме готови алатки за работа со податоци во etcd, не најдовме ништо што целосно го реши проблемот. (Патем, ако знаете за какви било алатки за работа со податоци директно во etcd, би ги цениле врските.) Сепак, добра почетна точка е итн.помошник од OpenShift (благодарение на неговите автори!).

Оваа алатка може да се поврзе со etcd користејќи сертификати и да чита податоци од таму користејќи команди ls, get, dump.

Додадете etcdhelper

Следната мисла е логична: „Што ве спречува да ја додадете оваа алатка со додавање на способност за пишување податоци на итн.?“

Стана изменета верзија на etcdhelper со две нови функции changeServiceCIDR и changePodCIDR. на неа можете да го видите кодот тука.

Што прават новите функции? Алгоритам changeServiceCIDR:

  • создадете десерилизатор;
  • состави регуларен израз за замена на CIDR;
  • ги поминуваме сите услуги со типот ClusterIP во кластерот:
    • дешифрирајте ја вредноста од etcd во објект Go;
    • користејќи регуларен израз ги заменуваме првите два бајта од адресата;
    • доделете на услугата IP адреса од новата подмрежа;
    • креирајте серијализатор, претворете го објектот Go во протобуф, напишете нови податоци во итн.

Функција changePodCIDR суштински слични changeServiceCIDR - само наместо да ја уредуваме спецификацијата на услугата, тоа го правиме за јазолот и менуваме .spec.PodCIDR до нова подмрежа.

Пракса

Променете ја услугата CIDR

Планот за имплементација на задачата е многу едноставен, но вклучува прекини во времето на повторно создавање на сите мешунки во кластерот. Откако ќе ги опишеме главните чекори, ќе споделиме и размислувања за тоа како, теоретски, ова време на застој може да се минимизира.

Подготвителни чекори:

  • инсталирање на потребниот софтвер и склопување на закрпениот etcdhelper;
  • резервна копија итн /etc/kubernetes.

Краток акционен план за промена на услугатаCIDR:

  • менување на манифестациите на apiserver и контролер-менаџер;
  • повторно издавање на сертификати;
  • менување на ClusterIP услугите во etcd;
  • рестартирање на сите мешунки во кластерот.

Следното е целосен редослед на дејства во детали.

1. Инсталирајте го etcd-client за депонирање податоци:

apt install etcd-client

2. Изгради etcdhelper:

  • Инсталирајте голанг:
    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
  • Заштедуваме за себе etcdhelper.go, преземете зависности, соберете:
    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. Направете резервна копија итн.

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. Променете ја услужната подмрежа во контролната рамнина на Кубернетес. Во датотеките /etc/kubernetes/manifests/kube-apiserver.yaml и /etc/kubernetes/manifests/kube-controller-manager.yaml сменете го параметарот --service-cluster-ip-range до нова подмрежа: 172.24.0.0/16 наместо 192.168.0.0/16.

5. Бидејќи ја менуваме подмрежата на услугата на која kubeadm издава сертификати за apiserver (вклучително), тие треба да се реиздадат:

  1. Ајде да видиме за кои домени и IP адреси е издаден тековниот сертификат:
    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. Ајде да подготвиме минимална конфигурација за 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. Ајде да ги избришеме старите crt и клуч, бидејќи без ова новиот сертификат нема да се издаде:
    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. Ајде повторно да издадеме сертификати за серверот API:
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. Ајде да провериме дали сертификатот е издаден за новата подмрежа:
    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. По повторното издавање на сертификатот за серверот API, рестартирајте го неговиот контејнер:
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. Ајде да ја регенерираме конфигурацијата за admin.conf:
    kubeadm alpha certs renew admin.conf
  8. Ајде да ги уредиме податоците во 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 

    Предупредување! Во овој момент, резолуцијата на доменот престанува да работи во кластерот, бидејќи во постоечките подлоги /etc/resolv.conf старата CoreDNS адреса (kube-dns) е регистрирана и kube-proxy ги менува правилата iptables од старата подмрежа во новата. Понатаму во написот пишува за можните опции за минимизирање на времето на застој.

  9. Ајде да ги поправиме ConfigMap во именскиот простор kube-system:
    kubectl -n kube-system edit cm kubelet-config-1.16

    - замени овде clusterDNS до новата IP адреса на услугата kube-dns: kubectl -n kube-system get svc kube-dns.

    kubectl -n kube-system edit cm kubeadm-config

    - ќе го поправиме data.ClusterConfiguration.networking.serviceSubnet до нова подмрежа.

  10. Бидејќи адресата kube-dns е променета, неопходно е да се ажурира конфигурацијата kubelet на сите јазли:
    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. Останува само да се рестартираат сите подлоги во кластерот:
    kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(S+)s+(S+).*/kubectl --namespace 1 delete pod 2/e'

Минимизирајте го времето на застој

Размислувања за тоа како да се минимизира времето на застој:

  1. Откако ќе ја смените контролната рамнина, креирајте нова услуга kube-dns, на пример, со името kube-dns-tmp и нова адреса 172.24.0.10.
  2. Направете if во etcdhelper, што нема да ја измени услугата kube-dns.
  3. Заменете ја адресата во сите кубелети ClusterDNS на нов, додека стариот сервис ќе продолжи да работи истовремено со новиот.
  4. Почекајте додека мешунките со апликации не се превртат сами од природни причини или во договорено време.
  5. Избришете ја услугата kube-dns-tmp и промена serviceSubnetCIDR за услугата kube-dns.

Овој план ќе ви овозможи да го минимизирате времето на застој на ~една минута - за времетраењето на отстранувањето на услугата kube-dns-tmp и промена на подмрежата за услугата kube-dns.

Подмрежа за модификација

Во исто време, решивме да погледнеме како да ја измениме podNetwork користејќи го добиениот etcdhelper. Редоследот на дејствата е како што следува:

  • фиксирање на конфигурации во kube-system;
  • фиксирање на манифестот кубе-контролер-менаџер;
  • промена на podCIDR директно во etcd;
  • рестартирајте ги сите јазли на кластерот.

Сега повеќе за овие акции:

1. Изменете ги ConfigMap's во именскиот простор kube-system:

kubectl -n kube-system edit cm kubeadm-config

- корекција data.ClusterConfiguration.networking.podSubnet до нова подмрежа 10.55.0.0/16.

kubectl -n kube-system edit cm kube-proxy

- корекција data.config.conf.clusterCIDR: 10.55.0.0/16.

2. Изменете го манифестот на контролор-менаџер:

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

- корекција --cluster-cidr=10.55.0.0/16.

3. Погледнете ги моменталните вредности .spec.podCIDR, .spec.podCIDRs, .InternalIP, .status.addresses за сите јазли на кластерот:

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. Заменете го podCIDR со правење промени директно во 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. Ајде да провериме дали podCIDR навистина се промени:

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. Ајде да ги рестартираме сите кластерски јазли еден по еден.

7. Ако оставите барем еден јазол стар podCIDR, тогаш kube-controller-manager нема да може да стартува, а pod-овите во кластерот нема да бидат закажани.

Всушност, менувањето на podCIDR може да се направи уште поедноставно (на пример, така). Но, сакавме да научиме како да работиме директно со etcd, бидејќи има случаи кога уредувате објекти на Kubernetes во etcd - единствениот можна варијанта. (На пример, не можете само да го промените полето Услуга без прекин spec.clusterIP.)

Вкупно

Статијата ја разгледува можноста за работа со податоци во etcd директно, т.е. заобиколувајќи го Kubernetes API. Понекогаш овој пристап ви овозможува да правите „незгодни работи“. Операциите дадени во текстот ги тестиравме на вистински кластери K8s. Сепак, нивниот статус на подготвеност за широка употреба е PoC (доказ за концепт). Затоа, ако сакате да користите изменета верзија на алатката etcdhelper на вашите кластери, направете го тоа на ваш сопствен ризик.

PS

Прочитајте и на нашиот блог:

Извор: www.habr.com

Додадете коментар