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ğerleritemplates/: 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.
