Lokaj dosieroj dum migrado de aplikaĵo al Kubernetes

Lokaj dosieroj dum migrado de aplikaĵo al Kubernetes

Dum konstruado de CI/KD-procezo uzante Kubernetes, foje la problemo ekestas de nekongruo inter la postuloj de la nova infrastrukturo kaj la aplikaĵo translokigita al ĝi. Precipe, ĉe la aplika etapo estas grave akiri один bildo kiu estos uzata en всех projektmedioj kaj aretoj. Ĉi tiu principo subestas la ĝustan laŭ Guglo kontenera administrado (pli ol unufoje pri tio parolis kaj nia teknika fako).

Tamen vi ne vidos iun ajn en situacioj, kie la kodo de la retejo uzas pretan kadron, kies uzo trudas limigojn al ĝia plua uzo. Kaj dum en "normala medio" ĉi tio estas facile trakti, en Kubernetes ĉi tiu konduto povas fariĝi problemo, precipe kiam vi renkontas ĝin por la unua fojo. Kvankam inventema menso povas elpensi infrastrukturajn solvojn, kiuj ŝajnas evidentaj kaj eĉ bonaj unuavide... estas grave memori, ke la plej multaj situacioj povas kaj devas. esti solvita arkitekture.

Ni analizos popularajn solvojn por stoki dosierojn, kiuj povas konduki al malagrablaj sekvoj dum funkciado de areto, kaj ankaŭ montros pli ĝustan vojon.

Senmova stokado

Por ilustri, konsideru TTT-aplikaĵon, kiu uzas ian statikan generatoron por akiri aron da bildoj, stiloj kaj aliaj aferoj. Ekzemple, la Yii PHP-kadro havas enkonstruitan valoradministranton kiu generas unikajn dosierujojn. Sekve, la eligo estas aro da vojoj por la senmova retejo, kiuj evidente ne intersekcas unu kun la alia (tio estis farita pro pluraj kialoj - ekzemple, por forigi duplikatojn kiam pluraj komponantoj uzas la saman rimedon). Do, el la skatolo, la unuan fojon kiam vi aliras retan rimedan modulon, statikaj dosieroj (fakte, ofte simbolaj ligiloj, sed pli pri tio poste) estas formitaj kaj aranĝitaj kun komuna radika dosierujo unika por ĉi tiu deplojo:

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

Kion ĉi tio signifas laŭ aro?

La plej simpla ekzemplo

Ni prenu sufiĉe oftan kazon, kiam PHP estas antaŭita de nginx por distribui senmovajn datumojn kaj prilabori simplajn petojn. La plej facila maniero - deplojo kun du ujoj:

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

En simpligita formo, la nginx-agordo resumas al la sekvanta:

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

Kiam vi unue aliras la retejon, valoraĵoj aperas en la PHP-ujo. Sed en la kazo de du ujoj ene de unu pod, nginx scias nenion pri ĉi tiuj senmovaj dosieroj, kiuj (laŭ la agordo) devus esti donitaj al ili. Kiel rezulto, la kliento vidos eraron 404 por ĉiuj petoj al dosieroj CSS kaj JS. La plej simpla solvo ĉi tie estus organizi komunan dosierujon por ujoj. Primitiva opcio - ĝenerala 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

Nun statikaj dosieroj generitaj en la ujo estas servataj de nginx ĝuste. Sed mi memorigu al vi, ke ĉi tio estas primitiva solvo, kio signifas, ke ĝi estas malproksime de ideala kaj havas siajn proprajn nuancojn kaj mankojn, kiuj estas diskutitaj sube.

Pli altnivela stokado

Nun imagu situacion, kie uzanto vizitis la retejon, ŝarĝis paĝon kun la stiloj disponeblaj en la ujo, kaj dum li legis ĉi tiun paĝon, ni re-deplojis la ujon. La katalogo de aktivaĵoj malpleniĝis kaj necesas peto al PHP por komenci generi novajn. Tamen, eĉ post ĉi tio, ligiloj al malnova statiko estos sensignivaj, kio kondukos al eraroj en montrado de statiko.

Krome, ni plej verŝajne havas pli-malpli ŝargitan projekton, kio signifas, ke unu kopio de la aplikaĵo ne sufiĉos:

  • Ni pligrandigu ĝin deplojo ĝis du kopioj.
  • Kiam la retejo unue estis alirita, aktivaĵoj estis kreitaj en unu kopio.
  • En iu momento, eniro decidis (por ŝarĝobalancado) sendi peton al la dua kopio, kaj ĉi tiuj aktivoj ankoraŭ ne estis tie. Aŭ eble ili ne plu estas tie ĉar ni uzas RollingUpdate kaj nuntempe ni faras deplojon.

Ĝenerale, la rezulto estas denove eraroj.

Por eviti perdi malnovajn valoraĵojn, vi povas ŝanĝi emptyDir sur hostPath, aldonante senmovan fizike al aretnodo. Ĉi tiu aliro estas malbona ĉar ni efektive devas ligi al specifa clusternodo via aplikaĵo, ĉar - en kazo de translokiĝo al aliaj nodoj - la dosierujo ne enhavos la necesajn dosierojn. Aŭ ia fona dosierujo-sinkronigo inter nodoj estas bezonata.

Kio estas la solvoj?

  1. Se aparataro kaj rimedoj permesas, vi povas uzi cephfs organizi same atingeblan dosierujon por senmovaj bezonoj. Oficiala dokumentaro rekomendas SSD-diskojn, almenaŭ trioblan reproduktadon kaj stabilan "dikan" ligon inter grapolnodoj.
  2. Malpli postulema opcio estus organizi NFS-servilon. Tamen, tiam vi devas konsideri la eblan pliiĝon de responda tempo por prilaborado de petoj de la retservilo, kaj misfunkciado lasos multon por deziri. La sekvoj de fiasko estas katastrofaj: la perdo de la monto kondamnas la areton al morto sub la premo de la LA-ŝarĝo rapidanta en la ĉielon.

Interalie, ĉiuj elektoj por krei konstantan stokadon postulos fonpurigado malmodernaj aroj de dosieroj akumuliĝis dum certa tempodaŭro. Antaŭ ujoj kun PHP vi povas meti DaemonSet de kaŝmemoro nginx, kiu stokos kopiojn de aktivoj por limigita tempo. Ĉi tiu konduto estas facile agordebla uzante proxy_cache kun stoka profundo en tagoj aŭ gigabajtoj da diskospaco.

Kombini ĉi tiun metodon kun la distribuitaj dosiersistemoj menciitaj supre provizas grandegan kampon por imago, limigita nur de la buĝeto kaj teknika potencialo de tiuj, kiuj efektivigos kaj subtenos ĝin. Laŭ sperto, ni povas diri, ke ju pli simpla estas la sistemo, des pli stabila ĝi funkcias. Kiam tiaj tavoloj estas aldonitaj, fariĝas multe pli malfacile konservi la infrastrukturon, kaj samtempe pliiĝas la tempo pasigita por diagnozi kaj rekuperi de iuj malsukcesoj.

Rekomendo

Se la efektivigo de la proponitaj stokaj opcioj ankaŭ ŝajnas al vi nepraviga (komplika, multekosta...), tiam indas rigardi la situacion de la alia flanko. Nome, fosi en la projektarkitekturo kaj ripari la problemon en la kodo, ligita al iu senmova datenstrukturo en la bildo, malambigua difino de la enhavo aŭ proceduro por "varmigado" kaj/aŭ antaŭkompilado de aktivaĵoj ĉe la bilda kunigostadio. Tiel ni ricevas absolute antaŭvideblan konduton kaj la saman aron de dosieroj por ĉiuj medioj kaj kopioj de la funkcianta aplikaĵo.

