Den beste arkitekturen med Docker og Kubernetes - myte eller virkelighet?

Hvordan har verden av programvareutvikling endret seg i Docker og Kubernetes-tiden? Er det mulig å bygge en arkitektur en gang for alle ved hjelp av disse teknologiene? Er det mulig å forene prosessene for utvikling og integrasjon når alt er "pakket" i containere? Hva er kravene til slike beslutninger? Hvilke begrensninger bringer de i spill? Vil de gjøre livet til utviklere enklere, eller i stedet legge unødvendige komplikasjoner til det?

Det er på tide å belyse disse (og noen andre) spørsmål! (I tekst og originale illustrasjoner.)

Denne artikkelen tar deg med på en reise fra det virkelige liv til utviklingsprosesser til arkitektur og tilbake til det virkelige liv, og gir svar på de viktigste spørsmålene på hvert av disse stoppene underveis. Vi vil prøve å identifisere en rekke komponenter og prinsipper som bør bli en del av en arkitektur og demonstrere noen få eksempler uten å gå inn på riket for implementeringen.

Konklusjonen på artikkelen kan forstyrre eller glede deg. Det avhenger av opplevelsen din, din oppfatning av denne tre-kapittel historien, og kanskje til og med humøret ditt når du leser. La meg få vite hva du synes ved å legge ut kommentarer eller spørsmål nedenfor!

Fra det virkelige til utviklingsarbeid

For det meste tjente alle utviklingsprosesser jeg noensinne har sett eller fått æren av å sette opp et enkelt mål - redusere tiden mellom fødselen av en idé og leveringen til produksjonen, samtidig som en viss grad av kodekvalitet opprettholdes.

Det har ikke noe å si om ideen er god eller dårlig. Dårlige ideer kommer og går raskt - du bare prøver dem og slår dem ned for å gå i oppløsning. Det som er verdt å nevne her er at å rulle tilbake fra en dårlig idé faller på skuldrene til en robot som automatiserer arbeidsflyten din.

Kontinuerlig integrering og levering virker som en livredder i programvareutviklingens verden. Hva kan tross alt være enklere enn det? Du har en idé, du har koden, så gå etter den! Det ville vært feilfritt om ikke for et lite problem - integrasjons- og leveringsprosessen er ganske vanskelig å formalisere isolert fra teknologien og forretningsprosessene som er spesifikke for bedriften din.

Til tross for oppgavens tilsynelatende kompleksitet, kaster livet stadig ut gode ideer som bringer oss (vel, meg selv med sikkerhet) litt nærmere å bygge en feilfri mekanisme som kan være nyttig i nesten enhver anledning. Det siste trinnet mot en slik mekanisme for meg har vært Docker og Kubernetes, hvis abstraksjonsnivå og den ideologiske tilnærmingen fikk meg til å tenke at 80% av problemene nå kan løses ved hjelp av praktisk talt de samme metodene.

De resterende 20% gikk tydeligvis ikke noe sted. Men det er akkurat her du kan fokusere ditt indre kreative geni på interessant arbeid, i stedet for å takle de repeterende rutineoppgavene. Ved å ta vare på "arkitektoniske rammer" bare en gang, vil du glemme 80% av de løste problemene.

Hva betyr alt dette, og hvordan løser Docker problemene med utviklingsarbeidsflyten? La oss se på en enkel prosess, som også tilfeldigvis er tilstrekkelig for et flertall av arbeidsmiljøene:

Med riktig tilnærming kan du automatisere og forene alt fra sekvensen nedenfor, og glemme det i flere måneder fremover.

Sette opp et utviklingsmiljø

Et prosjekt skal inneholde en docker-compose.yml-fil, som kan skåne deg problemer med å tenke på hva og hvordan du må gjøre for å kjøre applikasjonen / tjenesten på den lokale maskinen. En enkel docker-komponere-kommando bør starte applikasjonen din med alle dens avhengigheter, fylle databasen med inventar, laste opp den lokale koden inne i beholderen, aktivere kodesporing for kompilering på farten og til slutt begynne å svare på den forventede porten. Selv når du setter opp en ny tjeneste, trenger du ikke bekymre deg for hvordan du starter, hvor du skal forandre endringer eller hvilke rammer du skal bruke. Alt dette bør beskrives på forhånd i standardinstruksjonene og dikteres av servicemaler for forskjellige oppsett: frontend, backend og worker.

Automatisert testing

Alt du vil vite om den "svarte boksen" (mer om hvorfor jeg kaller beholder, vil dette følge senere i tekst) er at alt er i orden. Ja eller nei. 1 eller 0. Når du har et begrenset antall kommandoer som kan utføres inne i beholderen, og docker-compose.yml som beskriver alle dens avhengigheter, kan du enkelt automatisere og forene tester uten å fokusere for mye på implementeringsdetaljene.

For eksempel som dette!

Her betyr testing ikke bare og ikke så mye enhetstesting, men også funksjonstesting, integrasjonstesting, testing av (kodestil) og duplisering, kontroll av utdaterte avhengigheter, brudd på lisenser for brukte pakker og mange andre ting. Poenget er at alt dette bør være innkapslet i Docker-bildet.

Levering av systemer

Det spiller ingen rolle når og hvor du vil installere prosjektet. Resultatet, akkurat som installasjonsprosessen, skal alltid være det samme. Det er heller ingen forskjell om hvilken del av hele økosystemet du skal installere, eller hvilken gjensidig repo du får det fra. Den viktigste komponenten her er idempotens. Det eneste du bør spesifisere er variablene som kontrollerer installasjonen.

Her er algoritmen som virker veldig effektiv på å løse dette problemet:

  1. Samle bilder fra alle Dockerfiles (for eksempel som dette)
  2. Ved å bruke et metaprosjekt, kan du levere disse bildene til Kubernetes via Kube API. Å starte en leveranse krever vanligvis flere inndataparametere:
  • Kube API-sluttpunkt
  • et "hemmelig" objekt som varierer for forskjellige kontekster (lokal / showroom / iscenesettelse / produksjon)
  • navnene på systemene som skal vises og taggene til Docker-bildene for disse systemene (hentet på forrige trinn)
Som et eksempel på et metaprosjekt som omfatter alle systemer og tjenester (med andre ord et prosjekt som beskriver hvordan økosystemet er ordnet og hvordan oppdateringer leveres til det), foretrekker jeg å bruke Ansible playbooks med denne modulen for integrering med Kube API. Imidlertid kan sofistikerte automater referere til andre alternativer, og jeg vil dvele med mine egne valg senere. Imidlertid må du tenke på en sentralisert / enhetlig måte å styre arkitekturen på. Når du har en, kan du enkelt og enhetlig administrere alle tjenester / systemer og nøytralisere eventuelle komplikasjoner som den kommende jungelen av teknologier og systemer som utfører lignende funksjoner kan kaste deg.

Vanligvis er en installasjon av miljøet nødvendig i:

  • “ShowRoom” - for manuell kontroll eller feilsøking av systemet
  • “Staging” - for nærmest levende miljøer og integrasjoner med eksterne systemer (vanligvis lokalisert i DMZ i motsetning til ShowRoom)
  • “Produksjon” - det faktiske miljøet for sluttbrukeren

Kontinuitet i integrasjon og levering

Hvis du har en enhetlig måte å teste Docker-bilder - eller "svarte bokser" - kan du anta at resultatene av slike tester vil tillate deg å sømløst (og med god samvittighet) integrere funksjoner-gren i oppstrøms eller mestre grener av git oppbevaringssted.

Kanskje er den eneste avtalsbryteren her sekvensen for integrering og levering. Når det ikke er noen utgivelser, hvordan forhindrer du en "løpskondisjon" på ett system med et sett med parallelle funksjonsgrener?

Derfor bør denne prosessen startes bare når det ikke er konkurranse, ellers vil "løpstilstanden" fortsette å hjemsøke tankene dine:

  1. Forsøk å oppdatere funksjonsgrenen til oppstrøms (git rebase / merge)
  2. Bygg bilder fra Dockerfiles
  3. Test alle de innebygde bildene
  4. Start og vent til systemene med bildene fra trinn 2 er levert
  5. Hvis forrige trinn mislyktes, rull tilbake økosystemet til forrige tilstand
  6. Slå sammen inupstream med funksjonsgren og send den til depotet

Enhver feil på ethvert trinn bør avslutte leveringsprosessen og returnere oppgaven til utvikleren for å fikse feilen, enten det er en mislykket test eller en sammenslåingskonflikt.

Du kan bruke denne prosessen til å jobbe med mer enn ett depot. Bare gjør hvert trinn for alle depotene samtidig (trinn 1 for repos A og B, trinn 2 for repos A og B, og så videre), i stedet for å gjøre hele prosessen gjentatte ganger for hvert enkelt repository (trinn 1–6 for repo A , trinn 1–6 for repo B, og så videre).

