
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 (which has been mentioned multiple times) 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.confEgyszerű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.confMost 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
- cephfs ajánlja az SSD-meghajtókat, legalább háromszoros replikációt, és stabil „vastag” kapcsolatot a klaszter csomópontjai között. 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.
- 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:
- 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 .
- Külön hash-ek meghatározása az asset könyvtárak számára, ahogy azt például a (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 .
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 ), 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 . 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:
- «»;
- «»;
- «» (a Red Hat-től);
- «».
Forrás: habr.com
