Kubernetes'te ilk uygulamayı devreye alırken beş hata

Kubernetes'te ilk uygulamayı devreye alırken beş hataAris Dreamer tarafından başarısız

Pek çok kişi, uygulamayı Kubernetes'e aktarmanın (Helm kullanarak veya manuel olarak) yeterli olduğunu ve mutluluk olacağını düşünüyor. Ama her şey o kadar basit değil.

Ekip Mail.ru Bulut Çözümleri DevOps mühendisi Julian Gindy tarafından yazılan bir makaleyi tercüme etti. Aynı tırmığa basmamak için şirketinin taşıma sürecinde karşılaştığı tuzakları anlatıyor.

Birinci Adım: Kapsül İsteklerini ve Sınırlarını Ayarlayın

Kapsüllerimizin çalışacağı temiz bir ortam oluşturarak başlayalım. Kubernet'ler, pod zamanlama ve yük devretme konusunda harikadır. Ancak, başarılı bir şekilde çalışması için kaç kaynağa ihtiyaç duyduğunu tahmin etmek zorsa, zamanlayıcının bazen bir bölme yerleştiremeyeceği ortaya çıktı. Burası, kaynak ve limit taleplerinin açıldığı yerdir. İstekleri ve sınırları belirlemeye yönelik en iyi yaklaşım hakkında pek çok tartışma var. Bazen bunun bir bilimden çok bir sanat olduğu anlaşılıyor. İşte yaklaşımımız.

Kapsül istekleri bölmeyi en iyi şekilde yerleştirmek için programlayıcı tarafından kullanılan ana değerdir.

Of Kubernet belgeleri: Filtre adımı, bir Bölmenin programlanabileceği bir dizi düğüm tanımlar. Örneğin, PodFitsResources filtresi, bir düğümün bir bölmeden gelen belirli kaynak isteklerini karşılamak için yeterli kaynağa sahip olup olmadığını kontrol eder.

Uygulama isteklerini, kaç kaynak olduğunu tahmin edebilecek şekilde kullanırız. aslında Uygulamanın düzgün çalışması için buna ihtiyacı var. Bu şekilde zamanlayıcı, düğümleri gerçekçi bir şekilde yerleştirebilir. Başlangıçta, her bir Kapsül için yeterli kaynak sağlamak üzere istekleri fazla planlamak istedik, ancak planlama süresinin önemli ölçüde arttığını ve bazı Kapsüllerin, sanki kendileri için kaynak talebi yokmuş gibi tam olarak planlanmadığını fark ettik.

Bu durumda, programlayıcı genellikle bölmeleri "sıkıştırır" ve onları yeniden programlayamaz çünkü kontrol düzlemi, uygulamanın ne kadar kaynağa ihtiyaç duyacağı hakkında hiçbir fikre sahip değildir; bu, zamanlama algoritmasının önemli bir bileşenidir.

Kapsül sınırları bir bölme için daha net bir sınırdır. Kümenin kapsayıcıya ayıracağı maksimum kaynak miktarını temsil eder.

tekrar, dan resmi belgeler: Bir kapsayıcının 4 GiB bellek sınırı varsa, kubelet (ve kapsayıcı çalışma zamanı) bunu zorlar. Çalışma zamanı, kapsayıcının belirtilen kaynak sınırından fazlasını kullanmasını engeller. Örneğin, bir kapsayıcıdaki bir işlem izin verilenden daha fazla bellek kullanmaya çalıştığında, sistem çekirdeği işlemi "yetersiz bellek" (OOM) hatasıyla sonlandırır.

Bir kapsayıcı, her zaman kaynak isteğinde belirtilenden daha fazla kaynak kullanabilir, ancak hiçbir zaman sınırdan fazlasını kullanamaz. Bu değeri doğru bir şekilde ayarlamak zordur, ancak çok önemlidir.

İdeal olarak, bir bölmenin kaynak gereksinimlerinin, bir işlemin yaşam döngüsü boyunca sistemdeki diğer işlemlere müdahale etmeden değişmesini istiyoruz - bu, sınırları belirlemenin amacıdır.

Ne yazık ki, hangi değerlerin ayarlanacağına dair özel talimatlar veremem, ancak aşağıdaki kurallara kendimiz uyarız:

  1. Bir yük testi aracı kullanarak, temel düzeyde bir trafiği simüle ediyoruz ve bölme kaynaklarının (bellek ve işlemci) kullanımını gözlemliyoruz.
  2. Kapsül isteklerini keyfi olarak düşük bir değere ayarlayın (istek değerinin yaklaşık 5 katı bir kaynak limiti ile) ve gözlemleyin. İstekler çok düşük bir seviyede olduğunda, süreç başlayamaz ve genellikle şifreli Go çalışma zamanı hatalarına neden olur.

