Helm Nedir: Kubernetes Paket Yöneticisi mi Web Sunucusu mu?

Kubernetes öğrenmeye başladığınızda karşınıza çıkan ilk kavramlardan biri Helm oluyor. Ama şunu söyleyeyim: birçok kişi Helm’i yanlış anlıyor ya da kafası karışık başlıyor. “Helm bir web sunucusu mu?” diye soran arkadaşlar gördüm. Bu soruyu soran kişileri küçümsemiyorum çünkü isim gerçekten kafa karıştırıcı. Helm, İngilizce’de “dümen” anlamına geliyor ve Kubernetes’in deniz temasıyla uyuşuyor (Kubernetes Yunanca’da “dümenci” demek). Ama evet, Helm ne web sunucusu ne de Helm adında bir HTTP sunucusu. Helm, Kubernetes için geliştirilmiş bir paket yöneticisi. Bunu bir kez kafanıza yerleştirirseniz, geri kalan her şey çok daha kolay oturuyor.

Helm Ne Yapar, Neden Var?

Kubernetes’te bir uygulama deploy etmek istediğinizde ne yapıyorsunuz? YAML dosyaları yazıyorsunuz. Deployment, Service, ConfigMap, Secret, Ingress… Her şey ayrı ayrı YAML. Küçük bir uygulama için bile 5-10 dosya yazmanız gerekiyor. Büyük bir mikroservis mimarisinde bu sayı yüzlere çıkabiliyor.

Şimdi şunu düşünün: aynı uygulamayı hem staging hem production ortamına deploy etmeniz lazım. Ama staging’de replica sayısı 1, production’da 3. Staging’de küçük bir veritabanı kullanıyorsunuz, production’da managed bir servis var. Her ortam için ayrı YAML dosyaları mı tutacaksınız? Versiyonlamayı nasıl yapacaksınız? Güncelleme sırasında bir şeyler ters giderse nasıl geri alacaksınız?

İşte Helm tam bu noktada devreye giriyor. Helm, Kubernetes manifest dosyalarını paketliyor, versiyonluyor ve yönetilebilir hale getiriyor. Aynı zamanda parametrelendirme yapmanıza izin veriyor, yani tek bir paket yazıp farklı ortamlarda farklı değerlerle çalıştırabiliyorsunuz.

APT’yi düşünün. Ubuntu’ya nginx kurmak için apt install nginx yazıyorsunuz. Nginx nerede duruyor, hangi dosyaları kopyalanıyor, hangi servisler başlatılıyor bunları tek tek yapmak zorunda kalmıyorsunuz. Helm de Kubernetes için aynı şeyi yapıyor. helm install my-nginx nginx/nginx yazıyorsunuz ve nginx Kubernetes cluster’ınıza deploy ediliyor.

Chart Kavramını Anlamak

Helm’in temel birimi “chart” (harita, deniz haritası, temayla uyumlu). Bir chart, bir uygulamayı Kubernetes’e deploy etmek için gereken her şeyi içeren bir paket. İçinde ne var?

  • Chart.yaml: Chart’ın metadata bilgileri (isim, versiyon, açıklama)
  • values.yaml: Varsayılan konfigürasyon değerleri
  • templates/: Kubernetes manifest şablonları
  • charts/: Bağımlı chart’lar (opsiyonel)
  • README.md: Dokümantasyon (opsiyonel ama önemli)

Basit bir chart yapısına bakalım:

helm create my-app
tree my-app/

Bu komutun çıktısı şuna benzer:

my-app/
├── Chart.yaml
├── charts/
├── templates/
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests/
│       └── test-connection.yaml
└── values.yaml

Chart.yaml dosyası basit bir şekilde şöyle görünür:

apiVersion: v2
name: my-app
description: Benim uygulamam için Helm chart
type: application
version: 0.1.0
appVersion: "1.0.0"

values.yaml ise şablonlarınıza geçireceğiniz varsayılan değerleri tutar. Örneğin:

replicaCount: 1

image:
  repository: nginx
  tag: "1.24"
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

