ProHoster > блог > адміністраванне > Наш досвед працы з дадзенымі ў etcd Kubernetes-кластара напрамую (без K8s API)
Наш досвед працы з дадзенымі ў etcd Kubernetes-кластара напрамую (без K8s API)
Усё часцей да нас звяртаюцца кліенты з просьбай забяспечыць доступ у Kubernetes-кластар для магчымасці звароту да сэрвісаў унутры кластара: каб можна было напрамую падключыцца да нейкай базы даных або сэрвісу, для сувязі лакальнага дадатку з дадаткамі ўнутры кластара…
Напрыклад, узнікае запатрабаванне падлучыцца са сваёй лакальнай машыны да сэрвісу. memcached.staging.svc.cluster.local. Мы даем такую магчымасць з дапамогай VPN унутры кластара, да якога падключаецца кліент. Для гэтага анансуем падсеткі pod'аў, сэрвісаў і push'ім кластарныя DNS кліенту. Такім чынам, калі кліент спрабуе далучыцца да сэрвісу memcached.staging.svc.cluster.local, запыт сыходзіць у DNS кластара і ў адказ атрымлівае адрас дадзенага сэрвісу з сэрвіснай сеткі кластара ці адрас pod'а.
K8s-кластары мы наладжваем з дапамогай kubeadm, дзе па змаўчанні сэрвісная падсетка. 192.168.0.0/16, а сетка pod'ов - 10.244.0.0/16. Звычайна ўсё добра працуе, але ёсць пара момантаў:
Падсетка 192.168.*.* часта выкарыстоўваецца ў офісных сетках кліентаў, а яшчэ часцей - у хатніх сетках распрацоўшчыкаў. І тады ў нас атрымліваюцца канфлікты: хатнія роўтэры працуюць у гэтай падсетцы і VPN push'іт гэтыя падсеткі з кластара кліенту.
У нас ёсць некалькі кластараў (кластары production, stage і/або некалькі dev-кластэраў). Тады ва ўсіх іх па змаўчанні будуць аднолькавыя падсеткі для pod'ов і сэрвісаў, што стварае вялікія складанасці для адначасовай працы з сэрвісамі ў некалькіх кластарах.
Мы ўжо даўнавата прынялі практыку выкарыстання розных падсетак для сэрвісаў і pod'ов у рамках аднаго праекту — увогуле, каб усе кластары былі з рознымі сеткамі. Аднак ёсць вялікая колькасць кластараў у працы, якія не хацелася б перакочваць з нуля, бо ў іх запушчаны шматлікія сэрвісы, stateful-прыкладанні і да т.п.
І тады мы задаліся пытаннем: як бы памяняць падсетку ў існуючым кластары?
Пошук рашэнняў
Найбольш распаўсюджаная практыка - перастварыць ўсё сэрвісы з тыпам ClusterIP. Як варыянт, могуць параіць і такое:
Гэтыя працэсы маюць пытанне: пасля таго, як configured, pods pokračuje s starým IP, a to DNS nameserver in /etc/resolv.conf.
Так, я лічу, што не выконвае патрэбу, і яна павінна аднавіць цэнтр cluster with kubeadm reset and init it again.
Але не ўсім гэта падыходзіць… Вось больш дэталёвыя ўступныя для нашага выпадку:
Выкарыстоўваецца Flannel;
Ёсць кластара як у аблоках, так і на жалезе;
Жадалася бы пазбегнуць паўторнага дэплою ўсіх сэрвісаў у кластары;
Ёсць патрэба ўвогуле зрабіць усё з мінімальнай колькасцю праблем;
Версія Kubernetes - 1.16.6 (зрэшты, далейшыя дзеянні будуць аналагічныя і для іншых версій);
Асноўная задача зводзіцца да таго, каб у кластары, разгорнутым з дапамогай kubeadm з сэрвіснай падсеткай 192.168.0.0/16, замяніць яе на 172.24.0.0/16.
І так ужо супала, што нам даўно было цікава паглядзець, што і як у Kubernetes захоўваецца ў etcd, што ўвогуле з гэтым можна зрабіць… Вось і падумалі: «Чаму б проста не абнавіць дадзеныя ў etcd, замяніўшы старыя IP-адрасы (падсетку) на новыя? »
Пашукаўшы гатовыя прылады для працы з дадзенымі ў etcd, мы не знайшлі нічога цалкам вырашальнага пастаўленую задачу. (Дарэчы, калі вы ведаеце аб любых утылітах для працы з дадзенымі напрамую ў etcd – будзем удзячныя за спасылкі.) Аднак добрай адпраўной кропкай стала etcdhelper ад OpenShift(дзякуй яго аўтарам!).
Гэтая ўтыліта ўмее падлучацца да etcd з дапамогай сертыфікатаў і чытаць адтуль дадзеныя з дапамогай каманд ls, get, dump.
Дапісваем etcdhelper
Наступная думка заканамерная: "Што замінае дапісаць гэтую ўтыліту, дадаўшы магчымасць запісу дадзеных у etcd?"
Яна ўвасобілася ў мадыфікаваную версію etcdhelper з дзвюма новымі функцыямі changeServiceCIDR и changePodCIDR. На яе код можна паглядзець тут.
Што выконваюць новыя функцыі? Алгарытм changeServiceCIDR:
ствараем дэсерыялізатар;
кампілюемы рэгулярны выраз для замены CIDR;
праходзім па ўсіх сэрвісах з тыпам ClusterIP у кластары:
дэкадуем значэнне з etcd у Go-аб'ект;
з дапамогай рэгулярнага выразы заменны першыя два байта адрасу;
прысвойваем сэрвісу IP-адрас з новай падсеткі;
ствараем серыялізатар, пераўтворым Go-аб'ект у protobuf, запісваем новыя дадзеныя ў etcd.
Функцыя changePodCIDR па сутнасці аналагічна changeServiceCIDR — толькі замест рэдагавання спецыфікацыі сэрвісаў мы робім гэта для вузла і мяняем .spec.PodCIDR на новую падсетку.
Практыка
Змена serviceCIDR
План па рэалізацыі пастаўленай задачы - вельмі просты, але мае на ўвазе даунтайм на момант перастварэння ўсіх pod'ов ў кластары. Пасля апісання асноўных крокаў мы таксама падзелімся думкамі, як у тэорыі можна мінімізаваць гэты просты.
Падрыхтоўчыя дзеянні:
усталёўка неабходнага ПА і зборка пропатченного etcdhelper;
бэкап etcd і /etc/kubernetes.
Кароткі план дзеянняў па змене serviceCIDR:
змена маніфестаў apiserver'а і controller-manager'а;
перавыпуск сертыфікатаў;
змена ClusterIP сэрвісаў у etcd;
рэстарт ўсіх pod'аў у кластары.
Далей прадстаўлена поўная паслядоўнасць дзеянняў у дэталях.
Захоўваем сабе 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
4. Мяняем сэрвісную падсетку ў маніфестах Kubernetes control plane. У файлах /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'а (у тым ліку), іх неабходна перавыпусціць:
Паглядзім, на якія дамены і 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
Увага! У гэты момант у кластары перастае працаваць рэзалінг даменаў, бо ва ўжо існуючых pod'ах у /etc/resolv.conf прапісаны стары адрас CoreDNS (kube-dns), а kube-proxy змяніў правілы iptables са старой падсеткі на новую. Далей у артыкуле напісана аб магчымых варыянтах мінімізаваць просты.
Паправім 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 на новую падсетку.
Паколькі змяніўся адрас kube-dns, неабходна абнавіць канфіг kubelet на ўсіх вузлах:
7. Калі хаця б у аднаго вузла пакінуць стары podCIDR, то kube-controller-manager не зможа запусціцца, а pod'ы ў кластары не будуць планавацца.
Насамрэч, змена podCIDR можна зрабіць і прасцей (напрыклад, так). Але ж нам хацелася навучыцца працаваць з etcd напрамую, таму што існуюць выпадкі, калі праўка аб'ектаў Kubernetes у etcd. адзіны магчымы варыянт. (Напрыклад, нельга проста так без прастою змяніць у Service поле spec.clusterIP.)
Вынік
У артыкуле разгледжана магчымасць працы з дадзенымі ў etcd напрамую, г.зн. у абыход Kubernetes API. Часам такі падыход дазваляе рабіць "хітрыя штукі". Прыведзеныя ў тэксце аперацыі мы тэставалі на рэальных K8s-кластарах. Аднак іх статус гатоўнасці да шырокага прымянення. PoC (proof of concept). Таму, калі вы хочаце выкарыстоўваць мадыфікаваную версію ўтыліты etcdhelper на сваіх кластарах, рабіце гэта на свой страх і рызыку.