10 yleistä virhettä Kubernetesia käytettäessä

Huomautus. käännös: Tämän artikkelin kirjoittajat ovat pienen tšekkiläisen pipetail-yrityksen insinöörejä. He onnistuivat kokoamaan upean listan [joskus banaaleista, mutta silti] erittäin kiireellisistä ongelmista ja väärinkäsityksistä, jotka liittyvät Kubernetes-klusterien toimintaan.

10 yleistä virhettä Kubernetesia käytettäessä

Kubernetesin vuosien aikana olemme työskennelleet suuren määrän klustereita (sekä hallittuja että hallitsemattomia - GCP:ssä, AWS:ssä ja Azuressa) kanssa. Ajan myötä aloimme huomata, että joitain virheitä toistettiin jatkuvasti. Tässä ei kuitenkaan ole häpeällistä: olemme tehneet suurimman osan niistä itse!

Artikkeli sisältää yleisimmät virheet ja mainitsee myös niiden korjaamisen.

1. Resurssit: pyynnöt ja rajoitukset

Tämä kohde ansaitsee ehdottomasti eniten huomiota ja listan ensimmäisen paikan.

CPU-pyyntö yleensä joko ei ole määritelty ollenkaan tai sen arvo on erittäin pieni (sijoittaaksesi mahdollisimman monta palkoa jokaiseen solmuun). Siten solmut ylikuormituvat. Suuren kuormituksen aikana solmun prosessointiteho hyödynnetään täysin ja tietty työkuorma saa vain sen, mitä se "pyytää" CPU:n kuristus. Tämä lisää sovelluksen latenssia, aikakatkaisuja ja muita epämiellyttäviä seurauksia. (Lue tästä lisää toisesta tuoreesta käännöksestämme: "Suorittimen rajoitukset ja aggressiivinen kuristus Kubernetesissa"- n. käännös.)

Paras yritys (erittäin ei suositeltava):

resources: {}

Erittäin alhainen suorittimen pyyntö (erittäin ei suositeltava):

   resources:
      Requests:
        cpu: "1m"

Toisaalta CPU-rajoituksen olemassaolo voi johtaa kellojaksojen kohtuuttomaan ohittamiseen podien toimesta, vaikka solmuprosessori ei olisi täysin ladattu. Tämä taas voi johtaa lisääntyneisiin viivästyksiin. Kiista jatkuu parametrin ympärillä CPU CFS-kiintiö Linux-ytimen ja CPU:n kuristus asetetuista rajoituksista riippuen sekä CFS-kiintiön poistaminen käytöstä... Valitettavasti suorittimen rajoitukset voivat aiheuttaa enemmän ongelmia kuin ne voivat ratkaista. Lisätietoja tästä löytyy alla olevasta linkistä.

Liiallinen valikoima (yli sitoutuminen) muistiongelmat voivat johtaa suurempiin ongelmiin. CPU-rajan saavuttaminen edellyttää kellojaksojen ohittamista, kun taas muistirajan saavuttaminen johtaa podin tappamiseen. Oletko koskaan havainnut OOMkill? Kyllä, juuri siitä me puhumme.

Haluatko minimoida tämän todennäköisyyden? Älä yliallokoi muistia ja käytä taattua QoS:ää (Quality of Service) asettamalla muistipyynnön rajaan (kuten alla olevassa esimerkissä). Lue lisää tästä kohdasta Henning Jacobsin esitykset (Pääinsinööri Zalandossa).

Räjähtävä (suurempi mahdollisuus saada OOMkilled):

   resources:
      requests:
        memory: "128Mi"
        cpu: "500m"
      limits:
        memory: "256Mi"
        cpu: 2

Taattu:

   resources:
      requests:
        memory: "128Mi"
        cpu: 2
      limits:
        memory: "128Mi"
        cpu: 2

Mikä voi auttaa resurssien luomisessa?

Kanssa metriikka-palvelin näet nykyisen suorittimen resurssien ja muistin käytön koteloiden (ja niiden sisällä olevien säiliöiden) mukaan. Todennäköisesti käytät sitä jo. Suorita vain seuraavat komennot:

kubectl top pods
kubectl top pods --containers
kubectl top nodes

Ne näyttävät kuitenkin vain nykyisen käytön. Se voi antaa sinulle karkean käsityksen suuruusluokasta, mutta lopulta tarvitset mittareiden muutoshistoria ajan mittaan (vastataksesi kysymyksiin, kuten: "Mikä oli suorittimen huippukuormitus?", "Mikä oli kuormitus eilen aamulla?" jne.). Tätä varten voit käyttää Prometheus, DataDog ja muita työkaluja. He yksinkertaisesti saavat mittareita metrics-palvelimelta ja tallentavat ne, ja käyttäjä voi tehdä kyselyitä niistä ja piirtää ne vastaavasti.

