Skedarët lokalë kur migroni një aplikacion në Kubernetes

Skedarët lokalë kur migroni një aplikacion në Kubernetes

Kur ndërtohet një proces CI/CD duke përdorur Kubernetes, ndonjëherë lind problemi i papajtueshmërisë midis kërkesave të infrastrukturës së re dhe aplikacionit që transferohet në të. Në veçanti, në fazën e ndërtimit të aplikacionit është e rëndësishme të merrni një imazhi që do të përdoret në Të gjithë mjediset dhe grupimet e projektit. Ky parim qëndron në themel të së drejtës sipas Google menaxhimi i kontejnerëve (më shumë se një herë në lidhje me këtë foli dhe departamenti ynë teknik).

Sidoqoftë, nuk do të shihni askënd në situatat kur kodi i faqes përdor një kornizë të gatshme, përdorimi i të cilit imponon kufizime në përdorimin e tij të mëtejshëm. Dhe ndërsa në një "mjedis normal" kjo është e lehtë për t'u përballuar, në Kubernetes kjo sjellje mund të bëhet problem, veçanërisht kur e hasni për herë të parë. Ndërsa një mendje krijuese mund të dalë me zgjidhje infrastrukturore që duken të dukshme apo edhe të mira në shikim të parë... është e rëndësishme të mbani mend se shumica e situatave mund dhe duhet të zgjidhet arkitekturisht.

Ne do të analizojmë zgjidhjet popullore të zgjidhjes për ruajtjen e skedarëve që mund të çojnë në pasoja të pakëndshme kur përdorni një grup, dhe gjithashtu do të tregojmë një rrugë më të saktë.

Ruajtja statike

Për ta ilustruar, merrni parasysh një aplikacion ueb që përdor një lloj gjeneruesi statik për të marrë një grup imazhesh, stilesh dhe gjëra të tjera. Për shembull, korniza Yii PHP ka një menaxher të integruar të aseteve që gjeneron emra unikë të drejtorive. Prandaj, dalja është një grup shtigjesh për sitin statik që padyshim nuk kryqëzohen me njëra-tjetrën (kjo është bërë për disa arsye - për shembull, për të eliminuar dublikatat kur komponentë të shumtë përdorin të njëjtin burim). Pra, jashtë kutisë, herën e parë që hyni në një modul të burimit në internet, skedarët statikë (në fakt, shpesh simlinks, por më shumë për këtë më vonë) formohen dhe vendosen me një direktori të përbashkët rrënjë, unike për këtë vendosje:

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

Çfarë do të thotë kjo për sa i përket një grupi?

Shembulli më i thjeshtë

Le të marrim një rast mjaft të zakonshëm, kur PHP paraprihet nga nginx për të shpërndarë të dhëna statike dhe për të përpunuar kërkesa të thjeshta. Mënyra më e lehtë - shpërndarje me dy kontejnerë:

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

Në një formë të thjeshtuar, konfigurimi nginx zbret në sa vijon:

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

Kur hyni për herë të parë në sajt, aktivet shfaqen në kontejnerin PHP. Por në rastin e dy kontejnerëve brenda një pod, nginx nuk di asgjë për këto skedarë statikë, të cilët (sipas konfigurimit) duhet t'u jepen atyre. Si rezultat, klienti do të shohë një gabim 404 për të gjitha kërkesat për skedarët CSS dhe JS. Zgjidhja më e thjeshtë këtu do të ishte organizimi i një drejtorie të përbashkët për kontejnerët. Opsioni primitiv - i përgjithshëm 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

Tani skedarët statikë të krijuar në kontejner shërbehen nga nginx në mënyrë korrekte. Por më lejoni t'ju kujtoj se kjo është një zgjidhje primitive, që do të thotë se është larg idealit dhe ka nuancat dhe mangësitë e veta, të cilat do të diskutohen më poshtë.

Magazinim më i avancuar

Tani imagjinoni një situatë ku një përdorues vizitoi sitin, ngarkoi një faqe me stilet e disponueshme në kontejner, dhe ndërsa ai po lexonte këtë faqe, ne e rivendosëm kontejnerin. Katalogu i aseteve është bosh dhe kërkohet një kërkesë në PHP për të filluar gjenerimin e të rejave. Sidoqoftë, edhe pas kësaj, lidhjet me statikën e vjetër do të jenë të parëndësishme, gjë që do të çojë në gabime në shfaqjen e statikës.

