«Cloud native» (cloud native) eller blot «cloud» applikationer er designet specielt til at fungere i cloud-infrastrukturer. De bygges typisk som et sæt af svagt sammenkoblede mikroservices, pakket ind i containere, som igen styres af en cloud-platform. Sådanne applikationer er som standard fejltolerante, hvilket betyder, at de fungerer pålideligt og skaleres selv under alvorlige infrastrukturelle fejl. Ulempen er de begrænsninger (kontrakter), som cloud-platformen pålægger containerapplikationer for at kunne administrere dem automatisk.

Mens mange organisationer er fuldt bevidste om nødvendigheden og vigtigheden af at skifte til cloud-applikationer, ved de stadig ikke, hvor de skal begynde. I dette indlæg vil vi se på en række principper, hvis overholdelse under udviklingen af containerapplikationer vil muliggøre at frigive potentialet i cloud-platforme og opnå pålidelig drift og skalering af applikationer selv under alvorlige IT-infrastrukturfejl. Målet med de principper, der præsenteres her, er at lære at skabe applikationer, der kan administreres automatisk af cloud-platforme som Kubernetes.
Principper for softwaredesign
I programmeringsverdenen forstås principper som ret generelle regler, der skal følges ved udviklingen af software. De kan anvendes uanset programmeringssprog. Hvert princip har sine mål, som typisk opnås gennem skabeloner og praksis. Der findes også en række grundlæggende principper for at skabe kvalitetssoftware, hvoraf alle andre principper udspringer. Her er nogle eksempler på grundlæggende principper:
- (Keep it simple, stupid) – gør det ikke mere kompliceret;
- (Don’t repeat yourself) – undgå gentagelse;
- (You aren’t gonna need it) – skab ikke noget, medmindre der er et direkte behov for det;
- (Separation of concerns) – adskil ansvar.
Som man kan se, sætter disse principper ikke nogen specifikke regler, men hører til kategorien af såkaldte sund fornuft overvejelser baseret på praktisk erfaring, som mange udviklere deler og ofte henviser til.
Derudover findes der – et sæt af de fem første principper for objektorienteret programmering og design formuleret af Robert Martin. SOLID inkluderer generel og åbent fortolkede supplerende principper, som, når de anvendes samlet, hjælper med at skabe mere kvalitetsprogramsystemer og bedre vedligeholde dem på lang sigt.
SOLID-principperne relaterer sig til OOP og formuleres på et sprog af begreber og koncepter som klasser, interfaces og arv. På samme måde kan der også formuleres udviklingsprincipper for cloud-applikationer, hvor det grundlæggende element ikke er en klasse, men en container. Ved at følge disse principper kan man skabe containerapplikationer, der bedre opfylder målene og opgaverne for cloud-platforme som Kubernetes.
Cloud-orienterede containere: Red Hat-tilgangen
I dag kan man forholdsvis let pakke næsten enhver applikation ind i containere. Men for at applikationerne kan automatiseres og orkestreres effektivt inden for en cloud-platform som Kubernetes, kræves der yderligere indsats.
Grunden til de følgende ideer er og mange andre værker om forskellige aspekter af oprettelse af webapplikationer, fra kildekodeadministration til skaleringsmodeller. De beskrevne principper gælder kun for udviklingen af containerapplikationer, der er bygget på mikrotjenester og designet til cloud-platforme som Kubernetes. Det grundlæggende element i vores overvejelser er containerbilledet, mens den målrettede kørsel af containere forstås som en platform for containerorkestrering. Formålet med de foreslåede principper er at skabe containere, for hvilke opgaverne omkring planlægning (scheduling – valg af vært til at køre en containerinstans), skalerings og overvågning kan automatiseres på de fleste orkestreringsplatforme. Principperne præsenteres i vilkårlig rækkefølge.
Princip for enkelt ansvar (Single Concern Principle, SCP)
Dette princip ligner meget prinsippet om enkelt ansvar (Single Responsibility Principle, ), som er en del af SOLID-principperne og siger, at hver objekt skal have ét ansvar, og dette ansvar skal være fuldstændig inkapsuleret i klassen. Essensen af SRP er, at hver forpligtelse er en årsag til ændringer, og klassen bør have én og kun én årsag til ændring.
I SCP bruger vi ordet „opgave“ (concern) i stedet for „ansvar“ (responsibility) for at angive et højere niveau af abstraktion og en bredere anvendelse af containeren i forhold til en OOP-klasse. Og hvis målet med SRP er at have kun én årsag til ændringer, så bygger SCP på ønsket om at udvide mulighederne for genbrug og udskiftning af containere. Ved at følge SRP og skabe en container, der løser en enkelt opgave på en funktionelt afsluttet måde, øger du chancerne for at genbruge denne containers image i forskellige anvendelseskontekster.
SCP-princippet siger, at hver container skal løse en enkelt opgave og gøre det godt. Derudover opnås SCP i containerverdenen lettere end SRP i OOP-verdenen, da containere typisk udfører en enkelt proces, og denne proces løser oftest en enkelt opgave.
Hvis en eller anden container-mikrotjeneste skal løse flere opgaver samtidig, kan den opdeles i enopgave-containere og samles i en enkelt pod (enhed til implementering på containerplatformen) med hjælp af sidecar- og init-containermaler. Desuden letter SCP udskiftningen af en gammel container (f.eks. en webserver eller meddelelsesbroker) med en ny, der løser den samme opgave, men har udvidet funktionalitet eller bedre skalerbarhed.

Princippet om høj observerbarhed (High Observability Principle, HOP)
Når man bruger containere som en standardiseret metode til at pakke og køre applikationer, betragtes selve applikationerne som en «sort boks». Men hvis det drejer sig om cloud-containere, skal de tilbyde runtime-miljøet særlige API'er for at kontrollere containerens integritet og træffe de nødvendige foranstaltninger, hvis det er påkrævet. Uden dette er det umuligt at standardisere automatiseringen af containeropdateringer og deres livscyklusstyring, hvilket igen vil forringe stabiliteten og brugervenligheden af softwaresystemet.
I praksis skal en containerapplikation mindst have et API til forskellige typer integritetskontroller: livstest (liveness) og klarhedstest (readiness). Hvis applikationen kræver mere, skal den også tilbyde andre midler til at overvåge sin tilstand. For eksempel at logge vigtige hændelser via STDERR og STDOUT for at aggregere logs ved hjælp af Fluentd, Logstash og andre lignende værktøjer. Samt integration med sporings- og metrikindsamlingsbiblioteker, såsom OpenTracing, Prometheus osv.
Generelt kan applikationen stadig betragtes som en «sort boks», men den skal forsynes med alle API'er, der er nødvendige for platformen til at overvåge og administrere den på bedst mulige måde.
Livscyklusoverensstemmelsesprincip (Life-cycle Conformance Principle, LCP)
LCP er en antitese til HOP. Mens HOP siger, at containeren skal give platformen API'er til læsning, kræver LCP, at applikationen skal kunne modtage information fra platformen. Desuden skal containeren ikke kun modtage hændelser, men også tilpasse sig, med andre ord reagere på dem. Derfor er navnet på princippet, som kan betragtes som et krav om at give platformen API'er til skrivning.

Platforme har forskellige typer hændelser, der hjælper med at styre containerens livscyklus. Men det skal selv applikationen afgøre, hvilke hændelser den vil opfange, og hvordan den vil reagere.
Det er klart, at nogle hændelser er vigtigere end andre. For eksempel, hvis en applikation ikke håndterer et nødstop godt, så skal den kunne modtage signalerne: terminate (SIGTERM) og hurtigst muligt igangsætte sin afslutningsprocedure for at nå det, før den modtager signalet: kill (SIGKILL), som kommer efter SIGTERM.
Desuden kan hændelser som PostStart og PreStop være vigtige for applikationens livscyklus. For eksempel kan en applikation have brug for en vis opvarmningstid efter opstart, før den kan svare på anmodninger. Eller applikationen skal frigive ressourcer på en bestemt måde ved afslutning.
Princippet om immutabilitet af containerbilleder (Image Immutability Principle, IIP)
Det er alment accepteret, at containerapplikationer skal forblive uforandrede efter opbygning, selv om de køres i forskellige miljøer. Dette medfører behovet for at eksternalisere dataopbevaring under kørsel (med andre ord, bruge eksterne midler til det), samt at stole på eksterne konfigurationer, der er tilpasset til det specifikke køremiljø, i stedet for at ændre eller oprette unikke containere til hvert miljø. Efter ændringer i applikationen skal containerbilledet opbygges igen og distribueres i alle brugte miljøer. Forresten anvendes et lignende princip i IT-systemadministration, kendt som prinsippet om uforanderlighed af servere og infrastruktur.
Målet med IIP er at forhindre oprettelsen af separate containerbilleder til forskellige køremiljøer og i stedet bruge det samme billede sammen med den passende konfiguration til det specifikke miljø. At følge dette princip muliggør implementeringen af vigtige praksisser for automatisering af cloud-systemer, såsom roll-back og roll-forward opdateringer af applikationer.

Princippet om engangsprocesser (Process Disposability Principle, PDP)
En af de vigtigste egenskaber ved en container er dens ephemerality: en containerinstans kan nemt oprettes og nemt destrueres, så den når som helst let kan erstattes med en anden instans. Der kan være mange grunde til en sådan udskiftning: fejl ved tests, skalering af applikationen, overflytning til en anden vært, ressourceudtømning på platformen eller andre situationer.
Som følge heraf skal container-applikationer bevare deres tilstand ved hjælp af eksterne midler eller anvende interne distribuerede systemer med redundans. Desuden skal applikationen starte hurtigt og afslutte hurtigt og være klar til pludselige fatale hardwarefejl.
En af de praksisser, der hjælper med at realisere dette princip, er at skabe container med lille størrelse. Cloud-miljøer kan automatisk vælge en vært til at køre en container-forekomst, så jo mindre containeren er, desto hurtigere vil den starte – den kopieres hurtigere til mål-værten via netværket.
Selvforsyningsprincippet (Self-containment Principle, S-CP)
Ifølge dette princip inkluderes alle nødvendige komponenter i containeren under byggefasen. Containeren skal konstrueres med det for øje, at systemet kun har et rent Linux-kernel, så alle nødvendige biblioteker skal placeres i selve containeren. Her skal også være ting som runtime-miljøet for det relevante programmeringssprog, applikationsplatformen (hvis nødvendigt) og andre afhængigheder, der er nødvendige under drift af container-applikationen.

Undtagelser gøres kun for konfigurationer, der varierer fra miljø til miljø og skal leveres ved køretid, f.eks. gennem Kubernetes ConfigMap.
Applikationen kan omfatte flere containeriserede komponenter, f.eks. en separat databasecontainer som en del af en container-baseret webapplikation. Ifølge S-CP-princippet skal disse containere ikke kombineres til én, men sikres, at databasecontaineren indeholder alt nødvendigt for databasen, mens webapplikationscontaineren har alt nødvendigt for webapplikationen, herunder webserveren. Som følge heraf vil webapplikationscontaineren under drift afhænge af databasecontaineren og tilgå den efter behov.
Begrænsningsprincippet under køretid (Runtime Confinement Principle, RCP)
S-CP-princippet bestemmer, hvordan en container skal bygges, og hvad den binære fil af billedet skal indeholde. Men en container er ikke bare en "sort boks" med kun én egenskab – filstørrelse. Ved udførelse får containeren også andre dimensioner: mængden af anvendt hukommelse, CPU-tid og andre systemressourcer.

Her kommer RCP-princippet til nytte, som fastslår, at containeren skal afkoble sine krav til systemressourcerne og overføre dem til platformen. Med ressourceprofiler for hver container (hvor meget CPU, hukommelse, netværk og diskplads den har brug for) kan platformen optimere distributionen og autoskaleringen, styre IT-ressourcerne og opretholde SLA-niveauerne for containerne.
Udover at opfylde containerens ressourcekrav er det også vigtigt for applikationen ikke at overskride de rammer, den selv har sat. Ellers vil platformen med større sandsynlighed inkludere den på listen over applikationer, der skal afbrydes eller migreres, hvis ressourcerne bliver knappe.
Når vi taler om cloud-orientering, handler det primært om arbejdsmetoden.
Ovenfor har vi formuleret en række generelle principper, der danner det metodologiske fundament for at skabe kvalitetscontainere, der er tilpasset cloud-miljøer.
Bemærk, at ud over disse generelle principper vil du også have brug for yderligere avancerede metoder og teknikker til arbejdet med containere. Derudover har vi nogle korte anbefalinger, som er mere specifikke og skal anvendes (eller ikke anvendes) afhængigt af situationen:
- Stræb efter at reducere størrelsen af billederne: slet midlertidige filer og installer ikke unødvendige pakker – jo mindre containeren er, jo hurtigere kan den bygges og kopieres til den målhoste via netværket.
- Fokuser på arbitrære User-ID'er: brug ikke sudo-kommandoen eller specielle userid'er til at starte dine containere.
- Mærk vigtige porte: portnumre kan angives under udførelsen, men det er bedre at angive dem med EXPOSE-kommandoen – det bliver nemmere for andre mennesker og programmer at bruge dine billeder.
- Gem data på volumener: data, der skal bevares efter containerens destruktion, bør gemmes på volumener.
- Angiv metadata for billedet: tags, labels og annotationer gør det lettere at bruge billeder – andre udviklere vil sætte pris på det.
- Synkroniser værten og billederne: for visse containerapplikationer kræves det, at containeren synkroniseres med værten baseret på bestemte attributter, såsom tid eller maskin-ID.
- Til slut deler vi skabeloner og bedste praksisser, som vil hjælpe med mere effektivt at implementere de førnævnte principper:
11. juni kl. 11.00
Hvad du vil lære:
- Immutable Red Hat Enterprise Linux CoreOS
- OpenShift service mesh
- Operator framework
- Knative framework
Kilde: habr.com