resources:
  limits:
    cpu: 100m
    memory: 128Mi
  requests:
    cpu: 50m
    memory: 64Mi

Şablonlar içinde bu değerlere {{ .Values.replicaCount }} gibi erişiyorsunuz. Bu Go template sözdizimi, biraz alışmak gerekiyor ama mantığı oturduğunda çok güçlü bir araç oluyor.

Helm Kurulumu ve İlk Adımlar

Helm kurulumu gayet basit. Linux üzerinde:

curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

Ya da daha kontrollü bir yöntemle:

wget https://get.helm.sh/helm-v3.13.0-linux-amd64.tar.gz
tar -zxvf helm-v3.13.0-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin/helm
helm version

Helm kurulduktan sonra ilk işiniz bir repository eklemek olmalı. Bitnami reposu iyi bir başlangıç noktası:

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm search repo bitnami/nginx

Şimdi gerçek bir kurulum yapalım. Diyelim ki cluster’ınıza bir WordPress kurmanız gerekiyor (evet, klasik bir senaryo ama öğretici):

helm install my-wordpress bitnami/wordpress 
  --namespace production 
  --create-namespace 
  --set wordpressUsername=admin 
  --set wordpressPassword=guclu-bir-sifre 
  --set mariadb.primary.persistence.size=10Gi 
  --set persistence.size=5Gi

Bu tek komutla WordPress, MariaDB, PersistentVolumeClaim’ler, Service’ler, ConfigMap’ler… hepsi oluşturuluyor. Bunu elle yapmak saatler alırdı ve hata yapma olasılığı yüksek olurdu.

Helm 2 vs Helm 3: Tiller’ı Unutun

Eski kaynaklarda Tiller adında bir bileşenden bahsedildiğini görürsünüz. Tiller, Helm 2’de cluster içinde çalışan ve Helm komutlarını execute eden bir server bileşeniydi. Büyük güvenlik sorunlarına yol açıyordu çünkü genellikle cluster-admin yetkisiyle çalışırdı.

Helm 3 ile Tiller tamamen kaldırıldı. Artık Helm, kubectl’in kullandığı aynı kubeconfig ve RBAC mekanizmalarını kullanıyor. Eğer bir kaynakta hala Tiller’dan bahsediyorsa, o kaynak eskimiş demektir. Bugün kullanacağınız şey Helm 3.

Release Yönetimi: Helm’in Asıl Gücü

Helm’i basit bir template engine olarak düşünmek eksik bir bakış açısı. Helm aynı zamanda release yönetimi yapıyor. Her helm install komutu bir release oluşturuyor ve bu release cluster’da tracked durumda kalıyor.

# Mevcut release'leri listele
helm list -A

# Belirli bir release'in durumunu gör
helm status my-wordpress -n production

# Release'in geçmişini gör
helm history my-wordpress -n production

Bir güncelleme yapmak istediğinizde:

helm upgrade my-wordpress bitnami/wordpress 
  --namespace production 
  --set wordpressVersion=6.4.0 
  --reuse-values

--reuse-values flag’i çok önemli. Önceki kurulumda verdiğiniz değerleri koruyarak sadece değiştirmek istediğiniz parametreleri güncellemenizi sağlıyor. Bunu unutursanız, belirtmediğiniz değerler varsayılana dönüyor ve production’da sürprizler yaşayabilirsiniz.

Bir şeyler ters giderse rollback:

helm rollback my-wordpress 1 -n production

Buradaki “1” revision numarası. helm history komutuyla revision geçmişini görebilir ve istediğiniz noktaya dönebilirsiniz. Bu özellik production ortamlarda altın değerinde.

Kendi Chart’ınızı Yazmak

Hazır chart’lar kullanmak iyi bir başlangıç ama asıl değer kendi chart’larınızı yazmaktan geliyor. Şirketinize özel uygulamaları Helm ile paketleyebilirsiniz. Bir Python API servisi için basit bir chart yazalım.

templates/deployment.yaml içeriği:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "my-app.fullname" . }}
  labels:
    {{- include "my-app.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "my-app.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "my-app.selectorLabels" . | nindent 8 }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          env:
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: {{ include "my-app.fullname" . }}-secret
                  key: database-url
          ports:
            - containerPort: {{ .Values.service.targetPort }}
          resources:
            {{- toYaml .Values.resources | nindent 12 }}

Chart’ınızı deploy etmeden önce template’lerin doğru render edildiğini kontrol etmek için:

helm template my-api ./my-app 
  --values ./my-app/values-staging.yaml 
  --debug

Bu komut Kubernetes’e hiçbir şey göndermeden sadece çıktıyı ekrana basar. Syntax hatalarını ve mantık sorunlarını erken yakalamak için vazgeçilmez bir alışkanlık.

Gerçek deploy öncesinde dry-run yapmayı da ihmal etmeyin:

helm install my-api ./my-app 
  --values ./my-app/values-staging.yaml 
  --dry-run 
  --debug

Ortam Yönetimi: values.yaml Stratejisi

Birden fazla ortam yönetmenin en temiz yolu ayrı values dosyaları kullanmak. Bir yapı önerisi:

my-app/
├── Chart.yaml
├── values.yaml              # Varsayılan değerler
├── values-staging.yaml      # Staging overrides
├── values-production.yaml   # Production overrides
└── templates/

values-production.yaml sadece production’a özgü değerleri içerir, geri kalanı base values.yaml‘dan gelir:

replicaCount: 3

image:
  tag: "2.1.0"

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70

Deploy sırasında:

helm upgrade --install my-api ./my-app 
  --namespace production 
  --values ./my-app/values.yaml 
  --values ./my-app/values-production.yaml

--upgrade --install flag kombinasyonu da oldukça kullanışlı. Release yoksa install, varsa upgrade yapıyor. CI/CD pipeline’larında idempotent bir komut istediğinizde çok işe yarıyor.

Helm ve GitOps

Helm tek başına da güçlü ama ArgoCD veya Flux gibi GitOps araçlarıyla birleştiğinde gerçek potansiyelini gösteriyor. Git repo’nuzda chart ve values dosyalarınız duruyor, ArgoCD bunları izleyip cluster’ı otomatik sync ediyor.

ArgoCD ile bir Helm uygulaması tanımlamak böyle görünüyor:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-api-production
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/sirketim/k8s-charts
    targetRevision: main
    path: charts/my-api
    helm:
      valueFiles:
        - values-production.yaml
      parameters:
        - name: image.tag
          value: "2.1.0"
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Bu yapıda image tag’ini bir parametre olarak CI/CD pipeline’ınız güncelliyor, ArgoCD farkı algılıyor ve deploy ediyor. Temiz ve izlenebilir bir süreç.

Helm Hook’ları: Gözden Kaçan Bir Özellik

Helm hook’ları, deploy sürecinin belirli noktalarında işlem yapmanıza izin veriyor. Database migration çalıştırmak, sertifika oluşturmak, ön kontroller yapmak gibi işlemler için kullanabilirsiniz.

Örneğin bir database migration job’ı:

apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "my-app.fullname" . }}-migration
  annotations:
    "helm.sh/hook": pre-upgrade,pre-install
    "helm.sh/hook-weight": "-5"
    "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: migration
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          command: ["python", "manage.py", "migrate"]
          env:
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: {{ include "my-app.fullname" . }}-secret
                  key: database-url

helm.sh/hook: pre-upgrade,pre-install annotation’ı bu Job’ın asıl deployment’tan önce çalışmasını sağlıyor. Migration başarısız olursa deploy da duruyor. Bu tür bir güvenlik mekanizması elle yönetmek çok zor olurdu.

Güvenlik Konuları

Helm chart’larını kullanırken dikkat etmeniz gereken bazı güvenlik noktaları var. Public chart’ları olduğu gibi production’a almak riskli olabilir.

# Chart'ı indir ve incele
helm pull bitnami/nginx --untar
ls nginx/
cat nginx/templates/deployment.yaml

