İçeriğe geç
HA_

← Tüm yazılar

· 3 dk okuma

Güvenli şekilde başarısız olan migration’lar

ClickFortify’ın Prisma migration’larını bir ArgoCD PreSync hook’u olarak nasıl çalıştırdığı; böylece bozuk bir migration, herhangi bir yeni pod başlamadan sürümü durdurur.

devopskubernetesarchitecture

Makine çevirisi. Orijinalini okuyun

Şema değişikliği çoğu dağıtımın en riskli kısmıdır. Yeni kod saniyeler içinde geri alınabilir. İki yapı arasında yarıda kalmış bir veritabanı ise geri alınamaz. Baş mimarı olduğum ClickFortify’da servisler Kubernetes üzerinde çalışıyor ve ArgoCD bunları GitOps ile dağıtıyor. Migration adımından tek bir özellik istedim: başarısız olursa, yeni hiçbir şey çalışmasın.

Güvenli şekilde başarısız olmaktan kastım bu. Başarısız bir migration sürümü durdurmalı, yeni pod’ların beklemedikleri bir şemaya karşı başlamasına izin vermemeli.

Migration nerede çalışıyor

ClickFortify’ın NestJS servisleri PostgreSQL’i Prisma üzerinden kullanıyor. Migration’lar, bekleyen tüm migration’ları sırayla çalıştıran ve başka hiçbir şeyi değiştirmeyen prisma migrate deploy ile uygulanıyor.

Soru, bunun nerede çalıştırılacağıydı. Uygulama container’ı içinde başlangıçta çalıştırmak, her replikanın migration için yarışması demek ve bir hata, sürekli yeniden başlayan pod’lar olarak ortaya çıkıyor. Bir dizüstü bilgisayardan elle çalıştırmak ise birinin hatırlamasına bağlı olmak demek. İkisi de güvenli şekilde başarısız olmuyor.

Bunun yerine migration, ArgoCD’nin bir PreSync hook’u olarak çalıştırdığı bir Kubernetes Job’u. ArgoCD, PreSync hook’larını manifest’lerin geri kalanını uygulamadan önce çalıştırır. Hook Job’u başarısız olursa senkronizasyon iptal edilir ve yeni Deployment hiç uygulanmaz.

apiVersion: batch/v1
kind: Job
metadata:
  name: migrate
  annotations:
    argocd.argoproj.io/hook: PreSync
    argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
spec:
  backoffLimit: 0
  activeDeadlineSeconds: 600
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: migrate
          image: registry.example.com/api:sha-abc1234
          command: ['npx', 'prisma', 'migrate', 'deploy']

Bu manifest örnek amaçlıdır, gerçek bir manifest’ten kopyalanmamıştır.

Sürümle aynı imaj

Job, koruduğu sürümle aynı imajı çalıştırır. Dağıtım yapmak, ArgoCD’nin izlediği depoya yeni bir imaj etiketi commit etmek demektir ve bu etiket hem migration Job’una hem de api Deployment’ına uygulanır. Böylece çalışan migration’lar, tam olarak yayına girmek üzere olan kodla birlikte gelenlerdir. Senkronizasyonu bozulabilecek ayrı bir migration imajı yoktur.

Dağıtım durumu, uygulama kodundan ayrı olarak kendi deposunda tutulur. Bu, ArgoCD’nin her yenilemede büyük bir monorepo’yu yeniden klonlamasını önler ve ArgoCD’nin dağıttığı şeyin küçük, incelenebilir bir etiket ve manifest geçmişi olmasını sağlar.

Körlemesine yeniden deneme yok

backoffLimit: 0 bilinçli bir tercih. Kubernetes başarısız bir Job’u seve seve yeniden dener, ancak yarıda başarısız olan bir migration şemayı yarı uygulanmış bırakmış olabilir. Bakmadan yeniden çalıştırmak durumu kötüleştirebilir. Tek deneme, sonra dur ve log’ları bir insanın okumasına izin ver.

activeDeadlineSeconds, Job’un başarısız sayılmadan önce, örneğin bir kilit üzerinde, ne kadar süre takılı kalabileceğine bir üst sınır koyar.

Kalıcı log’lar

Hook silme politikası BeforeHookCreation. ArgoCD eski Job’u yalnızca bir sonrakini oluşturmak üzereyken siler. O zamana kadar başarısız Job ve pod log’ları kümede kalır; tam da onlara ihtiyaç duyduğunuz an. Hata durumunda hook’u silen bir politika kanıtları çöpe atardı.

Sağlıklı bir çalışma bu log’larda kolayca tanınır: Prisma bulduğu migration’ları bildirir, ardından uyguladıklarının listesini ya da bekleyen bir şey olmadığını yazar ve Job tamamlanır.

Sıra önemli olabilir

Migration’ları yeni pod’lardan önce çalıştırmak doğru varsayılandır ve bazen zorunludur. Yeni kodun bir sütuna yazmayı bıraktığı ve sütunun varsayılan değerinin artık yeni duruma uymadığı bir sürüm düşünün. Mevcut satırları ve varsayılan değeri düzelten migration’ın yeni kod başlamadan önce uygulanması gerekir; aksi halde yeni satırlar, düzeltecek hiçbir şey olmadan eski varsayılan değeri alır.

Bir PreSync hook’u bu sıralamayı ek bir çaba gerektirmeden sağlar.

Bunu kuracak birine ne söylerdim

  1. Migration’ları uygulama başlangıcında değil, sürümü iptal edebilen bir dağıtım öncesi hook olarak çalıştırın.
  2. Migration Job’unu sürümle aynı imaj etiketinden oluşturun ki kod ve şema birbirinden kopmasın.
  3. backoffLimit: 0 ayarlayın ve başarısız Job log’larını saklayın; yarı uygulanmış bir şemanın ihtiyacı yeniden deneme değil, bir insandır.
  4. Yalnızca senkronizasyonla dağıtım yapın, çünkü yeniden başlatma hook’ları atlar.