Për më tepër, ne ka shumë të ngjarë të kemi një projekt pak a shumë të ngarkuar, që do të thotë se një kopje e aplikacionit nuk do të jetë e mjaftueshme:

  • Le ta përshkallëzojmë atë shpërndarje deri në dy kopje.
  • Kur u hap për herë të parë faqja, asetet u krijuan në një kopje.
  • Në një moment, hyrja vendosi (për qëllime të balancimit të ngarkesës) të dërgonte një kërkesë në kopjen e dytë, dhe këto asete nuk ishin ende aty. Ose ndoshta nuk janë më aty sepse ne i përdorim RollingUpdate dhe për momentin jemi duke bërë vendosjen.

Në përgjithësi, rezultati është përsëri gabime.

Për të shmangur humbjen e aseteve të vjetra, mund të ndryshoni emptyDir mbi hostPath, duke shtuar fizikisht statike në një nyje grupi. Kjo qasje është e keqe sepse ne në fakt duhet lidheni me një nyje specifike të grupimit aplikacionin tuaj, sepse - në rast të zhvendosjes në nyje të tjera - drejtoria nuk do të përmbajë skedarët e nevojshëm. Ose kërkohet një lloj sinkronizimi i drejtorisë së sfondit midis nyjeve.

Cilat janë zgjidhjet?

  1. Nëse ju lejojnë hardueri dhe burimet, mund ta përdorni cephfs për të organizuar një drejtori po aq të aksesueshme për nevoja statike. Dokumentacioni zyrtar rekomandon disqet SSD, të paktën përsëritje të trefishtë dhe një lidhje të qëndrueshme "të trashë" midis nyjeve të grupimit.
  2. Një opsion më pak i kërkuar do të ishte organizimi i një serveri NFS. Sidoqoftë, atëherë duhet të merrni parasysh rritjen e mundshme të kohës së përgjigjes për përpunimin e kërkesave nga serveri në internet, dhe toleranca e gabimeve do të lërë shumë për të dëshiruar. Pasojat e dështimit janë katastrofike: humbja e malit e dënon grupin me vdekje nën presionin e ngarkesës LA që nxiton në qiell.

Ndër të tjera, të gjitha opsionet për krijimin e ruajtjes së vazhdueshme do të kërkojnë pastrimi i sfondit grupe dosjesh të vjetruara të grumbulluara gjatë një periudhe të caktuar kohore. Përpara kontejnerëve me PHP mund të vendosni DaemonSet nga caching nginx, i cili do të ruajë kopjet e aseteve për një kohë të kufizuar. Kjo sjellje është lehtësisht e konfigurueshme duke përdorur proxy_cache me thellësi ruajtjeje në ditë ose gigabajt hapësirë ​​në disk.

Kombinimi i kësaj metode me sistemet e skedarëve të shpërndarë të përmendur më sipër ofron një fushë të madhe imagjinate, e kufizuar vetëm nga buxheti dhe potenciali teknik i atyre që do ta zbatojnë dhe mbështesin atë. Nga përvoja, mund të themi se sa më i thjeshtë të jetë sistemi, aq më i qëndrueshëm funksionon. Kur shtohen shtresa të tilla, bëhet shumë më e vështirë mirëmbajtja e infrastrukturës dhe në të njëjtën kohë rritet koha e shpenzuar për diagnostikimin dhe rikuperimin nga çdo dështim.

rekomandim

Nëse zbatimi i opsioneve të propozuara të ruajtjes ju duket gjithashtu i pajustifikuar (i ndërlikuar, i shtrenjtë ...), atëherë ia vlen ta shikoni situatën nga ana tjetër. Gjegjësisht, për të gërmuar në arkitekturën e projektit dhe rregulloni problemin në kod, i lidhur me një strukturë statike të të dhënave në imazh, një përkufizim i qartë i përmbajtjes ose procedurës për "ngrohjen" dhe/ose parapërpilimin e aseteve në fazën e montimit të imazhit. Në këtë mënyrë marrim sjellje absolutisht të parashikueshme dhe të njëjtin grup skedarësh për të gjitha mjediset dhe kopjet e aplikacionit që funksionon.

