Mga lalagyan, microservice at service meshes

Sa internet isang bungkos Artikulo ΠΎ mesh ng serbisyo (service mesh), at narito ang isa pa. Hooray! Pero bakit? Pagkatapos, gusto kong ipahayag ang aking opinyon na mas maganda sana kung lumitaw ang mga service meshes 10 taon na ang nakakaraan, bago ang pagdating ng mga container platform tulad ng Docker at Kubernetes. Hindi ko sinasabi na ang aking pananaw ay mas mahusay o mas masahol kaysa sa iba, ngunit dahil ang mga service meshes ay medyo kumplikadong mga hayop, maraming mga punto ng view ay makakatulong upang mas maunawaan ang mga ito.

Pag-uusapan ko ang tungkol sa dotCloud platform, na binuo sa mahigit isang daang microservice at suportado ang libu-libong mga containerized na application. Ipapaliwanag ko ang mga hamon na aming hinarap sa pagbuo at paglulunsad nito, at kung paano makakatulong (o hindi) makakatulong ang mga service meshes.

Kasaysayan ng dotCloud

Isinulat ko ang tungkol sa kasaysayan ng dotCloud at ang mga pagpipilian sa arkitektura para sa platform na ito, ngunit hindi ko masyadong napag-usapan ang layer ng network. Kung ayaw mong sumabak sa pagbabasa huling artikulo tungkol sa dotCloud, narito ang diwa sa maikling salita: ito ay isang PaaS platform-as-a-service na nagbibigay-daan sa mga customer na magpatakbo ng malawak na hanay ng mga application (Java, PHP, Python...), na may suporta para sa malawak na hanay ng data mga serbisyo (MongoDB, MySQL, Redis...) at isang daloy ng trabaho tulad ng Heroku: Ina-upload mo ang iyong code sa platform, bubuo ito ng mga imahe ng lalagyan at ini-deploy ang mga ito.

Sasabihin ko sa iyo kung paano naidirekta ang trapiko sa platform ng dotCloud. Hindi dahil ito ay partikular na cool (bagaman ang system ay gumana nang maayos para sa oras nito!), ngunit higit sa lahat dahil sa mga modernong tool, ang gayong disenyo ay madaling maipatupad sa maikling panahon ng isang katamtamang koponan kung kailangan nila ng paraan upang iruta ang trapiko sa pagitan ng isang grupo. ng mga microservice o isang grupo ng mga application. Sa ganitong paraan, maaari mong ihambing ang mga opsyon: ano ang mangyayari kung ikaw mismo ang bubuo ng lahat o gumamit ng isang umiiral nang service mesh. Ang karaniwang pagpipilian ay gawin ito sa iyong sarili o bilhin ito.

Pagruruta ng trapiko para sa mga naka-host na application

Maaaring ilantad ng mga application sa dotCloud ang mga endpoint ng HTTP at TCP.

Mga endpoint ng HTTP dynamic na idinagdag sa configuration ng cluster ng load balancer Sakit ng ulo. Ito ay katulad ng ginagawa ng mga mapagkukunan ngayon Pagpasok sa Kubernetes at isang load balancer tulad ng Traefik.

Kumonekta ang mga kliyente sa mga HTTP endpoint sa pamamagitan ng mga naaangkop na domain, sa kondisyon na tumuturo ang domain name sa mga dotCloud load balancer. Normal lang, walang espesyal.

Mga endpoint ng TCP nauugnay sa isang numero ng port, na pagkatapos ay ipinapasa sa lahat ng mga container sa stack na iyon sa pamamagitan ng mga variable ng kapaligiran.

Maaaring kumonekta ang mga kliyente sa mga endpoint ng TCP gamit ang naaangkop na hostname (tulad ng gateway-X.dotcloud.com) at numero ng port.

Ang hostname na ito ay nagre-resolve sa "nats" server cluster (hindi nauugnay sa NATS), na magruruta ng mga papasok na koneksyon sa TCP sa tamang lalagyan (o, sa kaso ng mga serbisyong may balanseng pagkarga, sa mga tamang lalagyan).

Kung pamilyar ka sa Kubernetes, malamang na ito ay magpapaalala sa iyo ng Mga Serbisyo NodePort.

Walang katumbas na serbisyo sa dotCloud platform ClusterIP: Para sa pagiging simple, ang mga serbisyo ay na-access sa parehong paraan mula sa loob at labas ng platform.

Ang lahat ay naayos nang simple: ang mga unang pagpapatupad ng HTTP at TCP routing network ay malamang na ilang daang linya lamang ng Python bawat isa. Mga simpleng (masasabi kong walang muwang) na mga algorithm na pinino habang lumalago ang platform at lumitaw ang mga karagdagang kinakailangan.

