Vietiniai failai perkeliant programą į Kubernetes

Vietiniai failai perkeliant programą į Kubernetes

Kuriant CI/CD procesą naudojant Kubernetes, kartais iškyla naujos infrastruktūros ir į ją perkeliamos programos reikalavimų nesuderinamumo problema. Visų pirma, programos kūrimo etape svarbu gauti vienas vaizdas, kuris bus naudojamas visi projektų aplinkos ir klasteriai. Šis principas yra teisingo pagrindo pagal Google konteinerių valdymas (daugiau nei vieną kartą apie tai sakė ir mūsų techninis skyrius).

Tačiau jūs nematysite nieko situacijose, kai svetainės kodas naudoja paruoštą sistemą, kurios naudojimas apriboja tolesnį jos naudojimą. Ir nors „įprastoje aplinkoje“ su tuo susidoroti nesunku, Kubernetes toks elgesys gali tapti problema, ypač susidūrus su juo pirmą kartą. Nors išradingas protas gali sugalvoti infrastruktūros sprendimus, kurie iš pirmo žvilgsnio atrodo akivaizdūs ar net geri... svarbu atminti, kad daugeliu atvejų galima ir reikia būti išspręstas architektūriškai.

Pažvelkime į populiarius failų saugojimo sprendimus, kurie gali sukelti nemalonių pasekmių naudojant klasterį, taip pat nurodykite teisingesnį kelią.

Statinė saugykla

Norėdami iliustruoti, apsvarstykite žiniatinklio programą, kuri naudoja tam tikrą statinį generatorių, kad gautų vaizdų, stilių ir kitų dalykų rinkinį. Pavyzdžiui, Yii PHP sistemoje yra įmontuotas turto tvarkytuvas, kuris generuoja unikalius katalogų pavadinimus. Atitinkamai, išvestis yra kelių, skirtų statinei svetainei, rinkinys, kurie akivaizdžiai nesikerta vienas su kitu (tai buvo padaryta dėl kelių priežasčių – pavyzdžiui, siekiant pašalinti dublikatus, kai keli komponentai naudoja tą patį šaltinį). Taigi, pirmą kartą prisijungus prie žiniatinklio išteklių modulio, statiniai failai (iš tikrųjų dažnai simbolių nuorodos, bet apie tai vėliau) yra suformuojami ir išdėstomi naudojant bendrą šakninį katalogą, unikalų šiam diegimui:

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

Ką tai reiškia, kalbant apie klasterį?

Paprasčiausias pavyzdys

Paimkime gana įprastą atvejį, kai prieš PHP yra nginx, skirtas platinti statinius duomenis ir apdoroti paprastas užklausas. Lengviausias būdas - diegimo su dviem konteineriais:

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

Supaprastinta forma nginx konfigūracija yra tokia:

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

Kai pirmą kartą pasiekiate svetainę, ištekliai rodomi PHP konteineryje. Bet jei vienoje talpykloje yra du konteineriai, nginx nieko nežino apie šiuos statinius failus, kurie (pagal konfigūraciją) turėtų būti jiems suteikti. Dėl to klientas visoms užklausoms į CSS ir JS failus matys klaidą 404. Paprasčiausias sprendimas čia būtų sutvarkyti bendrą konteinerių katalogą. Primityvus variantas – bendras 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

Dabar konteineryje sugeneruotus statinius failus nginx tinkamai aptarnauja. Tačiau priminsiu, kad tai primityvus sprendimas, o tai reiškia, kad jis toli gražu nėra idealus ir turi savų niuansų bei trūkumų, kurie aptariami toliau.

Išplėstinė saugykla

Dabar įsivaizduokite situaciją, kai vartotojas apsilankė svetainėje, įkėlė puslapį su konteineryje esančiais stiliais, o jam skaitant šį puslapį mes iš naujo įdiegėme sudėtinį rodinį. Turto katalogas tapo tuščias ir norint pradėti kurti naujus, reikia pateikti PHP prašymą. Tačiau net ir po to nuorodos į seną statiką bus nereikšmingos, o tai sukels statikos rodymo klaidų.

Be to, greičiausiai turime daugiau ar mažiau įkeltą projektą, o tai reiškia, kad vienos programos kopijos nepakaks:

  • Padidinkime jo mastelį diegimo iki dviejų kopijų.
  • Kai svetainė buvo pirmą kartą atidaryta, ištekliai buvo sukurti vienoje kopijoje.
  • Tam tikru momentu ingress nusprendė (apkrovos balansavimo tikslais) nusiųsti užklausą antrajai kopijai, o šių išteklių dar nebuvo. O gal jų nebėra, nes naudojame RollingUpdate ir šiuo metu mes vykdome dislokavimą.

Apskritai rezultatas vėl yra klaidos.

Kad neprarastumėte seno turto, galite pakeisti emptyDir apie hostPathfiziškai pridedant statinį klasterio mazgą. Šis požiūris yra blogas, nes iš tikrųjų privalome susieti su konkrečiu klasterio mazgu savo programą, nes – perėjus į kitus mazgus – kataloge nebus reikalingų failų. Arba reikalingas tam tikras fono katalogų sinchronizavimas tarp mazgų.

Kokie yra sprendimai?

  1. Jei leidžia techninė įranga ir ištekliai, galite naudoti cephfs organizuoti vienodai prieinamą katalogą statiniams poreikiams. Oficiali dokumentacija rekomenduoja SSD diskus, bent tris kartus replikaciją ir stabilų „storą“ ryšį tarp klasterio mazgų.
  2. Mažiau reiklus pasirinkimas būtų organizuoti NFS serverį. Tačiau tuomet reikia atsižvelgti į galimą atsakymo laiko padidėjimą, kai žiniatinklio serveris apdoroja užklausas, o atsparumas gedimams paliks daug norimų rezultatų. Nesėkmės pasekmės yra katastrofiškos: kalno praradimas pasmerkia spiečius mirtinai dėl LA apkrovos, besiveržiančios į dangų.

Be kita ko, reikės visų nuolatinės saugyklos kūrimo parinkčių fono valymas pasenusių failų rinkinių, sukauptų per tam tikrą laikotarpį. Prieš konteinerius su PHP galite įdėti DaemonSet iš talpyklos „nginx“, kuri ribotą laiką saugos išteklių kopijas. Šią elgseną lengva konfigūruoti naudojant proxy_cache su saugojimo gyliu dienomis arba gigabaitais disko vietos.

Šio metodo derinimas su aukščiau paminėtomis paskirstytomis failų sistemomis suteikia didžiulį lauką vaizduotei, kurį riboja tik biudžetas ir techninis potencialas tų, kurie jį įgyvendins ir palaikys. Iš patirties galime pasakyti, kad kuo paprastesnė sistema, tuo stabiliau ji veikia. Pridėjus tokius sluoksnius, infrastruktūrą prižiūrėti tampa daug sunkiau, o kartu pailgėja laikas, skiriamas diagnozuojant ir atsigaunant po bet kokių gedimų.

Rekomendacija

Jei siūlomų saugojimo variantų įgyvendinimas jums taip pat atrodo nepateisinamas (sudėtingas, brangus...), tuomet verta pažvelgti į situaciją iš kitos pusės. Būtent, įsigilinti į projekto architektūrą ir ištaisykite problemą kode, susietas su tam tikra statine vaizdo duomenų struktūra, nedviprasmiškas turinio apibrėžimas arba „apšilimo“ ir (arba) išankstinio išteklių kompiliavimo procedūros vaizdo surinkimo etape. Tokiu būdu gauname absoliučiai nuspėjamą elgesį ir tą patį failų rinkinį visoms aplinkoms ir veikiančios programos kopijoms.

Jei grįšime prie konkretaus pavyzdžio su Yii sistema ir nesigilinsime į jo struktūrą (tai nėra straipsnio tikslas), pakanka nurodyti du populiarius metodus:

  1. Pakeiskite vaizdo kūrimo procesą, kad ištekliai būtų nuspėjamoje vietoje. Tai siūloma / įgyvendinama tokiuose plėtiniuose kaip yii2-static-assets.
  2. Apibrėžkite konkrečias turto katalogų maišas, kaip aptarta pvz. šis pristatymas (pradedant nuo skaidrės Nr. 35). Beje, ataskaitos autorius galiausiai (ir ne be reikalo!) pataria, kad surinkus aktyvus build serveryje, įkelti juos į centrinę saugyklą (pvz., S3), prieš kurią patalpinti CDN.

Atsisiuntimai

Kitas atvejis, kuris neabejotinai atsiras perkeliant programą į Kubernetes klasterį, yra vartotojo failų saugojimas failų sistemoje. Pavyzdžiui, vėl turime PHP programą, kuri priima failus per įkėlimo formą, veikia su jais ir siunčia atgal.

„Kubernetes“ šių failų vieta turėtų būti bendra visoms programos kopijoms. Priklausomai nuo programos sudėtingumo ir poreikio organizuoti šių failų išlikimą, aukščiau minėtos bendro naudojimo įrenginio parinktys gali būti tokia vieta, tačiau, kaip matome, jos turi savo trūkumų.

Rekomendacija

Vienas sprendimas yra naudojant su S3 suderinamą saugyklą (net jei tai yra kokia nors savarankiška kategorija, pvz., minio). Norint pereiti prie S3, reikės atlikti pakeitimus kodo lygiu, ir kaip turinys bus pateiktas priekinėje dalyje, jau žinojome писали.

Vartotojų sesijos

Atskirai verta paminėti vartotojo seansų saugojimo organizavimą. Dažnai tai taip pat yra diske esantys failai, dėl kurių „Kubernetes“ kontekste vartotojas nuolatos prašys leidimo, jei jo užklausa atsidurs kitame konteineryje.

Problema iš dalies išspręsta įjungus stickySessions patekus (funkcija palaikoma visuose populiariuose įėjimo valdikliuose – daugiau informacijos žr mūsų apžvalga)Norėdami susieti vartotoją su tam tikra priemone su programa:

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

Tačiau tai nepašalins problemų, susijusių su pakartotiniu diegimu.

Rekomendacija

Teisingesnis būdas būtų perkelti paraišką į seansų saugojimas „memcached“, „Redis“ ir panašiuose sprendimuose - apskritai visiškai atsisakykite failų parinkčių.

išvada

Tekste aptariami infrastruktūros sprendimai yra verti naudoti tik laikinų „ramentų“ formatu (kas gražiau skamba angliškai kaip išeitis). Jie gali būti svarbūs pirmaisiais programos perkėlimo į Kubernetes etapais, tačiau neturėtų įsitvirtinti.

Bendras rekomenduojamas būdas yra jų atsikratyti ir pakeisti programos architektūrą pagal tai, kas daugeliui jau gerai žinoma 12 faktorių programa. Tačiau tai – programos perkėlimas į bevalstybės formą – neišvengiamai reiškia, kad reikės keisti kodą, o čia svarbu rasti pusiausvyrą tarp verslo galimybių/reikalavimų ir pasirinkto kelio diegimo bei išlaikymo perspektyvų. .

PS

Taip pat skaitykite mūsų tinklaraštyje:

Šaltinis: www.habr.com

Добавить комментарий