VerticalPodAutoscaler sen avulla automatisoida Tämä prosessi. Se seuraa suorittimen ja muistin käyttöhistoriaa ja asettaa uusia pyyntöjä ja rajoja näiden tietojen perusteella.

Laskentatehon tehokas käyttö ei ole helppo tehtävä. On kuin pelaisi Tetrisiä koko ajan. Jos maksat liikaa laskentatehosta alhaisella keskikulutuksella (esim. ~10 %), suosittelemme tutustumaan AWS Fargateen tai Virtual Kubelet -järjestelmään perustuviin tuotteisiin. Ne on rakennettu palvelimettomaan/käyttökohtaiseen laskutusmalliin, joka voi osoittautua halvemmaksi tällaisissa olosuhteissa.

2. Elävyys- ja valmiusanturit

Oletusarvoisesti elävyyden ja valmiuden tarkistukset eivät ole käytössä Kubernetesissa. Ja joskus he unohtavat kytkeä ne päälle...

Mutta kuinka muuten voit käynnistää palvelun uudelleenkäynnistyksen vakavan virheen sattuessa? Ja mistä kuormantasaaja tietää, että pod on valmis vastaanottamaan liikennettä? Vai pystyykö se käsittelemään enemmän liikennettä?

Nämä testit sekoitetaan usein keskenään:

  • elävyyden — "selviytymiskyky"-tarkistus, joka käynnistää podin uudelleen, jos se epäonnistuu;
  • valmius — valmiustarkastus, jos se epäonnistuu, se katkaisee podin Kubernetes-palvelusta (tämän voi tarkistaa käyttämällä kubectl get endpoints) ja liikenne saapuu siihen vasta, kun seuraava tarkistus on suoritettu onnistuneesti.

Molemmat tarkastukset SUORITTUU PODIN KOKO ELINJAKAUDEN AIKANA. Se on erittäin tärkeää.

Yleinen väärinkäsitys on, että valmiusanturia ajetaan vain käynnistyksen yhteydessä, jotta tasapainotin tietää, että pod on valmis (Ready) ja voi alkaa käsitellä liikennettä. Tämä on kuitenkin vain yksi niiden käyttömahdollisuuksista.

Toinen on mahdollisuus saada selville, että podissa on liikaa liikennettä ja ylikuormittaa sitä (tai pod suorittaa resurssiintensiivisiä laskelmia). Tässä tapauksessa valmiustarkastus auttaa vähennä kotelon kuormitusta ja "jäähdytä" sitä. Valmiustarkastuksen onnistunut suorittaminen tulevaisuudessa mahdollistaa lisää pussin kuormitusta uudelleen. Tässä tapauksessa (jos valmiuskoe epäonnistuu) elävyystestin epäonnistuminen olisi erittäin haitallista. Miksi käynnistää uudelleen terve ja kovasti toimiva pod?

Siksi joissakin tapauksissa on parempi olla tekemättä tarkastuksia kuin ottaa ne käyttöön väärin määritetyillä parametreilla. Kuten edellä todettiin, jos elävyystarkastus kopioi valmiustarkastus, niin olet suuressa pulassa. Mahdollinen vaihtoehto on konfiguroida vain valmiuskoeJa vaarallinen eloisuus jättää sivuun.

Kummankaan tyyppisten tarkistusten ei pitäisi epäonnistua, kun yleiset riippuvuudet epäonnistuvat, muuten tämä johtaa peräkkäiseen (vyörymäiseen) epäonnistumiseen kaikissa podissa. Toisin sanoen, älä vahingoita itseäsi.

3. LoadBalancer jokaiselle HTTP-palvelulle

Todennäköisesti klusterissasi on HTTP-palveluita, jotka haluat välittää ulkomaailmaan.

Jos avaat palvelun nimellä type: LoadBalancer, sen ohjain (riippuen palveluntarjoajasta) tarjoaa ja neuvottelee ulkoisen LoadBalancerin (ei välttämättä käynnissä L7:ssä, vaan jopa L4:ssä), ja tämä voi vaikuttaa kustannuksiin (ulkoinen staattinen IPv4-osoite, laskentateho, sekuntilaskutus). ), koska on tarpeen luoda suuri määrä tällaisia ​​resursseja.

Tässä tapauksessa on paljon loogisempaa käyttää yhtä ulkoista kuormitustasainta, joka avaa palvelut kuten type: NodePort. Tai vielä parempi, laajentaa jotain vastaavaa nginx-ingress-ohjain (tai traefik), joka on ainoa Solmuportti päätepiste, joka liittyy ulkoiseen kuormantasaajaan ja reitittää liikenteen klusterissa käyttämällä sisääntulo-Kubernetes-resurssit.

Muut klusterin sisäiset (mikro)palvelut, jotka ovat vuorovaikutuksessa keskenään, voivat "kommunikoida" käyttämällä palveluita, kuten KlusteriIP ja sisäänrakennettu palvelunhakumekanismi DNS:n kautta. Älä vain käytä heidän julkista DNS-/IP-osoitettaan, koska tämä voi vaikuttaa latenssiin ja lisätä pilvipalvelujen kustannuksia.

4. Klusterin automaattinen skaalaus ottamatta huomioon sen ominaisuuksia

Kun lisäät solmuja klusteriin ja poistat niitä siitä, sinun ei pitäisi luottaa joihinkin perusmittareihin, kuten kyseisten solmujen suorittimen käyttöön. Pod-suunnittelussa on otettava huomioon monet rajoituksia, kuten pod/solmu-affiniteetti, tahrat ja toleranssit, resurssipyynnöt, QoS jne. Ulkoisen automaattisen skaalaimen käyttäminen, joka ei ota näitä vivahteita huomioon, voi johtaa ongelmiin.

Kuvittele, että tietty pod pitäisi ajastaa, mutta kaikki käytettävissä oleva suorittimen teho pyydetään/puretaan ja pod juuttuu tilaan Pending. Ulkoinen automaattinen skaalaaja näkee keskimääräisen nykyisen suorittimen kuormituksen (ei vaaditun) eikä aloita laajennusta (laajentaa) - ei lisää toista solmua. Tämän seurauksena tätä podia ei ajoiteta.

Tässä tapauksessa käänteinen skaalaus (skaalaus) — solmun poistaminen klusterista on aina vaikeampaa toteuttaa. Kuvittele, että sinulla on tilallinen pod (johon on kytketty pysyvä tallennustila). Pysyvät volyymit yleensä kuuluvat tietty saatavuusalue eikä niitä toisteta alueella. Näin ollen, jos ulkoinen automaattinen skaalaaja poistaa solmun tällä podilla, ajoitus ei voi ajoittaa tätä ryhmää toiselle solmulle, koska tämä voidaan tehdä vain käytettävyysvyöhykkeellä, jossa pysyvä tallennuspaikka sijaitsee. Kotelo jää kiinni tilaan Pending.

Erittäin suosittu Kubernetes-yhteisössä cluster-autoscaler. Se toimii klusterissa, tukee suurten pilvipalveluntarjoajien API:ita, ottaa huomioon kaikki rajoitukset ja voi skaalata yllä mainituissa tapauksissa. Se pystyy myös skaalautumaan säilyttäen kaikki asetetut rajat, mikä säästää rahaa (joka muuten kuluisi käyttämättömään kapasiteettiin).

5. IAM/RBAC-ominaisuuksien laiminlyöminen

Varo käyttämästä IAM-käyttäjiä, joilla on pysyviä salaisuuksia koneita ja sovelluksia. Järjestä väliaikainen käyttöoikeus roolien ja palvelutilien avulla (palvelutilit).

Kohtaamme usein sen tosiasian, että pääsyavaimet (ja salaisuudet) on koodattu sovelluksen määrityksissä, ja salaisuuksien kierto laiminlyödään huolimatta siitä, että meillä on pääsy Cloud IAM:iin. Käytä tarvittaessa IAM-rooleja ja palvelutilejä käyttäjien sijasta.

10 yleistä virhettä Kubernetesia käytettäessä

Unohda kube2iam ja siirry suoraan palvelutilien IAM-rooleihin (kuten kuvataan kohdassa samanniminen muistiinpano Štěpán Vraný):

apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/my-app-role
  name: my-serviceaccount
  namespace: default

Yksi huomautus. Ei niin vaikeaa, eihän?

Älä myöskään myönnä palvelutileille ja ilmentymäprofiileille käyttöoikeuksia admin и cluster-adminjos he eivät sitä tarvitse. Tämä on hieman vaikeampi toteuttaa, varsinkin RBAC K8s, mutta ehdottomasti vaivan arvoinen.

6. Älä luota koteloiden automaattiseen anti-affiniteettiin

Kuvittele, että sinulla on solmussa kolme kopiota jostain käyttöönotosta. Solmu putoaa ja sen mukana kaikki kopiot. Epämiellyttävä tilanne, eikö? Mutta miksi kaikki kopiot olivat samassa solmussa? Eikö Kubernetesin ole tarkoitus tarjota korkea saatavuus (HA)?!

