İçerik
Bu rehberde Helm Chart’ın yapı, bileşenler ve best practices konuları ele alınmaktadır.
Eğer Helm chart temellerini öğrenmek ve Helm chart’lar ile pratik yapmak istiyorsanız, bu rehber tam size göre.
Gereklilikler
Helm chart’lara başlamak için aşağıdakilere ihtiyacınız olacak:
- Çalışan bir Kubernetes cluster’ı
- Workspace’inize kurulmuş Helm CLI
- Cluster’a bağlanmak için geçerli bir kubeconfig
- Kubernetes ve YAML hakkında temel bilgi
Helm Chart Nedir?
Açıklama amacıyla, Kubernetes üzerinde Nginx kullanan bir front-end web sitesi deployment’ının çok basit bir örneğini seçiyorum.
Projenizde dört farklı environment olduğunu varsayalım: Dev, QA, Staging ve Prod. Her environment, Nginx deployment’ı için farklı parametrelere sahip olacaktır. Örneğin:
- Dev ve QA’da yalnızca bir replica gerekebilir.
- Staging ve production’da ise pod autoscaling ile daha fazla replica bulunabilir.
- Her environment için farklı ingress routing kuralları olabilir.
- Her environment için farklı config ve secret’lar olabilir.
Her environment için config ve deployment parametrelerindeki değişiklikler nedeniyle, her environment için ayrı Nginx deployment dosyalarını yönetmeniz gerekir. Ya da tek bir deployment dosyanız olur ve environment’a göre değerleri değiştirmek için özel shell veya Python script’leri yazmanız gerekir. Ancak, bu yöntem ölçeklenebilir bir yaklaşım değildir. İşte bu noktada Helm chart devreye girer.
Helm chart’lar, Kubernetes YAML manifest şablonları ve Helm’e özgü dosyaların bir kombinasyonudur. Bunu bir Helm paketi olarak adlandırabilirsiniz. Kubernetes YAML manifest’leri şablonlanabildiği için, farklı environment’lar için birden fazla Helm chart’ı yönetmek zorunda değilsiniz. Helm, şablonlama işlevi için Go templating engine kullanır.
Yalnızca tek bir Helm chart’a sahip olmanız yeterlidir ve her environment’ın deployment parametrelerini sadece tek bir values dosyasını değiştirerek modifiye edebilirsiniz. Helm, bu değerleri şablonlara uygulama işini halledecektir. Bunun hakkında daha fazla bilgiyi sonraki bölümlerde pratik olarak öğreneceksiniz.
Genel bir bakışla, Helm chart’lar, yalnızca bir şablon ile her environment’ın (dev, qa, stg, prod) karmaşıklığını ve Kubernetes manifest tekrarını azaltır.
Helm Chart Yapısı
Helm chart’ı anlamak için, Nginx deployment örneğini ele alalım. Kubernetes üzerinde Nginx’i deploy etmek için genellikle aşağıdaki YAML dosyalarına sahip olursunuz:
nginx-deployment
├── configmap.yaml
├── deployment.yaml
├── ingress.yaml
└── service.yaml
Yukarıdaki Nginx deployment’ı için bir Helm chart oluşturursak, aşağıdaki dizin yapısına sahip olursunuz:
nginx-chart/
|-- Chart.yaml
|-- charts
|-- templates
| |-- NOTES.txt
| |-- _helpers.tpl
| |-- deployment.yaml
| |-- configmap.yaml
| |-- ingress.yaml
| |-- service.yaml
| `-- tests
| `-- test-connection.yaml
`-- values.yaml
Gördüğünüz gibi, deployment YAML dosyaları template dizininin bir parçasıdır (kalın olarak işaretlenenler) ve Helm’e özgü dosyalar ve klasörler vardır. Şimdi bir Helm chart içerisindeki her dosya ve dizine bakalım ve bunların önemini anlayalım.
- .helmignore: Helm chart’ına dahil etmek istemediğimiz tüm dosyaları tanımlamak için kullanılır. .gitignore dosyasıyla benzer şekilde çalışır.
- Chart.yaml: Helm chart hakkında versiyon, isim, açıklama gibi bilgileri içerir.
- values.yaml: Bu dosyada YAML şablonları için değerleri tanımlarız. Örneğin, imaj adı, replica sayısı, HPA değerleri vb. Daha önce de açıkladığım gibi, her environment’ta sadece values.yaml dosyası değişir. Ayrıca, bu değerleri dinamik olarak veya chart’ı kurarken –values veya –set komutları kullanarak da geçersiz kılabilirsiniz.
- charts: Ana chart’larımızın diğerlerine bağımlılığı varsa, bu dizin içerisine başka bir chart yapısı ekleyebiliriz. Varsayılan olarak bu dizin boştur.
- templates: Bu dizin, bir uygulamayı oluşturan tüm Kubernetes manifest dosyalarını içerir. Bu manifest dosyaları, values.yaml dosyasından değer almak için şablonlanabilir. Helm, deployment.yaml, service.yaml gibi Kubernetes objeleri için bazı varsayılan şablonlar oluşturur; bunları doğrudan kullanabilir, değiştirebilir veya kendi dosyalarımızla geçersiz kılabiliriz.
- templates/NOTES.txt: Bu, chart başarıyla deploy edildikten sonra yazdırılan bir düz metin dosyasıdır.
- templates/_helpers.tpl: Bu dosya çeşitli metotlar ve alt şablonlar içerir. Bu dosyalar Kubernetes nesne tanımlarına dönüştürülmez ancak diğer chart şablonları içinde her yerde kullanılabilir.
- templates/tests/: Chart’larınızın kurulduğunda beklendiği gibi çalıştığını doğrulamak için testler tanımlayabiliriz.
Helm Chart Tutorial GitHub Reposu
Bu Helm Chart Tutorial’ında kullanılan örnek Helm chart ve manifestler, Helm Chart GitHub reposunda barındırılmaktadır. Reponun bir kopyasını alabilir ve rehberi takip etmek için kullanabilirsiniz.
git clone https://github.com/sezersanlikan/helm-chart-tutorial.git
Sıfırdan Helm Chart Oluşturma
Helm chart oluşturma konusunda pratik yapmak için, sıfırdan bir Nginx Helm chart oluşturalım.
Chart şablonunu oluşturmak için aşağıdaki komutu çalıştırın. Bu komut, nginx-chart
adında, varsayılan dosya ve klasörlerle bir chart oluşturur:
helm create nginx-chart
Oluşturulan chart’ı kontrol ederseniz, aşağıdaki dosya ve dizinlere sahip olacaktır:
nginx-chart
│ ├── Chart.yaml
│ ├── charts
│ ├── templates
│ │ ├── NOTES.txt
│ │ ├── _helpers.tpl
│ │ ├── deployment.yaml
│ │ ├── hpa.yaml
│ │ ├── ingress.yaml
│ │ ├── service.yaml
│ │ ├── serviceaccount.yaml
│ │ └── tests
│ │ └── test-connection.yaml
│ └── values.yaml
Oluşturduğumuz chart dizinine geçiş yapmak için aşağıdaki komutu kullanın:
cd nginx-chart
Dosyaları, deployment gereksinimlerimize göre tek tek düzenleyeceğiz.
Chart.yaml
Yukarıda bahsedildiği gibi, chart’ımızın detaylarını Chart.yaml dosyasına koyuyoruz. Chart.yaml dosyasının varsayılan içeriğini aşağıdaki ile değiştirin:
apiVersion: v2
name: nginx-chart
description: My First Helm Chart
type: application
version: 0.1.0
appVersion: "1.0.0"
maintainers:
- email: [email protected]
name: sezerin
- apiVersion: Chart API versiyonunu belirtir.
v2
, Helm 3 için,v1
ise önceki sürümler içindir. - name: Chart’ın adını belirtir.
- description: Helm chart’ının açıklamasını belirtir.
- type: Chart türü ‘application’ veya ‘library’ olabilir. ‘Application’ chart’ları Kubernetes üzerinde deploy ettiğiniz chart’lardır. ‘Library’ chart’ları ise diğer chart’larla birlikte kullanılabilecek yeniden kullanılabilir chart’lardır. Programlamadaki kütüphane (library) kavramına benzer.
- version: Chart sürümünü belirtir.
- appVersion: Uygulamamızın (Nginx) sürüm numarasını belirtir.
- maintainers: Chart’ın sahibine ait bilgileri içerir.
Uygulamaya her değişiklik yaptığımızda version ve appVersion’u artırmalıyız. dependencies, icons gibi başka alanlar da vardır.
Templates
Helm tarafından oluşturulan templates dizininde birden fazla dosya vardır. Bizim durumumuzda, basit bir Kubernetes Nginx deployment üzerinde çalışacağız.
Şimdi template dizinindeki tüm varsayılan dosyaları silelim.
rm -rf templates/*
Nginx YAML dosyalarımızı ekleyeceğiz ve daha iyi anlaşılması için bunları şablona dönüştüreceğiz.
Bir deployment.yaml dosyası oluşturun ve aşağıdaki içeriği kopyalayın.
apiVersion: apps/v1
kind: Deployment
metadata:
name: release-name-nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-chart
image: "nginx:1.16.0"
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
volumeMounts:
- name: nginx-index-file
mountPath: /usr/share/nginx/html/
volumes:
- name: nginx-index-file
configMap:
name: index-html-configmap
Yukarıdaki YAML dosyasına bakarsanız, değerlerin statik olduğunu görebilirsiniz. Helm chart’ın amacı, YAML dosyalarını şablonlayarak bu dosyaları birden fazla environment’ta dinamik olarak değer atayarak yeniden kullanabilmektir.
Bir değeri şablonlamak için, tek yapmanız gereken nesne parametresini aşağıda gösterildiği gibi süslü parantezler içine eklemektir. Bu, bir şablon yönergesi olarak adlandırılır ve Go templating’e özgü bir sözdizimidir.
{{ .Object.Parameter }}
İlk olarak, Object nedir, bunu anlayalım. Bu örnekte kullanacağımız üç Object aşağıda verilmiştir:
- Release: Her helm chart, bir release adıyla deploy edilir. Şablon içinde release adını kullanmak veya release ile ilgili dinamik değerlere erişmek istiyorsanız, release object’ini kullanabilirsiniz.
- Chart: Chart.yaml’de belirttiğiniz herhangi bir değeri kullanmak istiyorsanız, chart object’ini kullanabilirsiniz.
- Values: Values.yaml dosyasındaki tüm parametrelere, Values object’i kullanılarak erişilebilir.
Desteklenen Objects hakkında daha fazla bilgi edinmek için Helm Builtin Object dokümanına göz atabilirsiniz.
Aşağıdaki görsel, yerleşik object’lerin bir şablon içinde nasıl değiltirildiğini göstermektedir.
Öncelikle, hangi değerlerin değişebileceğini veya hangi değerleri şablonlamak istediğinizi belirlemeniz gerekir. Ben name, replicas, container name, image, imagePullPolicy ve configMap Name değerlerini seçtim ve bunları YAML dosyasında kalın olarak vurguladım.
- name:
name: {{ .Release.Name }}-nginx
: Helm, aynı adla release kurmamıza izin vermediği için her seferinde deployment adını değiştirmemiz gerekiyor. Bu yüzden deployment’ın adını release adıyla şablonlayacağız ve yanına -nginx ekleyeceğiz. Şimdi frontend adını kullanarak bir release oluşturursak, deployment adı frontend-nginx olacaktır. Bu şekilde, benzersiz adlara sahip olacağımızdan emin oluruz. - container name:
{{ .Chart.Name }}
: Container adı için, Chart object’ini kullanacağız ve chart.yaml’den chart adını container adı olarak kullanacağız. - Replicas:
{{ .Values.replicaCount }}
Replica değerine values.yaml dosyasından erişeceğiz. - image:
"{{ .Values.image.repository }}:{{ .Values.image.tag }}"
Burada tek bir satırda birden fazla şablon yönergesi kullanıyoruz ve Values dosyasındaki image anahtarının altındaki repository ve tag bilgilerine erişiyoruz. - configMap Name:
{{ .Release.Name }}-index-html-configmap
Burada configmap’e release adını ekliyoruz.
Benzer şekilde, YAML dosyasındaki gerekli değerleri şablonlayabilirsiniz.
İşte şablonları uyguladıktan sonra deployment.yaml dosyamızın son hali. Şablonlanmış kısımlar kalın olarak vurgulanmıştır. Deployment dosyasının içeriğini aşağıdakiyle değiştirin.
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-nginx
labels:
app: nginx
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
volumeMounts:
- name: nginx-index-file
mountPath: /usr/share/nginx/html/
volumes:
- name: nginx-index-file
configMap:
name: {{ .Release.Name }}-index-html-configmap
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-service
spec:
selector:
app.kubernetes.io/instance: {{ .Release.Name }}
type: {{ .Values.service.type }}
ports:
- protocol: {{ .Values.service.protocol | default "TCP" }}
port: {{ .Values.service.port }}
targetPort: {{ .Values.service.targetPort }}
Protokol şablon yönergesinde bir boru ( | ) işareti görebilirsiniz. Bu, protokolün varsayılan değerini TCP olarak tanımlamak için kullanılır. Bu, values.yaml dosyasında protokol değeri tanımlanmazsa veya boşsa, protokol için varsayılan değer olarak TCP’yi alacağı anlamına gelir.
Bir configmap.yaml dosyası oluşturun ve aşağıdaki içeriği ekleyin. Burada varsayılan Nginx index.html sayfasını özel bir HTML sayfası ile değiştiriyoruz. Ayrıca, HTML içinde environment adını değiştirmek için bir şablon yönergesi ekledik.
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-index-html-configmap
namespace: default
data:
index.html: |
<html>
<h1>Welcome</h1>
</br>
<h1>Hi! I got deployed in {{ .Values.env.name }} Environment using Helm Chart </h1>
</html>
Values.yaml
values.yaml dosyası, şablonlarda kullandığımız şablon yönergelerinde değiştirilmesi gereken tüm değerleri içerir. Örneğin, deployment.yaml şablonu, values.yaml dosyasından imaj repository’sini, tag’ini ve pullPolicy’sini almak için bir şablon yönergesi içerir. Aşağıdaki values.yaml dosyasını incelerseniz, repository, tag ve pullPolicy key-value çiftlerinin image anahtarının altında iç içe geçtiğini göreceksiniz. Bu yüzden Values.image.repository ifadesini kullandık.
Şimdi, varsayılan values.yaml içeriğini aşağıdakiyle değiştirin.
replicaCount: 2
image:
repository: nginx
tag: "1.16.0"
pullPolicy: IfNotPresent
service:
name: nginx-service
type: ClusterIP
port: 80
targetPort: 9000
env:
name: dev
Artık Nginx Helm chart’ımız hazır ve son Helm chart yapısı aşağıdaki gibi görünüyor:
nginx-chart
├── Chart.yaml
├── charts
├── templates
│ ├── configmap.yaml
│ ├── deployment.yaml
│ └── service.yaml
└── values.yaml
Helm Chart’ı Doğrulama
Chart’ımızın geçerli olduğundan ve tüm girintilerin düzgün olduğundan emin olmak için aşağıdaki komutu çalıştırabiliriz. Chart dizininin içinde olduğunuzdan emin olun.
helm lint .
Eğer bu komutu nginx-chart dizininin dışından çalıştırıyorsanız, nginx-chart dizininin tam yolunu belirtin:
helm lint /path/to/nginx-chart
Eğer bir hata veya sorun yoksa, şu sonucu gösterecektir:
==> Linting ./nginx
[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, 0 chart(s) failed
Şablonlarda değerlerin doğru şekilde yer değiştirip değiştirmediğini doğrulamak için, aşağıdaki komutu kullanarak şablonlanmış YAML dosyalarını değerlerle birlikte oluşturabilirsiniz. Bu komut, tüm manifest dosyalarını yer değiştirmiş değerlerle birlikte oluşturup görüntüler:
helm template .
Ayrıca, –dry-run komutunu kullanarak kontrol edebiliriz. Bu komut, chart’ı cluster’a yüklemeye çalışır gibi yapar ve bir sorun varsa hatayı gösterir:
helm install --dry-run my-release nginx-chart
Her şey yolundaysa, cluster’a deploy edilecek manifest çıktısını görürsünüz.
Helm Chart’ı Deploy Etme
Chart’ı deploy ettiğinizde, Helm chart ve değerleri values.yaml dosyasından okuyacak ve manifest dosyalarını oluşturacaktır. Daha sonra bu dosyaları Kubernetes API sunucusuna gönderir ve Kubernetes, istenen kaynakları cluster’da oluşturur.
Şimdi chart’ı yüklemeye hazırız.
Helm komutlarını helm-chart klasörünün dışındaki bir dizinden çalıştırdığınızdan emin olun.
Aşağıdaki komutu çalıştırın. frontend release adı, nginx-chart ise chart adıdır. Bu komut, nginx-chart‘ı varsayılan namespace’e kurar:
helm install frontend nginx-chart
NAME: frontend
LAST DEPLOYED: Wed Jun 19 11:12:20 2024
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
Şimdi bu komutu kullanarak release listesini kontrol edebilirsiniz. list yerine ls de kullanabilirsiniz:
helm list
Deployment, servisler ve pod’ları kontrol etmek için kubectl komutlarını çalıştırın:
kubectl get deployment
kubectl get services
kubectl get configmap
kubectl get pods
Aşağıdaki gibi, frontend-nginx deployment’ı, nginx-service ve pod’ların çalışır durumda olduğunu görebiliriz.
Tek bir Helm chart’ının, farklı values.yaml dosyalarını kullanarak birden fazla environment için nasıl kullanılabileceğini inceledik. Harici bir values.yaml dosyası ile bir Helm chart’ı yüklemek için, aşağıdaki komutu –values flag’i ve values dosyasının yolu ile kullanabilirsiniz:
helm install frontend nginx-chart --values env/prod-values.yaml
Helm, CI/CD pipeline’ınızın bir parçası olduğunda, environment’a bağlı olarak gerekli values dosyasını geçirmek için özel bir mantık yazabilirsiniz.
Helm Upgrade & Rollback
Şimdi, chart’ı değiştirmek ve güncellenmiş sürümü yüklemek istediğinizi varsayalım; aşağıdaki komutu kullanabilirsiniz:
helm upgrade frontend nginx-chart
Örneğin, replica sayısını 2’den 1’e değiştirdik. Revision numarasının 2 olduğunu ve yalnızca 1 pod’un çalıştığını görebilirsiniz.
Eğer yaptığımız değişiklikleri geri almak ve önceki sürümü tekrar deploy etmek istersek, bunu yapmak için rollback komutunu kullanabiliriz:
helm rollback frontend
Yukarıdaki komut, Helm release’ini bir önceki sürüme geri döndürecektir.
Rollback işleminden sonra, 2 pod’un tekrar çalıştığını görebiliriz. Helm’in rollback işlemini yeni bir revision olarak kabul ettiğini unutmayın, bu yüzden revision numarası 3 oluyor.
Belirli bir sürüme geri dönmek istiyorsak, revision numarasını şu şekilde belirtebiliriz:
helm rollback <release-name> <revision-number>
Örneğin:
helm rollback frontend 2
Helm Release’i Kaldırma
Helm release’i kaldırmak için uninstall komutunu kullanın. Bu, chart’ın son release’ine bağlı tüm kaynakları kaldıracaktır.
helm uninstall frontend
Eğer release’i belirli bir namespace’e deploy ettiyseniz, uninstall komutu ile namespace flag’ini de kullanabilirsiniz:
helm uninstall <release-name> --namespace <namespace>
Helm Chart Paketleme
Chart’ı paketleyebilir ve GitHub, S3 veya herhangi bir chart deposuna deploy edebiliriz.
nginx-chart‘ı paketlemek için aşağıdaki komutu çalıştırın:
helm package chart-name/
Örneğin:
helm package nginx-chart
Successfully packaged chart and saved it to: /home/vagrant/helm-tutorial/nginx-chart-0.1.0.tgz
Paketleme işlemi yaparken semver 2 sürüm yönergelerini takip eder.
Helm Charts Hata Ayıklama
Helm chart’ları ve şablonları hata ayıklamak için aşağıdaki komutları kullanabiliriz:
- helm lint: Bu komut, bir chart’a giden yolu alır ve chart’ın iyi biçimlendirilmiş olup olmadığını doğrulamak için bir dizi test çalıştırır.
- helm get values: Bu komut, cluster’a kurulan release değerlerini çıktılar.
- helm install –dry-run: Bu işlevi kullanarak, tüm kaynak manifestlerini kontrol edebilir ve tüm şablonların düzgün çalıştığından emin olabiliriz.
- helm get manifest: Bu komut, cluster’da çalışan manifestleri çıktılar.
- helm diff: İki sürüm arasındaki farkları çıktılar.
helm diff revision nginx-chart 1 2
Helm Chart Olası Hatalar
Mevcut bir Helm paketini yüklemeye çalışırsanız, aşağıdaki hatayı alırsınız:
Error: INSTALLATION FAILED: cannot re-use a name that is still in use
Release’i güncellemek veya yükseltmek için upgrade komutunu çalıştırmanız gerekir.
Farklı bir konumdan bir chart yüklemeye çalışırsanız ve chart’ın mutlak yolunu vermezseniz şu hatayı alırsınız:
Error: non-absolute URLs should be in form of repo_name/path_to_chart
Bunu düzeltmek için, chart’ın bulunduğu dizinden Helm komutunu çalıştırmalı veya chart dizininin mutlak veya göreli yolunu sağlamalısınız.
Helm Charts Best Practices
Helm chart geliştirirken aşağıdaki best practice’leri takip etmelisiniz:
- Chart’ınızı yorumlar ekleyerek ve bir README dosyası ekleyerek belgeleyin; belgeler, sürdürülebilir Helm chart’lar için önemlidir.
- Kubernetes manifest dosyalarını nesne türüne göre adlandırmalıyız, örneğin deployment, service, secret, ingress vb.
- Chart adını sadece küçük harfle yazın ve eğer birden fazla kelime içeriyorsa, kelimeleri tire (-) ile ayırın.
- values.yaml dosyasında field name küçük harfle olmalıdır.
- Dize değerlerini her zaman tırnak işaretleri arasında yazın.
- Daha basit ve daha güvenli sürümler için Helm sürüm 3’ü kullanın. Daha fazla ayrıntı için bu dokümana göz atın.
Sonuç
Özetlemek gerekirse,
- Helm Chart ve yapısını detaylıca inceledik.
- Sıfırdan bir Helm chart oluşturduk ve deploy ettik.
- Ayrıca nasıl Upgrade, Roll Back ve Uninstall edileceğini öğrendik.
Helm, Kubernetes için çok kullanışlı bir paket yöneticisidir. Farklı ortamlarla özel dağıtım gereksinimlerine sahip olduğunuzda, Helm, Kubernetes manifestlerini ihtiyaçlarımıza göre şablonlamak için harika bir yol sunar.
Helm’e özgü işlevler, chart bağımlılıkları ve chart yeniden kullanılabilirliği gibi özellikler, onu iyi Kubernetes araçlarından biri yapar.
Helm’in bir alternatifi Kustomize‘dır. Kustomize, şablon kullanmaz, bunun yerine overlays (katmanlar) kavramını kullanır. Daha fazla bilgi edinmek için Kustomize 101 ve Kustomize 102 yazılarıma bakabilirsiniz.