Özellikle şunlara bakın:

  • Container imajları: Hangi registry’den geliyor, resmi mi?
  • RBAC tanımları: Chart gereksiz yetkiler istiyor mu?
  • Secret yönetimi: Hassas veriler nasıl işleniyor?
  • SecurityContext: Container’lar root olarak mı çalışıyor?

Kendi chart’larınızda Helm Secrets veya External Secrets Operator kullanarak secret’ları Vault ya da AWS Secrets Manager gibi sistemlerle yönetmenizi öneririm. Values dosyalarına düz metin şifre koymak, bir gün başınızı ağrıtır.

Sık Yapılan Hatalar

Yıllarca Helm kullanan biri olarak şu hataları tekrar tekrar görüyorum:

Release adı çakışması: Aynı cluster’da farklı namespace’lerde aynı isimli release oluşturmaya çalışmak. Helm 3’te release isimleri namespace bazında unique olmalı.

–reuse-values unutmak: Upgrade sırasında bu flag’i atlamak, beklenmedik değer kayıplarına yol açıyor.

Chart versiyonunu sabitlememek: CI/CD pipeline’ında helm repo update sonrası en güncel chart’ı çekmek. Bu production’da sürprizlere davetiye çıkarıyor. Chart versiyonunu her zaman sabitleyin.

# Kötü pratik
helm upgrade my-app bitnami/nginx

# İyi pratik
helm upgrade my-app bitnami/nginx --version 15.9.0

Büyük values dosyaları: Tek bir values.yaml’a her şeyi doldurmak yerine mantıksal gruplara bölün ve çok büyük chart’lar için Helmfile kullanmayı düşünün.

Helmfile: Birden Fazla Chart’ı Yönetmek

Gerçek bir Kubernetes ortamında tek chart ile iş bitmiyor. Onlarca servis var, her birinin kendi chart’ı var. Helmfile bu koordinasyonu sağlıyor.

repositories:
  - name: bitnami
    url: https://charts.bitnami.com/bitnami

releases:
  - name: nginx-ingress
    namespace: ingress-nginx
    chart: bitnami/nginx-ingress-controller
    version: 11.0.0
    values:
      - values/ingress.yaml

  - name: cert-manager
    namespace: cert-manager
    chart: jetstack/cert-manager
    version: v1.13.0
    set:
      - name: installCRDs
        value: true

  - name: my-api
    namespace: production
    chart: ./charts/my-api
    values:
      - charts/my-api/values.yaml
      - charts/my-api/values-production.yaml
    needs:
      - ingress-nginx/nginx-ingress

helmfile sync komutu tüm bu release’leri sırayla ve bağımlılıklara göre deploy ediyor. needs alanı önemli: ingress kurulmadan my-api deploy edilmiyor.

Sonuç

Helm, Kubernetes ekosisteminin vazgeçilmez bir parçası haline geldi ve bu rastgele olmadı. Gerçekten çözdüğü problemler var: tutarlı deployment, kolay parametrelendirme, rollback kabiliyeti ve topluluk tarafından yazılmış hazır paketler.

Ama her araç gibi Helm’in de sınırları var. Çok karmaşık business logic için template’ler okunaksız hale gelebiliyor. Büyük chart’ları debug etmek bazen yorucu oluyor. Bu noktada Kustomize veya yak-shaving yapmadan doğrudan Kubernetes API’yi kullanan yaklaşımlar devreye girebilir.

Başlangıç için şu yolu öneririm: önce hazır chart’ları kullanın ve nasıl çalıştıklarını anlayın. Sonra helm create ile kendi basit chart’ınızı yazın. Ardından CI/CD pipeline’ınıza entegre edin. Son olarak ArgoCD veya Flux ile GitOps’a geçin. Her adımda bir öncekini gerçekten anlayarak ilerlemek, ilerleyen dönemde production sorunlarını çok daha hızlı çözmenizi sağlıyor.

Ve evet, Helm bir web sunucusu değil. Dümenin başında siz olun.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir