Lokale bestanden bij het migreren van een applicatie naar Kubernetes

Lokale bestanden bij het migreren van een applicatie naar Kubernetes

Bij het bouwen van een CI/CD-proces met behulp van Kubernetes doet zich soms het probleem voor van incompatibiliteit tussen de vereisten van de nieuwe infrastructuur en de applicatie die ernaar wordt overgebracht. Met name in de bouwfase van de applicatie is het belangrijk om dit te realiseren een afbeelding die zal worden gebruikt Alle projectomgevingen en clusters. Dit principe ligt ten grondslag aan het juiste volgens Google containerbeheer (meer dan eens hierover zei en onze technische afdeling).

Je zult echter niemand tegenkomen in situaties waarin de code van de site een kant-en-klaar raamwerk gebruikt, waarvan het gebruik beperkingen oplegt aan het verdere gebruik ervan. En hoewel dit in een “normale omgeving” gemakkelijk is om mee om te gaan, kan dit gedrag in Kubernetes een probleem worden, vooral als je het voor de eerste keer tegenkomt. Hoewel een inventieve geest infrastructuuroplossingen kan bedenken die op het eerste gezicht voor de hand liggend en zelfs goed lijken... is het belangrijk om te onthouden dat de meeste situaties architectonisch op te lossen.

Laten we eens kijken naar populaire tijdelijke oplossingen voor het opslaan van bestanden die tot onaangename gevolgen kunnen leiden bij het gebruik van een cluster, en ook een correcter pad aanwijzen.

Statische opslag

Neem ter illustratie een webtoepassing die een soort statische generator gebruikt om een ​​reeks afbeeldingen, stijlen en andere zaken te verkrijgen. Het Yii PHP-framework heeft bijvoorbeeld een ingebouwde asset manager die unieke mapnamen genereert. Dienovereenkomstig is de uitvoer een reeks paden voor de statische site die elkaar duidelijk niet kruisen (dit werd om verschillende redenen gedaan - bijvoorbeeld om duplicaten te elimineren wanneer meerdere componenten dezelfde bron gebruiken). Dus de eerste keer dat u een webresourcemodule opent, worden er standaard statische bestanden (in feite vaak symlinks, maar daarover later meer) gevormd en ingedeeld met een gemeenschappelijke hoofdmap die uniek is voor deze implementatie:

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

Wat betekent dit in termen van een cluster?

Het eenvoudigste voorbeeld

Laten we een vrij algemeen geval nemen, waarbij PHP wordt voorafgegaan door nginx om statische gegevens te distribueren en eenvoudige verzoeken te verwerken. De makkelijkste manier - Deployment met twee containers:

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

In vereenvoudigde vorm komt de nginx-configuratie neer op het volgende:

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

Wanneer u de site voor het eerst bezoekt, verschijnen er assets in de PHP-container. Maar in het geval van twee containers binnen één pod weet nginx niets van deze statische bestanden, die (volgens de configuratie) aan hen zouden moeten worden gegeven. Als gevolg hiervan ziet de client een 404-fout voor alle verzoeken om CSS- en JS-bestanden. De eenvoudigste oplossing hier zou zijn om een ​​gemeenschappelijke map voor containers te organiseren. Primitieve optie - algemeen 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

Nu worden statische bestanden die in de container zijn gegenereerd, correct door nginx weergegeven. Maar laat me u eraan herinneren dat dit een primitieve oplossing is, wat betekent dat deze verre van ideaal is en zijn eigen nuances en tekortkomingen heeft, die hieronder worden besproken.

Geavanceerdere opslag

Stel je nu een situatie voor waarin een gebruiker de site heeft bezocht, een pagina heeft geladen met de beschikbare stijlen in de container, en terwijl hij deze pagina aan het lezen was, hebben we de container opnieuw geïmplementeerd. De activacatalogus is leeg geworden en een verzoek aan PHP is vereist om nieuwe te genereren. Maar zelfs daarna zullen links naar oude statistieken niet meer relevant zijn, wat zal leiden tot fouten bij het weergeven van statistieken.

Bovendien hebben we hoogstwaarschijnlijk een min of meer geladen project, wat betekent dat één exemplaar van de applicatie niet voldoende zal zijn:

  • Laten we het opschalen Deployment maximaal twee replica's.
  • Toen de site voor het eerst werd bezocht, werden er assets in één replica gemaakt.
  • Op een gegeven moment besloot Ingress (voor taakverdelingsdoeleinden) een verzoek naar de tweede replica te sturen, maar deze assets waren er nog niet. Of misschien zijn ze er niet meer omdat we ze gebruiken RollingUpdate en op dit moment zijn we bezig met implementatie.

Over het algemeen is het resultaat opnieuw fouten.

Om te voorkomen dat u oude bezittingen kwijtraakt, kunt u overstappen emptyDir op hostPath, waarbij statische elektriciteit fysiek wordt toegevoegd aan een clusterknooppunt. Deze aanpak is slecht omdat we dat eigenlijk wel moeten doen binden aan een specifiek clusterknooppunt uw applicatie, omdat - in geval van verhuizing naar andere knooppunten - de map niet de benodigde bestanden zal bevatten. Of er is een soort achtergronddirectorysynchronisatie tussen knooppunten vereist.

Wat zijn de oplossingen?

  1. Als de hardware en bronnen het toelaten, kunt u gebruiken ceffs om een ​​even toegankelijke map te organiseren voor statische behoeften. Officiële documentatie beveelt SSD-schijven aan, minimaal drievoudige replicatie en een stabiele “dikke” verbinding tussen clusternodes.
  2. Een minder veeleisende optie zou zijn om een ​​NFS-server te organiseren. Dan moet u echter rekening houden met de mogelijke toename van de responstijd voor het verwerken van verzoeken door de webserver, en de fouttolerantie zal veel te wensen overlaten. De gevolgen van een mislukking zijn catastrofaal: het verlies van de berg veroordeelt de cluster tot de dood onder de aanval van de LA-lading die de lucht in schiet.