Nëse kthehemi te shembulli specifik me kornizën Yii dhe nuk thellohemi në strukturën e tij (që nuk është qëllimi i artikullit), mjafton të theksojmë dy qasje popullore:

  1. Ndryshoni procesin e krijimit të imazhit për të vendosur asetet në një vendndodhje të parashikueshme. Kjo sugjerohet/zbatohet në shtesa si yii2-statike-pasuri.
  2. Përcaktoni hash specifik për drejtoritë e aseteve, siç diskutohet në p.sh. këtë prezantim (duke filluar nga rrëshqitja nr. 35). Nga rruga, autori i raportit në fund të fundit (dhe jo pa arsye!) këshillon që pasi të keni montuar asetet në serverin e ndërtimit, t'i ngarkoni ato në një ruajtje qendrore (si S3), përpara së cilës vendosni një CDN.

Skedarët e shkarkueshëm

Një rast tjetër që patjetër do të hyjë në lojë kur migroni një aplikacion në një grupim Kubernetes është ruajtja e skedarëve të përdoruesit në sistemin e skedarëve. Për shembull, ne kemi përsëri një aplikacion PHP që pranon skedarë përmes një formulari të ngarkimit, bën diçka me ta gjatë funksionimit dhe i kthen ato.

Në Kubernetes, vendndodhja ku duhet të vendosen këta skedarë duhet të jetë e zakonshme për të gjitha kopjet e aplikacionit. Në varësi të kompleksitetit të aplikacionit dhe nevojës për të organizuar qëndrueshmërinë e këtyre skedarëve, opsionet e mësipërme të përbashkëta të pajisjes mund të jenë një vend i tillë, por, siç e shohim, ato kanë të metat e tyre.

rekomandim

Një zgjidhje është duke përdorur hapësirën ruajtëse të përputhshme me S3 (edhe nëse është një lloj kategorie e vetë-strehuar si minio). Kalimi në S3 do të kërkojë ndryshime në nivelin e kodit, dhe se si do të dorëzohet përmbajtja në pjesën e përparme, ne e kemi tashmë писали.

Sesionet e përdoruesve

Më vete, vlen të përmendet organizimi i ruajtjes së seancave të përdoruesve. Shpesh këto janë gjithashtu skedarë në disk, të cilët në kontekstin e Kubernetes do të çojnë në kërkesa të vazhdueshme autorizimi nga përdoruesi nëse kërkesa e tij përfundon në një kontejner tjetër.

Problemi zgjidhet pjesërisht duke ndezur stickySessions në hyrje (funksioni mbështetet në të gjithë kontrollorët e njohur të hyrjes - për më shumë detaje, shihni rishikimi ynë)për të lidhur përdoruesin në një pod specifik me aplikacionin:

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: /

Por kjo nuk do të eliminojë problemet me vendosjet e përsëritura.

rekomandim

Një mënyrë më e saktë do të ishte transferimi i aplikacionit në ruajtja e seancave në memcached, Redis dhe zgjidhje të ngjashme - në përgjithësi, braktisni plotësisht opsionet e skedarëve.

Përfundim

Zgjidhjet e infrastrukturës të diskutuara në tekst janë të denja për t'u përdorur vetëm në formatin e "patericave" të përkohshme (që tingëllon më bukur në anglisht si zgjidhje). Ato mund të jenë të rëndësishme në fazat e para të migrimit të një aplikacioni në Kubernetes, por nuk duhet të zënë rrënjë.

Rruga e përgjithshme e rekomanduar është të heqësh qafe prej tyre në favor të modifikimit arkitektonik të aplikacionit në përputhje me atë që tashmë është e njohur për shumë njerëz. Aplikacioni 12-Faktor. Megjithatë, kjo - sjellja e aplikacionit në një formë pa shtetësi - do të thotë në mënyrë të pashmangshme se do të kërkohen ndryshime në kod dhe këtu është e rëndësishme të gjendet një ekuilibër midis aftësive/kërkesave të biznesit dhe perspektivave për zbatimin dhe ruajtjen e rrugës së zgjedhur. .

PS

Lexoni edhe në blogun tonë:

Burimi: www.habr.com

Shto një koment