QueryProxy
Doküman menüsü

Kubernetes, Helm ve yüksek erişilebilirlik

QueryProxy'yi Helm chart'ıyla Kubernetes'te çalıştırın; SQLite'ta tek pod'luk denemeden PostgreSQL, S3 ve ayrı web, worker, scheduler pod'larıyla HA kuruluma.

Güncelleme:

QueryProxy, depoda bir Helm chart ile gelir: deploy/helm/queryproxy. Yayımlanan tek imajı çalıştırır. Harici bir uygulama veritabanıyla bu imajı, birbirinden bağımsız ölçeklenen ayrı web, worker ve scheduler Deployment’ları olarak başlatır. Bu sayfa bir özettir; tüm değer listesi ve ayrıntılar chart’ın README dosyasındadır. Chart Kubernetes 1.27 ya da daha yenisini ister. 0.4.1’den itibaren chart bir registry’ye de yayımlanır (bkz. OCI registry’den kurun); aksi hâlde çalıştırmak istediğiniz sürüm etiketindeki bir checkout’un chart dizininden kurun.

İki mod

database.connection Chart’ın ürettiği Replika
sqlite (varsayılan) Web, worker ve scheduler’ı çalıştıran tek bir Deployment Tam 1, Recreate, storage/app üzerinde bir volume
pgsql, mysql, mariadb web, worker ve scheduler Deployment’ları, ek olarak bir migration Job’ı web ve worker ayarladığınız kadar, scheduler her zaman 1

SQLite tek pod demektir. SQLite dosyası tek bir volume’de yaşar ve pod’lar arasında paylaşılamaz; bu yüzden SQLite ile chart, docker-compose’daki gibi tek bir hepsi bir arada Deployment kurar. Birden fazla web replikasıyla, worker otomatik ölçeklemesiyle ya da kalıcı volume olmadan üretmeyi reddeder. Bu modu QueryProxy’yi denemek ya da küçük bir ekip için kullanın; ölçeklemek için önce harici bir veritabanına geçin.

Rol ayrımı yalnızca harici uygulama veritabanıyla geçerlidir. Orada roller QUERYPROXY_RUN_WORKER ve QUERYPROXY_RUN_SCHEDULER ile ayrılır: web Deployment’ı ikisini de çalıştırmaz, worker Deployment’ı yalnızca kuyruk işçisini, scheduler Deployment’ı yalnızca zamanlayıcıyı çalıştırır. Bir worker’daki çökme döngüsü ya da pahalı bir sorgu artık arayüzü de düşürmez. docker-compose değişmez; her şeyi hâlâ tek konteynerde çalıştırır.

OCI registry’den kurun

Her sürüm etiketi chart’ı GitHub Container Registry’ye oci://ghcr.io/queryproxy/charts/queryproxy olarak yayımlar. Chart sürümü, v olmadan sürüm numarasıdır. Aşağıdaki örneklerde yerel yol yerine bu komutları kullanın:

helm upgrade --install queryproxy oci://ghcr.io/queryproxy/charts/queryproxy --version 0.4.1 \
  --namespace queryproxy --create-namespace \
  --set admin.email=admin@example.com --set secrets.adminPassword="$(openssl rand -hex 16)"

# Ya da önce indirin, örneğin values-ha.yaml'ı okumak için:
helm pull oci://ghcr.io/queryproxy/charts/queryproxy --version 0.4.1 --untar

Sürüm iş akışı chart’ı cosign ile anahtarsız (Sigstore, GitHub OIDC kimliği) imzalar, imajlarda yaptığı gibi, ve bitirmeden önce imzayı kendisi de doğrular. Kurmadan önce siz de cosign v3 ya da daha yenisiyle doğrulayın. Kimlik, bir sürüm etiketindeki QueryProxy deposunun sürüm iş akışı olmalı ve GitHub Actions tarafından verilmiş olmalıdır:

cosign verify \
  --certificate-identity-regexp '^https://github\.com/QueryProxy/QueryProxy/\.github/workflows/release\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  ghcr.io/queryproxy/charts/queryproxy:0.4.1

0.4.1 yerine kurduğunuz sürümü yazın. Bir sürüm yalnızca etiket, chart’ın Chart.yaml dosyasındaki version ve appVersion ile aynıysa yayımlanır; yani çektiğiniz chart her zaman aynı numaralı imaja aittir.

SQLite ile deneyin

helm upgrade --install queryproxy deploy/helm/queryproxy \
  --namespace queryproxy --create-namespace \
  --set admin.email=admin@example.com \
  --set secrets.adminPassword="$(openssl rand -hex 16)"

kubectl -n queryproxy port-forward svc/queryproxy 7432:80

Sonra http://localhost:7432 adresini açın. config.appUrl varsayılan olarak budur. QueryProxy yalnızca APP_URL’nin host’una, chart’ın eklediği Service’in küme içi adlarına ve config.trustedHosts’a yanıt verir; gerçek bir kurulumda config.appUrl’yi kullanıcıların yazdığı adrese, genelde Ingress’in HTTPS adresine ayarlayın.

Yüksek erişilebilirlik

Referans profil values-ha.yaml’dır:

                     Ingress / LoadBalancer
                              |
                      Service (80 -> 7432)
                              |
        +---------------------+----------------------+
        |                                            |
 web x N (nginx + php-fpm)           worker x M (queue:work)      scheduler x 1
        |                                            |                  |
        +--------------------+-----------------------+------------------+
                             |
     harici PostgreSQL / MySQL (kullanıcılar, talepler, kuyruk, oturumlar, denetim zinciri)
                             |
          S3 bucket (sonuç dosyaları)       hedef veritabanları (worker'lar ulaşır)

Profil, sslMode: require ile harici bir PostgreSQL, S3 sonuç depolama, iki web ve iki worker pod’u (zamanlayıcının yapabildiği yerde bölgelere yayılır: ScheduleAnyway), bir scheduler, TLS’li bir Ingress, web ve worker için PodDisruptionBudget ve bir NetworkPolicy ayarlar. Şöyle kurun:

  1. PostgreSQL’i (yönetilen bir servis ya da operator) QueryProxy için bir veritabanı ve rolle, sonuç dosyaları için de özel bir S3 bucket’ıyla hazırlayın.
  2. secrets.existingSecret içinde adı geçen Secret’ı kurulumdan önce oluşturun; migration hook’u ona ihtiyaç duyar.
  3. values-ha.yaml içindeki her example değerini değiştirin, sonra:
helm upgrade --install queryproxy deploy/helm/queryproxy \
  -f deploy/helm/queryproxy/values-ha.yaml \
  --namespace queryproxy --create-namespace

Kendiniz boyutlandıracaklarınız:

  • PostgreSQL durum tutan (stateful) tek bağımlılıktır. Kuyruğu, oturumları ve yalnızca eklenen denetim zincirini tutar; bu yüzden çoğaltılmış, yedeklenen bir servis kullanın. Her pod kendi bağlantılarını açar; çok sayıda worker için önüne bir pooler koyun.
  • Worker’lar onaylı sorguları çalıştırır. Paralellik worker.replicas çarpı config.workerProcesses’tir. Durdurulan bir worker pod’u, çalışan sorguyu bitirmek için config.executionTimeout + 30 saniye alır.
  • Scheduler tek replikadır ve Recreate stratejisini kullanır. İki scheduler, zamanlanmış her görevi (saklama süresi temizliği, hatırlatmalar, süreli tanımlamaların sona ermesi) iki kez çalıştırırdı.

Secret’lar

Tüm pod’lar aynı APP_KEY’e, ayrıca veritabanı parolasına ve kullanılıyorsa Redis parolasına, metrik token’ına ve S3 anahtarlarına ihtiyaç duyar.

  • Kendi Secret’ınız (üretim). secrets.existingSecret ayarlayın. Beklenen anahtarlar APP_KEY, DB_PASSWORD ve gerektiğinde REDIS_PASSWORD, QUERYPROXY_METRICS_TOKEN, QUERYPROXY_ADMIN_PASSWORD, AWS_ACCESS_KEY_ID ve AWS_SECRET_ACCESS_KEY’dir. Secret External Secrets Operator’dan gelebilir; chart README’sinde bir örnek var. Döndürdükten sonra pod’ları kendiniz yeniden başlatın.
  • Chart’ın yönettiği Secret (deneme). secrets.existingSecret’ı boş bırakın. Chart APP_KEY’i ilk kurulumda üretir ve korur. Secret bilerek helm uninstall’dan sağ çıkar; çünkü saklanan bağlantı kimlik bilgileri anahtar olmadan çözülemez: yedekleyin.
  • Dosya olarak secret’lar. secrets.mountAsFiles=true Secret’ı bağlar ve *_FILE değişkenlerini ayarlar; böylece değerler pod spesifikasyonunda görünmez. IRSA ya da Workload Identity ile S3 anahtarlarını dışarıda bırakabilirsiniz (results.s3.useSecretCredentials=false).

Bağlantı parolalarının QueryProxy’de durması da gerekmez. Harici gizli bilgi referanslarıyla pod, bir bağlantı açılırken parolayı Vault, AWS Secrets Manager ya da Azure Key Vault’tan okur: AWS için IRSA, Azure için workload identity ve Vault’un Kubernetes girişi saklanan kimlik bilgisi gerektirmez. QUERYPROXY_VAULT_*, QUERYPROXY_AWS_* ya da QUERYPROXY_AZURE_* ayarlarından düz olanları (QUERYPROXY_VAULT_ADDR, QUERYPROXY_VAULT_AUTH, QUERYPROXY_VAULT_K8S_ROLE, QUERYPROXY_AWS_REGION, QUERYPROXY_AZURE_TENANT_ID gibi) config.extraEnv ile geçirin. config.extraEnv değerleri bir ConfigMap’e ve pod spesifikasyonuna düz metin olarak yazılır; bu yüzden QUERYPROXY_VAULT_TOKEN, QUERYPROXY_VAULT_SECRET_ID ya da QUERYPROXY_AZURE_CLIENT_SECRET’ı oraya asla koymayın. Anahtar adları bu adlar olan bir Kubernetes Secret’ta tutun ve config.extraEnvFrom ile başvurun:

config:
  extraEnvFrom:
    - secretRef:
        name: queryproxy-secret-store

Tek oturum açma için QUERYPROXY_OIDC_* değişkenlerini config.extraEnv ile geçirin, istemci secret’ını da config.extraEnvFrom ile başvurduğunuz bir Secret’ta tutun. Bkz. Tek oturum açma.

Migration’lar ve yükseltmeler

Harici veritabanıyla bir pre-install,pre-upgrade Job’ı, yeni sürümün hiçbir pod’u başlamadan önce php artisan migrate --force çalıştırır. Başarısız olursa sürüm ilerlemez. ConfigMap, Secret ve ServiceAccount sıradan sürüm kaynaklarıdır; bu yüzden helm rollback önceki yapılandırmayı geri getirir. Geri alma migration’ları geri almaz; Yükseltme ve geri alma sayfasını izleyin ve veritabanı yedeğini elinizde tutun.

Mevcut bir SQLite kurulumunu PostgreSQL’e taşımak için onu durdurun ve php artisan queryproxy:migrate-appdb --to=<dsn> kullanın; sonra chart’ı yeni database.* değerleriyle kurun.

Worker’ları otomatik ölçekleme

worker.autoscaling.enabled=true, queryproxy_queue_depth harici metriğine göre ölçekleyen bir HorizontalPodAutoscaler üretir. Varsayılan olarak kapalıdır; çünkü şunları ister:

  1. secrets.metricsToken ile metrics.enabled=true.
  2. Prometheus’un /metrics’i Service adı üzerinden kazıması. QueryProxy yalnızca güvenilen host adlarına yanıt verir; bir pod IP’sini kazımak 400 döner.
  3. Metriği sunan bir metrics adapter; chart’ın values.yaml dosyasında bir prometheus-adapter kuralı var.

Ölçek küçültme bilerek yavaştır; çünkü sorgu çalıştıran bir pod’u durdurmak onu bekler. Metrik için bkz. İzleme.

Ağ, erişilebilirlik ve sertleştirme

  • Probe’lar config.appUrl’nin host’uyla GET /up çağırır.
  • Web ve worker için maxUnavailable: 1 ile PodDisruptionBudget. Scheduler’ın yoktur: tek pod’dur ve boşaltma onu yeniden başlatır.
  • NetworkPolicy (networkPolicy.enabled): yalnızca networkPolicy.ingressFrom eşleri 7432 portuna ulaşır; ingressFrom boşsa (varsayılan) her kaynak yine de ulaşabilir, diğer tüm portlar kapalıdır. NetworkPolicy, ağ eklentiniz onu uygularsa etkili olur (örneğin Calico ya da Cilium). Egress varsayılan olarak açıktır; çünkü worker’ların kaydettiğiniz her hedef veritabanına ulaşması gerekir. networkPolicy.egress.restrict=true ile DNS’i, uygulama veritabanını, S3’ü, hedef veritabanlarınızı ve sohbet ile SIEM uç noktalarınızı networkPolicy.egress.rules içinde listeleyin. Ingress kuralı sürümün her pod’unu kapsar; /metrics’i kazıyan Prometheus’un namespace’ini ingressFrom’a ekleyin.
  • Güvenlik bağlamı. Pod’lar root olmayan bir kullanıcıyla, tüm capability’ler düşürülmüş ve ayrıcalık yükseltmesi kapalı çalışır.
  • Kök dosya sistemi hâlâ yazılabilir. İmajın entrypoint’i başlangıçta ona yazar; bu yüzden readOnlyRootFilesystem kapalıdır. Chart bugün bundan fazlasını vaat edemez.

S3 ve Redis

İmaj S3 adaptörünü ve predis Redis istemcisini taşır; ikisi de isteğe bağlıdır. results.disk=s3 sonuç dosyalarını S3’te ya da S3 API’sini sunan bir uç noktada saklar; S3 olmadan web ve worker’ın paylaştığı bir ReadWriteMany volume kullanın. redis.enabled cache’i, kuyruğu ve oturumları Redis’e taşır; her şey yalnızca veritabanıyla da çalışır.

Sonraki adımlar

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