Bölmenin yeterli kaynağa sahip bir hedef düğüme ihtiyacı olduğundan, daha yüksek kaynak sınırlarının zamanlamayı daha zor hale getirdiğini unutmayın.

4 GB bellek gibi çok yüksek kaynak sınırına sahip hafif bir web sunucunuz olduğunu hayal edin. Bu işlemin büyük olasılıkla yatay olarak ölçeklendirilmesi gerekecek ve her yeni bölmenin en az 4 GB kullanılabilir belleğe sahip bir düğümde programlanması gerekecek. Böyle bir düğüm yoksa, kümenin bu bölmeyi işlemek için yeni bir düğüm tanıtması gerekir, bu biraz zaman alabilir. Hızlı ve sorunsuz ölçeklendirmeyi sağlamak için kaynak istekleri ile sınırlar arasında minimum bir fark elde etmek önemlidir.

İkinci Adım: Canlılık ve Hazırlık Testlerini Ayarlayın

Bu, Kubernetes topluluğunda sıklıkla tartışılan başka bir incelikli konudur. Yazılımın kararlı çalışması için bir mekanizma sağladıklarından ve arıza süresini en aza indirdiklerinden, Canlılık ve Hazırlık testlerini iyi anlamak önemlidir. Ancak, doğru şekilde yapılandırılmazlarsa uygulamanızın performansını ciddi şekilde etkileyebilirler. Aşağıda, her iki numunenin ne olduğunun bir özeti bulunmaktadır.

Canlılık kapsayıcının çalışıp çalışmadığını gösterir. Başarısız olursa, kubelet kabı öldürür ve bunun için yeniden başlatma ilkesi etkinleştirilir. Konteyner bir Canlılık Sondası ile donatılmamışsa, o zaman varsayılan durum - içinde belirtildiği gibi başarılı olacaktır. Kubernet belgeleri.

Liveness araştırmaları ucuz olmalı, yani çok fazla kaynak tüketmemelidir, çünkü sıklıkla çalışırlar ve Kubernetes'e uygulamanın çalıştığını bildirmelidirler.

Seçeneği her saniye çalışacak şekilde ayarlarsanız, bu, saniyede 1 istek ekleyecektir, dolayısıyla bu trafiği işlemek için ek kaynaklar gerekeceğini unutmayın.

Şirketimizde Liveness testleri, veriler tamamen mevcut olmasa bile (örneğin uzak bir veritabanından veya önbellekten) bir uygulamanın temel bileşenlerini test eder.

Uygulamalarda yalnızca 200 yanıt kodu döndüren bir "sağlık" uç noktası oluşturduk. Bu, sürecin çalıştığının ve istekleri işleyebildiğinin (ancak henüz trafiği değil) bir göstergesidir.

test hazır olma kapsayıcının istekleri sunmaya hazır olup olmadığını gösterir. Hazırlık araştırması başarısız olursa uç nokta denetleyicisi, bölmenin IP adresini, bölmeyle eşleşen tüm hizmetlerin uç noktalarından kaldırır. Bu, Kubernetes belgelerinde de belirtilmiştir.

Hazırlık araştırmaları, uygulamanın istekleri kabul etmeye hazır olduğunu gösterecek şekilde arka uca vurmaları gerektiğinden daha fazla kaynak tüketir.

Veritabanına doğrudan erişilip erişilemeyeceği konusunda toplulukta pek çok tartışma var. Ek yükü göz önünde bulundurarak (kontroller sıktır, ancak kontrol edilebilirler), bazı uygulamalar için trafiği sunmaya hazır olma durumunun yalnızca kayıtların veritabanından döndürüldüğünü kontrol ettikten sonra sayılmasına karar verdik. İyi tasarlanmış hazırlık denemeleri, daha yüksek seviyelerde kullanılabilirlik sağladı ve devreye alma sırasında kesinti süresini ortadan kaldırdı.

Uygulamanızın hazır olup olmadığını test etmek için veritabanını sorgulamaya karar verirseniz, mümkün olduğunca ucuz olduğundan emin olun. Bu sorguyu ele alalım:

SELECT small_item FROM table LIMIT 1

İşte bu iki değeri Kubernetes'te nasıl yapılandırdığımıza bir örnek:

livenessProbe: 
 httpGet:   
   path: /api/liveness    
   port: http 
