Kohalikud failid rakenduse teisaldamisel Kubernetesesse

Kohalikud failid rakenduse teisaldamisel Kubernetesesse

CI/CD protsessi loomisel Kubernetesega võib tekkida probleem, kus uue infrastruktuuri nõudmised ja sinna kantav rakendus ei ühti. Eelkõige on rakenduse ehitamise etapis oluline saada ühe pildi, mida kasutatakse kõikides keskkondades ja projekti klastrites. Selline põhimõte on õige Google'i arvates konteinerite haldamise aluseks (meie tehniline direktor on seda korduvalt maininud). konteinerihalduse (pole sellest kunagi varem ütles Kuid ei ole haruldane kohtuda olukordadega, kus saidi koodis kasutatakse valmis raamistiku, mille kasutamine toob kaasa piiranguid edasisele kasutamisele. Ja kui "tavakeskkonnas" on sellega lihtne toime tulla, siis Kuberneteses võib selline käitumine muutuda probleemiks, eriti kui kohtad seda esmakordselt. Kuigi leidlik meel suudab pakkuda infrastruktuuri lahendusi, mis näivad esmapilgul ilmsed ja isegi head ... on oluline meeles pidada, et enamik olukordi võib ja peab olema

Siiski ei näe sa kedagi olukordades, kus veebikoodis kasutatakse valmis raamistiku, mille kasutamine seab piiranguid selle edasisele kasutamisele. Kui "tavalises keskkonnas" on sellega lihtne toime tulla, siis Kuberneteses võib selline käitumine muutuda probleemiks, eriti kui kohtub sellega esmakordselt. Kuigi leidlik meel suudab pakkuda infrastruktuuri lahendusi, mis tunduvad esmapilgul ilmselged ja isegi head… on oluline meeles pidada, et enamik olukordi võivad ja peavad lahendatud arhitektuuriliselt.

Käime läbi populaarsed workaround-lahendused failide hoidmiseks, mis võivad põhjustada ebameeldivaid tagajärgi klastrite kasutamisel, ja näitame üles õigemad teed.

Statika hoidmine

Kujutame ette veebirakendust, mis kasutab mingit staatika genereerijat piltide, stiilide ja muu komplekti saamiseks. Näiteks PHP-raamistikus Yii on sisseehitatud varade haldur, mis genereerib unikaalsed kaustade nimetused. Seega saadakse väljastusena kogum omavahel mittetükkivad teed saidi staatikale (see on tehtud mitmel põhjusel — näiteks, et välistada dubleeritud ressursid, mida kasutavad mitmed komponendid). Nii et välja peal, esimesel pöördumisel veebiresursi mooduli poole toimub staatika genereerimine ja paigutamine (tõenäoliselt sümlinkide, kuid sellest hiljem) unikaalse juurkaustaga selle versiooni jaoks:

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

Millised on selle tagajärjed klastrite osas?

Lihtsaim näide

Võtame üsna levinud juhtumi, kus PHP ees on nginx staatika serveerimiseks ja lihtsate päringute töötlemiseks. Kõige lihtsam viis on Deployment kaks konteinerit:

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 koondub nginx 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;
        }
    }

Esimese korral, kui külastatakse PHP konteineris asuvat saiti, kuvatakse varad. Kuid kahe konteineri puhul ühe pod'i raames ei tea nginx neist staatilistest failidest midagi, mis (vastavalt konfiguratsioonile) peaks just neile edastatama. Tulemuseks on see, et kõikidele CSS- ja JS-failide päringutele näeb klient viga 404. Lihtsaim lahendus oleks korraldada konteineritele ühine direktorium. Primitiivne variant — ühine. 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 edastab nginx konteineris genereeritud staatilised failid õigesti. Kuid tuletan meelde, et see on primitiivne lahendus, mis tähendab, et see on kaugel ideest ning sellel on oma nüansid ja puudused, millest allpool räägin.

Täpsem salvestus

Kujutage nüüd olukorda, kus kasutaja on veebilehel, on laadinud lehe, mis sisaldab konteineris olevaid stiile, ja samal ajal, kui ta seda lehte loeb, oleme konteineri uuesti välja deployinud. Varade kataloog on tühi ja vajame PHP päringut uute genereerimiseks. Kuid isegi pärast seda on vanad staatilised lingid ebatäpsed, mis toob kaasa staatika kuvamise vead.

Lisaks on tõenäoliselt tegemist suhteliselt suure projekti, mis tähendab, et ühekordne rakendus ei piisa:

  • Suurendame Deployment kuni kahte koopiat.
  • Esimese külastuse ajal ühe koopiaga loodi varad.
  • Mingil hetkel otsustas ingress (koormuse tasakaalustamise eesmärgil) saata päringu teisele koopiale, ja seal pole neid varasid veel. Võib-olla ei ole neid seal enam, sest kasutame RollingUpdate ja praegu teeme deployd.

Kokkuvõttes — jälle vead.

Vanade varade kaotamise vältimiseks saab muuta emptyDir järgnevaga hostPath, ladustades staatikat füüsiliselt klastrite sõlme. See lähenemine on halb, sest me peame tegelikult seonduma konkreetse klastrite sõlmega oma rakendusega, kuna — kui kolitakse teistesse sõlmedesse — ei sisalda kataloog vajalikke faile. Vastasel juhul on vajalik teatud taustasünkroonimine katalooge vahel sõlmede.

Millised on lahenduste võimalused?

  1. Kui riistvara ja ressursid seda võimaldavad, võib kasutada cephfs statiiliste vajaduste jaoks ühtse juurdepääsuga katalooge korraldamiseks. Ametlik dokumentatsioon soovitab SSD-ketasid, vähemalt kolmekordset replikatsiooni ja stabiilset "paksu" ühendust kahe sõlme vahel klastris.
  2. Vähem nõudlik variant on NFS-serveri korraldamine. Siiski tuleb arvesse võtta võimalikku vastuse ajahüpet veebiserveri päringute töötlemisel, ning ka tõrkekindlus ei jää palju soovida. Tõrke tagajärjed on katastroofilised: mount'i kadumine viib klastrisse hävinguni koormuse LA all, mis tõuseb taevasse.

Peale selle on kõigi alalise salvestamise loomise variantide jaoks vajalik taustapuhastus aegunud failikomplektide, mis on kogunenud teatud aja jooksul. PHP konteinerite ette võib seada DaemonSet nginx'i vahemälu, mis hoiab koopiat vara piiratud aja. Seda käitumist on lihtne seadistada koos proxy_cache päevade või gigabaitide salvestusruumi sügavusega.

Selle meetodi ühendamine eespool mainitud jagatud failisüsteemidega annab tohutult võimalusi, ainus piirang on eelarve ja tehniline potentsiaal nende teostajate ja hoidjate seas. Kogemuste põhjal võib öelda, et mida lihtsam on süsteem, seda stabiilsem see töötab. Kui selliseid kihte lisada, muutub infrastruktuuri hooldamine palju keerukamaks ja sellega koos suureneb ka ajaline kulu diagnostikale ja taastamisele igasuguste tõrgete korral.

Soovitus

Kui pakutud salvestusvõimaluste rakendamine tundub teile samuti ebamugav (keeruline, kallis...), siis tasub vaadata olukorda teisest küljest. Nimelt - kaevuda projekti arhitektuuri ja kaotada probleem koodis, seondades mõnedele staatilistele andmestruktuuridele pildis, ühemõtteline sisu või „soojendamise“ ja / või ressursside eelkompileerimise protseduurid pildi ehitamise etapis. Nii saame täiesti ennustatavat käitumist ja ühesuguse failide kogumi kõigis keskkondades ja rakenduse replikates.

Kui minna tagasi konkreetse näite juurde Yii raamistikuga ja mitte süveneda selle struktuuri (mis ei ole artikli eesmärk), piisab, kui märkida ära kaks populaarset lähenemist:

  1. Muuda pildi ehitusprotsessi nii, et asetada ressursid etteennustatavasse kohta. Nii soovitab / rakendab laiendustes nagu yii2-static-assets.
  2. Määrata konkreetseid hash'e ressursside kataloogidele, nagu on näiteks kirjeldatud selles esituses (alates slaidist nr 35). Üksikasjalikult, et esituse autor soovitab, et pärast ressursside ehitamist ehitusserveris laadida need üles kesksetesse ladustamisse (nt S3), mille ees on CDN.

Üles laetavad failid

Teine juhtum, mis kindlasti toimib rakenduse Kubernetes klastrisse kolimisel, on kasutajafailide salvestamine failisüsteemis. Näiteks on meil taas PHP rakendus, mis võtab faile üleslaadimisvormi kaudu, teeb nende vormimise käigus midagi ja annab need tagasi.

Koht, kuhu need failid peaksid minema, peaks Kuberneteses olema kõigi rakenduse koopia jaoks ühine. Olenevalt rakenduse keerukusest ja vajadusest täiustatud failide korralduse järele, võivad sellised kohad olla eelmainitud shared-seadmed, kuid nagu näeme, on neil omad miinused.

Soovitus

Ühe lahendusena on S3-ühilduva salvestuse kasutamine (isegi kui mõni variant isehoidlast, nagu minio). Üleminek S3-le toob kaasa muudatusi kooditasandil, ja kuidas sisu edastatakse frontendi, on juba kirjutanud.

Kasutajaseansid

Eraldi väärib mainimist kasutajaseansside salvestamise korraldus. Tihti on need samuti failid kettal, mis Kubernetesis toob kaasa pidevad autentimispäringud kasutajalt, kui tema päring jõuab teise konteinerisse.

Osaliselt lahendab probleemi kõigi seda aktiveerimise stickySessions ingressil (funktsioon on toetatud kõigis populaarsetes ingressi kontrollerites — lisateavet leiate meie ülevaatest), et siduda kasutaja konkreetse rakenduse pod'iga:

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 vabasta korduvate väljalasetega seotud probleemidest.

Soovitus

Õigem lähenemine oleks rakenduse üleviimine sessioonide salvestamiseks memcachedi, Redis ja sarnaste lahenduste kasutamisele — üldiselt loobuda täielikult failipõhisest lähenemisest.

Kokkuvõte

Tööstuses arutletud infrastruktuuri lahendused sobivad rakendamiseks ainult ajutiste "toetuste" vormis. Need võivad olla asjakohased rakenduse migratsiooni varastes etappides Kubernetesesse, kuid ei peaks "juurduma".

Soovitatav tee on neist loobuda rakenduse arhitektuuri kohandamise kasuks, järgides juba paljudele tuntud põhimõtteid. 12-Factor App. Siiski tähendab rakenduse viimine stateless vormi, et koodis on vajalikud muudatused, ning siin on oluline leida tasakaal äri võimaluste/nõudmiste ja valitud tee elluviimise ning hooldamise perspektiivide vahel.

P.S.

Lugege ka meie blogist:

Allikas: habr.com

Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster