Helyi fájlok az alkalmazás Kubernetesbe való áthelyezésekor

Helyi fájlok az alkalmazás Kubernetesbe való áthelyezésekor

A CI/CD process using Kubernetes often encounters a problem of compatibility between the requirements of the new infrastructure and the application being migrated. In particular, at the application build stage, it is essential to obtain ; ideális esetben a felhasználónak két vagy több titkos kérdést kellene választania an image that will be used in adattal, tehát csak a TXE jelző nem lesz elegendő. the project's environments and clusters. This principle is the basis of proper container management, according to Google (which has been mentioned multiple times) by our tech director. However, you often find situations where a ready-made framework is used in the website's code, which imposes limitations on its further operation. If in a 'traditional environment' this is easy to handle, in Kubernetes, such behavior can become problematic, especially when you encounter it for the first time. Although a creative mind can propose infrastructural solutions that seem obvious and even quite good at first glance... it is important to remember that most situations can and should be

resolved architecturally. Let's explore popular workaround solutions for file storage that may lead to unpleasant consequences in cluster operation, as well as point out a more correct path..

Static File Storage

To illustrate, let's consider a web application that uses a certain static generator to create a set of images, styles, and more. For example, in the PHP framework Yii, there is a built-in asset manager that generates unique directory names. Accordingly, the output results in a set of paths for the website's static files that do not overlap (this is done for several reasons—such as preventing duplicates when the same resource is used by multiple components). Thus, out of the box, when the module of the web resource is first accessed, the static files are generated and laid out (actually, often symlinks, but more on that later) with a unique common root directory for this deployment:

webroot/assets/2072c2df/css/…

  • webroot/assets/2072c2df/images/…
  • webroot/assets/2072c2df/js/…
  • What are the implications of this in the context of the cluster?

A simple example

Let's take a fairly common case where nginx is used in front of PHP to serve static files and handle simple requests. The simplest way is to use

two containers: Deployment két konténerrel:

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

Egyszerűsítve a nginx konfigurációja a következőre egyszerűsödik:

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

Amikor a felhasználó először hozzáfér a weboldalhoz a PHP tartalmú konténerben, megjelennek az erőforrások. De amikor két konténer van egy pod-ban, a nginx nem tud ezekről a statikus fájlokról, amelyek (a konfiguráció szerint) neki kellene, hogy szolgáltasson. Ennek eredményeként a CSS- és JS-fájlokhoz intézett összes kérés 404-es hibát fog visszaadni. A legegyszerűbb megoldás itt közös könyvtár létrehozása a konténerek között. Az egyszerű megoldás - közös 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

Most már a konténerben generált statikus fájlok helyesen kerülnek átadásra az nginx által. De emlékeztetnék arra, hogy ez egy primitív megoldás, tehát messze nem ideális, és vannak saját finomításai és hiányosságai, amelyeket alább ismertetek.

Fejlettebb tároló

Most képzeljünk el egy helyzetet, amikor a felhasználó belépett a weboldalra, betöltötte az oldalakat, amelyek a konténer stílusaival rendelkeznek, és amíg olvasta ezt az oldalt, újra telepítettük a konténert. Az eszközök mappája üres lett, és szükség van egy PHP kérésre az új generálás kezdeményezéséhez. Azonban még ezután is az öreg statikus linkek elavultak maradnak, ami a statikus tartalmak megjelenítési hibáihoz vezet.

Ráadásul valószínűleg egy viszonylag terhelt projektről van szó, tehát egyetlen példány az alkalmazásból nem lesz elegendő:

  • Skálázzuk Deployment két replikára.
  • Az első látogatáskor az egyik replikán létrejöttek az eszközök.
  • Egy bizonyos ponton az ingress úgy döntött (a terhelés egyensúlyozása érdekében), hogy a második replikára küldje a lekérdezést, és ott nincsenek még ezek az eszközök. Vagy lehet, hogy ott sincsenek, mert használjuk a RollingUpdate és jelenleg telepítjük.

Összességében, a végeredmény — újra hibák.

A régi eszközök megőrzése érdekében megváltoztathatjuk a emptyDir Gyorsan emlékezzünk vissza, hogyan működik a moduláris aritmetika. Az óra már egy ismert koncepció. Az órák használata hostPath, fizikailag a klaszter csomópontján tárolva a statikus tartalmakat. Ez a megközelítés azzal a hátránnyal jár, hogy gyakorlatilag a konkrét klaszter csomóponthoz kell hozzárendelni az alkalmazásunkat, mivel — ha más csomópontokra váltunk — a könyvtár nem fogja tartalmazni a szükséges fájlokat. Alternatív megoldásként szükség van valamilyen háttér szinkronizációra a könyvtárak között. Mik a lehetséges megoldások?

Ha a hardver és az erőforrások lehetővé teszik, használhatjuk a

  1. cephfs a statikus igényekhez szükséges egyenlő hozzáférésű könyvtár létrehozásához. ajánlja az SSD-meghajtókat, legalább háromszoros replikációt, és stabil „vastag” kapcsolatot a klaszter csomópontjai között. Hivatalos dokumentáció A kevésbé igényes alternatíva az NFS-szerver létrehozása. Azonban ekkor figyelembe kell venni a webkiszolgáló lekérdezéseinek feldolgozására szükséges válaszidő növekedését, és a hibamentesség is hagy kívánnivalót maga után. A hiba következményei katasztrofálisak lehetnek: a mount elvesztése a klasztert a terhelés LA nyomása alatt megsemmisítővé teszi.
  2. Ezen kívül minden tartós tároló megoldásnál szükség van

háttér törlésére a régi fájlhalmazokból, amelyek egy bizonyos időszak alatt halmozódtak fel. A PHP konténerek elé tehetünk egy DaemonSet a cache-elő nginx-ből, amelyek korlátozott időre tárolják az eszközök másolatát. Ez a viselkedés könnyen beállítható a proxy_cache proxy_cache napokban vagy gigabájtokban tárolási mélységgel.

E módszer összevonása a fent említett elosztott fájlrendszerekkel hatalmas lehetőségeket nyújt, a határt csak a költségvetés és a technikai potenciál szabja meg azok számára, akik ezt megvalósítják és fenntartják. Tapasztalataink szerint minél egyszerűbb egy rendszer, annál stabilabban működik. Az ilyen rétegek hozzáadása sokkal bonyolultabbá teszi az infrastruktúra fenntartását, és együtt ezzel nő az idő, amely a hibák diagnosztizálására és helyreállítására megy el.

Ajánlás

Ha az ajánlott tárolási lehetőségek megvalósítása Önnek is indokolatlannak (bonyolultnak, drágának ...) tűnik, érdemes más szemszögből megvizsgálni a helyzetet. Nevezetesen - ásni egy kicsit a projekt architektúrájába és megszüntetni a problémát a kódban, kapcsolódva egy statikus adatszerkezethez a képben, egyértelmű meghatározva a tartalmat vagy a "melegítés" eljárását és/vagy az assetek újrafeldolgozását a kép elkészítésekor. Így teljesen kiszámítható viselkedést és az összes környezet és az indított alkalmazás replikái számára azonos fájlhalmazt kapunk.

Ha visszatérünk a Yii keretrendszer konkrét példájához, anélkül, hogy mélyebben belemennénk a szerkezetébe (ami nem a cikk célja), elegendő megjegyezni a két népszerű megközelítést:

  1. Megváltoztatni a kép készítési folyamatát, hogy az asseteket kiszámítható helyre helyezzék. Ezt javasolják/valósítják meg olyan kiegészítésekben, mint a yii2-static-assets.
  2. Külön hash-ek meghatározása az asset könyvtárak számára, ahogy azt például a prezentációból származnak. (35. diától kezdődően) bemutatják. Érdekesség, hogy az előadás szerzője végül (nem ok nélkül!) azt javasolja, hogy az assetek build szerveren való elkészítése után töltsük fel őket egy központi tárolóba (mint például S3), amit egy CDN elé helyezünk.

Feltöltött fájlok

Egy másik eset, amely biztosan sikeres lesz az alkalmazás Kubernetes klaszterbe történő áthelyezésekor – felhasználói fájlok tárolása a fájlrendszerben. Például ismét egy PHP alkalmazásunk van, amely fájlokat fogad egy feltöltő űrlapon, valamit tesz velük a munka során, majd visszaadja azokat.

A hely, ahová ezeknek a fájloknak kerülniük kell, Kubernetes keretein belül közösnek kell lennie az alkalmazás összes példánya számára. Az alkalmazás összetettségétől és a fájlok tartósságának szükségességétől függően ez lehet az említett megoldások bármelyike a shared eszközök körében, de ahogy látjuk, ezeknek megvannak a hátrányai.

Ajánlás

Az egyik lehetséges megoldás az S3-kompatibilis tároló használata (akár egy self-hosted változat, mint például a minio). Az S3-ra való áttérés kód szintű módosításokat igényel a kód szintjén, és hogy a tartalom hogyan fog átkerülni a frontendbe, azt már írták.

Felhasználói ülések

Külön említést érdemel a felhasználói sessionök tárolásának megszervezése. Gyakran ezek is lemezen lévő fájlok, ami Kubernetes környezetben folyamatos hitelesítési kérelmeket eredményez a felhasználónál, ha a kérése egy másik konténerbe kerül.

Részben a probléma megoldható a stickySessions engedélyezésével az ingressnél (ez a funkció minden népszerű ingress vezérlő által támogatott — részletesebben lásd a mi útmutatónkban), hogy a felhasználót egy adott pod-hoz kössük az alkalmazásban:

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

De ez nem oldja meg a problémákat a többszöri telepítések során.

Ajánlás

A helyesebb megoldás az lenne, ha az alkalmazást a sessionök memcached, Redis és hasonló megoldások áthelyezésére —— általában teljesen megszüntetve a fájlalapú megoldásokat.

Zárás

A szövegben tárgyalt infrastrukturális megoldások alkalmazása csupán átmeneti "bottleneck" formájában javasolt (angolul ez szebben hangzik, mint workaround). Ezek relevánsak lehetnek az alkalmazás Kubernetes-be történő migrálásának első szakaszaiban, de nem szabad, hogy "gyökeret verjenek".

A javasolt általános út pedig az, hogy megszabaduljunk tőlük, a már jól ismert architekturális fejlesztések javára 12-Factor App. Azonban ez az alkalmazás stateless állapotra való átállítása elkerülhetetlenül kódmódosításokat igényel, és itt fontos megtalálni az egyensúlyt a vállalkozás lehetőségei és követelményei, valamint a választott út megvalósításának és fenntartásának perspektívái között.

P.S.

Olvasson további információkat a blogunkban:

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster