Bir uygulamayı Kubernetes'e taşırken yerel dosyalar

Bir uygulamayı Kubernetes'e taşırken yerel dosyalar

Kubernetes kullanarak bir CI/CD süreci oluştururken bazen yeni altyapının gereksinimleri ile ona aktarılan uygulama arasında uyumsuzluk sorunu ortaya çıkar. Özellikle, uygulama oluşturma aşamasında aşağıdakileri elde etmek önemlidir: biri kullanılacak resim Tüm proje ortamları ve kümeler. Bu prensip doğru yaklaşımın temelini oluşturur. Google'a göre konteyner yönetimi (bu konuda bir kereden fazla adı geçen ve teknik departmanımız).

Bununla birlikte, site kodunun, kullanımı daha sonraki kullanımına kısıtlamalar getiren hazır bir çerçeve kullandığı durumlarda kimseyi görmezsiniz. Ve "normal bir ortamda" bununla başa çıkmak kolay olsa da Kubernetes'te bu davranış, özellikle de ilk kez karşılaştığınızda sorun haline gelebilir. Yaratıcı bir zihin, ilk bakışta bariz ve hatta iyi görünen altyapı çözümleri üretebilirken, çoğu durumun bunu yapabileceğini ve yapması gerektiğini unutmamak önemlidir. mimari olarak çözülmesi.

Bir kümeyi çalıştırırken hoş olmayan sonuçlara yol açabilecek dosyaları depolamak için popüler geçici çözüm çözümlerine bakalım ve ayrıca daha doğru bir yola işaret edelim.

Statik depolama

Örnek olarak, bir dizi görüntü, stil ve diğer şeyleri elde etmek için bir tür statik oluşturucu kullanan bir web uygulamasını düşünün. Örneğin, Yii PHP çerçevesi, benzersiz dizin adları üreten yerleşik bir varlık yöneticisine sahiptir. Buna göre çıktı, statik site için birbiriyle açıkça kesişmeyen bir dizi yoldur (bu, birkaç nedenden dolayı yapıldı - örneğin, birden fazla bileşen aynı kaynağı kullandığında kopyaları ortadan kaldırmak için). Yani, bir web kaynağı modülüne ilk kez eriştiğinizde, statik dosyalar (aslında genellikle sembolik bağlantılar, ancak daha sonra bu konuya daha fazla değineceğiz) oluşturulur ve bu dağıtım için benzersiz bir ortak kök dizinle düzenlenir:

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

Bu küme açısından ne anlama geliyor?

En basit örnek

Statik verileri dağıtmak ve basit istekleri işlemek için PHP'den önce nginx'in geldiği oldukça yaygın bir durumu ele alalım. En kolay yol - açılma iki konteyner ile:

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

Basitleştirilmiş bir biçimde, nginx yapılandırması aşağıdakilere indirgenir:

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

Siteye ilk eriştiğinizde varlıklar PHP kapsayıcısında görünür. Ancak bir bölmede iki kapsayıcı olması durumunda, nginx bu statik dosyalar hakkında hiçbir şey bilmez ve bu dosyalara (yapılandırmaya göre) verilmesi gerekir. Sonuç olarak istemci, CSS ve JS dosyalarına yapılan tüm isteklerde 404 hatası görecektir.Buradaki en basit çözüm, kapsayıcılar için ortak bir dizin düzenlemek olacaktır. İlkel seçenek - genel 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

Artık kapta oluşturulan statik dosyalar nginx tarafından doğru şekilde sunuluyor. Ancak bunun ilkel bir çözüm olduğunu, yani ideal olmaktan uzak olduğunu ve aşağıda tartışılan kendi nüansları ve eksiklikleri olduğunu hatırlatmama izin verin.

Daha gelişmiş depolama

Şimdi bir kullanıcının siteyi ziyaret ettiği, kapsayıcıda mevcut olan stillerin bulunduğu bir sayfayı yüklediği ve bu sayfayı okurken bizim kapsayıcıyı yeniden konuşlandırdığımız bir durum hayal edin. Varlık kataloğu boşaldı ve yenilerini oluşturmaya başlamak için PHP'ye bir istek yapılması gerekiyor. Ancak bundan sonra bile eski statiklere olan bağlantılar geçerliliğini yitirecek ve bu da statiklerin görüntülenmesinde hatalara yol açacaktır.

Ek olarak, büyük olasılıkla az çok yüklü bir projemiz var, bu da uygulamanın bir kopyasının yeterli olmayacağı anlamına geliyor:

  • Haydi büyütelim açılma en fazla iki kopya.
  • Siteye ilk erişildiğinde varlıklar tek bir kopyada oluşturuldu.
  • Bir noktada, giriş (yük dengeleme amacıyla) ikinci kopyaya bir istek göndermeye karar verdi ve bu varlıklar henüz orada değildi. Ya da belki de kullandığımız için artık orada değiller. RollingUpdate ve şu anda dağıtım yapıyoruz.

Genel olarak sonuç yine hatalardır.

Eski varlıkları kaybetmemek için şunları değiştirebilirsiniz: emptyDir üzerinde hostPath, bir küme düğümüne fiziksel olarak statik ekleme. Bu yaklaşım kötü çünkü aslında bunu yapmak zorundayız. belirli bir küme düğümüne bağlan uygulamanız, çünkü - diğer düğümlere taşınması durumunda - dizin gerekli dosyaları içermeyecektir. Veya düğümler arasında bir tür arka plan dizin senkronizasyonu gereklidir.

Çözümler nelerdir?

  1. Donanım ve kaynaklar izin veriyorsa kullanabilirsiniz cephf'ler Statik ihtiyaçlar için eşit derecede erişilebilir bir dizin düzenlemek. Resmi belgeler SSD sürücüleri, en az üç kat çoğaltma ve küme düğümleri arasında istikrarlı bir "kalın" bağlantı önerir.
  2. Daha az talepkar bir seçenek, bir NFS sunucusu düzenlemek olacaktır. Bununla birlikte, web sunucusunun isteklerini işleme koyma süresindeki olası artışı hesaba katmanız gerekir ve hata toleransı arzulanan çok şey bırakacaktır. Başarısızlığın sonuçları felakettir: Bineğin kaybı, gökyüzüne hızla koşan LA yükünün baskısı altında kümeyi ölüme mahkum eder.

Diğer şeylerin yanı sıra, kalıcı depolama oluşturmaya yönelik tüm seçenekler şunları gerektirecektir: arka plan temizliği Belirli bir süre boyunca biriken güncel olmayan dosya kümeleri. PHP ile kapların önüne koyabilirsiniz DaemonSet Varlıkların kopyalarını sınırlı bir süre için saklayacak olan nginx'i önbelleğe almaktan. Bu davranış kullanılarak kolayca yapılandırılabilir. proxy_cache Gün cinsinden depolama derinliği veya gigabaytlarca disk alanı ile.

Bu yöntemi yukarıda bahsedilen dağıtılmış dosya sistemleriyle birleştirmek, uygulayacak ve destekleyecek kişilerin yalnızca bütçesi ve teknik potansiyeli ile sınırlı olan çok büyük bir hayal gücü alanı sağlar. Deneyimlerimize dayanarak şunu söyleyebiliriz: sistem ne kadar basitse o kadar kararlı çalışır. Bu tür katmanlar eklendiğinde altyapının bakımı çok daha zor hale gelir ve aynı zamanda arızaların teşhis edilmesi ve arızaların giderilmesi için harcanan zaman da artar.

tavsiye

Önerilen depolama seçeneklerinin uygulanması size de haksız görünüyorsa (karmaşık, pahalı...), o zaman duruma diğer taraftan bakmaya değer. Yani, proje mimarisini derinlemesine incelemek ve koddaki sorunu düzeltin, görüntüdeki bazı statik veri yapılarına bağlı olarak içeriğin net bir tanımı veya görüntü birleştirme aşamasında varlıkların "ısınması" ve/veya ön derleme prosedürü. Bu şekilde, çalışan uygulamanın tüm ortamları ve kopyaları için kesinlikle öngörülebilir davranış ve aynı dosya kümesini elde ederiz.

Yii çerçevesiyle ilgili spesifik örneğe dönersek ve yapısını derinlemesine incelemezsek (ki bu makalenin amacı değil), iki popüler yaklaşımı belirtmek yeterlidir:

  1. Varlıkları öngörülebilir bir konuma yerleştirmek için görüntü oluşturma sürecini değiştirin. Bu, aşağıdaki gibi uzantılarda önerilir/uygulanır yii2-statik-varlıklar.
  2. Varlık dizinleri için belirli karmaları tanımlayın; bu sunum (35 numaralı slayttan başlayarak). Bu arada, raporun yazarı sonuçta (ve sebepsiz değil!), varlıkları derleme sunucusunda birleştirdikten sonra, bunları önüne bir CDN yerleştirilecek merkezi bir depolama birimine (S3 gibi) yüklemelerini tavsiye ediyor.

İndirilenler

Bir uygulamayı Kubernetes kümesine taşırken mutlaka devreye girecek bir diğer durum, kullanıcı dosyalarının dosya sisteminde saklanmasıdır. Örneğin, yine bir yükleme formu aracılığıyla dosyaları kabul eden, işlem sırasında onlarla bir şeyler yapan ve bunları geri gönderen bir PHP uygulamamız var.

Kubernetes'te bu dosyaların yerleştirilmesi gereken konum, uygulamanın tüm replikaları için ortak olmalıdır. Uygulamanın karmaşıklığına ve bu dosyaların kalıcılığını düzenleme ihtiyacına bağlı olarak yukarıda belirtilen paylaşımlı cihaz seçenekleri böyle bir yer olabilir ancak gördüğümüz gibi dezavantajları da var.

tavsiye

Çözümlerden biri S3 uyumlu depolamayı kullanma (minio gibi bir tür kendi kendine barındırılan kategori olsa bile). S3'e geçiş değişiklik gerektirecek kod düzeyindeve içeriğin ön uçta nasıl teslim edileceğini zaten biliyoruz писали.

Kullanıcı oturumları

Ayrı olarak, kullanıcı oturumlarının depolanmasının organizasyonuna dikkat etmek önemlidir. Bunlar genellikle diskteki dosyalardır ve Kubernetes bağlamında, isteği başka bir kapsayıcıya düşerse kullanıcıdan sürekli yetkilendirme taleplerine yol açacaktır.

Sorun kısmen açıldığında çözüldü stickySessions girişte (bu özellik tüm popüler giriş denetleyicilerinde desteklenir; daha fazla ayrıntı için bkz. incelememiz)kullanıcıyı uygulamayla belirli bir bölmeye bağlamak için:

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

Ancak bu, tekrarlanan dağıtımlardan kaynaklanan sorunları ortadan kaldırmayacaktır.

tavsiye

Başvuruyu aktarmak daha doğru bir yol olacaktır. oturumları memcached, Redis ve benzeri çözümlerde depolama - genel olarak dosya seçeneklerini tamamen terk edin.

Sonuç

Metinde tartışılan altyapı çözümleri yalnızca geçici "koltuk değneği" biçiminde kullanılmaya değerdir (bu, geçici çözüm olarak İngilizce'de kulağa daha güzel gelir). Bir uygulamayı Kubernetes'e taşımanın ilk aşamalarında faydalı olabilirler ancak kök salmamalıdırlar.

Önerilen genel yol, birçok kişi tarafından zaten iyi bilinenlere uygun olarak uygulamanın mimari modifikasyonu lehine bunlardan kurtulmaktır. 12 Faktörlü Uygulama. Bununla birlikte, bu - başvurunun vatansız bir forma getirilmesi - kaçınılmaz olarak kodda değişikliklerin gerekli olacağı anlamına gelir ve burada işletmenin yetenekleri/gereksinimleri ile seçilen yolu uygulama ve sürdürme beklentileri arasında bir denge bulmak önemlidir. .

PS

Blogumuzda da okuyun:

Kaynak: habr.com

Yorum ekle