pnpm Monorepo'yu 30 Dakikalık Bir Build Olmadan Docker'a Nasıl Gönderirsiniz
Soğuk derlemeleri beş dakikanın altında ve artımlı derlemeleri otuz saniyenin altında tutan bir pnpm monorepo için Docker build stratejisi. Çalışma alanına duyarlı Dockerfile, sabitlenmiş lockfile kurulumu ve birinci gün bizi ısıran dağıtım tuzağı.
pnpm monorepo'nun üretime ilk dağıtımı, ekibin "kısa Dockerfile"ın gerçekte ne anlama geldiğini öğrendiği andır. Saf bir Dockerfile her CI çalıştırmasında tüm lockfile'ı yeniden oluşturur. 10 dakikalık appleboy/ssh-action varsayılan zaman aşımının soğuk bir derleme tarafından yendiğini izledik. İşte konduğumuz kalıp ve birinci gün bizi ısıran tuzak.
Çalışma alanına duyarlı Dockerfile
Bir monorepo Dockerfile'ı için iki tartışılmaz tasarım kuralı:
-
Bağlam monorepo köküdür. Build bağlamı
apps/backendveyaapps/webdeğil, çalışma alanı kökü olmalıdır. Paketler çalışma alanı genelinde birbirine referans verir; kurulumun tüm lockfile ve çalışma alanı bildirimlerini görmesi gerekir. -
Lockfile sözleşmedir. Geliştiricinin yerel olarak çalıştırdığı aynı
pnpm-lock.yaml, CI'ın kurduğu dosyadır. Bu nedenle Docker'da ve CI'dafrozen-lockfile=trueile sabitliyoruz.
Arka uç Dockerfile kalıbı:
- Tam
node:20-alpinegörüntüsünü kullanan vepnpm install --frozen-lockfile'ı bir kez çalıştıran bir builder aşaması. - Yalnızca
apps/backend/dist, çalışma zamanı içinnode_modulesveapps/backend/package.json'ı kopyalayan bir runner aşaması. Kaynak yok, test fikstürü yok, build araçları yok.
Web Dockerfile kalıbı (ayrı endişeler, farklı aşama):
output: "standalone"ile Next.js derleyen bir builder aşaması ve bu bağımsız çıktı zaten yalnızca çalışma zamanı bağımlılıklarına sahip birnode_modulesiçerir.- Bağımsız çıktıyı ve genel varlıkları kopyalayan, sonra
node server.jsçalıştıran bir runner aşaması.
Birinci gün bizi ısıran dağıtım tuzağı
İlk dağıtım girişimimiz klasik hataydı: her uygulamanın kendi Dockerfile'ı var, her Compose dosyası söz konusu uygulama için build bağlamını kullanıyor ve üretim Compose dosyası geliştirme dosyasından farklı bir proje adına işaret ediyor. İki süreç aynı ana bağlantı noktasına bağlandı.
Düzeltme:
-
Uygulama başına tek build bağlamı. Dockerfile build bağlamı her zaman monorepo köküdür. Uygulamalar
apps/web/Dockerfileveapps/backend/Dockerfiledosyalarını kullanır, ancak bağlam. -
Açık Compose proje adı. Üretim Compose'u, kapları aynı ana bilgisayarda olabilecek diğer uygulamalardan ad alanı ayırmak için
-p 2runbe-monorepokullanır. Bu olmadan, iki Compose dosyası sessizce aynı bağlantı noktasını talep edebilir. -
Compose dış ağı. Üretim, arka uç ve web'i aynı MongoDB ve Redis örneklerini paylaşan diğer uygulamalarla birlikte paylaşılan bir
fenix-shared-servicesağında çalıştırır. Yerel geliştirme, kendi MongoDB ve Redis'ini başlatan--profile fullprofiliyleappağında kendi compose'unu çalıştırır.
Lockfile sürüklenme tespiti
Lockfile sürüklenmesinin sizi iki yoldan yakaladığı yerler:
-
Bir geliştirici
pnpm-lock.yamldosyasını günceller, CI bunu sabit bir yerden kopyalayan eski Dockerfile'a karşı çalışır ve lockfile, bağımlılık ağacından daha yeni olduğu için kurulum başarısız olur. -
İkinci bir geliştirici yerel olarak frozen lockfile olmadan
pnpm installçalıştırır ve CI'dan biraz farklı bir lockfile alır.
Her iki ucu da kilitliyoruz:
-
Pre-commit kancası
pnpm install --frozen-lockfileçalıştırır ve başarısız olursa taahhüt etmeyi reddeder. -
CI de frozen lockfile kullanır. Geliştirici kancayı atlatsa bile, CI onu dağıtımdan önce yakalar.
Soğuk vs artımlı derlemeler
Çalışma alanına duyarlı Dockerfile ve sabitlenmiş lockfile ile soğuk derleme süreleri:
-
Arka uç. 4 çekirdekli bir koşucuda ~3 dakika. Sürenin çoğu tüm çalışma alanı üzerinde
pnpm installiçindir. -
Web. ~4 dakika.
pnpm installönbelleğe alındıktan sonra Next.js derlemeleri baskındır.
Artımlı derleme süreleri (pnpm install önbellek isabeti):
-
Arka uç. Tek bağımlılık yükseltmesi için ~25 saniye, NestJS kaynak değişikliği için ~40 saniye.
-
Web. Tek kaynak değişikliği için ~30 saniye, bağımlılık yükseltmesi için ~90 saniye.
Bunu işe yarar hale getiren CI önbellek stratejisi:
-
Önbellek
pnpm storetam lockfile karması üzerinde anahtarlanır. Herhangi bir paketteki değişiklik önbellek anahtarını yükseltir, ancak ilgisiz değişiklikler önbelleği isabetler. -
Önbellek
node_modulesuygulama başına lockfile artı çalışma alanı package.json üzerinde anahtarlanır. Aynı lockfile'a sahip iki uygulama, bağımlılık ağacı izin verdiğinde node_modules'u paylaşır.
CI komut zaman aşımını uzatma
appleboy/ssh-action varsayılan komut zaman aşımı 10 dakikadır. Taze lockfile ile arka uç soğuk derlemesi yavaş bir koşucuda ~10 dakika sürer ve bu tam başarısızlık eşiğindedir. Bir Docker build içeren herhangi bir dağıtım adımı için zaman aşımını 30 dakikaya çıkarın. 9 dakika 50 saniyede zaman aşımına uğrayan dağıtım betiği, 23:00'te hata ayıklamak zorunda olduğunuz dağıtım betiğidir.