Valitettavasti Kubernetes-aikataulu ei omasta aloitteestaan ​​noudata erillisen olemassaolon sääntöjä (antiaffiniteetti) paloille. Ne on mainittava nimenomaisesti:

// опущено для краткости
      labels:
        app: zk
// опущено для краткости
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "app"
                    operator: In
                    values:
                    - zk
              topologyKey: "kubernetes.io/hostname"

Siinä kaikki. Nyt podit ajoitetaan eri solmuihin (tämä ehto tarkistetaan vain ajoituksen aikana, mutta ei niiden toiminnan aikana - siis requiredDuringSchedulingIgnoredDuringExecution).

Täällä puhutaan podAntiAffinity eri solmuissa: topologyKey: "kubernetes.io/hostname", - eikä eri saatavuusvyöhykkeistä. Jotta voit toteuttaa täysimittaisen HA:n, sinun on kaivettava tätä aihetta syvemmälle.

7. PodDisruptionBudgetsin huomioimatta jättäminen

Kuvittele, että sinulla on Kubernetes-klusterin tuotantokuormitus. Ajoittain solmut ja itse klusteri on päivitettävä (tai poistettava käytöstä). PodDisruptionBudget (PDB) on klusterin ylläpitäjien ja käyttäjien välinen palvelutakuusopimus.

PDB:n avulla voit välttää palvelukatkoksia, jotka johtuvat solmujen puutteesta:

apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: zk-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: zookeeper

Tässä esimerkissä sinä klusterin käyttäjänä ilmoitat järjestelmänvalvojille: "Hei, minulla on eläintarhanhoitajapalvelu, ja mitä tahansa teetkin, haluaisin, että tästä palvelusta on aina saatavilla vähintään kaksi kopiota .”

Voit lukea tästä lisää täällä.

8. Useita käyttäjiä tai ympäristöjä yhteisessä klusterissa

Kubernetes-nimiavaruudet (nimiavaruudet) eivät tarjoa vahvaa eristystä.

Yleinen väärinkäsitys on, että jos otat käyttöön ei-tuotekuorman yhteen nimiavaruuteen ja prod-kuorman toiseen, eivät vaikuta toisiinsa millään tavalla... Tietty eristyksen taso voidaan kuitenkin saavuttaa käyttämällä resurssipyyntöjä/rajoituksia, asettamalla kiintiöitä ja asettamalla prioriteettiluokkia. Tietynlainen "fyysinen" eristys datatasolla saadaan aikaan affiniteetilla, toleraatioilla, tahroilla (tai solmuvalitsimilla), mutta tällainen erottelu on melko vaikea toteuttaa.

Niiden, joiden on yhdistettävä molempia työkuormia samaan klusteriin, on kohdattava monimutkaisuus. Jos sellaista tarvetta ei ole, ja sinulla on varaa sellaisen hankkimiseen vielä yksi klusteri (esimerkiksi julkisessa pilvessä), on parempi tehdä niin. Tällä saavutetaan paljon korkeampi eristystaso.

9. ulkoinen liikennekäytäntö: klusteri

Hyvin usein näemme, että kaikki klusterin sisäinen liikenne tulee NodePortin kaltaisen palvelun kautta, jolle on asetettu oletuskäytäntö externalTrafficPolicy: Cluster... Se tarkoittaa sitä Solmuportti on avoinna jokaisessa klusterin solmussa, ja voit käyttää mitä tahansa niistä vuorovaikutuksessa halutun palvelun (joukko podd) kanssa.

10 yleistä virhettä Kubernetesia käytettäessä

Samanaikaisesti yllä mainittuun NodePort-palveluun liittyvät oikeat podit ovat yleensä saatavilla vain tietyllä näiden solmujen osajoukko. Toisin sanoen, jos muodostan yhteyden solmuun, jossa ei ole vaadittua podia, se välittää liikenteen toiseen solmuun, lisäämällä humalan ja latenssin lisääminen (jos solmut sijaitsevat eri käytettävyysvyöhykkeillä/tietokeskuksissa, latenssi voi olla melko korkea; lisäksi ulosmenoliikenteen kustannukset kasvavat).

Toisaalta, jos tietylle Kubernetes-palvelulle on asetettu käytäntö externalTrafficPolicy: Local, NodePort avautuu vain niissä solmuissa, joissa vaaditut podit ovat todella käynnissä. Kun käytetään ulkoista kuormantasainta, joka tarkistaa tilan (terveystarkastus) päätepisteet (miten se toimii AWS ELB), Hän lähettää liikennettä vain tarvittaviin solmuihin, jolla on myönteinen vaikutus viivästyksiin, laskentatarpeisiin, ulostulolaskuihin (ja terve järki sanelee saman).

