# 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.

- Dokümantasyon: Kılavuzlar
- Güncelleme: 2026-11-04
- Kaynak: https://queryproxy.com/tr/docs/kubernetes-ve-helm/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
QueryProxy, depoda bir Helm chart ile gelir:
[`deploy/helm/queryproxy`](https://github.com/QueryProxy/QueryProxy/tree/main/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](https://github.com/QueryProxy/QueryProxy/blob/main/deploy/helm/queryproxy/README.md)
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](#oci-registryden-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:

```bash
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](https://github.com/sigstore/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:

```bash
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

```bash
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:

```text
                     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:

```bash
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](/tr/docs/harici-gizli-bilgiler/) 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:

```yaml
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](/tr/docs/tek-oturum-acma/).

## 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](/tr/docs/yukseltme/) 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](/tr/docs/izleme/).

## 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

- Hâlâ geçerli kontrol listesi için [Üretim güvenliği](/tr/docs/uretim-guvenligi/).
- Chart'ın geçirebildiği tüm ortam değişkenleri için [Yapılandırma](/tr/docs/yapilandirma/).
- Veritabanı ve `APP_KEY` için [Yedekleme ve geri yükleme](/tr/docs/yedekleme-ve-geri-yukleme/).
