Kubernetes on kaikkialla läsnä konttien orkestroinnissa, eikä sen suosio näytä hiipumisen merkkejä. Tämä ei kuitenkaan tarkoita, että konttien orkestrointi olisi pysähtynyt paikalleen. Tässä blogissa esitetään perusteluja sille, miksi erityisesti Kubernetesin käyttäjien ja kehittäjien kannattaa katsoa viime vuosina tutuksi tulleen perinteisen Kubernetesin ohi kohti paradigmoja, jotka voivat soveltua paremmin Cloud Native -sovelluksiin.
Michael Vittrup Larsen
Michael is a Consultant at our office in Aarhus. He has an MScEE from Aalborg University where he specialized in digital signal processing. Before joining us Michael was working on building and optimizing cloud infrastructure for the telecoms sector. In his spare time, he likes to explore the wilderness on his mountain bike.
Kubernetesin nousu
Yksi syy Kubernetesin suureen suosioon on se, että se rakennettiin Dockerin päälle. Konteilla on pitkä historia Linuxissa ja BSD-varianteissa, mutta Docker teki niistä erittäin suosittuja keskittymällä käyttäjäkokemukseen ja tekemällä konttien rakentamisesta ja ajamisesta erittäin helppoa. Kubernetes hyödynsi konttien suosiota ja helpotti konttien ajamista eli orkestrointia laskentasolmukkeiden klusterissa.
Toinen syy Kubernetesin suosioon ja laajaan käyttöönottoon on se, että se ei muuttanut ohjelmistojen ajamisen mallia kovin paljon. Oli melko helppoa hahmottaa siirtymä siitä, miten ohjelmistoja ajettiin ennen Kubernetesia, siihen, miten niitä voidaan ajaa Kubernetesissa.
Vanhoille paradigmoille ei voi opettaa uusia temppuja
Kontti-imagien rakentaminen riippuvuuksien lukitsemiseksi ja kaikkialla toimivan käyttökokemuksen luomiseksi sekä Kubernetesin Deployment-resurssimääritykset konttireplikoiden orkestroinnin hallintaan ovat erittäin tehokas yhdistelmä. Se ei kuitenkaan poikkea radikaalisti siitä, miten hallinnoimme virtuaalikoneita ennen Dockeria ja Kubernetesia. Pieni ajattelutavan muutos helpotti Kubernetesin käyttöönottoa, mutta siksi meidän tulisi myös katsoa nykyisin tuntemamme perinteisen Kubernetesin ulkopuolelle.
Tässä blogissa tarkastellaan Kubernetesin tulevaisuutta kehittäjän näkökulmasta. Yleisesti ottaen nykyisin tuntemamme Kubernetes häviää, eikä kehittäjiä kiinnosta se. Tämä ei tarkoita, ettei Kubernetes olisi osa työkaluketjuamme, vaan että parannamme tapaa, jolla rakennamme ja operoimme sovelluksia uusien abstraktioiden avulla. Nämä abstraktiot rakentuvat Kubernetesin päälle. Sovellukset rakennetaan Kubernetes-alustalle rakennettujen alustojen avulla:
Mielenkiintoista on, että Linux oli alusta, jonka päälle rakensimme kaiken vähintään vuosikymmen sitten. Linux on edelleen kaikkialla läsnä ja osa työkaluketjuamme, mutta harva kehittäjä välittää siitä juuri, koska sen päälle on sittemmin lisätty useita abstraktioita. Sama tapahtuu nykyisin tuntemallemme perinteiselle Kubernetesille.
Uudet paradigmat pyyhkivät puhtaammaksi
Tietoturva: OIDC on salaisuuksia parempi
Kubernetes tarjoaa Secret-resurssin staattisten salaisuuksien, kuten API-avainten ja salasanojen, määrittämiseen. Kehittäjien ei tulisi käyttää Kubernetesin Secret-resursseja.
Secret-resursseihin koodatut erilliset salaisuudet voivat vuotaa, ja niiden kierrättäminen ja mitätöinti on hankalaa. GitOps-työnkuluissa salaisuudet vaativat myös erityistä huomiota, jotta niitä ei tallenneta selväkielisinä. Sovellusten tulisi sen sijaan käyttää roolipohjaista lähestymistapaa todennukseen ja valtuutukseen. Tämä tarkoittaa, että sovellusten todennuksen ja valtuutuksen tulisi perustua "siihen, keitä olemme" eikä "siihen, mitä tiedämme" eli salasanoihin tai API-avaimiin.
Vahvat identiteetit ovat kaiken tietoturvan perusta. Verkkoliikennettä ei kannata salata, jos et voi olla varma palvelimen identiteetistä, jonka kanssa kommunikoit. Sertifikaatit ja varmentajat tekevät tämän HTTPS-liikenteelle, joka yleisesti ottaen suojaa internetiä.
Kubernetesissa on järjestelmä vahvoille työkuormaidentiteeteille. Kaikki työkuormat liitetään palvelutileihin, ja niillä on Kubernetesin myöntämiä lyhytkestoisia OpenID-Connect (OIDC) identiteettitokeneita. Kubernetes API -palvelin allekirjoittaa nämä OIDC-tokenit, ja muut työkuormat voivat validoida tokenit Kubernetes API -palvelimen kautta. Tämä tarjoaa vahvat identiteetit Kubernetesissa ajettaville työkuormille, ja sitä voidaan käyttää roolipohjaisen todennuksen ja valtuutuksen perustana.
Kubernetes Secretsin sijaan kehittäjien tulisi perustaa todennus ja valtuutus OIDC-tokeneihin. Tämä tarkoittaa, että esimerkiksi tietokannan salasanan tallentamisen sijaan Secret-resurssiin meidän tulisi varmistaa, että tietokanta hyväksyy pyynnöt vain, kun niissä esitetään voimassa oleva, vanhentumaton token.
Esimerkkejä OIDC-tokenien käytöstä ulkoisiin järjestelmiin integroitumisessa ovat AWS IAM -roolit palvelutileille ja Hashicorp Vault Kubernetes auth.
Verkottuminen: Ingress ei riitä
Kubernetes tarjoaa Ingress-resurssin HTTP-liikenteen reitittämiseksi työkuormiin. Kuten Tim Hockin, yksi Kubernetesin perustajista, toteaa, Ingress-resurssissa on paljon ongelmia. Keskeinen ongelma on, että sen avulla voidaan hallita vain HTTP-liikenteen reitityksen perusteita. Jos kehittäjien annetaan käyttää Ingress-resursseja, se aiheuttaa päänvaivaa infrastruktuuri- ja Site Reliability Engineering (SRE) -tiimeille, joiden on yhdistettävä laaja infrastruktuuri ja varmistettava sen luotettava toiminta. Ingress-resurssi on liian yksinkertainen, eikä kehittäjien tulisi käyttää sitä verkottumisen määrittämiseen.
Tarve hallita ja ohjelmoida Kubernetes-verkkoa entistä paremmin näkyy service meshien yleistymisessä (katso koulutuksemme Istio service meshistä, Kialista ja Jaegerista). Ne jakavat Ingress-resurssin useiksi resursseiksi vastuiden selkeämpää erottelua varten ja tarjoavat lisätoimintoja reititykseen, havainnoitavuuteen, tietoturvaan ja vikasietoisuuteen.
Yhä useammat Kubernetesin päälle rakennetut abstraktiot edellyttävät ohjelmoitavaa verkkoa, joka tarjoaa enemmän kuin Ingress mahdollistaa (Knative, Kubeflow, Continuous Delivery -työkalut, kuten Argo Rollouts jne.). Tämä korostaa, että vankempi verkkomalli Kubernetesissa on jo de facto -standardi.
Kubernetes-yhteisö on kehittänyt Ingress v2:n eli gateway-API:n. Vaikka se ratkaisee joitakin Ingressin haasteita, se kattaa vain pienen osan toiminnoista, joita useimmat service meshit tukevat.
Kubernetes tukee ACL:iä, joilla voidaan rajoittaa, mitkä työkuormat voivat kommunikoida keskenään NetworkPolicy-resurssin avulla. Tämä resurssi toteutetaan Kubernetesin verkkoplugineissa, ja se kääntyy usein Linuxin iptables-suodatussäännöiksi eli IP-osoitteisiin perustuvaksi ratkaisuksi, joka muistuttaa palomuureja – jälleen kerran vanha paradigma. Jotkin service meshit laajentavat Kubernetesin vahvoja OIDC-pohjaisia työkuormaidentiteettejä toteuttaakseen työkuormien välisen molemminpuolisen TLS:n. Tämä tuo Kubernetesin verkkoviestintään luottamuksellisuutta ja autenttisuutta IP-osoitteita vahvempien periaatteiden pohjalta.
Kubernetes-sovellusten paketoinnissa verkkokonfiguraation sisällyttämiseen on erilaisia tapoja. Monissa Helm charteissa on Ingress-resurssimalleja. Edistyneempiin verkkoratkaisuihin siirryttäessä näitä määrityksiä ei kuitenkaan voi käyttää. Jatkossa sovellusten käyttöönottojen, kuten Helm chartien, tulisi käsitellä verkkokonfiguraatiota erillisenä kokonaisuutena, joka jätetään sovelluksen käyttöönottoartefaktin ulkopuolelle. Sovellusten verkkokonfiguraatioon ei välttämättä ole yhtä kaikille sopivaa ratkaisua, ja organisaatiot haluavat todennäköisesti kehittää omat sovellusten reitityksen käyttöönottoartefaktinsa.
Kubernetes teki verkkoyhteyksistä helppoja luomalla yhtenäisen verkon klusterin kaikkien solmujen välille. Jos sovelluksesi toimii useissa klustereissa tai pilvissä, se voi hyötyä vastaavasti yhtenäisestä verkosta klustereiden tai pilvien välillä. Kubernetesin verkkomalli ei tarjoa tätä, joten tarvitset kyvykkäämmän ratkaisun, kuten service meshin.
Organisatorisesta ja arkkitehtonisesta näkökulmasta on siis useita syitä, joiden vuoksi kehittäjien ei tulisi ohjelmoida verkkoa Ingress-resursseilla. Vaihtoehtoja on tärkeää tarkastella koko organisaation näkökulmasta, jotta verkkokonfiguraatioon ja sen hallintaan löytyy hallittava ja pitkällä aikavälillä toimiva lähestymistapa.
Työkuorman määrittely: asiaan
Lähes kaikkien Kubernetes-sovellusten ytimessä on Deployment-resurssi. Deployment on resurssi, joka määrittää, miten Podien sisällä olevista konteista koostuva työkuormamme suoritetaan. Deploymentin skaalausta voidaan hallita HorizontalPodAutoscaler-resurssilla (HPA), jotta vaihtelevaan kapasiteettitarpeeseen voidaan vastata. HPA:t käyttävät usein konttien CPU-kuormitusta Podien lisäämisen tai poistamisen mittarina, ja HPA-algoritmin vuoksi tavoitekäyttöaste on usein noin 70 %. Tämä tarkoittaa, että suunnittelemme 30 %:n hukalle. Toinen syy konservatiivisten tavoitekäyttöasteiden käyttöön on, että HPA:n reagointiaika on usein minuutti tai enemmän. Vaihtelevan kapasiteettitarpeen hallintaan tarvitsemme jonkin verran varakapasiteettia, kun HPA lisää uusia Podeja.
Työkuormien hallinta Deploymentien ja HPA:iden avulla toimii hyvin, jos sovelluksen kapasiteettitarve vaihtelee hitaasti. Mikropalveluihin, tapahtumaohjattuihin arkkitehtuureihin ja funktioihin siirryttäessä (jotka käsittelevät yhden tai mahdollisesti muutaman tapahtuman tai pyynnön ja päättyvät sitten) tämä työkuormien hallintatapa on kuitenkin kaukana ihanteellisesta.
Kubernetes Event-Driven Autocaler (KEDA) voi parantaa mikropalvelujen ja nopeasti muuttuvien työkuormien, kuten funktioiden, skaalautumista. KEDA määrittää oman joukkonsa Kubernetes-resursseja skaalautumiskäyttäytymisen määrittelyyn, ja sitä voidaan pitää HPA v3:na (koska HPA-resurssi on jo versiossa v2).
Kubernetesin Deployment-mallin, skaalauksen sekä tapahtumien ja verkon reitityksen yhdistävä kehys on Knative. Knative on Kubernetesin päälle rakentuva alusta, joka tarjoaa selkeän näkemyksen työkuormien hallintaan Knative-Service-resurssin avulla. Knativen ytimessä on CloudEvents, ja Knative-palvelut ovat käytännössä funktioita, jotka käynnistyvät ja skaalautuvat tapahtumien – joko CloudEvents-tapahtumien tai tavallisten HTTP-pyyntöjen – perusteella. Knative käyttää Pod sidecaria tapahtumamäärien seuraamiseen ja skaalautuu siksi erittäin nopeasti tapahtumamäärien muuttuessa. Knative tukee myös skaalausta nollaan, mikä mahdollistaa tarkemman työkuormien skaalauksen, joka sopii paremmin mikropalveluille ja funktioille.
Knative-palvelut toteutetaan perinteisillä Kubernetes Deployment- ja Service-resursseilla, ja Knative-palvelujen päivitykset (esimerkiksi uusi kontti-image) luovat rinnakkaiset Kubernetes Deployment- ja Service-resurssit. Knative hyödyntää tätä blue/green- ja canary-deployment-mallien toteuttamiseen, ja HTTP-liikenteen reititys on osa Knative-palveluresurssin määrittelyä.
Näin ollen Knative-palveluresurssista ja siihen liittyvistä tapahtumien reitityksen määrittelyresursseista tulee ensisijaisia resursseja, joita kehittäjät käyttävät määritellessään sovelluksensa käyttöönottoa Kubernetesissa. Kuten nykyisin käytämme Kubernetesia usein Deployment-resurssien kautta ja annamme Kubernetesin hallita Podeja, Knativen käyttö tarkoittaa, että kehittäjät keskittyvät pääasiassa Knative-palveluun ja Knative-alusta hallitsee Deploymentit.
Vaikka odotan Knative-mallin sopivan valtaosaan käyttötapauksista, kokemuksesi voi olla erilainen. Jos teet koneoppimista, Kubeflow voi olla parempi abstraktiotaso. Jos keskityt enemmän DevOpsiin ja toimitusputkiin, kpack, Tekton tai Cartographer voi olla sinulle sopiva abstraktiotaso. Teitpä Kubernetesissa mitä tahansa, siihen löytyy abstraktiotaso!
Tallennus: pois persistent volumeista
Kubernetes tarjoaa PersistentVolume- ja PersistentVolumeClaim-resurssit työkuormien tallennuksen hallintaan. Se on luultavasti vähiten suosikkini resursseista, jotka sallisin kehittäjien käyttää mihinkään muuhun kuin väliaikaiseen välimuistidataan.
Yleisellä tasolla PersistentVolumejen (PV) ongelma on, että ne yhdistävät sovelluksemme ensisijaisen vastuualueen tallennukseen liittyvään vastuualueeseen, mikä ei ole ihanteellinen Cloud Native -suunnittelumalli. Twelve-factor app -menetelmä ohjaa meitä pitämään kaikkia taustapalveluja verkon kautta liitettävinä. Tämä johtuu siitä, miten skaalaamme työkuormia vaakasuunnassa Kubernetesissa ja hallitsemme dataa (ajattele CAP-teoreemaa).
PV:t edustavat tiedostoista ja hakemistoista koostuvia tiedostojärjestelmiä, ja dataa käsitellään POSIX-tiedostojärjestelmärajapinnan kautta. Myös käyttöoikeudet perustuvat POSIX-malliin, jossa käyttäjille ja ryhmille myönnetään luku- tai kirjoitusoikeuksia. Malli ei ainoastaan sovi huonosti Cloud Native -sovellusten suunnitteluun, vaan sitä on myös hankala käyttää käytännössä. Siksi PV:t liitetään useimmiten tilassa, jossa ”kontti voi käyttää kaikkea dataa”.
Kehittäjien tulisi rakentaa tilallisia sovelluksia tilattomiksi. Tämä tarkoittaa, että dataa tulisi käsitellä sovelluksen ulkopuolella muilla abstraktioilla kuin tiedostojärjestelmillä, esimerkiksi tietokannoissa tai objektitallennuksessa. Tietokanta- ja objektitallennussovellukset voivat käyttää PV:itä tallennustarpeisiinsa, mutta infrastruktuuri-/SRE-tiimien tulisi hallinnoida näitä järjestelmiä, ja kehittäjien tulisi käyttää niitä palveluna.
Kun tallennusta tarkastellaan verkkoon liitettynä, voidaan saavuttaa huomattava parannus datan tietoturvassa. Ajatellaan esimerkiksi objektitallennusta REST APIen kautta. REST APIen avulla voimme toteuttaa todennuksen ja valtuutuksen lyhytkestoisilla käyttöoikeustokeneilla, jotka perustuvat edellä kuvattuihin Kubernetes-työkuormaidentiteetteihin.
Kun otamme käyttöön serverless-työkuormamallin, työkuormista tulee todennäköisesti dynaamisempia ja lyhytkestoisempia. Esimerkiksi serverless-funktiot voivat käsitellä yhden tapahtuman Podia kohden. Työkuormien ja ”vanhanaikaisten levyjen” välinen epäsuhta korostuu tällaisissa tilanteissa entisestään.
Kubernetesissa Container Storage Interface (CSI) on ollut rajapinta, jolla työkuormiin lisätään PV:iden kautta tiedostojärjestelmä- ja lohkotallennusta. Kubernetesin objektitallennukseen keskittyvä erityisryhmä kehittää Container Object Storage Interfacea (COSI), joka saattaa tehdä objektitallennuksesta ensiluokkaisen osan Kubernetesia.
Oi uljas uusi maailma
Olen tässä blogissa esittänyt, että Kubernetes-sovelluksia määriteltäessä on hyviä syitä katsoa ”perinteisiä” Kubernetes-resursseja pidemmälle. Tämä ei tarkoita, ettemmekö koskaan käyttäisi perinteisiä resurssityyppejä. Käytössä on edelleen legacy-sovelluksia, joita emme voi helposti muuntaa, ja SRE-tiimien voi yhä olla tarpeen ajaa tilallisia palveluita, joita kehittäjien rakentamat sovellukset voivat käyttää. Tämä korostuu erityisesti yksityisissä pilvi-infrastruktuureissa.
Kubernetesin tulevaisuus on mukautetuissa resurssimääritelmissä (CRD) ja abstraktioissa, jotka rakennamme Kubernetesin päälle ja tarjoamme käyttäjille CRD:iden kautta. Kubernetesista tulee abstraktioiden ohjaustaso, ja kehittäjien tulisi keskittyä näiden abstraktioiden CRD:ihin. Kubernetesin ohjaustasot voivat hallita resursseja Kubernetesin sisällä tai jopa sen ulkopuolella, kuten Crossplane hallitsee pilvi-infrastruktuuria.
Kuten edellä tiivistettiin, useimmille perinteisille Kubernetes-resursseille voi olla kehittäjien kannalta parempia vaihtoehtoja. Vaihtoehtojen käyttö parantaa Cloud Native -sovellusten kehittämistä ja operointia tulevina vuosina. Kubernetes on loppujen lopuksi alusta alustojen rakentamiseen. Se ei ole päätepiste!
- DevOps
- Pilvi
Subscribe to our newsletter
Related blogs