Kohalikud failid rakenduse Kubernetesesse migreerimisel

Kohalikud failid rakenduse Kubernetesesse migreerimisel

Kubernetese abil CI/CD protsessi ülesehitamisel tekib mõnikord probleemiks uue infrastruktuuri nõuete ja sellele ülekantava rakenduse vaheline ühildamatus. Eelkõige on rakenduse ehitamise etapis oluline hankida üks pilt, mida kasutatakse Kõik projektikeskkonnad ja klastrid. See põhimõte on õige aluseks Google'i järgi konteinerite haldamine (selle kohta rohkem kui üks kord ütles ja meie tehniline osakond).

Kuid te ei näe kedagi olukordades, kus saidi kood kasutab valmis raamistikku, mille kasutamine seab piirangud selle edasisele kasutamisele. Ja kuigi "tavakeskkonnas" on sellega lihtne toime tulla, võib Kubernetesis see käitumine muutuda probleemiks, eriti kui puutute sellega kokku esimest korda. Kuigi leidlik meel võib tulla välja infrastruktuurilahendustega, mis tunduvad esmapilgul ilmsed või isegi head, on oluline meeles pidada, et enamik olukordi saab ja peaks lahendatakse arhitektuurselt.

Vaatame populaarseid lahendusi failide salvestamiseks, mis võivad klastri kasutamisel põhjustada ebameeldivaid tagajärgi, ja osutame ka õigemale teele.

Staatiline salvestusruum

Illustreerimiseks kaaluge veebirakendust, mis kasutab piltide, stiilide ja muude asjade kogumi saamiseks mingit staatilist generaatorit. Näiteks Yii PHP raamistikul on sisseehitatud varahaldur, mis genereerib kordumatuid katalooginimesid. Sellest lähtuvalt on väljund staatilise saidi radade kogum, mis ilmselgelt ei ristu üksteisega (seda tehti mitmel põhjusel - näiteks duplikaatide kõrvaldamiseks, kui mitu komponenti kasutavad sama ressurssi). Niisiis, kui avate esimest korda veebiressursimooduli juurde, moodustatakse staatilised failid (tegelikult sageli sümboolsed lingid, kuid sellest hiljem rohkem) ja paigutatakse need koos selle juurutuse jaoks ainulaadse juurkataloogiga:

  • webroot/assets/2072c2df/css/…
  • webroot/assets/2072c2df/images/…
  • webroot/assets/2072c2df/js/…

Mida see klastri mõistes tähendab?

Lihtsaim näide

Võtame näiteks üsna levinud juhtumi, kus staatiliste andmete levitamiseks ja lihtsate päringute töötlemiseks eelneb PHP-le nginx. Lihtsaim viis - Deployment kahe konteineriga:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: site
spec:
  selector:
    matchLabels:
      component: backend
  template:
    metadata:
      labels:
        component: backend
    spec:
      volumes:
        - name: nginx-config
          configMap:
            name: nginx-configmap
      containers:
      - name: php
        image: own-image-with-php-backend:v1.0
        command: ["/usr/local/sbin/php-fpm","-F"]
        workingDir: /var/www
      - name: nginx
        image: nginx:1.16.0
        command: ["/usr/sbin/nginx", "-g", "daemon off;"]
        volumeMounts:
        - name: nginx-config
          mountPath: /etc/nginx/conf.d/default.conf
          subPath: nginx.conf

Lihtsustatud kujul taandub nginxi konfiguratsioon järgmisele:

apiVersion: v1
kind: ConfigMap
metadata:
  name: "nginx-configmap"
data:
  nginx.conf: |
    server {
        listen 80;
        server_name _;
        charset utf-8;
        root  /var/www;

        access_log /dev/stdout;
        error_log /dev/stderr;

        location / {
            index index.php;
            try_files $uri $uri/ /index.php?$args;
        }

        location ~ .php$ {
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            include fastcgi_params;
        }
    }

Kui avate esimest korda saidile, kuvatakse varad PHP konteineris. Aga kui ühes podis on kaks konteinerit, siis nginx ei tea midagi nendest staatilistest failidest, mis (vastavalt konfiguratsioonile) neile tuleks anda. Selle tulemusena näeb klient kõigi CSS- ja JS-failide päringute puhul viga 404. Siin oleks lihtsaim lahendus konteinerite jaoks ühise kataloogi korraldamine. Primitiivne variant - üldine emptyDir:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: site
spec:
  selector:
    matchLabels:
      component: backend
  template:
    metadata:
      labels:
        component: backend
    spec:
      volumes:
        - name: assets
          emptyDir: {}
        - name: nginx-config
          configMap:
            name: nginx-configmap
      containers:
      - name: php
        image: own-image-with-php-backend:v1.0
        command: ["/usr/local/sbin/php-fpm","-F"]
        workingDir: /var/www
        volumeMounts:
        - name: assets
          mountPath: /var/www/assets
      - name: nginx
        image: nginx:1.16.0
        command: ["/usr/sbin/nginx", "-g", "daemon off;"]
        volumeMounts:
        - name: assets
          mountPath: /var/www/assets
        - name: nginx-config
          mountPath: /etc/nginx/conf.d/default.conf
          subPath: nginx.conf

Nüüd teenindab nginx konteineris loodud staatilisi faile õigesti. Kuid lubage mul teile meelde tuletada, et see on primitiivne lahendus, mis tähendab, et see pole kaugeltki ideaalne ja sellel on oma nüansid ja puudused, mida arutatakse allpool.

Täiustatud salvestusruum

Kujutage nüüd ette olukorda, kus kasutaja külastas saiti, laadis konteineris saadaolevate stiilidega lehe ja sel ajal, kui ta seda lehte luges, juurutasime konteineri uuesti. Varade kataloog on tühjaks saanud ja uute genereerimise alustamiseks on vaja päringut PHP-le. Kuid isegi pärast seda on vanade staatikate lingid ebaolulised, mis põhjustab staatika kuvamisel vigu.

Lisaks on meil suure tõenäosusega enam-vähem laetud projekt, mis tähendab, et ühest rakenduse eksemplarist ei piisa:

  • Suurendame seda Deployment kuni kaks koopiat.
  • Kui saidile esmakordselt juurde pääseti, loodi varad ühes koopias.
  • Mingil hetkel otsustas ingress (koormuse tasakaalustamise eesmärgil) saata päringu teisele koopiale ja neid varasid veel polnud. Või pole neid enam seal, sest me kasutame RollingUpdate ja hetkel tegeleme juurutamisega.

Üldiselt on tulemuseks jälle vead.

Vanade varade kaotamise vältimiseks saate muuta emptyDir edasi hostPath, lisades klastri sõlme füüsiliselt staatilisuse. Selline lähenemine on halb, sest tegelikult peame seda tegema seostuda konkreetse klastri sõlmega oma rakendust, sest teistesse sõlmedesse liikumise korral ei sisalda kataloog vajalikke faile. Või on vaja mingit taustakataloogi sünkroonimist sõlmede vahel.

Millised on lahendused?

  1. Kui riistvara ja ressursid lubavad, saate seda kasutada tseffid staatiliste vajaduste jaoks võrdselt juurdepääsetava kataloogi korraldamiseks. Ametlik dokumentatsioon soovitab SSD-draive, vähemalt kolmekordset replikatsiooni ja stabiilset "paksust" ühendust klastri sõlmede vahel.
  2. Vähem nõudlik variant oleks organiseerida NFS-server. Kuid siis tuleb arvestada võimaliku reageerimisaja pikenemisega veebiserveri päringute töötlemisel ja veataluvus jätab soovida. Ebaõnnestumise tagajärjed on katastroofilised: mäe kaotus hukutab klastri taevasse sööstva LA koorma survel.

Muu hulgas on vaja kõiki püsiva salvestusruumi loomise võimalusi tausta puhastamine teatud aja jooksul kogunenud aegunud failikomplektid. PHP-ga konteinerite ette saab panna DaemonSet nginxi vahemällu salvestamisest, mis salvestab varade koopiaid piiratud aja jooksul. Seda käitumist on lihtne kasutades konfigureerida proxy_cache salvestussügavusega päevades või gigabaitides kettaruumi.

Selle meetodi kombineerimine ülalmainitud hajutatud failisüsteemidega annab tohutult palju kujutlusvõimet, mida piiravad ainult selle rakendajate ja toetajate eelarve ja tehniline potentsiaal. Kogemuste põhjal võime öelda, et mida lihtsam on süsteem, seda stabiilsemalt see töötab. Selliste kihtide lisamisel muutub infrastruktuuri ülalpidamine palju keerulisemaks ning samal ajal pikeneb ka diagnoosimisele ja tõrgetest taastumisele kuluv aeg.

Soovitus

Kui ka pakutud hoiustamisvõimaluste rakendamine tundub sulle põhjendamatu (keeruline, kallis...), siis tasub vaadata olukorda teisest küljest. Nimelt süveneda projekti arhitektuuri ja parandage probleem koodis, mis on seotud pildi mõne staatilise andmestruktuuriga, sisu või protseduuri ühemõtteline määratlus kujutise kokkupaneku etapis "soojendamiseks" ja/või varade eelkompileerimiseks. Nii saame absoluutselt etteaimatava käitumise ja sama failide komplekti kõigi keskkondade ja töötava rakenduse koopiate jaoks.

Kui pöördume tagasi konkreetse näite juurde Yii raamistikuga ja ei süvene selle ülesehitusse (mis pole artikli eesmärk), siis piisab kahe populaarse lähenemise väljatoomisest:

  1. Muutke pildi koostamise protsessi, et paigutada varad ennustatavasse asukohta. Seda soovitatakse/rakendatud laiendustes nagu yii2-staatilised varad.
  2. Määratlege varade kataloogide jaoks konkreetsed räsid, nagu on kirjeldatud nt. see esitlus (alates slaidilt nr 35). Muide, aruande autor soovitab lõpuks (ja mitte ilma põhjuseta!) pärast varade kokkupanemist ehitusserveris üles laadida keskmällu (nagu S3), mille ette asetada CDN.

Allalaadimised

Teine juhtum, mis rakenduse Kubernetese klastrisse migreerimisel kindlasti mängu tuleb, on kasutajate failide salvestamine failisüsteemi. Näiteks on meil jälle PHP-rakendus, mis võtab failid vastu üleslaadimisvormi kaudu, teeb nendega töötamise ajal midagi ja saadab need tagasi.

Kubernetesis peaks nende failide asukoht olema kõigi rakenduse koopiate jaoks ühine. Sõltuvalt rakenduse keerukusest ja vajadusest korraldada nende failide püsivust, võivad ülalmainitud jagatud seadme valikud olla selliseks kohaks, kuid nagu näeme, on neil oma puudused.

Soovitus

Üks lahendus on kasutades S3-ga ühilduvat salvestusruumi (isegi kui see on mingi isehostitav kategooria, näiteks minio). S3-le üleminek nõuab muudatusi koodi tasemelja kuidas sisu esiotsas edastatakse, oleme juba teinud писали.

Kasutajaseansid

Eraldi väärib märkimist kasutajaseansside salvestamise korraldus. Sageli on need ka kettal olevad failid, mis Kubernetese kontekstis põhjustavad kasutajalt pidevaid autoriseerimistaotlusi, kui tema päring satub teise konteinerisse.

Probleem lahendatakse osaliselt sisselülitamisega stickySessions sissepääsul (funktsioon on toetatud kõigis populaarsetes sisestuskontrollerites – lisateabe saamiseks vt meie ülevaade)kasutaja sidumiseks rakendusega konkreetse podiga:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: nginx-test
  annotations:
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "route"
    nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"

spec:
  rules:
  - host: stickyingress.example.com
    http:
      paths:
      - backend:
          serviceName: http-svc
          servicePort: 80
        path: /

Kuid see ei kõrvalda korduva kasutuselevõtuga probleeme.

Soovitus

Õigem viis oleks taotlus üle kanda seansside salvestamine memcached, Redis ja sarnastes lahendustes - üldiselt loobuge failivalikutest täielikult.

Järeldus

Tekstis käsitletud taristulahendused väärivad kasutamist vaid ajutiste “karkude” vormis (mis kõlab inglise keeles lahendusena ilusamini). Need võivad olla olulised rakenduse Kubernetesesse üleviimise esimestel etappidel, kuid need ei tohiks juurduda.

Üldine soovituslik tee on neist lahti saada ja muuta rakendust arhitektuurselt vastavalt paljudele juba hästi teadaolevale 12-faktoriline rakendus. See aga - rakenduse viimine olekuta vormile - tähendab paratamatult seda, et koodis tuleb teha muudatusi ning siin on oluline leida tasakaal ettevõtte võimaluste/nõuete ning valitud tee juurutamise ja säilitamise väljavaadete vahel. .

PS

Loe ka meie blogist:

Allikas: www.habr.com

Lisa kommentaar