
NĂ€r man bygger en CI/CD-process med Kubernetes kan det ibland uppstĂ„ problem med inkompatibiliteten mellan kraven för den nya infrastrukturen och den applikation som flyttas dit. SĂ€rskilt under applikationsbyggnadssteget Ă€r det viktigt att fĂ„ en en bild som kommer att anvĂ€ndas i alla projektets miljöer och kluster. Denna princip ligger till grund för korrekt och vĂ„r teknikchef). Men man ser sĂ€llan situationer dĂ€r en fĂ€rdig ramverk anvĂ€nds i webbplatsens kod, vilket bygger upp begrĂ€nsningar för dess framtida drift. Och om man i en "vanlig miljö" lĂ€tt kan hantera detta, kan sĂ„dant beteende i Kubernetes bli ett problem, sĂ€rskilt nĂ€r man stöter pĂ„ det första gĂ„ngen. Ăven om en uppfinningsrik hjĂ€rna kan föreslĂ„ infrastrukturlösningar som verkar sjĂ€lvklara och till och med bra vid första anblicken⊠Àr det viktigt att komma ihĂ„g att de flesta situationer kan och bör
lösas arkitektoniskt. Vi ska ta en titt pÄ populÀra workaround-lösningar för lagring av filer, som kan leda till obehagliga konsekvenser vid drift av klustret, och vi kommer Àven att peka pÄ en mer korrekt vÀg..
Lagring av statiska filer
För att illustrera detta, lĂ„t oss titta pĂ„ en webbapplikation som anvĂ€nder en slags statisk generator för att fĂ„ en uppsĂ€ttning bilder, stilar och annat. Till exempel har PHP-ramverket Yii en inbyggd asset-manager som genererar unika namn för katalogerna. Följaktligen fĂ„r vi en uppsĂ€ttning vĂ€gar för webbplatsens statiska filer som inte överlappar varandra (detta görs av flera skĂ€l â till exempel för att undvika dubbletter nĂ€r samma resurs anvĂ€nds av flera komponenter). SĂ„, frĂ„n början, vid första anropet av en modul pĂ„ webbresursen, skapas och lĂ€ggs statiken ut (egentligen ofta symboliska lĂ€nkar, men mer om detta senare) med en unik gemensam rotkatalog för denna distribution:
webroot/assets/2072c2df/css/âŠ
-
webroot/assets/2072c2df/images/⊠-
webroot/assets/2072c2df/js/⊠-
Vad innebÀr detta i relation till klustret?
Ett enkelt exempel
LÄt oss ta ett ganska vanligt fall dÀr nginx stÄr framför PHP för att leverera statiska filer och hantera enkla förfrÄgningar. Det enklaste sÀttet Àr
med tvĂ„ containrar: Deployment Ń ĐŽĐČŃĐŒŃ ĐșĐŸĐœŃĐ”ĐčĐœĐ”ŃĐ°ĐŒĐž:
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.confI en förenklad version sammanfattas nginx-konfigurationen till följande:
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;
}
} Vid det första besöket pÄ webbplatsen i containern med PHP genereras tillgÄngar. Men nÀr det gÀller tvÄ containrar inom samma pod, vet nginx ingenting om dessa statiska filer, som enligt konfigurationen ska levereras av dem. Resultatet blir att klienten ser ett 404-fel för alla förfrÄgningar om CSS- och JS-filer. Den enklaste lösningen hÀr skulle vara att skapa en gemensam katalog för containrarna. En primitiv version Àr gemensam. 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.confNu levereras de genererade statiska filerna i containern korrekt av nginx. Men jag pÄminner om att detta Àr en primitiv lösning, vilket innebÀr att den ligger lÄngt ifrÄn perfekt och har sina nyanser och brister, som diskuteras nedan.
Ett mer avancerat lagringssystem
LÄt oss nu förestÀlla oss en situation dÀr anvÀndaren har gÄtt in pÄ webbplatsen, laddat sidan med de stilar som finns i containern, och medan han lÀste sidan har vi Äterigen distribuerat containern. I katalogen för tillgÄngar har det blivit tomt och en begÀran till PHP krÀvs för att starta genereringen av nya. Men Àven efter detta kommer lÀnkarna till den gamla statiska innehÄllet att vara irrelevanta, vilket kommer att leda till fel vid visning av statiskt innehÄll.
Dessutom har vi troligtvis ett mer eller mindre belastat projekt, vilket innebÀr att en kopia av applikationen inte kommer att vara tillrÀcklig:
- Vi skalar Deployment upp till tvÄ repliker.
- Vid det första besöket pÄ webbplatsen skapades tillgÄngar i en av replikerna.
- Vid nÄgot tillfÀlle bestÀmde ingressen (för att balansera belastningen) att skicka en begÀran till den andra repliken, och dÀr finns dessa tillgÄngar inte Ànnu. Kanske finns de redan inte dÀr, för vi anvÀnder
RollingUpdateoch just nu gör vi en distribution.
I allmĂ€nhet, slutsatsen â Ă„terigen fel.
För att inte förlora gamla tillgĂ„ngar kan vi Ă€ndra emptyDir till hostPath, lĂ€ggande statiskt innehĂ„ll fysiskt pĂ„ klusterknuten. Denna metod Ă€r dĂ„lig eftersom vi praktiskt taget mĂ„ste binda vĂ„rt program till en specifik klusterknut eftersom â om vi flyttar till andra knutar â kommer katalogen inte att innehĂ„lla nödvĂ€ndiga filer. Alternativt krĂ€vs det nĂ„gon form av bakgrundssynkronisering av katalogen mellan knutarna.
Vilka lösningar finns det?
- Om hÄrdvaran och resurserna tillÄter, kan vi anvÀnda för att organisera en tillgÀnglighetsdirektory för statiskt innehÄll. rekommenderar SSD-diskar, minst trippelreplikering och en stabil "tjock" anslutning mellan klusterknutar.
- Ett mindre krÀvande alternativ skulle vara att organisera en NFS-server. Men dÄ mÄste man ta hÀnsyn till den möjliga ökningen av svarstiden för begÀrningar frÄn webbservern, och Àven redundansen kommer att vara bristande. Konsekvenserna av en felaktig operation Àr katastrofala: förlust av mount gör klustret dömt att falla under trycket av LA-belastningen som skjuter i höjden.
Utöver allt detta kommer för alla alternativ av att skapa permanenta lagringslösningar att krÀvas bakgrundsrensning av förÄldrade filuppsÀttningar som samlats under en viss tidsperiod. Framför containrar med PHP kan man stÀlla in DaemonSet cacheande nginx, som kommer att lagra kopior av tillgÄngarna under en begrÀnsad tid. Detta beteende kan enkelt konfigureras med hjÀlp av proxy_cache med lagringsdjup i dagar eller gigabyte diskutrymme.
Kombineringen av denna metod med de ovan nÀmnda distribuerade filsystemen erbjuder enorma möjligheter, dÀr begrÀnsningen endast Àr budgeten och den tekniska kapaciteten hos dem som ska implementera och underhÄlla det. UtifrÄn erfarenhet kan vi sÀga att ju enklare systemet Àr, desto stabilare fungerar det. NÀr man lÀgger till sÄdana lager blir det betydligt svÄrare att underhÄlla infrastrukturen, och dÀrmed ökar ocksÄ tiden som spenderas pÄ felsökning och ÄterstÀllning vid eventuella fel.
Rekommendation
Om implementeringen av de föreslagna lagringsalternativen ocksÄ verkar orimlig (komplicerad, dyr...), bör man se pÄ situationen frÄn en annan synvinkel. NÀmligen att grÀva djupt i projektets arkitektur och utrota problemet i koden, knutna till nÄgon statisk databasstruktur i bilden, entydig identifiering av innehÄllet eller proceduren för "uppvÀrmning" och/eller förkompilering av tillgÄngar i byggprocessen. PÄ sÄ sÀtt fÄr vi helt förutsÀgbart beteende och samma uppsÀttning filer för alla miljöer och repliker av den körda applikationen.
Om vi ÄtergÄr till det specifika exemplet med ramverket Yii och inte fördjupar oss i dess struktur (vilket inte Àr syftet med artikeln), rÀcker det med att pÄpeka tvÄ populÀra tillvÀgagÄngssÀtt:
- Ăndra byggprocessen för bilden sĂ„ att tillgĂ„ngar placeras pĂ„ en förutsĂ€gbar plats. SĂ„dana förslag/implementeringar finns i tillĂ€gg som .
- Definiera specifika hash-vÀrden för tillgÄngsmappar, som det berÀttas om till exempel i (frÄn och med bild nummer 35). För övrigt rekommenderar föredragshÄllaren i slutÀndan (och inte utan skÀl!) att efter byggandet av tillgÄngarna pÄ byggservern ladda upp dem till ett centralt lagringsutrymme (som S3), framför vilket man ska sÀtta upp en CDN.
Uppladdade filer
Ett annat fall som garanterat kommer att intrÀffa vid flytt av applikationen till ett Kubernetes-kluster Àr lagring av anvÀndarfiler i filsystemet. Till exempel har vi Äterigen en PHP-applikation som tar emot filer via ett inmatningsformulÀr, gör nÄgot med dem under drift och ger dem tillbaka.
Platsen dÀr dessa filer ska placeras, i verkligheten av Kubernetes, bör vara gemensam för alla instanser av applikationen. Beroende pÄ applikationens komplexitet och behovet av att organisera bestÀndighet för dessa filer, kan sÄdana platser vara de nÀmnda tidigare delade enheterna, men som vi ser har de sina nackdelar.
Rekommendation
Ett av alternativen till lösningar Ă€r att anvĂ€nda S3-kompatibel lagring (Ă€ven nĂ„gon variant av sjĂ€lvhostade kategorin som minio). ĂvergĂ„ngen till att arbeta med S3 kommer att krĂ€va förĂ€ndringar pĂ„ kodnivĂ„, och hur innehĂ„llet kommer att levereras pĂ„ frontend har vi redan .
AnvÀndarsessioner
Det Àr vÀrt att sÀrskilt notera hur anvÀndarsessioner lagras. Ofta handlar det ocksÄ om filer pÄ disk, vilket i Kubernetes leder till stÀndiga autentiseringsförfrÄgningar frÄn anvÀndaren om deras begÀran hamnar i en annan container.
Delvis löses problemet genom att aktivera stickySessions pĂ„ ingress (denna funktion stöds av alla populĂ€ra ingresskontroller â mer info kan ses i ), för att binda anvĂ€ndaren till en specifik pod med applikationen:
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: /Men det kommer inte att avhjÀlpa problem vid upprepade distributioner.
Rekommendation
Ett mer korrekt sĂ€tt skulle vara att överföra applikationen till lagring av sessioner i memcached, Redis och liknande lösningar â i allmĂ€nhet att helt överge filalternativen.
Slutsats
De infrastrukturella lösningar som diskuteras i texten Àr endast vÀrda att tillÀmpa som temporÀra "snabblösningar" (vilket lÄter mer elegant pÄ engelska som workaround). De kan vara aktuella i de inledande stegen av applikationens migration till Kubernetes, men bör inte "rota sig".
Den allmĂ€nt rekommenderade vĂ€gen Ă€r att bli av med dem till förmĂ„n för en arkitekturförbĂ€ttring av applikationen i enlighet med det som redan Ă€r vĂ€lkĂ€nt av mĂ„nga . Det Ă€r dock â att omvandla applikationen till ett stateless-format â oundvikligen betyder att förĂ€ndringar i koden kommer att krĂ€vas, och hĂ€r Ă€r det viktigt att finna en balans mellan affĂ€rens möjligheter/krav och perspektiven för implementering och underhĂ„ll av den valda vĂ€gen.
P.S.
LÀs Àven i vÄr blogg:
- «»;
- «»;
- «» (frÄn Red Hat);
- «».
KĂ€lla: habr.com