readinessProbe:  
 httpGet:    
   path: /api/readiness    
   port: http  periodSeconds: 2

Bazı ek yapılandırma seçenekleri ekleyebilirsiniz:

  • initialDelaySeconds - konteynerin fırlatılması ile sondaların fırlatılmasının başlaması arasında kaç saniye geçeceği.
  • periodSeconds — numune çalışmaları arasındaki bekleme aralığı.
  • timeoutSeconds — bölmenin acil durum olarak kabul edildiği saniye sayısı. Normal zaman aşımı.
  • failureThreshold bölmeye bir yeniden başlatma sinyali gönderilmeden önceki test başarısızlıklarının sayısıdır.
  • successThreshold bölme hazır duruma geçmeden önceki başarılı denemelerin sayısıdır (kapsül başlatıldığında veya kurtarıldığında meydana gelen bir arızadan sonra).

Üçüncü Adım: Bölmenin Varsayılan Ağ İlkelerini Ayarlama

Kubernetes "düz" bir ağ topografyasına sahiptir, varsayılan olarak tüm bölmeler birbiriyle doğrudan iletişim kurar. Bazı durumlarda bu arzu edilmez.

Potansiyel bir güvenlik sorunu, bir saldırganın ağdaki tüm bölmelere trafik göndermek için güvenlik açığı bulunan tek bir uygulama kullanabilmesidir. Birçok güvenlik alanında olduğu gibi burada da en az ayrıcalık ilkesi geçerlidir. İdeal olarak, ağ politikaları bölmeler arasında hangi bağlantılara izin verilip hangilerinin verilmediğini açıkça belirtmelidir.

Örneğin, aşağıdaki, belirli bir ad alanı için gelen tüm trafiği reddeden basit bir ilkedir:

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:  
 name: default-deny-ingress
spec:  
 podSelector: {}  
 policyTypes:  
   - Ingress

Bu konfigürasyonun görselleştirilmesi:

Kubernetes'te ilk uygulamayı devreye alırken beş hata
(https://miro.medium.com/max/875/1*-eiVw43azgzYzyN1th7cZg.gif)
Daha fazla bilgi burada.

Dördüncü Adım: Kancalar ve Başlatma Kapları ile Özel Davranış

Ana hedeflerimizden biri, geliştiriciler için kesinti süresi olmadan Kubernetes'te dağıtım sağlamaktı. Bu zordur çünkü uygulamaları kapatmak ve kullanılan kaynakları serbest bırakmak için birçok seçenek vardır.

ile özel zorluklar ortaya çıktı. nginx. Bu Bölmeleri sırayla dağıtırken, etkin bağlantıların başarıyla tamamlanmadan önce kesildiğini fark ettik.

İnternette yapılan kapsamlı araştırmalardan sonra, Kubernetes'in bölmeyi kapatmadan önce Nginx bağlantılarının kendilerini tüketmesini beklemediği ortaya çıktı. Ön durdurma kancasının yardımıyla aşağıdaki işlevselliği uyguladık ve kesinti süresinden tamamen kurtulduk:

lifecycle: 
 preStop:
   exec:
     command: ["/usr/local/bin/nginx-killer.sh"]

ve burada nginx-killer.sh:

#!/bin/bash
sleep 3
PID=$(cat /run/nginx.pid)
nginx -s quit
while [ -d /proc/$PID ]; do
   echo "Waiting while shutting down nginx..."
   sleep 10
done

Bir başka son derece yararlı paradigma, belirli uygulamaların başlatılmasını işlemek için init kapsayıcılarının kullanılmasıdır. Bu, özellikle uygulama başlamadan önce çalıştırılması gereken yoğun kaynak kullanan bir veritabanı taşıma işleminiz varsa kullanışlıdır. Ana uygulama için böyle bir sınır belirlemeden de bu işlem için daha yüksek bir kaynak sınırı belirleyebilirsiniz.

Diğer bir yaygın şema, ana uygulama modülünün kendisinden sırlara yetkisiz erişimi önleyen ana modüle bu kimlik bilgilerini sağlayan init konteynerindeki sırlara erişmektir.

Her zamanki gibi, belgelerden bir alıntı: init kapları, aksi takdirde uygulamanın kapsayıcı görüntüsünün güvenliğini tehlikeye atacak kullanıcı kodunu veya yardımcı programları güvenli bir şekilde çalıştırır. Gereksiz araçları ayrı tutarak, uygulamanın kapsayıcı görüntüsünün saldırı yüzeyini sınırlandırırsınız.

Beşinci Adım: Çekirdek Yapılandırması

Son olarak, daha gelişmiş bir teknikten bahsedelim.

Kubernetes, iş yüklerini uygun gördüğünüz şekilde çalıştırmanıza izin veren son derece esnek bir platformdur. Son derece kaynak yoğun olan bir dizi yüksek verimli uygulamamız var. Kapsamlı yük testi yaptıktan sonra, varsayılan Kubernetes ayarları etkinken uygulamalardan birinin beklenen trafik yüküne ayak uydurmakta zorlandığını tespit ettik.

Ancak Kubernetes, yalnızca belirli bir bölme için çekirdek parametrelerini değiştiren ayrıcalıklı bir kapsayıcı çalıştırmanıza izin verir. İşte maksimum açık bağlantı sayısını değiştirmek için kullandıklarımız:

initContainers:
  - name: sysctl
     image: alpine:3.10
     securityContext:
         privileged: true
      command: ['sh', '-c', "sysctl -w net.core.somaxconn=32768"]

Bu, genellikle ihtiyaç duyulmayan daha gelişmiş bir tekniktir. Ancak uygulamanız ağır bir yükle başa çıkmakta zorlanıyorsa, bu ayarlardan bazılarını değiştirmeyi deneyebilirsiniz. Bu süreç ve farklı değerler ayarlama hakkında daha fazla bilgi - her zaman olduğu gibi resmi belgelerde.

Sonuç olarak

Kubernet'ler kullanıma hazır bir çözüm gibi görünse de, uygulamaların sorunsuz çalışmasını sağlamak için atılması gereken birkaç önemli adım vardır.

Kubernetes'e geçiş boyunca "yük testi döngüsünü" takip etmek önemlidir: uygulamayı çalıştırın, yük altında test edin, ölçümleri ve ölçekleme davranışını gözlemleyin, bu verilere göre yapılandırmayı ayarlayın ve ardından bu döngüyü tekrar tekrarlayın.

Beklenen trafik konusunda gerçekçi olun ve önce hangi bileşenlerin bozulduğunu görmek için bunun ötesine geçmeye çalışın. Bu yinelemeli yaklaşımla, listelenen önerilerden yalnızca birkaçı başarıya ulaşmak için yeterli olabilir. Veya daha derinlemesine özelleştirme gerektirebilir.

Her zaman kendinize şu soruları sorun:

  1. Uygulamalar ne kadar kaynak tüketiyor ve bu miktar nasıl değişecek?
  2. Gerçek ölçeklendirme gereksinimleri nelerdir? Uygulama ortalama olarak ne kadar trafik işleyecek? Yoğun trafik ne olacak?
  3. Hizmetin ölçeğinin ne sıklıkla genişletilmesi gerekecek? Trafiği almak için yeni bölmelerin ne kadar hızlı hazır ve çalışır durumda olması gerekir?
  4. Bölmeler ne kadar zarif bir şekilde kapanıyor? Hiç gerekli mi? Devre dışı kalma süresi olmadan dağıtıma ulaşmak mümkün mü?
  5. Güvenlik riskleri nasıl en aza indirilir ve güvenliği ihlal edilmiş bölmelerden kaynaklanan hasar nasıl sınırlanır? Herhangi bir hizmetin ihtiyaç duymadığı izinleri veya erişimleri var mı?

Kubernetes, binlerce hizmeti bir kümede dağıtmak için en iyi uygulamaları kullanmanıza izin veren inanılmaz bir platform sağlar. Ancak, tüm uygulamalar farklıdır. Bazen uygulama biraz daha fazla çalışma gerektirir.

Neyse ki Kubernetes, tüm teknik hedeflere ulaşmak için gerekli ayarları sağlar. Kaynak istekleri ve limitleri, Liveness ve Readiness araştırmaları, init konteynerleri, ağ ilkeleri ve özel çekirdek ayarının bir kombinasyonunu kullanarak hata toleransı ve hızlı ölçeklenebilirlik ile birlikte yüksek performans elde edebilirsiniz.

Okumak için başka ne var:

  1. Üretim Ortamlarında Kapsayıcıları ve Kubernet'leri Çalıştırmaya Yönelik En İyi Uygulamalar ve En İyi Uygulamalar.
  2. Kubernet'ler için 90+ Yararlı Araç: Dağıtım, Yönetim, İzleme, Güvenlik ve Daha Fazlası.
  3. Telegram'da Kubernetes Çevresindeki Kanalımız.

Kaynak: habr.com

Yorum ekle