Se ni revenos al la specifa ekzemplo kun la kadro Yii kaj ne enprofundiĝos en ĝian strukturon (kio ne estas la celo de la artikolo), sufiĉas atentigi du popularajn alirojn:

  1. Ŝanĝu la procezon de konstruo de bildoj por meti aktivaĵojn en antaŭvidebla loko. Ĉi tio estas sugestita/efektivigata en etendoj kiel yii2-statika-aktivoj.
  2. Difinu specifajn haŝojn por aktivo-dosierujoj, kiel diskutite en ekz. ĉi tiu prezento (komencante de glito n-ro 35). Cetere, la aŭtoro de la raporto finfine (kaj ne senkaŭze!) konsilas, ke post kunmeti aktivaĵojn sur la konstruservilo, alŝutu ilin al centra stokado (kiel S3), antaŭ kiu metu CDN.

Elŝuteblaj dosieroj

Alia kazo, kiu certe venos en ludon kiam migros aplikaĵon al Kubernetes-grupo, estas stokado de uzantdosieroj en la dosiersistemo. Ekzemple, ni denove havas PHP-aplikaĵon, kiu akceptas dosierojn per alŝuta formularo, faras ion per ili dum operacio kaj resendas ilin.

En Kubernetes, la loko kie ĉi tiuj dosieroj devas esti metitaj devus esti komuna al ĉiuj kopioj de la aplikaĵo. Depende de la komplekseco de la aplikaĵo kaj la bezono organizi la persiston de ĉi tiuj dosieroj, la supre menciitaj komunaj aparatoj povas esti tia loko, sed, kiel ni vidas, ili havas siajn malavantaĝojn.

Rekomendo

Unu solvo estas uzante S3-kongruan stokadon (eĉ se ĝi estas ia memgastigita kategorio kiel minio). Ŝanĝi al S3 postulos ŝanĝojn ĉe la kodnivelo, kaj kiel enhavo estos liverita ĉe la antaŭa finaĵo, ni jam havas skribis.

Uzantaj kunsidoj

Aparte, indas noti la organizon de stokado de uzantkunsidoj. Ofte ĉi tiuj ankaŭ estas dosieroj sur disko, kiuj en la kunteksto de Kubernetes kondukos al konstantaj rajtigaj petoj de la uzanto se lia peto finiĝas en alia ujo.

La problemo estas parte solvita per ŝaltado stickySessions sur eniro (la funkcio estas subtenata en ĉiuj popularaj enirregiloj - por pliaj detaloj, vidu nia recenzo)por ligi la uzanton al specifa pod kun la aplikaĵo:

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

Sed ĉi tio ne forigos problemojn kun ripetaj deplojoj.

Rekomendo

Pli ĝusta maniero estus translokigi la aplikaĵon al stokante sesiojn en memcached, Redis kaj similaj solvoj - ĝenerale, tute forlasu dosiero-opciojn.

konkludo

La infrastrukturaj solvoj diskutitaj en la teksto estas indaj je uzo nur en la formato de provizoraj "lambastonoj" (kiu sonas pli bele en la angla kiel solvo). Ili povas esti gravaj en la unuaj etapoj de migrado de aplikaĵo al Kubernetes, sed ne devus enradikiĝi.

La ĝenerala rekomendita vojo estas forigi ilin favore al arkitektura modifo de la aplikaĵo konforme al tio, kio jam estas konata de multaj. 12-Faktora Apo. Tamen, ĉi tio - alporti la aplikaĵon al sennacia formo - neeviteble signifas, ke ŝanĝoj en la kodo estos postulataj, kaj ĉi tie gravas trovi ekvilibron inter la kapabloj/postuloj de la komerco kaj la perspektivoj por efektivigi kaj konservi la elektitan vojon. .

PS

Legu ankaŭ en nia blogo:

fonto: www.habr.com

Aldoni komenton