Alle opties voor het creëren van permanente opslag zijn onder andere vereist achtergrond schoonmaken verouderde sets bestanden die gedurende een bepaalde periode zijn verzameld. Voor containers met PHP kun je zetten DaemonSet van het cachen van nginx, waarmee kopieën van assets voor een beperkte tijd worden opgeslagen. Dit gedrag kan eenvoudig worden geconfigureerd met behulp van proxy_cache met opslagdiepte in dagen of gigabytes aan schijfruimte.

Het combineren van deze methode met de hierboven genoemde gedistribueerde bestandssystemen biedt een enorm speelveld voor verbeelding, alleen beperkt door het budget en het technische potentieel van degenen die het zullen implementeren en ondersteunen. Uit ervaring kunnen we zeggen dat hoe eenvoudiger het systeem, hoe stabieler het werkt. Wanneer dergelijke lagen worden toegevoegd, wordt het veel moeilijker om de infrastructuur te onderhouden, en tegelijkertijd neemt de tijd die wordt besteed aan het diagnosticeren en herstellen van eventuele storingen toe.

aanbeveling

Als de implementatie van de voorgestelde opslagopties u ook niet gerechtvaardigd lijkt (ingewikkeld, duur...), dan is het de moeite waard om de situatie van de andere kant te bekijken. Namelijk om in de projectarchitectuur te graven en los het probleem op in de code, gekoppeld aan een statische datastructuur in de afbeelding, een ondubbelzinnige definitie van de inhoud of procedure voor het “opwarmen” en/of het vooraf compileren van assets in de fase van het samenstellen van de afbeelding. Op deze manier krijgen we absoluut voorspelbaar gedrag en dezelfde set bestanden voor alle omgevingen en replica's van de actieve applicatie.

Als we terugkeren naar het specifieke voorbeeld met het Yii-framework en niet ingaan op de structuur ervan (wat niet het doel van dit artikel is), volstaat het om twee populaire benaderingen aan te wijzen:

  1. Verander het image-buildproces om assets op een voorspelbare locatie te plaatsen. Dit wordt voorgesteld/geïmplementeerd in extensies zoals yii2-statische activa.
  2. Definieer specifieke hashes voor activamappen, zoals besproken in b.v. deze presentatie (vanaf dia nr. 35). Overigens adviseert de auteur van het rapport uiteindelijk (en niet zonder reden!) om na het samenstellen van assets op de buildserver deze te uploaden naar een centrale opslag (zoals S3), waarvoor een CDN wordt geplaatst.

Downloads

Een ander geval dat zeker een rol zal spelen bij het migreren van een applicatie naar een Kubernetes-cluster is het opslaan van gebruikersbestanden in het bestandssysteem. We hebben bijvoorbeeld weer een PHP-applicatie die bestanden accepteert via een uploadformulier, er tijdens het gebruik iets mee doet en ze terugstuurt.

In Kubernetes moet de locatie waar deze bestanden moeten worden geplaatst gemeenschappelijk zijn voor alle replica's van de applicatie. Afhankelijk van de complexiteit van de applicatie en de noodzaak om de persistentie van deze bestanden te organiseren, kunnen de bovengenoemde gedeelde apparaatopties zo'n plek zijn, maar zoals we zien hebben ze hun nadelen.

aanbeveling

Eén oplossing is gebruik van S3-compatibele opslag (zelfs als het een soort zelfgehoste categorie is zoals minio). Overstappen naar S3 vereist wijzigingen op codeniveau, en hoe de inhoud aan de voorkant wordt geleverd, hebben we al gedaan писали.

Gebruikerssessies

Afzonderlijk is het vermeldenswaard de organisatie van de opslag van gebruikerssessies. Vaak zijn dit ook bestanden op schijf, wat in de context van Kubernetes zal leiden tot constante autorisatieverzoeken van de gebruiker als zijn verzoek in een andere container terechtkomt.

Door het inschakelen wordt het probleem deels opgelost stickySessions op het binnenkomen (de functie wordt ondersteund in alle populaire ingangscontrollers - zie voor meer details onze recensie)om de gebruiker aan een specifieke pod te binden met de applicatie:

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

Maar dit zal de problemen met herhaalde implementaties niet wegnemen.

aanbeveling

Een correctere manier zou zijn om de applicatie over te dragen naar sessies opslaan in memcached, Redis en soortgelijke oplossingen - laat in het algemeen de bestandsopties volledig achterwege.

Conclusie

De infrastructuuroplossingen die in de tekst worden besproken, zijn alleen bruikbaar in de vorm van tijdelijke ‘krukken’ (wat in het Engels mooier klinkt als oplossing). Ze kunnen relevant zijn in de eerste fasen van het migreren van een applicatie naar Kubernetes, maar mogen geen wortel schieten.

Het algemeen aanbevolen pad is om ze te verwijderen ten gunste van architectonische aanpassing van de applicatie in overeenstemming met wat bij velen al bekend is. 12-factor-app. Dit – het in een staatloze vorm brengen van de applicatie – betekent echter onvermijdelijk dat er wijzigingen in de code nodig zullen zijn, en hier is het belangrijk om een ​​evenwicht te vinden tussen de mogelijkheden/vereisten van het bedrijf en de vooruitzichten voor het implementeren en onderhouden van het gekozen pad. .

PS

Lees ook op onze blog:

Bron: www.habr.com

Voeg een reactie