Modern web uygulamaları geliştirirken karşılaşılan en büyük zorluklardan biri, değişen kullanıcı trafiğine göre uygulamanın performansını ve erişilebilirliğini korumaktır. Node.js tabanlı uygulamalarınızın yüksek talepleri karşılayabilmesi ve maliyet etkin bir şekilde çalışabilmesi için doğru ölçeklendirme stratejilerine ihtiyacınız var. Peki, Node.js uygulamalarınızı Kubernetes’in gücü ve Helm’in kolaylığıyla nasıl otomatik olarak ölçeklendirebilirsiniz? Bu makale, bu karmaşık süreci adım adım açıklayarak, uygulamanızın her zaman en iyi performansı sunmasını sağlamanıza yardımcı olacak.
Node.js Uygulama Ölçeklendirme Neden Bu Kadar Önemli?
Günümüz dijital dünyasında, kullanıcı beklentileri her zamankinden daha yüksek. Bir web uygulamasının yavaş yüklenmesi veya erişilemez hale gelmesi, potansiyel müşteri kaybına ve marka itibarının zedelenmesine yol açabilir. Özellikle Node.js gibi tek iş parçacıklı (single-threaded) yapısıyla dikkat çeken platformlarda, gelen yoğun istekleri eş zamanlı olarak yönetmek ve yanıt sürelerini optimize etmek kritik bir öneme sahiptir. Ölçeklendirme, tam da bu noktada devreye girer ve uygulamanızın değişen yük altında bile kararlı ve hızlı çalışmasını garanti eder.
Ölçeklendirme temelde iki ana yaklaşıma ayrılır: dikey (vertical) ve yatay (horizontal). Dikey ölçeklendirme, uygulamanın çalıştığı sunucunun kaynaklarını (CPU, RAM gibi) artırmak anlamına gelir. Bu yöntem, başlangıçta kolay ve hızlı olsa da, belirli bir noktadan sonra fiziksel sınırlarla karşılaşır ve maliyeti hızla artırır. Ayrıca, tek bir sunucunun arızalanması durumunda tüm uygulamanızın çevrimdışı kalma riskini taşır. Yatay ölçeklendirme ise, uygulamanın birden fazla sunucu veya “örnek” (instance) üzerinde çalıştırılması ve gelen trafiğin bu örnekler arasında dağıtılması prensibine dayanır. Bu yaklaşım, çok daha esnek, dayanıklı ve maliyet etkin bir çözüm sunar. Uygulamanızın kapasitesini ihtiyaca göre kolayca artırabilir veya azaltabilir, böylece kaynakları daha verimli kullanabilirsiniz. Özellikle mikroservis mimarileri ve bulut tabanlı dağıtımlar için yatay ölçeklendirme vazgeçilmez bir stratejidir.
Node.js uygulamaları için yatay ölçeklendirme, tek iş parçacıklı yapının getirdiği kısıtlamaları aşmanın en etkili yoludur. Gelen her isteği tek bir işlem yerine birden fazla Node.js işlemine dağıtarak, CPU kullanımını optimize edebilir ve genel işlem hacmini (throughput) artırabilirsiniz. Bu, özellikle I/O yoğun işlemlerde (veritabanı sorguları, ağ istekleri vb.) Node.js’in asenkron doğasından tam anlamıyla faydalanmanızı sağlar. Ancak bu yatay ölçeklendirmeyi manuel olarak yönetmek, her bir uygulama örneğini dağıtmak, izlemek ve gerektiğinde yeniden yapılandırmak oldukça karmaşık ve hataya açık bir süreçtir. İşte tam da bu noktada Kubernetes gibi kapsayıcı düzenleme (container orchestration) platformları ve Helm gibi paket yöneticileri devreye girerek bu süreci otomatikleştirmemizi ve basitleştirmemizi sağlar.
Sonuç olarak, uygulamanızın kullanıcı deneyimini iyileştirmek, operasyonel maliyetleri düşürmek, yüksek erişilebilirlik sağlamak ve gelecekteki büyüme ihtiyaçlarına hazırlıklı olmak için doğru ölçeklendirme stratejilerini benimsemek kritik öneme sahiptir. Bu makalenin devamında, Node.js uygulamanızı Kubernetes ve Helm ile nasıl yatay olarak ölçeklendirebileceğinizi adım adım keşfedeceğiz.
Kubernetes ve Helm: Modern Dağıtımın Temel Taşları Nelerdir?
Modern bulut yerel uygulamaların dağıtımı ve yönetimi, geleneksel yöntemlerle oldukça karmaşık hale gelebilir. Milyonlarca kullanıcının aynı anda eriştiği bir Node.js uygulamasının performansını ve erişilebilirliğini garanti altına almak için güçlü araçlara ihtiyacımız var. İşte bu noktada Kubernetes ve Helm ikilisi, geliştiricilere ve DevOps mühendislerine muazzam kolaylıklar sunar. Bu bölümde, bu iki temel teknolojinin ne olduğunu ve neden birlikte bu kadar güçlü olduklarını detaylıca inceleyeceğiz.
Kubernetes Nedir ve Neden Kullanılır?
Kubernetes, açık kaynaklı bir kapsayıcı düzenleme platformudur. Yani, Docker gibi araçlarla oluşturduğunuz kapsayıcıları (container) otomatik olarak dağıtmanıza, ölçeklendirmenize, yönetmenize ve izlemenize olanak tanır. Google tarafından geliştirilen ve şu anda Cloud Native Computing Foundation (CNCF) tarafından yönetilen Kubernetes, “K8s” olarak da bilinir ve dünya genelinde en popüler kapsayıcı düzenleme aracı haline gelmiştir. Temel amacı, uygulamaların farklı ortamlarda (yerel makine, özel bulut, genel bulut) tutarlı bir şekilde çalışmasını sağlamaktır.
Kubernetes’in sunduğu başlıca avantajlar şunlardır:
- Otomatik Dağıtım ve Yönetim: Uygulama örneklerini (pod’lar) otomatik olarak başlatır, durdurur ve yeniden başlatır.
- Otomatik Ölçeklendirme: Uygulamanızın CPU veya bellek kullanımına göre otomatik olarak yeni örnekler ekler veya mevcut örnekleri azaltır. (Horizontal Pod Autoscaler – HPA)
- Kendi Kendini İyileştirme (Self-healing): Başarısız olan veya yanıt vermeyen kapsayıcıları otomatik olarak tespit eder ve yeniden başlatır.
- Yük Dengeleme: Gelen trafiği, çalışan uygulama örnekleri arasında eşit şekilde dağıtır.
- Hizmet Keşfi (Service Discovery): Uygulama bileşenlerinin birbirini kolayca bulmasını sağlar.
- Depolama Orkestrasyonu: Uygulamalarınız için kalıcı depolama birimlerini yönetir.
- Gizli Bilgi (Secrets) ve Yapılandırma Yönetimi: Veritabanı şifreleri, API anahtarları gibi hassas bilgileri güvenli bir şekilde saklar ve uygulamalara sağlar.
Bir Node.js uygulaması söz konusu olduğunda, Kubernetes, uygulamanızın kapsayıcısını (Docker imajı) alıp, onu bir veya daha fazla “pod” içinde çalıştırır. Her pod, bir veya daha fazla kapsayıcıyı barındıran en küçük dağıtılabilir birimdir. Kubernetes, bu pod’ların sağlıklı kalmasını, gerektiğinde ölçeklenmesini ve dış dünyaya erişilebilir olmasını sağlar. Bu sayede, geliştiriciler altyapı detaylarıyla uğraşmak yerine doğrudan uygulama mantığına odaklanabilirler.
Helm Nedir ve Neden Kubernetes ile Birlikte Kullanılır?
Kubernetes, kapsayıcı düzenleme konusunda oldukça güçlü bir araç olsa da, karmaşık uygulamaların dağıtımını ve yönetimini manuel olarak yapmak yine de zaman alıcı ve hataya açık olabilir. İşte Helm tam da bu noktada devreye girer. Helm, Kubernetes için bir paket yöneticisidir. Linux dünyasındaki apt veya yum gibi, Helm de Kubernetes uygulamaları için “chart” adı verilen önceden yapılandırılmış paketler oluşturmanıza, dağıtmanıza ve yönetmenize olanak tanır.
Helm’in sunduğu başlıca faydalar şunlardır:
- Uygulama Paketleme: Bir uygulamayı (Node.js backend, veritabanı, ön yüz gibi tüm bileşenleriyle birlikte) tek bir “chart” içinde paketlemenizi sağlar.
- Tekrarlanabilir Dağıtımlar: Aynı uygulamayı farklı ortamlara (geliştirme, test, üretim) tutarlı bir şekilde dağıtabilirsiniz.
- Yapılandırma Yönetimi: Uygulamanın farklı ortamlar için özelleştirilebilir yapılandırmalarını (values.yaml dosyası aracılığıyla) kolayca yönetir.
- Sürüm Kontrolü: Dağıtılan uygulamaların sürümlerini izler, kolayca geri alabilir (rollback) veya yükseltebilir (upgrade) olanağı sunar.
- Bağımlılık Yönetimi: Bir chart’ın diğer chart’lara olan bağımlılıklarını yönetir.
Node.js uygulamamızı Kubernetes’e dağıtırken, Helm bize bir Node.js uygulamasının gerektirdiği tüm Kubernetes kaynaklarını (Deployment, Service, Ingress, HPA vb.) içeren bir şablon seti sağlar. Bu şablonlar, values.yaml dosyası aracılığıyla kolayca özelleştirilebilir. Örneğin, uygulama imajının adını, replica sayısını, kaynak limitlerini veya ortam değişkenlerini bu dosya üzerinden değiştirebiliriz. Bu, özellikle CI/CD (Sürekli Entegrasyon/Sürekli Teslimat) süreçlerinde büyük kolaylık sağlar ve dağıtım otomasyonunu basitleştirir.
Özetle, Kubernetes uygulamalarınızı çalıştıran güçlü bir motor gibiyken, Helm bu motoru çalıştırmak için gereken tüm parçaları (uygulama yapılandırmaları, kaynak tanımları) düzenli bir şekilde paketleyen ve yöneten bir anahtar takımı gibidir. Birlikte kullanıldıklarında, Node.js uygulamalarınızı bulutta yüksek performansla ve kolayca ölçeklendirilebilir bir şekilde dağıtmak için eşsiz bir kombinasyon sunarlar.
Node.js Uygulamanızı Kapsayıcı Hale Getirme: Dockerfile Nasıl Yazılır?
Kubernetes ile Node.js uygulamalarını ölçeklendirmeye başlamadan önce, uygulamanızın bir kapsayıcı (container) içinde çalışabilir durumda olması gerekir. Docker, bu kapsayıcıları oluşturmak için endüstri standardı bir araçtır. Bir Node.js uygulamasını Docker kapsayıcısına dönüştürmek için Dockerfile adı verilen basit bir metin dosyası yazmamız gerekiyor. Bu dosya, Docker’a uygulamanızın nasıl oluşturulacağını ve hangi ortamda çalışacağını adım adım anlatır.
Bir Node.js uygulamasını kapsayıcı hale getirmenin temel amacı, uygulamanın tüm bağımlılıkları ve çalışma zamanı ortamı ile birlikte taşınabilir, izole edilmiş ve tutarlı bir birim oluşturmaktır. Bu, “bir kere yaz, her yerde çalıştır” felsefesinin temelini oluşturur ve geliştirme, test ve üretim ortamları arasındaki uyumsuzluk sorunlarını ortadan kaldırır. Aşağıda, tipik bir Node.js uygulaması için adım adım bir Dockerfile örneği ve açıklamaları bulunmaktadır.
Adım 1: Temel İmaj Seçimi
Her Dockerfile, bir temel imaj ile başlar. Node.js uygulamaları için genellikle resmi Node.js Docker imajları kullanılır. Bu imajlar, Node.js çalışma zamanını ve npm gibi gerekli araçları içerir. Genellikle alpine tabanlı imajlar, daha küçük boyutları nedeniyle tercih edilir.
FROM node:18-alpine
Burada node:18-alpine, Node.js’in 18. sürümünü Alpine Linux üzerinde çalıştıran bir imajı temel aldığımızı belirtir. Alpine Linux, minimalist yapısıyla bilinen küçük boyutlu bir Linux dağıtımıdır, bu da nihai Docker imajınızın boyutunu küçültür.
Adım 2: Çalışma Dizini Belirleme
Kapsayıcı içinde uygulamanızın nerede bulunacağını belirlemek için bir çalışma dizini ayarlamanız gerekir. Bu, tüm komutların bu dizin bağlamında çalışmasını sağlar.
WORKDIR /app
Bu komut, kapsayıcı içinde /app adında bir dizin oluşturur ve sonraki tüm komutların bu dizin içinde çalışmasını sağlar.
Adım 3: Bağımlılıkları Kopyalama ve Yükleme
Uygulamanızın bağımlılıklarını (örneğin package.json ve package-lock.json) kopyalayıp yüklemek, imaj boyutunu optimize etmek ve katman önbelleklemesinden faydalanmak için önemli bir adımdır. Önce bağımlılık dosyalarını kopyalar, sonra npm install çalıştırırız. Bu, uygulama kodunda bir değişiklik olduğunda bağımlılıkların yeniden yüklenmesini engeller.
COPY package*.json ./
RUN npm install --production
COPY package*.json ./ komutu, yerel dizindeki package.json ve package-lock.json dosyalarını kapsayıcıdaki /app dizinine kopyalar. Ardından RUN npm install –production komutu, yalnızca üretim bağımlılıklarını yükler, bu da imaj boyutunu daha da küçültür.
Adım 4: Uygulama Kodunu Kopyalama
Bağımlılıklar yüklendikten sonra, uygulamanızın geri kalan kodunu kapsayıcıya kopyalayabilirsiniz.
COPY . .
Bu komut, Dockerfile‘ın bulunduğu dizindeki tüm dosyaları (bağımlılık dosyaları hariç, çünkü zaten kopyalandılar) kapsayıcıdaki çalışma dizinine kopyalar. Genellikle .dockerignore dosyası kullanarak gereksiz dosyaların (örneğin node_modules, .git) kopyalanmasını engellersiniz.
Adım 5: Uygulamanın Dinleyeceği Portu Belirtme
Uygulamanızın hangi port üzerinden dış dünyaya hizmet vereceğini belirtmek iyi bir pratiktir.
EXPOSE 3000
Bu, uygulamanızın 3000 numaralı portu kullanacağını belgeler. Bu, kapsayıcının dışarıdan erişilebilir olmasını sağlamaz, sadece bir bildirimdir. Ağ yapılandırması Kubernetes veya Docker komutları ile yapılır.
Adım 6: Uygulamayı Başlatma Komutu
Son olarak, kapsayıcı başlatıldığında hangi komutun çalışacağını belirtmeniz gerekir.
CMD ["node", "server.js"]
Bu komut, kapsayıcı her başladığında node server.js komutunu çalıştırarak Node.js uygulamanızı başlatır. server.js yerine kendi ana dosyanızın adını kullanmalısınız.
Tamamlanmış Dockerfile Örneği:
# Temel imajı seç
FROM node:18-alpine
# Çalışma dizinini belirle
WORKDIR /app
# package.json ve package-lock.json dosyalarını kopyala
# ve bağımlılıkları yükle
COPY package*.json ./
RUN npm install --production
# Uygulama kodunun geri kalanını kopyala
COPY . .
# Uygulamanın dinleyeceği portu belirt
EXPOSE 3000
# Uygulamayı başlat
CMD ["node", "server.js"]
Docker İmajını Oluşturma ve Çalıştırma
Dockerfile‘ı oluşturduktan sonra, aynı dizinde terminali açıp aşağıdaki komutu çalıştırarak Docker imajını oluşturabilirsiniz:
docker build -t my-nodejs-app:1.0 .
Burada -t my-nodejs-app:1.0 imajınıza bir isim ve etiket (tag) verirken, . ise Dockerfile‘ın mevcut dizinde olduğunu belirtir.
İmajı oluşturduktan sonra, yerel olarak test etmek için aşağıdaki komutu kullanabilirsiniz:
docker run -p 80:3000 my-nodejs-app:1.0
Bu komut, kapsayıcıdaki 3000 numaralı portu yerel makinenizin 80 numaralı portuna eşler. Artık web tarayıcınızdan http://localhost adresine giderek Node.js uygulamanıza erişebilirsiniz.
Node.js uygulamanızı Docker kapsayıcısına dönüştürmek, Kubernetes ile ölçeklendirme yolculuğunuzun ilk ve en kritik adımıdır. Bu adımı tamamladığınızda, uygulamanızın herhangi bir Kubernetes kümesinde tutarlı bir şekilde çalışacağından emin olabilirsiniz.
Helm Chart Oluşturma ve Yapılandırma Adımları Nelerdir?
Node.js uygulamanızı Docker kapsayıcısına dönüştürdüğünüze göre, şimdi bu kapsayıcıyı Kubernetes’e dağıtmak için Helm’i kullanmanın zamanı geldi. Helm, Kubernetes uygulamalarını paketlemek ve dağıtmak için “chart” adı verilen yapıları kullanır. Bir Helm chart’ı, bir uygulamanın tüm Kubernetes kaynaklarını (Deployment, Service, Ingress, HPA vb.) tanımlayan bir şablon koleksiyonudur. Bu bölümde, Node.js uygulamanız için nasıl bir Helm chart oluşturacağınızı ve onu nasıl yapılandıracağınızı adım adım öğreneceksiniz.
Adım 1: Yeni Bir Helm Chart Oluşturma
İlk olarak, Helm CLI’yi kullanarak yeni bir chart iskeleti oluşturmalısınız. Terminalinizde aşağıdaki komutu çalıştırın:
helm create my-nodejs-app-chart
Bu komut, my-nodejs-app-chart adında yeni bir dizin oluşturur ve içine temel bir Helm chart yapısını yerleştirir. Bu dizinin içeriği genellikle şuna benzer:
my-nodejs-app-chart/
├── Chart.yaml # Chart hakkında meta bilgiler
├── values.yaml # Chart için varsayılan yapılandırma değerleri
├── charts/ # Bağımlı chart'lar için dizin
├── templates/ # Kubernetes manifest dosyaları için şablonlar
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── _helpers.tpl
│ └── tests/
│ └── test-connection.yaml
└── .helmignore # Helm'in pakete dahil etmemesi gereken dosyalar
Adım 2: Chart.yaml Dosyasını İnceleme
Chart.yaml dosyası, chart’ınız hakkında temel bilgileri içerir. Bu bilgiler, chart’ın adı, sürümü, açıklaması ve Kubernetes API sürümü gibi detaylardır. Node.js uygulamanız için bu dosyayı güncelleyebilirsiniz:
apiVersion: v2
name: my-nodejs-app-chart
description: A Helm chart for my Node.js application.
version: 0.1.0
appVersion: "1.0.0" # Uygulamanızın versiyonu
appVersion alanı, dağıttığınız Node.js uygulamasının sürümünü belirtir ve chart sürümünden bağımsız olabilir.
Adım 3: values.yaml Dosyasını Yapılandırma
values.yaml dosyası, chart’ınız için varsayılan yapılandırma değerlerini içerir. Bu dosya, templates dizinindeki Kubernetes manifest dosyalarında kullanılan değişkenleri tanımlar. Node.js uygulamanız için bu dosyayı özelleştireceğiz:
# my-nodejs-app-chart/values.yaml
replicaCount: 2 # Uygulamanın kaç kopyasının çalışacağını belirtir
image:
repository: your-dockerhub-username/my-nodejs-app # Docker imajınızın yolu
pullPolicy: IfNotPresent # İmaj çekme politikası (Always, IfNotPresent, Never)
tag: "1.0" # Kullanacağınız imaj etiketi (Dockerfile'da oluşturduğunuz etiket)
service:
type: ClusterIP # Kubernetes Service tipi (ClusterIP, NodePort, LoadBalancer)
port: 80 # Servisin dinleyeceği port
targetPort: 3000 # Uygulamanın dinlediği port (Node.js uygulamanızın portu)
ingress:
enabled: true # Ingress Controller kullanılıp kullanılmayacağını belirtir
className: nginx
annotations:
kubernetes.io/ingress.class: nginx
# cert-manager.io/cluster-issuer: letsencrypt-prod # SSL için örnek annotation
hosts:
- host: myapp.example.com # Uygulamanızın etki alanı
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-nodejs-app-chart # Servis adı
port:
number: 80
resources: # Uygulamanın kullanabileceği CPU ve bellek kaynakları
limits:
cpu: 500m # 0.5 CPU çekirdeği
memory: 512Mi # 512 Megabayt bellek
requests:
cpu: 200m
memory: 256Mi
autoscaling: # Horizontal Pod Autoscaler (HPA) ayarları
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70 # CPU kullanımı %70'e ulaşınca ölçeklendir
nodeSelector: {} # Uygulamanın belirli düğümlerde çalışmasını istiyorsanız
tolerations: [] # Belirli düğümlerdeki taint'leri tolere etmek için
affinity: {} # Uygulamanın düğüm veya pod'lara yakınlığını/uzaklığını ayarlamak için
Bu values.yaml dosyası, Node.js uygulamanızın Kubernetes üzerinde nasıl dağıtılacağına dair kapsamlı bir yapılandırma sağlar. Örneğin, replicaCount ile başlangıçta kaç adet uygulama kopyasının çalışacağını, image ile Docker imajınızın nerede olduğunu ve service ile uygulamanızın nasıl erişilebilir olacağını belirtirsiniz. Özellikle autoscaling bölümü, uygulamanızın otomatik ölçeklendirme davranışını tanımlar.
Adım 4: templates Dizini İçindeki Dosyaları Düzenleme
templates dizini, Kubernetes manifest dosyalarını (Deployment, Service, Ingress vb.) içeren Jinja benzeri şablonları barındırır. Bu dosyalar, values.yaml dosyasındaki değerleri kullanarak nihai Kubernetes kaynaklarını oluşturur. Varsayılan olarak oluşturulan dosyaları Node.js uygulamanıza göre özelleştirelim.
deployment.yaml Dosyası
Bu dosya, uygulamanızın pod’larını ve bunların nasıl çalışacağını tanımlar. values.yaml‘deki image, replicaCount ve resources değerlerini kullanır.
# my-nodejs-app-chart/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "my-nodejs-app-chart.fullname" . }}
labels:
{{- include "my-nodejs-app-chart.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "my-nodejs-app-chart.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "my-nodejs-app-chart.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
resources:
{{- toYaml .Values.resources | nindent 12 }}
# Sağlık kontrolleri
livenessProbe:
httpGet:
path: /healthz # Uygulamanızın sağlık kontrolü endpoint'i
port: http
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready # Uygulamanızın hazır olma kontrolü endpoint'i
port: http
initialDelaySeconds: 5
periodSeconds: 5
env: # Ortam değişkenleri
- name: NODE_ENV
value: production
- name: PORT
value: "{{ .Values.service.targetPort }}"
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
Bu deployment.yaml dosyasında, Node.js uygulamanızın imajını, portunu, kaynak limitlerini ve sağlık kontrollerini (livenessProbe, readinessProbe) values.yaml‘den gelen değerlerle dinamik olarak yapılandırıyoruz. Sağlık kontrolleri, Kubernetes’in uygulamanızın sağlıklı olup olmadığını anlaması için kritik öneme sahiptir.
service.yaml Dosyası
Bu dosya, uygulamanızın pod’larına dışarıdan veya diğer pod’lardan nasıl erişileceğini tanımlar.
# my-nodejs-app-chart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ include "my-nodejs-app-chart.fullname" . }}
labels:
{{- include "my-nodejs-app-chart.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.targetPort }}
protocol: TCP
name: http
selector:
{{- include "my-nodejs-app-chart.selectorLabels" . | nindent 4 }}
Burada, service.type ve service.port değerleri values.yaml dosyasından alınır.
ingress.yaml Dosyası
Eğer uygulamanıza dışarıdan HTTP/HTTPS üzerinden erişim sağlamak istiyorsanız, bir Ingress kaynağına ihtiyacınız vardır. Bu dosya, trafiği Kubernetes Service’inize yönlendirir.
# my-nodejs-app-chart/templates/ingress.yaml
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "my-nodejs-app-chart.fullname" . }}
labels:
{{- include "my-nodejs-app-chart.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.className }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "my-nodejs-app-chart.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- toYaml .Values.ingress.tls | nindent 4 }}
{{- end }}
{{- end }}
Ingress tanımı, values.yaml‘deki ingress.enabled, ingress.hosts ve ingress.annotations gibi değerleri kullanarak dinamik olarak oluşturulur.
hpa.yaml (Horizontal Pod Autoscaler) Dosyası
Otomatik ölçeklendirme için HorizontalPodAutoscaler (HPA) kaynağını tanımlamanız gerekir. Bu dosya, Node.js uygulamanızın CPU veya bellek kullanımına göre pod sayısını otomatik olarak artırıp azaltmasını sağlar.
# my-nodejs-app-chart/templates/hpa.yaml
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "my-nodejs-app-chart.fullname" . }}
labels:
{{- include "my-nodejs-app-chart.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "my-nodejs-app-chart.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
# Bellek bazlı ölçeklendirme için aşağıdaki bölümü etkinleştirebilirsiniz
# - type: Resource
# resource:
# name: memory
# target:
# type: Utilization
# averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
Bu HPA tanımı, values.yaml‘deki autoscaling ayarlarını kullanarak uygulamanızın CPU kullanımına göre otomatik olarak ölçeklenmesini sağlar. Örneğin, CPU kullanımı %70’i aştığında yeni pod’lar oluşturulacak, altına düştüğünde ise mevcut pod’lar azaltılacaktır.
Bu adımları tamamladığınızda, Node.js uygulamanızı Kubernetes’e dağıtmak ve otomatik ölçeklendirme özelliklerinden faydalanmak için tamamen yapılandırılmış bir Helm chart’ınız olacaktır. Bir sonraki bölümde, bu chart’ı kullanarak uygulamanızı Kubernetes kümesine nasıl dağıtacağımızı ve ölçeklendirme mekanizmalarını nasıl etkinleştireceğimizi göreceğiz.
Kubernetes’e Dağıtım ve Ölçeklendirme Nasıl Yapılır?
Helm chart’ınızı Node.js uygulamanız için başarıyla oluşturduğunuza göre, artık bu chart’ı Kubernetes kümenize dağıtmanın ve otomatik ölçeklendirme özelliklerini etkinleştirmenin zamanı geldi. Bu bölüm, uygulamanızı dağıtım, güncelleme ve izleme adımlarını detaylandırarak, Kubernetes’in sunduğu güçlü ölçeklendirme yeteneklerinden nasıl faydalanacağınızı gösterecektir.
Adım 1: Docker İmajını Bir Kayıt Defterine Gönderme (Push)
Kubernetes kümeniz, uygulamanızın Docker imajını çekebilmesi için bir Docker kayıt defterine (Registry) erişebilmelidir. Bu genellikle Docker Hub, Google Container Registry (GCR), Amazon Elastic Container Registry (ECR) veya Azure Container Registry (ACR) gibi herkese açık veya özel bir kayıt defteri olabilir. Daha önce oluşturduğunuz imajı bu kayıt defterine göndermelisiniz.
# Docker Hub'a giriş yapın
docker login
# İmajınızı etiketleyin (tag)
docker tag my-nodejs-app:1.0 your-dockerhub-username/my-nodejs-app:1.0
# İmajınızı kayıt defterine gönderin
docker push your-dockerhub-username/my-nodejs-app:1.0
Kayıt defteri yolunu ve imaj etiketini values.yaml dosyanızda doğru şekilde belirttiğinizden emin olun.
Adım 2: Helm Chart’ı Kubernetes Kümesine Dağıtma
Helm chart’ınızı dağıtmak için helm install komutunu kullanırız. Bu komut, chart’ı alır, values.yaml dosyasındaki değerlerle birleştirir ve ortaya çıkan Kubernetes manifest dosyalarını kümenize uygular.
helm install my-nodejs-app my-nodejs-app-chart/
Burada my-nodejs-app, dağıtımınız için bir “release” adı, my-nodejs-app-chart/ ise chart’ınızın bulunduğu dizinin yoludur. Başarılı bir dağıtımın ardından, Helm size dağıtım hakkında bilgiler gösterecektir.
Dağıtımın durumunu kontrol etmek için aşağıdaki komutları kullanabilirsiniz:
kubectl get deployments
kubectl get pods
kubectl get services
kubectl get ingress
Pod’larınızın Running durumunda olduğundan ve READY sütununun doğru değerleri gösterdiğinden emin olun. Eğer bir Ingress kaynağı yapılandırdıysanız, kubectl get ingress komutu size uygulamanızın dış IP adresini veya DNS adını verecektir.
Adım 3: Otomatik Ölçeklendirme (Horizontal Pod Autoscaler – HPA)
Helm chart’ınızda hpa.yaml dosyasını etkinleştirdiyseniz ve values.yaml‘de autoscaling.enabled: true olarak ayarladıysanız, uygulamanız otomatik olarak ölçeklenmeye başlayacaktır. HPA’nın durumunu kontrol etmek için:
kubectl get hpa
Bu komut, HPA’nızın hedeflediği CPU yüzdesini, mevcut CPU kullanımını, minimum ve maksimum pod sayısını gösterecektir. Uygulamanızın yükü arttığında, HPA otomatik olarak yeni pod’lar oluşturacak ve maxReplicas değerine kadar ölçeklenecektir. Yük azaldığında ise pod sayısı minReplicas değerine kadar düşürülecektir.
Adım 4: Uygulama Güncelleme ve Geri Alma (Rollback)
Uygulamanızda bir değişiklik yaptığınızda (örneğin yeni bir kod sürümü veya yapılandırma değişikliği), Helm ile kolayca güncelleyebilirsiniz. Yeni Docker imajınızı kayıt defterine gönderdikten sonra, values.yaml dosyasındaki image.tag değerini güncelleyin ve ardından helm upgrade komutunu kullanın:
# values.yaml dosyasını düzenleyin: image.tag: "1.1" (yeni sürüm)
helm upgrade my-nodejs-app my-nodejs-app-chart/
Helm, bu komutla yeni değişiklikleri güvenli bir şekilde kümenize uygular (rolling update stratejisi kullanarak). Eğer bir sorunla karşılaşırsanız, önceki sürüme kolayca geri dönebilirsiniz:
helm history my-nodejs-app # Geçmiş sürümleri listeler
helm rollback my-nodejs-app [REVİZYON_NUMARASI] # Belirli bir revizyona geri döner
Bu yetenekler, üretim ortamında güvenli ve kontrollü dağıtımlar yapmanızı sağlar.
Adım 5: Manuel Ölçeklendirme (Gerektiğinde)
Otomatik ölçeklendirme genellikle tercih edilen yöntem olsa da, bazı durumlarda anlık yük artışları için manuel olarak ölçeklendirme yapmanız gerekebilir. kubectl scale komutunu kullanarak bir Deployment’ın replica sayısını manuel olarak değiştirebilirsiniz:
kubectl scale deployment/my-nodejs-app-chart --replicas=5
Bu komut, my-nodejs-app-chart adlı Deployment’ın pod sayısını anında 5’e çıkaracaktır. Ancak unutmayın ki HPA etkinse, manuel ölçeklendirme HPA’nın otomatik ayarlamalarıyla çakışabilir. Genellikle HPA varken manuel müdahaleden kaçınılmalıdır.
Node.js uygulamanızı Kubernetes’e Helm ile dağıtmak ve ölçeklendirmek, uygulamanızın performansını ve erişilebilirliğini artırmanın yanı sıra operasyonel yükü de önemli ölçüde azaltır. Bu güçlü kombinasyon sayesinde, uygulamanızın gelecekteki büyüme ihtiyaçlarına kolayca uyum sağlayabilirsiniz.
Gerçek Dünya Senaryolarında Performans Optimizasyonu ve İzleme İpuçları Nelerdir?
Node.js uygulamalarını Kubernetes ve Helm ile ölçeklendirmek, yüksek performans ve erişilebilirlik sağlamanın önemli bir adımıdır. Ancak sadece dağıtmak yeterli değildir; gerçek dünya senaryolarında uygulamanızın en iyi şekilde çalışmasını sağlamak için sürekli optimizasyon ve dikkatli izleme stratejilerine ihtiyacınız vardır. Bu bölümde, performans optimizasyonu için ipuçlarını ve etkili izleme yaklaşımlarını inceleyeceğiz.
Kaynak Limitleri ve İsteklerini Doğru Ayarlama
Kubernetes’te her pod için CPU ve bellek kaynak istekleri (requests) ve limitleri (limits) tanımlamak kritik öneme sahiptir. requests, Kubernetes’in pod’u bir düğüme yerleştirirken (scheduling) garantilemesi gereken minimum kaynak miktarını belirtir. limits ise bir pod’un kullanabileceği maksimum kaynak miktarını belirler. Bu değerler olmadan, pod’larınız düğüm kaynaklarını aşırı kullanabilir ve diğer pod’ların performansını etkileyebilir veya düğümün çökmesine neden olabilir.
# values.yaml dosyasından örnek
resources:
limits:
cpu: 500m # 0.5 CPU çekirdeği (aşarsa kısıtlanır)
memory: 512Mi # 512 Megabayt bellek (aşarsa sonlandırılır)
requests:
cpu: 200m # 0.2 CPU çekirdeği (garanti edilen)
memory: 256Mi # 256 Megabayt bellek (garanti edilen)
Node.js uygulamaları genellikle CPU yerine I/O yoğun olabilir. Bu nedenle, uygulamanızın gerçek dünya yükü altında ne kadar CPU ve bellek tükettiğini izleyerek bu değerleri hassas bir şekilde ayarlamak önemlidir. Yanlış ayarlar, gereksiz yere kaynak israfına veya performans darboğazlarına yol açabilir.
Liveness ve Readiness Probları ile Sağlık Kontrolü
Kubernetes, pod’larınızın sağlığını izlemek için livenessProbe ve readinessProbe adı verilen mekanizmalar sunar. Bu probları doğru yapılandırmak, uygulamanızın kararlılığı için hayati öneme sahiptir:
- Liveness Probe: Bir kapsayıcının çalışır durumda olup olmadığını kontrol eder. Eğer probe başarısız olursa, Kubernetes kapsayıcıyı yeniden başlatır. Node.js uygulamanızda, bu genellikle uygulamanın ana sunucusunun hala yanıt verip vermediğini kontrol eden bir HTTP endpoint’i (/healthz gibi) olabilir.
- Readiness Probe: Bir kapsayıcının trafiği kabul etmeye hazır olup olmadığını kontrol eder. Eğer probe başarısız olursa, Kubernetes bu kapsayıcıya trafik yönlendirmeyi durdurur ve hazır hale gelene kadar bekler. Bu, uygulamanızın başlatma sırasında veritabanı bağlantısı kurması veya önbelleği doldurması gibi uzun süren işlemler için kullanışlıdır.
# deployment.yaml dosyasından örnek
livenessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 5 # Kapsayıcı başladıktan sonra ilk kontrol için bekleme süresi
periodSeconds: 10 # Kontroller arasındaki süre
timeoutSeconds: 3 # Kontrolün zaman aşımı süresi
failureThreshold: 3 # Kaç başarısızlıktan sonra yeniden başlatılacağı
readinessProbe:
httpGet:
path: /ready
port: http
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 1
Bu probları dikkatlice yapılandırmak, uygulamanızın sadece çalışır durumda olmasını değil, aynı zamanda sağlıklı bir şekilde hizmet vermesini de sağlar.
İzleme ve Günlük Kaydı (Monitoring & Logging)
Uygulamanızın performansını ve sağlığını sürekli olarak izlemek, potansiyel sorunları proaktif bir şekilde tespit etmek için vazgeçilmezdir. Kubernetes ekosisteminde popüler izleme araçları şunlardır:
- Prometheus: Metrik toplama ve depolama için kullanılan açık kaynaklı bir sistemdir. Node.js uygulamanızdan özel metrikler (örneğin istek sayısı, yanıt süreleri, hata oranları) toplayabilir.
- Grafana: Prometheus ile toplanan metrikleri görselleştirmek için kullanılır. Özelleştirilebilir panolar aracılığıyla uygulamanızın performansını anlık olarak takip edebilirsiniz.
Günlük kaydı (logging) ise, uygulamanızın iç işleyişini anlamak ve sorunları ayıklamak için kritik öneme sahiptir. Node.js uygulamanızın standart çıktıya (stdout) ve standart hataya (stderr) günlük yazmasını sağlamalısınız. Kubernetes, bu günlükleri otomatik olarak toplar. Bu günlükleri merkezi bir yerde toplamak ve analiz etmek için ELK Stack (Elasticsearch, Logstash, Kibana) veya Loki gibi çözümleri kullanabilirsiniz.
Frontend ve Kullanıcı Deneyimi Optimizasyonu (Mobil Uyumluluk)
Bir Node.js uygulamasının backend’ini Kubernetes ile ölçeklendirmek, uygulamanın genel performansının sadece bir parçasıdır. Kullanıcı deneyimi, frontend’in hızı ve duyarlılığı ile de yakından ilgilidir. Uygulamanızın yüksek performanslı bir backend’e sahip olması, frontend’in farklı cihazlarda (masaüstü, tablet, mobil) sorunsuz çalışmasını sağlamaz.
Mobil uyumluluk ve duyarlı tasarım (responsive design), günümüz web uygulamaları için bir zorunluluktur. Kullanıcıların büyük bir kısmı mobil cihazlardan erişim sağladığı için, uygulamanızın ekran boyutuna ve cihaz özelliklerine göre kendini otomatik olarak ayarlaması gerekir. Bu, CSS media queries gibi tekniklerle sağlanır:
/* Örnek bir media query kullanımı */
@media screen and (max-width: 768px) {
.container {
width: 100%;
padding: 15px;
}
.sidebar {
display: none; /* Mobil cihazlarda kenar çubuğunu gizle */
}
}
Bu tür media queries, tarayıcının genişliğine göre farklı stil kurallarının uygulanmasını sağlar. Node.js backend’iniz ne kadar hızlı olursa olsun, eğer frontend’iniz mobil cihazlarda yavaş yükleniyor veya kötü görünüyor ise, kullanıcı deneyimi olumsuz etkilenecektir. Dolayısıyla, backend ölçeklendirme çabalarınızı, frontend optimizasyonları ve duyarlı tasarım prensipleriyle desteklemek bütünsel bir yaklaşım sunar.
Gerçek dünya senaryolarında Node.js uygulamalarınızın Kubernetes üzerinde başarılı bir şekilde ölçeklenmesi ve çalışması için bu optimizasyon ve izleme ipuçlarını uygulamak kritik öneme sahiptir. Sürekli iyileştirme ve proaktif yönetim, uygulamanızın her zaman en iyi performansı sunmasını sağlar.
Sonuç: Node.js Uygulamalarınız İçin Ölçeklenebilir Bir Gelecek
Bu makale boyunca, Node.js uygulamalarınızı Kubernetes ve Helm kullanarak nasıl ölçeklendirebileceğinizi adım adım inceledik. Modern web dünyasında, değişen kullanıcı taleplerine hızlı ve esnek bir şekilde yanıt verebilmek, bir uygulamanın başarısı için temel bir gerekliliktir. Node.js’in performans potansiyelini Kubernetes’in güçlü kapsayıcı düzenleme yetenekleri ve Helm’in dağıtım kolaylığıyla birleştirmek, bu ihtiyacı karşılamanın en etkili yollarından biridir.
Başlangıçta, Node.js uygulamanızı Docker kapsayıcısına dönüştürerek taşınabilir ve tutarlı bir çalışma ortamı sağladık. Ardından, Helm’in sunduğu “chart” yapısı ile uygulamanızın tüm Kubernetes kaynaklarını (Deployment, Service, Ingress, HPA) tek bir paket halinde nasıl tanımlayacağımızı ve yapılandıracağımızı öğrendik. Özellikle values.yaml dosyasının esnekliği sayesinde, farklı ortamlar için kolayca özelleştirilebilir dağıtımlar oluşturabildik. Son olarak, uygulamanızı Kubernetes kümesine dağıtma, otomatik ölçeklendirme (HPA) mekanizmalarını etkinleştirme ve performans optimizasyonu ile izleme için kritik ipuçlarını ele aldık. Bu süreç, uygulamanızın yalnızca anlık yükleri yönetmesini sağlamakla kalmaz, aynı zamanda gelecekteki büyüme ve değişikliklere de kolayca uyum sağlamasına olanak tanır.
Unutmayın ki teknoloji sürekli gelişiyor ve en iyi uygulamalar zamanla değişebilir. Bu nedenle, Kubernetes ve Helm ekosistemindeki yenilikleri takip etmek, uygulamanızın performansını ve güvenliğini sürekli olarak iyileştirmek için önemlidir. Kaynak limitlerini ve isteklerini doğru ayarlamak, liveness ve readiness probları ile sağlık kontrollerini titizlikle yapılandırmak, Prometheus ve Grafana gibi araçlarla sürekli izleme yapmak ve merkezi günlük kaydı sistemleri kullanmak, uygulamanızın istikrarlı ve yüksek performanslı çalışmasını garanti altına alacaktır. Node.js uygulamalarınızı Kubernetes ve Helm ile ölçeklendirmek, yalnızca teknik bir başarı değil, aynı zamanda iş sürekliliği ve müşteri memnuniyeti açısından da stratejik bir yatırımdır. Bu güçlü kombinasyonla, uygulamalarınızın geleceğe hazır olduğundan emin olabilirsiniz.
Sıkça Sorulan Sorular (SSS)
-
Kubernetes’te Node.js uygulamaları için neden Helm kullanmalıyım?
Helm, Kubernetes uygulamalarını paketlemek, dağıtmak ve yönetmek için bir paket yöneticisidir. Node.js uygulamanız için bir Helm chart oluşturmak, Kubernetes kaynaklarını (Deployment, Service, Ingress, HPA) tek bir şablon seti halinde birleştirir. Bu, dağıtım süreçlerini basitleştirir, tekrarlanabilirliği artırır, yapılandırma yönetimini kolaylaştırır ve sürüm kontrolü ile geri alma (rollback) yetenekleri sunar. Özellikle karmaşık uygulamalar ve CI/CD süreçleri için vazgeçilmezdir.
-
Horizontal Pod Autoscaler (HPA) ve Vertical Pod Autoscaler (VPA) arasındaki fark nedir?
HPA (Horizontal Pod Autoscaler), pod’ların CPU veya bellek kullanımına (veya özel metriklere) göre otomatik olarak yeni pod’lar ekleyerek veya mevcut pod’ları azaltarak yatay ölçeklendirme yapar. VPA (Vertical Pod Autoscaler) ise, mevcut pod’ların CPU ve bellek kaynak isteklerini (requests) ve limitlerini (limits) otomatik olarak ayarlayarak dikey ölçeklendirme yapar. HPA, değişen trafiğe yanıt verirken, VPA kaynak optimizasyonuna odaklanır. Genellikle HPA ve VPA birlikte kullanılmaz, çünkü VPA’nın yaptığı değişiklikler HPA’nın hesaplamalarını etkileyebilir. Çoğu senaryoda HPA tercih edilir.
-
Node.js uygulamam için Docker imajı oluştururken nelere dikkat etmeliyim?
Docker imajı oluştururken şunlara dikkat etmelisiniz: Küçük boyutlu bir temel imaj kullanın (örneğin node:18-alpine). .dockerignore dosyasını kullanarak gereksiz dosyaların (örneğin node_modules, .git) imaja dahil edilmesini engelleyin. Bağımlılıkları ayrı bir katmanda yükleyin (COPY package*.json && npm install), bu katman önbelleklemesini optimize eder. Yalnızca üretim bağımlılıklarını yükleyin (npm install –production). Son olarak, güvenlik için root olmayan bir kullanıcıyla çalıştırın ve multi-stage build kullanarak nihai imajın boyutunu küçültün.
-
Kubernetes’te Node.js uygulamasının performansını nasıl izleyebilirim?
Node.js uygulamanızın performansını izlemek için Prometheus ve Grafana gibi araçları kullanabilirsiniz. Uygulamanızdan CPU, bellek kullanımı, istek sayısı, yanıt süreleri ve hata oranları gibi metrikleri toplayarak Prometheus’a gönderebilirsiniz. Grafana ile bu metrikleri görselleştiren özelleştirilebilir panolar oluşturarak uygulamanızın sağlığını ve performansını anlık olarak takip edebilirsiniz. Ayrıca, uygulamanızın günlüklerini merkezi bir günlük kaydı sisteminde (ELK Stack, Loki) toplayarak sorunları ayıklayabilir ve davranış analizleri yapabilirsiniz.
-
Node.js uygulamamda neden liveness ve readiness probları kullanmalıyım?
Liveness ve readiness probları, Kubernetes’in pod’larınızın sağlığını ve trafiği kabul etmeye hazır olup olmadığını anlaması için kritik öneme sahiptir. Liveness probe, uygulamanızın hala çalıştığından emin olur ve başarısız olursa pod’u yeniden başlatır. Readiness probe ise, uygulamanızın trafiği işlemeye hazır olduğunu bildirir; bu sayede Kubernetes, uygulamanızın başlatma veya kendini iyileştirme aşamasında olduğu durumlarda ona trafik yönlendirmez. Bu problar, uygulamanızın yüksek erişilebilirliğini ve kararlılığını sağlamak için vazgeçilmezdir.