Локални датотеки при мигрирање на апликација во Kubernetes

Локални датотеки при мигрирање на апликација во Kubernetes

Кога се гради процес CI/CD со користење на Kubernetes, понекогаш се јавува проблемот со некомпатибилноста помеѓу барањата на новата инфраструктура и апликацијата што се пренесува на неа. Особено, во фазата на изградба на апликацијата важно е да се добие една слика која ќе се користи во Сите проектни околини и кластери. Овој принцип лежи во основата на правилното според Google управување со контејнери (повеќе од еднаш за ова кажа и нашиот технички оддел).

Сепак, нема да видите никого во ситуации кога кодот на страницата користи готова рамка, чија употреба наметнува ограничувања за неговата понатамошна употреба. И додека во „нормална средина“ е лесно да се справите со ова, во Кубернетес ова однесување може да стане проблем, особено кога ќе се сретнете со него за прв пат. Додека инвентивниот ум може да дојде до инфраструктурни решенија кои изгледаат очигледни или дури добри на прв поглед... важно е да се запамети дека повеќето ситуации можат и треба да се реши архитектонски.

Да ги погледнеме популарните решенија за заобиколување за складирање датотеки што можат да доведат до непријатни последици при ракување со кластерот, а исто така да посочиме поточна патека.

Статично складирање

За илустрација, размислете за веб-апликација која користи некој вид статички генератор за да добие збир на слики, стилови и други работи. На пример, рамката Yii PHP има вграден менаџер на средства што генерира уникатни имиња на директориуми. Според тоа, излезот е збир на патеки за статичната локација кои очигледно не се вкрстуваат една со друга (ова е направено од неколку причини - на пример, за да се елиминираат дупликатите кога повеќе компоненти користат ист ресурс). Значи, надвор од кутијата, првиот пат кога ќе пристапите до модул за веб-ресурси, статичните датотеки (всушност, често символики, но повеќе за тоа подоцна) се формираат и се поставуваат со заеднички root директориум единствен за ова распоредување:

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

Што значи ова во смисла на кластер?

Наједноставниот пример

Да земеме прилично вообичаен случај, кога на PHP му претходи nginx за дистрибуција на статички податоци и обработка на едноставни барања. Најлесен начин - распоредување со два контејнери:

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

Во поедноставена форма, конфигурацијата nginx се сведува на следново:

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

Кога првпат ќе пристапите на страницата, средствата се појавуваат во контејнерот PHP. Но, во случај на два контејнери во една подлога, nginx не знае ништо за овие статични датотеки, кои (според конфигурацијата) треба да им се дадат. Како резултат на тоа, клиентот ќе види грешка 404 за сите барања до датотеките CSS и JS. Наједноставното решение овде би било да се организира заеднички директориум за контејнери. Примитивна опција - општа 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

Сега статичните датотеки генерирани во контејнерот се сервирани од nginx правилно. Но, дозволете ми да ве потсетам дека ова е примитивно решение, што значи дека е далеку од идеално и има свои нијанси и недостатоци, кои се дискутирани подолу.

Понапредно складирање

Сега замислете ситуација кога корисникот ја посетил страницата, вчитал страница со стиловите достапни во контејнерот и додека ја читал оваа страница, ние повторно го распоредивме контејнерот. Каталогот на средства стана празен и потребно е барање до PHP за да се започне со генерирање на нови. Сепак, и после ова, врските до стара статика ќе бидат ирелевантни, што ќе доведе до грешки во прикажувањето на статиката.

Покрај тоа, најверојатно имаме повеќе или помалку вчитан проект, што значи дека една копија од апликацијата нема да биде доволна:

  • Ајде да го зголемиме распоредување до две реплики.
  • Кога првпат беше пристапен до страницата, средствата беа креирани во една реплика.
  • Во одреден момент, влезот одлучи (за цели на балансирање на оптоварување) да испрати барање до втората реплика, а овие средства сè уште не беа таму. Или можеби веќе ги нема затоа што ние користиме RollingUpdate и во моментов правиме распоредување.

Во принцип, резултатот е повторно грешки.

За да избегнете губење на старите средства, можете да се промените emptyDir на hostPath, додавајќи статички физички на јазол кластер. Овој пристап е лош затоа што всушност мораме се врзуваат за специфичен јазол на кластерот вашата апликација, бидејќи - во случај на преместување во други јазли - директориумот нема да ги содржи потребните датотеки. Или потребна е некаква синхронизација на директориумот во заднина помеѓу јазлите.

Кои се решенијата?

  1. Ако дозволуваат хардверот и ресурсите, можете да користите cephfs да се организира подеднакво достапен именик за статички потреби. Официјална документација препорачува SSD-дискови, најмалку трикратна репликација и стабилна „дебела“ врска помеѓу јазлите на кластерот.
  2. Помалку барана опција би била да се организира NFS сервер. Сепак, тогаш треба да го земете предвид можното зголемување на времето на одговор за обработка на барањата од веб-серверот, а толеранцијата на грешки ќе остави многу да се посакува. Последиците од неуспехот се катастрофални: губењето на планината го осудува кластерот на смрт под притисокот на товарот на LA што брза кон небото.

Меѓу другото, ќе бидат потребни сите опции за создавање на постојано складирање чистење на позадината застарени групи на датотеки акумулирани во одреден временски период. Пред контејнери со PHP можете да ставите DaemonSet од кеширање на nginx, кој ќе складира копии на средства за ограничено време. Ова однесување лесно се конфигурира со користење proxy_cache со длабочина на складирање во денови или гигабајти простор на дискот.

Комбинирањето на овој метод со дистрибуираните датотечни системи споменати погоре обезбедува огромно поле за имагинација, ограничено само од буџетот и техничкиот потенцијал на оние кои ќе го имплементираат и поддржат. Од искуство, можеме да кажеме дека колку е поедноставен системот, толку постабилно функционира. Кога ќе се додадат такви слоеви, станува многу потешко да се одржува инфраструктурата, а во исто време се зголемува времето потрошено за дијагностицирање и закрепнување од какви било дефекти.

Препорака

Ако имплементацијата на предложените опции за складирање ви изгледа неоправдано (комплицирано, скапо...), тогаш вреди да се погледне ситуацијата од другата страна. Имено, да се копа во проектната архитектура и поправете го проблемот во кодот, поврзана со некоја статична структура на податоци на сликата, недвосмислена дефиниција за содржината или процедурата за „загревање“ и/или прекомпајлирање средства во фазата на склопување на сликата. На овој начин добиваме апсолутно предвидливо однесување и ист сет на датотеки за сите околини и реплики на апликацијата која работи.

Ако се вратиме на конкретниот пример со рамката Yii и не навлегуваме во нејзината структура (што не е целта на статијата), доволно е да се истакне два популарни пристапи:

  1. Променете го процесот на создавање слика за да ги поставите средствата на предвидлива локација. Ова е предложено/имплементирано во екстензии како yii2-статички-средства.
  2. Дефинирајте специфични хаши за директориуми со средства, како што е дискутирано во на пр. оваа презентација (почнувајќи од слајдот бр. 35). Патем, авторот на извештајот на крајот (и не без причина!) советува откако ќе ги соберете средствата на серверот за изградба, да ги поставите на централно складирање (како S3), пред кое ставете CDN.

Преземања

Друг случај што дефинитивно ќе влезе во игра при мигрирање на апликација во кластерот Kubernetes е складирање на кориснички датотеки во датотечниот систем. На пример, повторно имаме PHP апликација која прифаќа датотеки преку формулар за подигнување, прави нешто со нив за време на работата и ги испраќа назад.

Во Kubernetes, локацијата каде што треба да се постават овие датотеки треба да биде заедничка за сите реплики на апликацијата. Во зависност од сложеноста на апликацијата и потребата да се организира истрајноста на овие датотеки, горенаведените опции за споделени уреди може да бидат такво место, но, како што гледаме, тие имаат свои недостатоци.

Препорака

Едно решение е користење складирање компатибилно со S3 (дури и ако тоа е некој вид на самодомаќин категорија како минио). Префрлувањето на S3 ќе бара промени на ниво на код, и како содржината ќе биде испорачана на предниот дел, веќе имаме пишува.

Кориснички сесии

Одделно, вреди да се забележи организацијата на складирање на кориснички сесии. Честопати ова се и датотеки на дискот, што во контекст на Кубернетес ќе доведе до постојани барања за авторизација од корисникот доколку неговото барање заврши во друг контејнер.

Проблемот делумно се решава со вклучување stickySessions на влез (Функцијата е поддржана во сите популарни контролери за влез - за повеќе детали, видете нашиот преглед)за да го поврзете корисникот за одредена подлога со апликацијата:

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

Но, ова нема да ги елиминира проблемите со повторените распоредувања.

Препорака

Поправилен начин би бил да ја префрлите апликацијата на зачувување на сесии во memcached, Redis и слични решенија - воопшто, целосно напуштајте ги опциите за датотеки.

Заклучок

Инфраструктурните решенија дискутирани во текстот заслужуваат употреба само во формат на привремени „патерици“ (што звучи поубаво на англиски како замена). Тие може да бидат релевантни во првите фази на мигрирање на апликација во Kubernetes, но не треба да се вкорени.

Општата препорачана патека е да се ослободите од нив во корист на архитектонска модификација на апликацијата во согласност со она што е веќе добро познато на многумина. Апликација 12-Factor. Сепак, ова - доведување на апликацијата во форма без државјанство - неизбежно значи дека ќе бидат потребни промени во кодот и тука е важно да се најде баланс помеѓу можностите/барањата на бизнисот и изгледите за имплементација и одржување на избраниот пат. .

PS

Прочитајте и на нашиот блог:

Извор: www.habr.com

Додадете коментар