Contextator
ENTR

İşletim

Kubernetes Üzerinde Çalıştırma

Helm chart'ının kurulumu — veritabanı ve SECRET_KEY yönetimi, ingress, kalıcılık, probe'lar, security context, kaynak boyutlandırma ve kaldırma.

Güncelleme:

Contextator’ı Kubernetes üzerinde çalıştırmanın desteklenen yolu bir Helm chart’ıdır. Bu sayfadaki her şeyin kaynağı: depodaki charts/contextator/ altındaki chart’ın kendisi ve onun kendi, daha uzun charts/contextator/README.md’si.

Kurulum

helm repo add contextator https://contextator.github.io/Contextator
helm repo update
helm install contextator contextator/contextator \
  --set database.url="postgres://user:pass@host:5432/contextator" \
  --set-string image.tag="<version>-slim"

database.url (ya da zaten yönettiğiniz bir Secret için database.existingSecret) ve image.tag ikisi de zorunludur ve varsayılanı yoktur — ikisinden biri eksikse chart hiçbir şey render etmeden önce helm install/helm template’i anında başarısız kılar. image.tag bir -slim build’ine işaret etmelidir; o son ek olmadan gelen tag’ler gömülü PostgreSQL’li tam imajdır, bu chart için yanlış topolojidir. Ya da chart dizininin checkout edilmiş bir kopyasından doğrudan kurun: helm install contextator ./charts/contextator -f my-values.yaml — aynı iki değer, değer dosyasında ya da komut satırında olsun, yine zorunludur.

Tasarım gereği tek replica

replicaCount desteklenen bir değer değildir — chart onu doğrudan reddeder (additional properties 'replicaCount' not allowed) ve bu bilerek yapılmıştır, bir eksiklik değil: Contextator kendi indeksleme kuyruğuna karşı tek bir yazıcı çalıştırır, ve onu kümelemek ürünün henüz sahip olmadığı bir koordinasyon katmanı gerektirirdi (ADR-0078). Pod’un sayısını değil, kendi kaynaklarını ölçekleyin; aşağıdaki Kaynak boyutlandırma bölümüne bakın.

Veritabanı

Chart’a ya doğrudan bir bağlantı dizesi verin (database.url) ya da zaten yönettiğiniz bir Secret’a işaret edin (database.existingSecret) — Yapılandırma’nın Kubernetes dışında DATABASE_URL için anlattığı seçimin aynısı. PostgreSQL’in kendisi bu chart’ın parçası değildir; onu ayrıca çalıştırın ya da yönetilen bir örneğe işaret edin.

SECRET_KEY: bir kez üretilir, sabit kalır

SECRET_KEY kaynak kimlik bilgilerini durağan halde şifreler — git, Notion ve Confluence tokenları ve webhook sırları — bu yüzden onu kaybetmek yalnızca herkesi oturumdan atmaz, aynı zamanda o saklanan kimlik bilgilerini kurtarılamaz hale getirir. Ayarlanmadan bırakıldığında chart ilk kurulumda bir tane üretir ve — yeni bir tane üretmeye karar vermeden önce çalışan kümenin Secret’ını Helm’in lookup fonksiyonuyla okuduğu için — siz hiçbir şey yapmadan sonraki her helm upgrade boyunca aynı değeri korur.

lookup fonksiyonu yalnızca gerçek, erişilebilir bir kümeye karşı çalışır. Chart’ı offline render etmek — helm template, ya da render edilmiş bir manifestten canlı bir lookup olmadan reconcile eden bir GitOps controller’ı — her seferinde var olan bir Secret görmez ve her render’da yeni bir anahtar üretir, ki bu tam olarak çalışan bir örneğin altında değişmemesi gereken değerdir. Böyle bir kurulumda, anahtarı bir kez kendiniz üretin ve chart’a onu üretmesine izin vermek yerine var olan bir Secret olarak elden verin:

kubectl create secret generic contextator-secret-key \
  --from-literal=SECRET_KEY=$(openssl rand -hex 32)
secretKey:
  existingSecret: contextator-secret-key
  existingSecretKey: SECRET_KEY

Onu rotasyona sokmak bir değer değişimi değil, iki adımlı bir harekettir. Önce mevcut değeri yeni bir adla saklayın — contextator-secret-key yeni anahtarla üzerine yazılmak üzeredir, bu yüzden herhangi bir şey üretmeden önce eskisini kopyalayıp çıkarın:

kubectl -n <namespace> create secret generic contextator-secret-key-previous \
  --from-literal=SECRET_KEY="$(kubectl -n <namespace> get secret contextator-secret-key -o jsonpath='{.data.SECRET_KEY}' | base64 -d)"

Sonra yeni anahtarı üretin ve onu contextator-secret-key’e yerinde yazın (kubectl create tek başına zaten var olan bir Secret’ta başarısız olur):

kubectl -n <namespace> create secret generic contextator-secret-key \
  --from-literal=SECRET_KEY="$(openssl rand -hex 32)" \
  --dry-run=client -o yaml | kubectl -n <namespace> apply -f -

Yeni anahtar yukarıdaki gibi sabitlenmişken (secretKey.existingSecret/secretKey.existingSecretKey), sürece eskisini envSecret üzerinden SECRET_KEY_PREVIOUS olarak verin; onun girdileri her zaman AD: {secretName, secretKey} biçimindedir:

envSecret:
  SECRET_KEY_PREVIOUS:
    secretName: contextator-secret-key-previous
    secretKey: SECRET_KEY

İkisi de mevcutken ve Pod yeniden başlatıldıktan sonra, Deployment adını bulun (<release>-contextator, release adı zaten contextator içermiyorsa ve fullnameOverride ayarlanmamışsa) ve rotasyonu onun içinde çalıştırın:

kubectl -n <namespace> get deploy -l app.kubernetes.io/instance=<release>
kubectl -n <namespace> exec deploy/<deployment-name> -- npm run rotate-secret

Eski anahtarın şifrelediğini çözer ve yenisinin altında yeniden şifreler. Dönüştürülecek bir şey kalmadığını bildirdiğinde, SECRET_KEY_PREVIOUS’ı (envSecret girdisini) kaldırın ve Pod’un tekrar yeniden başlamasına izin verin — eski anahtarı emekliye ayıran o kaldırmadır. Anahtar tamamen kaybolduysa ve kurtaracak bir SECRET_KEY_PREVIOUS yoksa, onun altında saklanan kaynak kimlik bilgileri çözülemez — geri dönüşün tek yolu o kaynakları yeniden eklemektir.

Ingress ve reverse-proxy üçlüsü

Chart’ın önündeki bir Ingress, herhangi bir başka reverse proxy gibidir, ve Yapılandırma’daki aynı üçlü geçerlidir: config.trustProxy, config.publicBaseUrl ve env.AUTH_COOKIE_SECURE birlikte hareket eder, yoksa IP başına oturum açma sınırı, MCP connector yetkilendirmesi ve oturum çerezi her biri kendi sessiz biçiminde bozulur.

Bir sıçrama sayısı (2, 3, …) reddedilir; 1/true kabul edilir ve her sıçramaya güven anlamına gelir. Bu, Yapılandırma’nın Kubernetes dışında anlattığı aynı korumadır: chart config.trustProxy’yi doğrulamadan geçirir, bu yüzden "1" her sıçramada X-Forwarded-For başlığını kim yazdıysa ona güvenir — yalnızca bu Pod’un portuna ingress controller’dan başka bir şeyin ulaşmasına izin vermeyen bir NetworkPolicy arkasında güvenlidir. Bunun yerine proxy’yi adlandırın, onu gerçekten kapsayan en dar aralığı:

config:
  publicBaseUrl: "https://contextator.example.com"
  trustProxy: "<ingress-controller-pod-ip-or-cidr>"
env:
  AUTH_COOKIE_SECURE: "1"

Değer yalnızca socket’in eşine karşı değil her sıçramaya karşı eşleştirilir, bu yüzden tüm pod CIDR’ını yapıştırmak bu Service’e ulaşabilen her diğer pod’a da güvenir — yalnızca ingress controller’dan başka bir şeyin bu pod’un portuna ulaşmasına izin vermeyen bir NetworkPolicy arkasında güvenlidir.

Kalıcılık

İki ReadWriteOnce PersistentVolumeClaim: /data (veritabanına bitişik çalışma dosyaları) ve /app/.cache/models (indirilen gömme modeli, böylece bir pod yeniden başlatması onu yeniden indirmez). /data’nın, canlı bir kümede, bir pod yeniden başlatmasından bütün çıktığı doğrulanmıştır.

Probe’lar

Liveness, porttaki salt bir TCP kontrolüdür — veritabanına bağımlı olmadan tıkanmış bir süreci yakalamaya yeter. Readiness ve startup ikisi de gerçek bir GET /api/health çağrısıdır, bu yüzden bir pod yalnızca bir bağlantı kabul ettiğinde değil, uygulama gerçekten cevap verebildiğinde ready işaretlenir. Bir veritabanı kesintisine karşı canlı bir kümede doğrulanmıştır: pod bu süre boyunca READY 0/1 raporlar, liveness hiçbir zaman veritabanına bağımlı olmadığı için sıfır restart alır, ve veritabanı geri geldiği anda hiçbir manuel pod restart’ı gerekmeden otomatik olarak ready’e döner.

Security context

Container uid 0 olarak başlamak zorundadır — opsiyonel değildir, ve bunu yasaklayan sertleştirilmiş bir securityContext, “the container must start as root” hatasıyla başlangıçta başarısız olur. Bu kısa, yapısal bir gerekliliktir, kalıcı değil: entrypoint o ilk anı root olarak yukarıdaki iki bağlı volume’un sahipliğini düzeltmek için kullanır (taze bir PVC varsayılan olarak root sahiplidir), sonra herhangi bir uygulama kodu çalışmadan önce gosu ile ayrıcalıksız bir node kullanıcısına hemen devreder. Trafiği gerçekten sunan süreç hiçbir zaman root olarak çalışmaz.

İmaj ayrıca wget ya da curl taşımaz — kendi healthcheck’i ve chart testleri, Dockerfile’dan varsayılmak yerine gerçek bir helm test çalıştırmasıyla doğrulanmış şekilde, Node’un yerleşik fetch()’iyle birlikte node -e kullanır.

Kaynak boyutlandırma

Aşağıdaki sayılar tahmin edilmemiş, çalışan bir örneğe karşı ölçülmüştür:

Durum CPU Bellek
Boşta düşük ~770–820 MiB RSS
İndeksleme patlaması 2–3 saniye boyunca ~10 çekirdek —
Soğuk başlangıç — ~72,4 saniyede hazır

resources.requests/resources.limits’i boşta değerinin üzerinde bir marjla ve indeksleme patlamaları için yeterli burst kapasitesiyle ayarlayın; bir patlama sırasında sıkı bir CPU limiti diğer pod’ları etkilemek yerine yalnızca tek bir indeksleme çalışmasını yavaşlatır, çünkü zaten hep tek bir replica vardır.

Kaldırma

helm uninstall varsayılan olarak iki PersistentVolumeClaim’i geride bırakır — bunlar bir helm.sh/resource-policy: keep anotasyonu taşır, bu yüzden indekslenmiş veri ve önbelleğe alınmış model kazara bir kaldırmadan sağ çıkar. SECRET_KEY Secret’ı böyle bir politika taşımaz ve release ile birlikte silinir; aynı veriye karşı yeniden kurmayı planlıyorsanız önce anahtarı kaydedin (yukarıdaki SECRET_KEY: bir kez üretilir, sabit kalır’e bakın) yoksa hayatta kalan PVC’lerin hâlâ referans verdiği kaynak kimlik bilgilerini çözemezsiniz.

Katı values şeması

Chart, değerlerini katı bir JSON Schema’ya karşı doğrular (ADR-0092) — tanınmayan bir key, sessizce yok sayılmak yerine helm install/helm upgrade’i anında başarısız kılar. Yanlış yolda aranması kolay olduğu için adıyla bilinmeye değer iki key: config.confluenceAllowedHosts ve config.mcpStructuredOutput ikisi de tipli, üst düzey config.* key’leridir, başka bir yerde iç içe serbest değerler değil.

Yayımlama

Chart release’leri deponun kendi release iş akışını izler ve gh-pages üzerinde barındırılan bir Helm deposuna yayımlanır, uygulamanın kendi sürümünden bağımsız olarak sürümlenir — tam release ve sürümleme kurallarını depodaki chart’ın kendi charts/contextator/README.md’sinde bulabilirsiniz.

Gezinmek için ok tuşları, açmak için Enter.