Hindi kinakailangan ang malawakang refactoring ng umiiral na code. Sa partikular, 12 kadahilanan na apps maaaring direktang gamitin ang address na nakuha sa pamamagitan ng mga variable ng kapaligiran.

Paano ito naiiba sa isang modernong service mesh?

Limitado kakayahang makita. Wala kaming anumang sukatan para sa TCP routing mesh. Pagdating sa pagruruta ng HTTP, ang mga susunod na bersyon ay nagpakilala ng mga detalyadong sukatan ng HTTP na may mga error code at oras ng pagtugon, ngunit ang mga modernong serbisyo ng mga mesh ay higit pa, na nagbibigay ng pagsasama sa mga sistema ng pagkolekta ng sukatan tulad ng Prometheus, halimbawa.

Ang visibility ay mahalaga hindi lamang mula sa isang operational perspective (upang makatulong sa pag-troubleshoot ng mga isyu), kundi pati na rin kapag naglalabas ng mga bagong feature. Ito ay tungkol sa ligtas asul-berdeng deployment ΠΈ paglalagay ng canary.

Episyente sa pagruruta ay limitado rin. Sa dotCloud routing mesh, ang lahat ng trapiko ay kailangang dumaan sa isang kumpol ng mga nakalaang routing node. Nangangahulugan ito na potensyal na tumawid sa maraming mga hangganan ng AZ (Availability Zone) at makabuluhang pagtaas ng latency. Naaalala ko ang code sa pag-troubleshoot na gumagawa ng higit sa isang daang SQL query sa bawat page at nagbukas ng bagong koneksyon sa SQL server para sa bawat query. Kapag lokal na tumatakbo, agad na naglo-load ang page, ngunit sa dotCloud ay tumatagal ng ilang segundo upang ma-load dahil ang bawat koneksyon sa TCP (at kasunod na SQL query) ay tumatagal ng sampu-sampung millisecond. Sa partikular na kaso na ito, nalutas ng mga paulit-ulit na koneksyon ang problema.

Ang mga modernong service meshes ay mas mahusay sa pagharap sa mga ganitong problema. Una sa lahat, sinusuri nila na ang mga koneksyon ay naruta sa pinanggalingan. Ang lohikal na daloy ay pareho: ΠΊΠ»ΠΈΠ΅Π½Ρ‚ β†’ мСш β†’ сСрвис, ngunit ngayon ang mesh ay gumagana nang lokal at hindi sa mga malalayong node, kaya ang koneksyon ΠΊΠ»ΠΈΠ΅Π½Ρ‚ β†’ мСш ay lokal at napakabilis (microsecond sa halip na millisecond).

Ang mga modernong service meshes ay nagpapatupad din ng mas matalinong mga algorithm sa pagbalanse ng load. Sa pamamagitan ng pagsubaybay sa kalusugan ng mga backend, maaari silang magpadala ng mas maraming trapiko sa mas mabilis na mga backend, na nagreresulta sa pinahusay na pangkalahatang pagganap.

katiwasayan mas mabuti din. Ang dotCloud routing mesh ay ganap na tumakbo sa EC2 Classic at hindi nag-encrypt ng trapiko (batay sa pag-aakalang kung may nakapaglagay ng sniffer sa EC2 network traffic, ikaw ay nasa malaking problema). Malinaw na pinoprotektahan ng mga modernong service meshes ang lahat ng aming trapiko, halimbawa, na may magkaparehong pagpapatunay ng TLS at kasunod na pag-encrypt.

Pagruruta ng trapiko para sa mga serbisyo ng platform

Okay, napag-usapan na namin ang trapiko sa pagitan ng mga application, ngunit paano ang mismong dotCloud platform?

Ang platform mismo ay binubuo ng halos isang daang microservice na responsable para sa iba't ibang mga function. Ang ilan ay tumanggap ng mga kahilingan mula sa iba, at ang ilan ay mga background na manggagawa na kumonekta sa iba pang mga serbisyo ngunit hindi tumatanggap ng mga koneksyon mismo. Sa anumang kaso, dapat malaman ng bawat serbisyo ang mga endpoint ng mga address na kailangan nitong kumonekta.

Maaaring gamitin ng maraming serbisyong may mataas na antas ang routing mesh na inilarawan sa itaas. Sa katunayan, marami sa mahigit isang daang microservice ng dotCloud ang na-deploy bilang mga regular na application sa mismong platform ng dotCloud. Ngunit ang isang maliit na bilang ng mga serbisyong mababa ang antas (lalo na ang mga nagpapatupad ng routing mesh na ito) ay nangangailangan ng isang bagay na mas simple, na may mas kaunting mga dependency (dahil hindi sila umasa sa kanilang sarili upang gumana - ang magandang lumang problema sa manok at itlog).

Ang mababang antas, kritikal sa misyon na mga serbisyong ito ay na-deploy sa pamamagitan ng direktang pagpapatakbo ng mga container sa ilang pangunahing node. Sa kasong ito, hindi ginamit ang mga karaniwang serbisyo ng platform: linker, scheduler at runner. Kung gusto mong ihambing sa mga modernong container platform, ito ay tulad ng pagpapatakbo ng isang control plane na may docker run direkta sa mga node, sa halip na italaga ang gawain sa Kubernetes. Ito ay medyo katulad sa konsepto mga static na module (pods), na ginagamit nito kubeadm o bootkube kapag nagbo-boot ng isang standalone na kumpol.

Ang mga serbisyong ito ay nalantad sa simple at magaspang na paraan: isang YAML file ang nakalista sa kanilang mga pangalan at address; at ang bawat kliyente ay kailangang kumuha ng kopya ng YAML file na ito para sa pag-deploy.

Sa isang banda, ito ay lubos na maaasahan dahil hindi ito nangangailangan ng suporta ng isang panlabas na key/value store tulad ng Zookeeper (tandaan, etcd o Consul ay wala pa noong panahong iyon). Sa kabilang banda, naging mahirap ang paglipat ng mga serbisyo. Sa tuwing may gagawing paglipat, lahat ng kliyente ay makakatanggap ng na-update na YAML file (at posibleng mag-reboot). Hindi masyadong komportable!

Kasunod nito, nagsimula kaming magpatupad ng bagong scheme, kung saan ang bawat kliyente ay nakakonekta sa isang lokal na proxy server. Sa halip na isang address at port, kailangan lamang nitong malaman ang numero ng port ng serbisyo, at kumonekta sa pamamagitan ng localhost. Pinangangasiwaan ng lokal na proxy ang koneksyong ito at ipinapasa ito sa aktwal na server. Ngayon, kapag inililipat ang backend sa isa pang makina o pag-scale, sa halip na i-update ang lahat ng kliyente, kailangan mo lang i-update ang lahat ng mga lokal na proxy na ito; at hindi na kailangan ng reboot.

(Pinaplano din na i-encapsulate ang trapiko sa mga koneksyon sa TLS at maglagay ng isa pang proxy server sa gilid ng pagtanggap, pati na rin i-verify ang mga sertipiko ng TLS nang walang paglahok ng serbisyo sa pagtanggap, na naka-configure upang tumanggap ng mga koneksyon lamang sa localhost. Higit pa tungkol dito mamaya).

Ito ay halos kapareho sa SmartStack mula sa Airbnb, ngunit ang makabuluhang pagkakaiba ay ang SmartStack ay ipinatupad at na-deploy sa produksyon, habang ang panloob na sistema ng pagruruta ng dotCloud ay naitigil nang ang dotCloud ay naging Docker.

Personal kong itinuturing ang SmartStack bilang isa sa mga nauna sa mga system tulad ng Istio, Linkerd at Consul Connect dahil lahat sila ay sumusunod sa parehong pattern:

  • Magpatakbo ng proxy sa bawat node.
  • Kumonekta ang mga kliyente sa proxy.
  • Ina-update ng control plane ang proxy configuration kapag nagbago ang mga backend.
  • ... Kita!

Modernong pagpapatupad ng isang service mesh

Kung kailangan nating magpatupad ng katulad na grid ngayon, maaari tayong gumamit ng mga katulad na prinsipyo. Halimbawa, i-configure ang isang panloob na DNS zone sa pamamagitan ng pagmamapa ng mga pangalan ng serbisyo sa mga address sa espasyo 127.0.0.0/8. Pagkatapos ay patakbuhin ang HAProxy sa bawat node sa cluster, tumatanggap ng mga koneksyon sa bawat address ng serbisyo (sa subnet na iyon 127.0.0.0/8) at pag-redirect/pagbalanse ng load sa naaangkop na mga backend. Maaaring kontrolin ang configuration ng HAProxy confd, na nagbibigay-daan sa iyong mag-imbak ng impormasyon sa backend sa etcd o Consul at awtomatikong itulak ang na-update na configuration sa HAProxy kapag kinakailangan.

Ito ay halos kung paano gumagana ang Istio! Ngunit may ilang mga pagkakaiba:

  • Mga gamit Sugong Proxy sa halip na HAProxy.
  • Nag-iimbak ng configuration ng backend sa pamamagitan ng Kubernetes API sa halip na etcd o Consul.
  • Ang mga serbisyo ay mga inilalaan na address sa panloob na subnet (mga Kubernetes ClusterIP address) sa halip na 127.0.0.0/8.
  • May karagdagang bahagi (Citadel) upang magdagdag ng magkaparehong pagpapatunay ng TLS sa pagitan ng kliyente at mga server.
  • Sinusuportahan ang mga bagong feature gaya ng circuit breaking, distributed tracing, canary deployment, atbp.

Tingnan natin ang ilan sa mga pagkakaiba.

Sugong Proxy

Ang Envoy Proxy ay isinulat ni Lyft [kakumpitensya ng Uber sa merkado ng taxi - approx. lane]. Ito ay katulad sa maraming paraan sa iba pang mga proxy (hal. HAProxy, Nginx, Traefik...), ngunit isinulat ni Lyft ang kanila dahil kailangan nila ng mga feature na kulang sa ibang mga proxy, at tila mas matalinong gumawa ng bago kaysa i-extend ang dati.

Maaaring gamitin ang sugo sa sarili nitong. Kung mayroon akong partikular na serbisyo na kailangang kumonekta sa iba pang mga serbisyo, maaari ko itong i-configure upang kumonekta sa Envoy, at pagkatapos ay dynamic na i-configure at muling i-configure ang Envoy sa lokasyon ng iba pang mga serbisyo, habang nakakakuha ng maraming mahusay na karagdagang pag-andar, tulad ng visibility. Sa halip na isang custom na library ng kliyente o mag-inject ng mga bakas ng tawag sa code, nagpapadala kami ng trapiko sa Envoy, at nangongolekta ito ng mga sukatan para sa amin.

Ngunit si Envoy ay may kakayahang magtrabaho bilang data plane (data plane) para sa service mesh. Ibig sabihin, naka-configure na ngayon si Envoy para sa mesh ng serbisyong ito kontrol na eroplano (kontrol na eroplano).

Kontrolin ang eroplano

Para sa control plane, umaasa si Istio sa Kubernetes API. Ito ay hindi masyadong naiiba sa paggamit ng confd, na umaasa sa etcd o Consul upang tingnan ang hanay ng mga susi sa data store. Ginagamit ng Istio ang Kubernetes API upang tingnan ang isang hanay ng mga mapagkukunan ng Kubernetes.

Sa pagitan nito at pagkatapos: Personal kong nakita itong kapaki-pakinabang Paglalarawan ng Kubernetes APIna nagbabasa:

Ang Kubernetes API Server ay isang β€œdumb server” na nag-aalok ng storage, versioning, validation, update, at semantics para sa API resources.

Istio ay dinisenyo upang gumana sa Kubernetes; at kung gusto mong gamitin ito sa labas ng Kubernetes, kailangan mong magpatakbo ng isang instance ng Kubernetes API server (at ang etcd helper service).

Mga address ng serbisyo

Umaasa ang Istio sa mga ClusterIP address na inilalaan ng Kubernetes, kaya ang mga serbisyo ng Istio ay tumatanggap ng panloob na address (wala sa hanay 127.0.0.0/8).

Ang trapiko sa ClusterIP address para sa isang partikular na serbisyo sa isang Kubernetes cluster na walang Istio ay naharang ng kube-proxy at ipinadala sa backend ng proxy na iyon. Kung interesado ka sa mga teknikal na detalye, ang kube-proxy ay nagse-set up ng mga panuntunan sa iptables (o mga IPVS load balancer, depende sa kung paano ito na-configure) upang muling isulat ang patutunguhang mga IP address ng mga koneksyon na papunta sa ClusterIP address.

Kapag na-install na ang Istio sa isang cluster ng Kubernetes, walang magbabago hanggang sa tahasan itong i-enable para sa isang partikular na consumer, o maging sa buong namespace, sa pamamagitan ng pagpapakilala ng container sidecar sa mga custom na pod. Ang container na ito ay magpapaikot ng isang instance ng Envoy at magse-set up ng isang set ng mga iptables na panuntunan upang harangin ang trapikong papunta sa iba pang mga serbisyo at i-redirect ang trapikong iyon sa Envoy.

Kapag isinama sa Kubernetes DNS, nangangahulugan ito na ang aming code ay maaaring kumonekta sa pamamagitan ng pangalan ng serbisyo at lahat ay "gumagana lang." Sa madaling salita, ang aming code ay naglalabas ng mga query tulad ng http://api/v1/users/4242pagkatapos api lutasin ang kahilingan para sa 10.97.105.48, haharangin ng mga panuntunan ng iptables ang mga koneksyon mula 10.97.105.48 at ipapasa ang mga ito sa lokal na Envoy proxy, at ipapasa ng lokal na proxy na iyon ang kahilingan sa aktwal na backend API. Phew!

Mga karagdagang frills

Nagbibigay din ang Istio ng end-to-end na pag-encrypt at pagpapatotoo sa pamamagitan ng mTLS (mutual TLS). Isang sangkap na tinatawag Muog.

Mayroon ding isang bahagi panghalo, na maaaring hilingin ng Envoy ng bawat isa humiling na gumawa ng espesyal na desisyon tungkol sa kahilingang iyon depende sa iba't ibang salik gaya ng mga header, backend load, atbp... (huwag mag-alala: maraming paraan para mapanatiling gumagana ang Mixer, at kahit na mag-crash ito, patuloy na gagana ang Envoy fine bilang isang proxy).

At, siyempre, binanggit namin ang visibility: Kinokolekta ng Envoy ang isang malaking halaga ng mga sukatan habang nagbibigay ng distributed tracing. Sa isang arkitektura ng microservices, kung ang isang kahilingan sa API ay dapat dumaan sa mga microservice A, B, C, at D, pagkatapos ay sa pag-log in, ang distributed tracing ay magdaragdag ng natatanging identifier sa kahilingan at iimbak ang identifier na ito sa pamamagitan ng mga subrequest sa lahat ng mga microservice na ito, na magbibigay-daan lahat ng kaugnay na tawag na kukunan. mga pagkaantala, atbp.

Paunlarin o bilhin

May reputasyon si Istio sa pagiging kumplikado. Sa kaibahan, ang pagbuo ng routing mesh na inilarawan ko sa simula ng post na ito ay medyo simple gamit ang mga umiiral na tool. Kaya, makatuwiran bang gumawa ng sarili mong service mesh sa halip?

Kung mayroon tayong katamtamang mga pangangailangan (hindi natin kailangan ang visibility, circuit breaker at iba pang mga subtleties), pagkatapos ay maiisip natin ang pagbuo ng sarili nating tool. Ngunit kung gagamitin natin ang Kubernetes, maaaring hindi na ito kailangan dahil nagbibigay na ang Kubernetes ng mga pangunahing tool para sa pagtuklas ng serbisyo at pagbalanse ng load.

Ngunit kung mayroon kaming mga advanced na kinakailangan, kung gayon ang "pagbili" ng isang mesh ng serbisyo ay tila isang mas mahusay na pagpipilian. (Ito ay hindi palaging isang "bumili" dahil ang Istio ay open source, ngunit kailangan pa rin nating maglaan ng oras sa engineering upang maunawaan, mai-deploy, at pamahalaan ito.)

Dapat ko bang piliin ang Istio, Linkerd o Consul Connect?

Sa ngayon ay Istio lang ang pinag-uusapan natin, ngunit hindi lang ito ang service mesh. Popular na alternatibo - Linkerd, at marami pa Consul Connect.

Ano ang pipiliin?

Sa totoo lang, hindi ko alam. Sa ngayon ay hindi ko itinuturing ang aking sarili na sapat ang kakayahan upang sagutin ang tanong na ito. Mayroong kaunti kawili-wili Artikulo na may paghahambing ng mga tool na ito at kahit na mga benchmark.

Isang promising diskarte ay ang paggamit ng isang tool tulad ng SuperGloo. Nagpapatupad ito ng abstraction layer upang pasimplehin at pag-isahin ang mga API na inilantad ng mga mesh ng serbisyo. Sa halip na matutunan ang partikular (at, sa palagay ko, medyo kumplikado) na mga API ng iba't ibang mga mesh ng serbisyo, maaari naming gamitin ang mga mas simpleng konstruksyon ng SuperGloo - at madaling lumipat mula sa isa't isa, na parang mayroon kaming intermediate na format ng pagsasaayos na naglalarawan sa mga interface ng HTTP at may kakayahang backend. ng pagbuo ng aktwal na pagsasaayos para sa Nginx, HAProxy, Traefik, Apache...

Nakipag-usap ako ng kaunti sa Istio at SuperGloo, at sa susunod na artikulo gusto kong ipakita kung paano magdagdag ng Istio o Linkerd sa isang umiiral na cluster gamit ang SuperGloo, at kung paano nagagawa ng huli ang trabaho, ibig sabihin, pinapayagan kang lumipat mula sa isang service mesh sa isa pa nang hindi nag-o-overwrite ng mga configuration.

Pinagmulan: www.habr.com

Magdagdag ng komento