On suuri mahdollisuus, että käytät jo jotain vastaavaa traefik tai nginx-ingress-ohjain NodePort-päätepisteenä (tai LoadBalancerina, joka myös käyttää NodePortia) reitittämään HTTP-sisääntuloliikennettä, ja tämän asetuksen asettaminen voi vähentää merkittävästi tällaisten pyyntöjen viivettä.

В tämä julkaisu Voit oppia lisää ulkoisesta liikennepolitiikasta, sen eduista ja haitoista.

10. Älä sitoudu klusteriin äläkä käytä väärin ohjaustasoa

Aikaisemmin oli tapana kutsua palvelimia erisnimillä: Anton, HAL9000 ja Colossus... Nykyään ne on korvattu satunnaisesti luoduilla tunnisteilla. Tapa kuitenkin säilyi, ja nyt oikeat nimet menevät klustereihin.

Tyypillinen tarina (perustuu tositapahtumiin): kaikki alkoi konseptin todistamisesta, joten klusterilla oli ylpeä nimi testaus... Vuodet ovat kuluneet ja sitä käytetään edelleen tuotannossa, ja kaikki pelkäävät koskea siihen.

Ei ole mitään hauskaa siinä, että klusterit muuttuvat lemmikkeiksi, joten suosittelemme poistamaan ne säännöllisesti harjoittelun aikana. katastrofipalautus (tämä auttaa kaaoksen suunnittelu - noin käännös.). Lisäksi ohjauskerroksen työstäminen ei haittaisi (ohjaustaso). Pelkääminen koskettaa häntä ei ole hyvä merkki. jne kuollut? Kaverit, olette todella pulassa!

Toisaalta sen manipuloimiseen ei pidä innostua. Ajan kanssa ohjauskerros voi hidastua. Todennäköisesti tämä johtuu siitä, että suuri määrä objekteja luodaan ilman niiden kiertämistä (yleinen tilanne käytettäessä Helmia oletusasetuksissa, minkä vuoksi sen tilaa konfiguraatiokartoissa/salaisuuksissa ei päivitetä - seurauksena tuhansia objekteja kerääntyy ohjauskerros) tai jatkuvalla kube-api-objektien muokkauksella (automaattista skaalausta varten, CI/CD:lle, valvontaan, tapahtumalokeihin, ohjaimiin jne.).

Lisäksi suosittelemme tarkistamaan SLA/SLO-sopimukset hallinnoidun Kubernetes-toimittajan kanssa ja kiinnittämään huomiota takuisiin. Myyjä voi taata ohjaa kerroksen saatavuutta (tai sen alikomponentit), mutta ei sille lähettämiesi pyyntöjen p99-viivettä. Toisin sanoen, voit tulla sisään kubectl get nodes, ja saat vastauksen vasta 10 minuutin kuluttua, eikä tämä ole palvelusopimuksen ehtojen rikkomista.

11. Bonus: uusimman tunnisteen käyttö

Mutta tämä on jo klassikko. Viime aikoina olemme törmänneet tähän tekniikkaan harvemmin, koska monet katkerasta kokemuksesta oppineet ovat lopettaneet tunnisteen käytön :latest ja alkoi kiinnittää versioita. Hurraa!

ECR säilyttää kuvatunnisteiden muuttumattomuuden; Suosittelemme, että tutustut tähän merkittävään ominaisuuteen.

Yhteenveto

Älä odota kaiken toimivan yhdessä yössä: Kubernetes ei ole ihmelääke. Huono sovellus säilyy sellaisena myös Kubernetesissä (ja se todennäköisesti pahenee). Huolimattomuus johtaa ohjauskerroksen liialliseen monimutkaisuuteen, hitaaseen ja stressaavaan työhön. Lisäksi saatat jäädä ilman katastrofipalautusstrategiaa. Älä odota Kubernetesin tarjoavan eristystä ja korkeaa käytettävyyttä heti valmiina. Vietä aikaa tehdäksesi sovelluksestasi todella pilvipohjaisen.

Voit tutustua eri tiimien epäonnistuneisiin kokemuksiin tämä tarinakokoelma Kirjailija: Henning Jacobs

Ne, jotka haluavat täydentää tässä artikkelissa annettua virheluetteloa, voivat ottaa meihin yhteyttä Twitterissä (@MarekBartik, @MstrsObserver).

PS kääntäjältä

Lue myös blogistamme:

Lähde: will.com

Lisää kommentti