Neden Kaniko
Kubernetes kümelerinde container imajı derlemek denildiğinde akla ilk gelen çözüm genellikle Docker-in-Docker veya host'a mount edilmiş paylaşımlı bir Docker socket olur. Her iki yaklaşımda da bir daemon süreci çalıştırmak, imajları host dosya sistemine yazmak ve bu sürece erişim vermek gerekir. Güvenlik perspektifinden baktığında bu, yönetim karmaşıklığını artırır ve saldırı yüzeyini genişletir. Kaniko, bu bağımlılığı ortadan kaldıran bir build aracı olarak tasarlanmıştır. Pod içinde executor imajını çalıştırarak Dockerfile'ı okur, her talimatı sırayla işler ve ortaya çıkan katmanları doğrudan registry'ye gönderir. Docker daemon'a ihtiyaç duymaz; tüm komutlar userspace'de koşar.
Bir not: proje GoogleContainerTools çatısı altında arşivlendi. Kod tarihsel amaçla erişilebilir durumda; yaygın kullanımı hâlâ sürdüğü için mevcut pipeline'larda karşılaşmak normal, yeni tasarımlarda bu durumu hesaba katmak gerekir.
Çalışma Prensibi
Kaniko, Dockerfile'daki her talimatı yorumlar ve geçici bir dosya sistemi üzerinde çalıştırır. Executor, base imajın (FROM satırındaki imajın) filesystem'ini kendi container root'una açar, her komuttan sonra userspace'de snapshot alır ve değişen dosyaları base imaja katman olarak ekler. Build context pod filesystem'inden, bir git repository'sinden veya bir bucket'tan alınabilir. Destination parametresi ile hedef registry ve imaj adı belirlenir.
Pod Konfigürasyonu
Kaniko çalıştırmak için bir pod tanımı yeterlidir. Aşağıdaki örnek, git üzerinden context alıp Docker Hub tarzı bir registry'ye push eden bir build pod'u gösterir.
apiVersion: v1
kind: Pod
metadata:
name: kaniko-build
spec:
restartPolicy: Never
containers:
- name: kaniko
image: gcr.io/kaniko-project/executor:latest
args:
- "--dockerfile=Dockerfile"
- "--context=git://github.com/kullanici/proje.git#refs/heads/main"
- "--destination=registry.example.com/uygulama:1.4.0"
volumeMounts:
- name: kaniko-secret
mountPath: /kaniko/.docker
volumes:
- name: kaniko-secret
secret:
secretName: docker-config
items:
- key: .dockerconfigjson
path: config.json
Secret, registry'ye erişim için gerekli kimlik bilgilerini taşır. Kaniko bu dosyayı /kaniko/.docker/config.json yolundan okuyarak push işlemini gerçekleştirir. ECR için credential helper executor imajının içinde gömülü gelir; instance role kullanılıyorsa secret'a gerek kalmaz, AWS_SDK_LOAD_CONFIG=true ortam değişkeni yeterli olur. Harbor gibi registry'ler docker config auth mekanizmasıyla çalışır.
Context Türleri
Kaniko, farklı context kaynaklarını destekler. Local pod filesystem'ından build etmek için context parametresine
dir:///workspace biçiminde bir dizin yolu verilir; prefix verilmezse kaniko zaten local dizin varsayar. Git repository'sinden derlemek için URL scheme olarak
git:// kullanılır; dal adı
#refs/heads/ referansıyla, commit ise sonuna eklenen hash ile sabitlenebilir.
tar:// ile lokal veya stdin üzerinden tar.gz,
gs:// ve
s3:// ile bucket, Azure Blob Storage için https URL'si kullanılır. Bucket kullananlarda context önce sıkıştırılıp yüklenir, kaniko indirip açar ve build'e başlar.
Katman Cache
Ephemeral pod'larda her build sıfırdan başlar; Docker'daki local layer cache karşılığı yoktur. Kaniko'nun çözümü registry üstünde katman cache'i.
--cache=true ile
RUN ve
COPY katmanları uzak bir repository'de saklanır; komut çalıştırılmadan önce cache'e bakılır, katman bulunursa çekilip açılır. Cache repository'si
--cache-repo ile verilir; verilmezse destination'dan türetilir. Cache miss yaşandığında kalan katmanların hiçbiri cache'e danışılmadan lokal kurulur; Dockerfile'daki satır sırası bu yüzden halen önemli. Cache ömrü
--cache-ttl ile ayarlanır.
Base imajlar için ayrı bir mekanizma var.
gcr.io/kaniko-project/warmer imajı ile bir volume içine önceden indirilen base imajlar, pod'a mount edilen
--cache-dir üzerinden okunur. Bu lokal cache salt okunurdur, warmer ile doldurulması gerekir.
Snapshot Mode Seçimleri
Daemon olmadığı için katman farkları filesystem snapshot'ı ile hesaplanır.
--snapshot-mode parametresi bu snapshot sırasında hangi dosya özelliklerinin karşılaştırılacağını belirler. Varsayılan
full; dosya içeriği ve metadata tamamen incelenir, en yavaş ama en güvenilir seçenek.
redo modunda mtime, boyut, mode, uid ve gid değerlerine bakılır; çok dosyalı projelerde full'e göre %50'ye varan hız artışı verir.
time yalnızca mtime'a bakar; mtime güncellemesi gecikmeli olduğu için RUN komutlarının yaptığı değişiklikleri kaçırabilir. Üretim işlerinde time modundan uzak durmak mantıklı.
Deneysel
--use-new-run flag'i ise snapshot'a hiç bel bağlamaz; RUN öncesi bir marker dosyası oluşturup modtime'ı ondan büyük dosyaları tarar, build sürelerinde %75'e varan iyileşme bildirilmiş durumda. Doğruluk pahasına hız alır, bu yüzden dikkatli kullanılmalı.
Gerçek Dünya Kullanımı
Birçok kurumsal ortamda Kubernetes worker node'larında Docker daemon çalıştırmak güvenlik politikalarına aykırıdır. Kaniko, build'i pod içine hapseder. Tek başına güvenlik garantisi vermez; container runtime'ın izolasyonuna güvenir. Ek sınır istenirse gVisor runtime'ı ile çalıştırılabilir, bu durumda runtime tespiti yapılamadığından
--force flag'i eklenmelidir.
CI/CD tarafında Jenkins, GitLab CI veya Cloud Build adımlarında executor imajı bir build step olarak tanımlanır. GitOps yaklaşımı benimseyen ekiplerde kod commit'i geldiğinde imajın build edilip registry'ye push edilmesi, sonrasında ArgoCD benzeri bir aracın bu değişikliği fark ederek deployment'i güncellemesi yaygın bir kalıptır.
Sınırlar
Kaniko, Docker ile birebir aynı davranan bir Dockerfile yorumlayıcısı değildir. Windows container build'i desteklemez. v1 Registry API'sini desteklemez. Executor binary'sinin resmi imaj dışında bir imajda veya başka bir imaja kopyalanarak çalıştırılması desteklenmez; chroot ve bind-mount kullanamaz, base imajı doğrudan kendi container root'una açtığı için üzerine yazabileceği her şey tehlike sınırında sayılır. Build argümanları ve secret'lar doğru aktarılmazsa build başarısız olur; registry kimlik bilgilerinin secret içinde doğru formatta saklanması kritik.
Çok büyük context'ler network üzerinden transfer edilirken bant genişliği sorunu yaşanabilir. Bu durumda context'i önceden hazırlayıp bir volume içinden vermek veya bucket tabanlı context kullanmak daha verimli olur.
Kaniko, dockersız build ihtiyacının en bilinen cevabı. Katman cache'i, çeşitli context kaynakları ve snapshot mode seçenekleri farklı senaryolara uyum sağlıyor. Docker tabanlı eski build sistemlerini taşıyan ekipler için geçiş sürtünmesi düşük; arşiv durumunu ve runtime izolasyonunu hesaba katan herkes için sağlam bir seçenek.