I tillegg lar Kubernetes deg rulle ut oppdateringer i deler for å utføre forskjellige AB-tester og risikoanalyse. Kubernetes gjør det internt ved å skille tjenester (tilgangspunkter) og applikasjoner. Du kan alltid balansere de nye og gamle versjonene av en komponent i ønsket proporsjon for å lette problemanalyse og gjøre plass for en potensiell tilbakeføring.

Rollback-systemer

Et av de obligatoriske kravene til et arkitektonisk rammeverk er muligheten til å reversere enhver utrulling. Dette innebærer igjen en rekke eksplisitte og implisitte nyanser. Her er noen av de viktigste av dem:

  • En tjeneste skal kunne sette opp miljøet så vel som tilbakeføringsendringer. For eksempel databasemigrering, RabbitMQ-skjema og så videre.
  • Hvis det ikke er mulig å gjenopprette miljøet, bør tjenesten være polymorf og støtte både den gamle og den nye versjonen av koden. For eksempel: databasemigrasjoner skal ikke forstyrre de gamle versjonene av tjenesten (vanligvis 2 eller 3 tidligere versjoner)
  • Bakoverkompatibilitet for enhver tjenesteoppdatering. Vanligvis er dette API-kompatibilitet, meldingsformater og så videre.
Det er ganske enkelt å tilbakestille tilstander i en Kubernetes-klynge (kjør kubectl-utrulling angre distribusjon / noe-distribusjon og Kubernetes vil gjenopprette det forrige "øyeblikksbildet"), men for at dette skal fungere, bør metaprosjektet ditt inneholde informasjon om dette øyeblikksbildet. Mer komplekse leveringsrulleringsalgoritmer frarådes sterkt, selv om de noen ganger er nødvendige.

Dette er hva som kan utløse tilbakestillingsmekanismen:

  • Høy prosentandel av applikasjonsfeil etter en utgivelse
  • Signaler fra viktige overvåkingspunkter
  • Mislykkede røykprøver
  • Manuell modus - menneskelig faktor

Sikre informasjonssikkerhet og revisjon

Det er ingen enkelt arbeidsflyt som på magisk vis kan “bygge” skuddsikker sikkerhet og beskytte økosystemet ditt mot både eksterne og interne trusler, så du må sørge for at dine arkitektoniske rammer blir utført med et øye på selskapets standarder og sikkerhetspolitikk på hver side. nivå og i alle delsystemer.

Jeg vil ta opp alle tre nivåene i den foreslåtte løsningen senere, i delen om overvåking og varsling, som også tilfeldigvis er kritiske for systemintegriteten.

Kubernetes har et sett med gode innebygde mekanismer for tilgangskontroll, nettverkspolitikk, revisjon av hendelser og andre kraftige verktøy relatert til informasjonssikkerhet, som kan brukes til å bygge en utmerket beskyttelsesomkrets som kan motstå og forhindre angrep og dataslekkasjer .

Fra utviklingsarbeidsflyter til arkitektur

Et forsøk på å bygge en tett integrasjon mellom utviklingsarbeidene og økosystemet bør tas på alvor. Å legge et krav for slik integrasjon til det tradisjonelle settet med krav til en arkitektur (fleksibilitet, skalerbarhet, tilgjengelighet, pålitelighet, beskyttelse mot trusler og så videre), kan øke verdien av det arkitektoniske rammeverket betydelig. Det er et så viktig aspekt at det har resultert i fremveksten av et konsept kalt “DevOps” (Utviklingsdrift), som er et logisk skritt mot total automatisering og optimalisering av infrastrukturen. Imidlertid, gitt en godt designet arkitektur og pålitelige delsystemer, kan DevOps-oppgaver minimeres.

Mikro-tjenestearkitektur

Det er ikke nødvendig å gå inn på detaljene om fordelene med en tjenesteorientert arkitektur - SOA, inkludert hvorfor tjenester skal være "mikro". Jeg vil bare si at hvis du har bestemt deg for å bruke Docker og Kubernetes, så forstår du sannsynligvis (og godtar) at det er vanskelig og til og med ideologisk galt å ha en monolitisk arkitektur. Docker er designet for å kjøre en enkelt prosess og arbeide med utholdenhet, og tvinger oss til å tenke innenfor DDD-rammeverket (Domain-Driven Development). I Docker blir pakket kode behandlet som en svart boks med noen utsatte porter.

Kritiske komponenter og løsninger i økosystemet

Fra min erfaring med å designe systemer med økt tilgjengelighet og pålitelighet, er det flere komponenter som er avgjørende for driften av mikrotjenester. Jeg lister og snakker om hver av disse komponentene senere, og selv om jeg vil henvise til dem i sammenheng med et Kubernetes-miljø, kan du referere til listen min som en sjekkliste for enhver annen plattform.

Hvis du (som meg) har kommet til den konklusjon at det ville være flott å administrere hver av disse komponentene som en vanlig Kubernetes-tjeneste, vil jeg anbefale deg å kjøre dem i en annen klynge enn "produksjon". For eksempel en "iscenesettelse" klynge, fordi den kan redde livet ditt når produksjonsmiljøet er ustabilt og du desperat trenger en kilde til dets bilde, kode eller overvåkningsverktøy. Som løser kylling- og eggproblemet, så å si.

Identitetstjeneste

Som vanlig starter det hele med tilgang - til servere, virtuelle maskiner, applikasjoner, kontorpost og så videre. Hvis du er eller ønsker å være en klient for en av de største bedriftsplattformene (IBM, Google, Microsoft), vil tilgangsproblemet håndteres av en av leverandørens tjenester. Men hvis du vil ha din egen løsning, bare administrert av deg og innenfor budsjettet?

Denne listen skal hjelpe deg med å bestemme deg for riktig løsning og estimere innsatsen som kreves for å sette opp og vedlikeholde den. Naturligvis må valget ditt være i samsvar med selskapets sikkerhetspolicy og godkjent av informasjonssikkerhetsavdelingen.

Automatisert tjenesteyting

Selv om Kubernetes bare trenger å ha en håndfull komponenter på fysiske maskiner / sky-VM-er (docker, kubelet, kube proxy, etcd cluster), må du fremdeles automatisere tillegg av nye maskiner og klyngestyring. Her er noen enkle måter å gjøre det på:

  • KOPS - dette verktøyet lar deg installere en klynge på en av de to skyleverandørene - AWS eller GCE
  • Teraform - dette lar deg administrere infrastrukturen for ethvert miljø, og følger ideologien til IAC (Infrastructure as Code)
  • Ansible - allsidig verktøy for automatisering av noe slag
Personlig foretrekker jeg det tredje alternativet (med en liten Kubernetes integrasjonsmodul), siden det lar meg jobbe med både servere og k8s-objekter og utføre alle slags automatisering. Ingenting hindrer deg i å bruke Teraform og dens Kubernetes-modul. KOPS fungerer ikke bra med "bare metal", men det er fortsatt et flott verktøy å bruke med AWS / GCE, også!

Git repository og en task tracker

Unødvendig å si at for å sørge for fullverdig arbeid av utviklere og andre relaterte roller, må du ha et sted for diskusjoner om teamarbeid og kodelager. Jeg vil være hardt presset for å finne ut hvilken tjeneste som er best for dette, men min personlige gullstandard for oppgavesporing er redmine (gratis) eller Jira (betalt), og for kodelager - "old school" [gerrit] ( https://www.gerritcodereview.com/) (gratis) eller bitbucket (betalt).

Det er verdt å ta hensyn til de to mest konsistente (selv om kommersielle) stablene for samarbeid i et bedriftsmiljø: Atlassian og Jetbrains. Du kan bruke en av dem som en frittstående løsning eller kombinere forskjellige komponenter av begge deler.

For å få mest mulig ut av en kombinasjon av en tracker og depot, bør du tenke på integreringsstrategien. For eksempel et par tips for å sikre integriteten til koden og relaterte oppgaver (selvfølgelig kan du velge din egen tilnærming):

  • Muligheten til å "skyve" inn i et eksternt lagringssted skal bare være aktivert hvis en gren som man prøver å skyve til har det tilsvarende oppgavenummeret (TASK-1 / feature-34)
  • Enhver gren skal være tilgjengelig for sammenslåing bare etter et visst antall positive kodevurderings-iterasjoner
  • Enhver gren skal blokkeres og deaktiveres for fremtidige oppdateringer hvis den tilsvarende oppgaven ikke er “Pågår” eller en lignende status
  • Trinn beregnet på automatisering skal ikke være direkte tilgjengelig for utviklere
  • Bare autoriserte utviklere skal kunne endre modiggrenen direkte - alt annet kontrollert av en automatiseringsrobot
  • En gren skal ikke være tilgjengelig for sammenslåing hvis den tilsvarende oppgaven har noen annen status enn “For levering” eller lignende

Docker-register

Spesielt oppmerksomhet bør rettes mot et Docker-bildestyringssystem, da det er kritisk viktig for lagring og levering av tjenester. I tillegg skal dette systemet støtte tilgang for brukere og grupper av brukere, kunne slette gamle og unødvendige bilder, gi et GUI og et RESTful API.

Du kan bruke en skyløsning (for eksempel hub.docker.com) eller en privat vertskapstjeneste, som til og med kan installeres i din veldig Kubernetes-klynge. Vmware Harbor, posisjonert som en bedriftsløsning for Docker Registry, er et godt eksempel på sistnevnte. I verste fall kan du til og med bruke det gode gamle Docker-registeret hvis du bare vil lagre bilder og ikke har noe behov i et komplekst system.

CI / CD og leveringssystem for tjenester

Ingen av komponentene vi diskuterte tidligere (git repo, task tracker, metaprosjekt med Ansible Playbooks, eksterne avhengigheter) kan fungere bortsett fra hverandre som om de er suspendert i et vakuum. Det som forbinder dem er kontinuerlig integrasjons- og leveringstjeneste.

CI - Kontinuerlig integrasjons-CD - Kontinuerlig levering

Tjenesten skal være ganske enkel og fratas enhver logikk relatert til systemlevering eller konfigurasjon. Alt som en CI / CD-tjeneste skal gjøre er å reagere på hendelser fra omverdenen (endringer i git-depotet, flytte oppgaver rundt task trackeren) og starte handlingene beskrevet i metaprosjektet. I tillegg er tjenesten et kontrollpunkt for alle depotene og et verktøy for å administrere dem (grenesammenslåing, oppdateringer fra oppstrøm / master).

Jeg har historisk brukt et ganske kraftig, men likevel veldig enkelt verktøy fra Jetbrains - TeamCity, men jeg ser ikke noe problem hvis du bestemmer deg for å prøve noe annet, for eksempel gratis Jenkins.

I ordningen som vi beskrev ovenfor, er integrasjonstjenesten i det vesentlige ansvarlig for å starte de fire hovedprosessene og en tilleggsprosess, som er som følger:

  • Automatisk tjenestetesting - vanligvis for et enkelt depot, når en grenstat har endret seg eller når statusen er endret til “Venter på autotester” (eller lignende)
  • Tjenesteleveranse - vanligvis fra et metaprosjekt og for et antall tjenester (henholdsvis et antall lagre), når statusen er endret til henholdsvis “Venter på showroom” eller “Venter på levering” for QA og distribusjon av produksjonsmiljø
  • Rollback - som regel fra et metaprosjekt og for en bestemt del av en enkelt tjeneste eller en hel tjeneste, utløst av en ekstern hendelse eller i tilfelle en mislykket levering
  • Fjerning av tjenester - dette kreves for å fjerne hele økosystemet helt fra et enkelt testmiljø (showroom), når In QA-statusen er utløpt eller miljøet ikke lenger er nødvendig
  • Bildebygger (hjelpeprosessen) - kan integreres i tjenesteleveranseprosessen eller brukes uavhengig til å kompilere Docker-bilder og sende dem til Docker-registeret. Håndterer ofte brukte bilder (DB, generelle tjenester eller tjenester som ikke krever hyppige endringer)

Loggsamlings- og analysesystem

Den eneste måten for enhver Docker-container å gjøre loggene tilgjengelige er å skrive dem til STDOUT eller STDERR for root-prosessen som kjører i containeren. Tjenesteutvikler bryr seg ikke egentlig hva som skjer videre med loggdataene, det viktigste er at de skal være tilgjengelige når det er nødvendig og helst inneholde poster til et visst punkt i fortiden. Alt ansvar for å oppfylle disse forventningene ligger hos Kubernetes og ingeniørene som støtter økosystemet.

I den offisielle dokumentasjonen kan du finne en beskrivelse av den grunnleggende (og en gode) strategien for å jobbe med logger, som vil hjelpe deg å velge en tjeneste for aggregering og lagring av enorme tekstdata.

Blant de anbefalte tjenestene for et loggesystem nevner den samme dokumentasjonen flytende for innsamling av data (når de lanseres som en agent på hver node i klyngen), og Elasticsearch for lagring og indeksering av data. Selv om effektiviteten til enten du kanskje er uenig i effektiviteten til denne løsningen, men den er pålitelig og enkel å bruke, så jeg tror det i det minste er en god start.

Elasticsearch er en ressurskrevende løsning, men den skalerer godt og har ferdige Docker-bilder for å kjøre både en individuell nod og en klynge av ønsket størrelse.

Sporingssystem

Så perfekt som koden din kan være, skjer feil, og så vil du studere dem med en fin tannkam under produksjon og prøve å forstå "hva i helvete gikk galt hvis alt fungerte fint på min lokale maskin?". Sakte databaseforespørsler, feil cache, sakte disker eller tilkobling med en ekstern ressurs, transaksjoner i økosystemet, flaskehalser og underskalerte databehandlingstjenester er noen av grunnene til at du blir tvunget til å spore og estimere tiden du bruker på å utføre koden under en virkelig belastning.

Opentracing og Zipkin takler denne oppgaven for de fleste moderne programmeringsspråk og uten å legge på noen ekstra belastning etter at du har kodet inn koden. Selvfølgelig skal alle innsamlede data lagres på et passende sted, som brukes som en av komponentene.

Kompleksitetene som oppstår når du instrumenterer koden og videresender "Trace Id" gjennom alle tjenestene, meldingskøer, databaser og så videre, løses av de ovennevnte utviklingsstandardene og tjenestemaler. Sistnevnte sørger også for enhetlighet i tilnærmingen.

Overvåking og varsling

Prometheus har blitt de facto standard i moderne systemer, og enda viktigere, det støttes i Kubernetes nesten utenfor boksen. Du kan se den offisielle Kubernetes-dokumentasjonen for å finne ut mer om overvåking og varsling.

Overvåking er et av få hjelpesystemer som må installeres i en klynge. Og klyngen er en enhet som er underlagt overvåking. Men overvåking av et overvåkningssystem (unnskyld tautologien) kan bare utføres utenfra (for eksempel fra det samme ”iscenesettelsesmiljøet”). I dette tilfellet er kryssjekking nyttig som en praktisk løsning for alle distribuerte omgivelser, noe som ikke vil komplisere arkitekturen til det svært enhetlige økosystemet ditt.

Hele spekteret av overvåkning er delt inn i tre fullstendig logisk isolerte nivåer. Dette er hva jeg tror er de viktigste eksemplene på sporingspunkter på hvert nivå:

  • Fysisk nivå: - Nettverksressurser og tilgjengelighet - Disker (i / o, tilgjengelig plass) - Grunnleggende ressurser for individuelle noder (CPU, RAM, LA)
  • Klyngenivå: - Tilgjengeligheten til de viktigste klyngesystemene på hver node (kubelet, kubeAPI, DNS, osv., Og så videre) - Antallet gratis ressurser og deres enhetlige distribusjon - Overvåking av tillatt kontra faktisk ressursforbruk av tjenester - Omlasting av pods
  • Servicenivå: - Enhver form for applikasjonsovervåking - fra databaseinnhold til en frekvens av API-anrop - Antall HTTP-feil på API-gatewayen - Størrelse på køene og bruken av arbeiderne - Flere beregninger for databasen (replikasjonsforsinkelse, tid og antall transaksjoner, sakte forespørsler og mer) - Feilanalyse for ikke-HTTP-prosesser - Overvåking av forespørsler sendt til loggsystemet (du kan forvandle eventuelle forespørsler til beregninger)

Når det gjelder varslingsvarslene på hvert nivå, vil jeg anbefale å bruke en av de utallige eksterne tjenestene som kan sende varsler til e-post, SMS eller ringe til et mobilnummer. Jeg vil også nevne et annet system - OpsGenie - som har en tett integrasjon med Prometheus 'alarmmanager.

OpsGenie er et fleksibelt verktøy for varsling som hjelper deg med å håndtere opptrappinger, døgnet rundt, valg av varslingskanal og mye mer. Det er også enkelt å fordele varsler mellom team. For eksempel bør forskjellige nivåer av overvåking sende varsler til forskjellige team / avdelinger: fysisk - Infra + Devops, klynge - Devops, applikasjoner - hver til et relevant team.

API-gateway og Single Sign-on

For å håndtere oppgaver som autorisasjon, autentisering, brukerregistrering (eksterne brukere-klienter i selskapet) og andre typer tilgangskontroll, trenger du en svært pålitelig tjeneste som kan opprettholde en fleksibel integrasjon med API-porten din. Ingen skader ved å bruke den samme løsningen som for "Identitetstjenesten", men det kan være lurt å skille de to ressursene for å oppnå et annet nivå på tilgjengelighet og pålitelighet.

Integrasjonen mellom tjenester skal ikke være komplisert, og tjenestene dine skal ikke bekymre seg for autorisasjon og autentisering av brukere og hverandre. I stedet bør arkitekturen og økosystemet ha en proxy-tjeneste som håndterer all kommunikasjon og HTTP-trafikk.

La oss vurdere den mest passende måten å integrere med API-gatewayen, derav med hele ditt økosystem - tokens. Denne metoden er bra for alle tre tilgangsscenarier: fra brukergrensesnittet, fra tjeneste til service og fra et eksternt system. Da ligger oppgaven med å motta et token (basert på pålogging og passord) hos selve brukergrensesnittet eller hos tjenesteutvikleren. Det er også fornuftig å skille mellom levetiden til symboler som brukes i brukergrensesnittet (kortere TTL) og i andre tilfeller (lengre og tilpasset TTL).

Her er noen av problemene som API-gatewayen løser:

  • Tilgang til økosystemets tjenester utenfra og innenfra (tjenester kommuniserer ikke direkte med hverandre)
  • Integrasjon med en enkelt påloggingstjeneste: - Transformasjon av symboler og vedlegg til HTTPS-forespørsler med overskrifter som inneholder brukeridentifikasjonsdata (ID, roller, andre detaljer) for den forespurte tjenesten - Aktivering / deaktivering av tilgangskontroll til den forespurte tjenesten basert på rollene mottatt fra Single Sign-on-tjenesten
  • Enkelt overvåkingspunkt for HTTP-trafikk
  • Kombinere API-dokumentasjon fra forskjellige tjenester (for eksempel å kombinere Swaggers json / yml-filer
  • Evne til å administrere ruting for hele økosystemet basert på domenene og forespurte URI-er
  • Enkelt tilgangspunkt for ekstern trafikk, og integrasjon med tilgangsleverandøren

Eventbuss og Enterprise Integration / Service buss

Hvis økosystemet ditt inneholder hundrevis av tjenester som fungerer i ett makrodomen, må du håndtere tusenvis av mulige måter tjenestene kan kommunisere på. For å strømlinjeforme datastrømmer, bør du tenke på muligheten til å distribuere meldinger over et stort antall mottakere ved forekomsten av visse hendelser, uavhengig av sammenhengen til hendelsene. Med andre ord trenger du en hendelsesbuss for å publisere hendelser basert på en standardprotokoll og for å abonnere på dem.

Som en eventbuss kan du bruke et hvilket som helst system som kan betjene en såkalt megler: RabbitMQ, Kafka, ActiveMQ og andre. Generelt er høy tilgjengelighet og konsistens av data avgjørende for mikrotjenestene, men du må fortsatt ofre noe for å oppnå en riktig distribusjon og gruppering av bussen, på grunn av CAP-teoremet.

Eventuelt skal eventbussen være i stand til å løse alle slags problemer med kommunikasjon mellom tjenestene, men ettersom antallet tjenester vokser fra hundrevis til tusenvis til titusener, vil selv den beste hendelsesbussbaserte arkitekturen mislykkes, og du vil trenger å se etter en annen løsning. Et godt eksempel vil være en integrasjonsbuss-tilnærming, som kan utvide mulighetene til “Dumb pipe - Smart Consumer” -taktikken beskrevet ovenfor.

Det er mange grunner til å bruke "Enterprise Integration / Service Bus" -tilnærmingen, som har som mål å redusere kompleksiteten i en serviceorientert arkitektur. Her er bare noen av disse grunnene:

  • Aggregering av flere meldinger
  • Deling av ett arrangement i flere arrangementer
  • Synkron / transaksjonsanalyse av systemets respons på en hendelse
  • Koordinering av grensesnitt, noe som er spesielt viktig for integrasjon med eksterne systemer
  • Avansert logikk for ruting av hendelser
  • Flere integrasjoner med de samme tjenestene (utenfra og innenfra)
  • Ikke-skalerbar sentralisering av databussen
Som en åpen kildekode-programvare for en bedriftsintegrasjonsbuss, kan det være lurt å vurdere Apache ServiceMix, som inkluderer flere komponenter som er viktige for design og utvikling av denne typen SOA.

Databaser og andre stateful tjenester

I tillegg til Kubernetes, har Docker endret spillereglene en gang for alle for tjenester som krever datafasthet og jobber tett med disken. Noen sier at tjenestene skal “leve” på den gamle måten på fysiske servere eller virtuelle maskiner. Jeg respekterer denne oppfatningen, og jeg vil ikke gå inn i argumenter om fordeler og ulemper, men jeg er ganske sikker på at slike utsagn bare eksisterer på grunn av den midlertidige mangelen på kunnskap, løsninger og erfaring med å håndtere statlige tjenester i et Docker-miljø.

Jeg bør også nevne at en database ofte inntar den sentrale plassen i lagringsverdenen, og derfor bør løsningen du velger være fullt forberedt på å fungere i et Kubernetes-miljø.

Basert på min erfaring og markedssituasjonen, kan jeg skille følgende grupper av stateful tjenester sammen med eksempler på de mest passende Docker-orienterte løsningene for hver av dem:

  • Databaseadministrasjonssystemer - PostDock er en enkel og pålitelig løsning for PostgreSQL i ethvert Docker-miljø
  • Kø / meldingsmeglere - RabbitMQ er en klassisk programvare for å bygge et meldingskøsystem og dirigere meldingene. Parameteren cluster_formation i RabbitMQs konfigurasjon er uunnværlig for et klyngeoppsett
  • Bufringstjenester - gjenvurderes som en av de mest pålitelige og fleksible datacaching-løsningene
  • Fulltekstsøk - Elasticsearch-stabelen som jeg allerede har nevnt ovenfor, opprinnelig brukt til fulltekstsøk, men like bra til å lagre logger og til alle slags arbeider med store mengder tekstdata
  • Fillagringstjenester - en generaliserende gruppe tjenester for alle typer lagring og levering av filer (ftp, sftp, og så videre)

Avhengighetsspeil

Hvis du ennå ikke har opplevd en situasjon der pakkene eller avhengighetene du trenger har blitt fjernet eller gjort midlertidig utilgjengelige fra en offentlig server, ikke tro at dette aldri vil skje. For å unngå uønsket utilgjengelighet og gi sikkerhet for de interne systemene, må du sørge for at verken bygging eller levering av tjenestene dine krever en Internett-tilkobling. Konfigurer speiling og kopiering av alle avhengigheter til det interne nettverket: Docker-bilder, rpm-pakker, kildelager, python / go / js / php-moduler.

Hver av disse og andre typer avhengigheter har sine egne løsninger. Det vanligste kan googles av spørringen "privat avhengighetsspeil for ..."

Fra arkitektur til det virkelige liv

Liker det eller ikke, før eller senere vil hele arkitekturen bli dømt til å mislykkes. Det skjer alltid: teknologier blir foreldet raskt (1–5 år), metoder og tilnærminger - litt tregere (5–10 år), designprinsipper og grunnleggende - av og til (10–20 år), men likevel uunngåelig.

Vær oppmerksom på foreldelsen fra teknologi, prøv alltid å holde økosystemet ditt på toppen av teknologiske nyvinninger, planlegg og rulle ut nye tjenester for å imøtekomme behovene til utviklere, næringsliv og sluttbrukere, promoter nye verktøy til interessentene dine, leverer kunnskap for å flytte dine team og selskapet fremover.

Hold deg oppdatert på spillet ved å integrere deg i fagmiljøet, lese relevant litteratur og omgås kolleger. Vær oppmerksom på mulighetene dine, så vel som riktig bruk av nye trender i prosjektet ditt. Eksperimenter og bruk vitenskapelige metoder for å analysere resultatene av forskningen din, eller stole på konklusjonene fra andre mennesker som du stoler på og respekterer.

Det er vanskelig å forberede deg på grunnleggende endringer, men likevel mulig hvis du er en ekspert på ditt felt. Alle av oss vil bare være vitne til noen få store teknologiske endringer i løpet av livet, men det er ikke mengden kunnskap i hodene våre som gjør oss profesjonelle og bringer oss til toppen, det er åpenheten for ideene våre og muligheten til å akseptere metamorfose.

Når du går tilbake til spørsmålet fra tittelen, "er det mulig å bygge en bedre arkitektur?" Nei, ikke "en gang for alle", men sørg for å strebe etter det og på et tidspunkt "for en kort tid", du vil helt sikkert lykkes!

PS:

Den opprinnelige artikkelen ble skrevet på russisk, så takk til min kollega i Lazada Sergey Rodin for fantastisk hjelp til å oversette den!