Laravel Zero Kesinti Süresi Dağıtımı

Yayınlanan: 2022-03-11

Canlı bir uygulamayı güncellemek söz konusu olduğunda, bununla ilgili temelde iki farklı yol vardır.

İlk yaklaşımda, sistemimizin durumunda artımlı değişiklikler yaparız. Örneğin, dosyaları günceller, ortam özelliklerini değiştirir, ek gereksinimler yükleriz vb. İkinci yaklaşımda, tüm makineleri yıkıyor ve sistemi yeni görüntüler ve bildirime dayalı yapılandırmalarla (örneğin, Kubernetes kullanarak) yeniden oluşturuyoruz.

Laravel Dağıtımı Kolaylaştı

Bu makale esas olarak bulutta barındırılamayan nispeten küçük uygulamaları kapsar, ancak Kubernetes'in “bulutsuz” senaryonun ötesindeki dağıtımlarda bize nasıl büyük ölçüde yardımcı olabileceğinden bahsedeceğim. Ayrıca, yalnızca Laravel dağıtımıyla değil, bir dizi farklı durumda geçerli olabilecek başarılı güncellemeler gerçekleştirmeye yönelik bazı genel sorunları ve ipuçlarını da tartışacağız.

Bu gösterimin amaçları için, bir Laravel örneği kullanacağım, ancak herhangi bir PHP uygulamasının benzer bir yaklaşımı kullanabileceğini unutmayın.

sürüm oluşturma

Yeni başlayanlar için, şu anda üretimde dağıtılan kod sürümünü bilmemiz çok önemlidir. Bazı dosyalara veya en azından bir klasör veya dosya adına dahil edilebilir. Adlandırmaya gelince, semantik versiyonlamanın standart uygulamasını takip edersek, ona tek bir sayıdan daha fazla bilgi ekleyebiliriz.

İki farklı yayına baktığımızda, bu eklenen bilgiler, aralarında yapılan değişikliklerin doğasını kolayca anlamamıza yardımcı olabilir.

Anlamsal sürüm oluşturmanın açıklamasını gösteren resim.

Sürümün sürümlendirilmesi Git gibi bir sürüm kontrol sistemi ile başlar. Diyelim ki dağıtım için bir sürüm hazırladık, örneğin 1.0.3 sürümü. Bu sürümleri ve kod akışlarını düzenlemeye gelince, ekibinizin tercihlerine ve projenizin özelliklerine göre seçebileceğiniz veya karıştırabileceğiniz ana hat tabanlı geliştirme ve Git akışı gibi farklı geliştirme stilleri vardır. Sonunda, büyük olasılıkla, ana şubemizde uygun şekilde etiketlenmiş yayınlarımızla sonuçlanacağız.

Taahhütten sonra şöyle basit bir etiket oluşturabiliriz:

git tag v1.0.3

Ardından, push komutunu yürütürken etiketleri ekliyoruz:

git push <origin> <branch> --tags

Karmalarını kullanarak eski taahhütlere etiketler de ekleyebiliriz.

Yayın Dosyalarını Hedeflerine Alma

Laravel dağıtımı, yalnızca dosyaları kopyalamak olsa bile zaman alır. Ancak çok uzun sürmese de hedefimiz sıfır kesinti süresine ulaşmaktır .

Bu nedenle, güncellemeyi yerinde yüklemekten kaçınmalı ve canlı olarak sunulan dosyaları değiştirmemeliyiz. Bunun yerine, başka bir dizine konuşlandırmalı ve yalnızca kurulum tamamen hazır olduğunda geçiş yapmalıyız.

Aslında, Envoyer.io (Laravel.com tasarımcısı Jack McDade tarafından), Capistrano, Deployer, vb. gibi dağıtımlarda bize yardımcı olabilecek çeşitli araçlar ve hizmetler var. Bunların hepsini henüz üretimde kullanmadım, bu yüzden yapamam önerilerde bulunun veya kapsamlı bir karşılaştırma yazın, ancak bu ürünlerin arkasındaki fikri göstermeme izin verin. Bazıları (veya tümü) gereksinimlerinizi karşılayamazsa, süreci en uygun şekilde otomatikleştirmek için her zaman özel komut dosyalarınızı oluşturabilirsiniz.

Bu gösterimin amaçları doğrultusunda, diyelim ki Laravel uygulamamıza aşağıdaki yoldan bir Nginx sunucusu tarafından hizmet veriliyor:

/var/www/demo/public

İlk olarak, her dağıtım yaptığımızda yayın dosyalarını yerleştirmek için bir dizine ihtiyacımız var. Ayrıca, mevcut çalışan sürüme işaret edecek bir sembolik bağlantıya ihtiyacımız var. Bu durumda, /var/www/demo sembolik bağlantımız olarak hizmet edecektir. İşaretçiyi yeniden atamak, sürümleri hızla değiştirmemize olanak tanır.

Laravel Dağıtım dosyası işleme

Bir Apache sunucusuyla uğraşıyorsak, konfigürasyonda aşağıdaki sembolik bağlantılara izin vermemiz gerekebilir:

Options +FollowSymLinks

Yapımız şöyle bir şey olabilir:

 /opt/demo/release/v0.1.0 /opt/demo/release/v0.1.1 /opt/demo/release/v0.1.2

Farklı dağıtımlar yoluyla devam etmemiz gereken bazı dosyalar olabilir, örneğin günlük dosyaları (tabii ki Logstash kullanmıyorsak). Laravel dağıtımı durumunda, depolama dizinini ve .env yapılandırma dosyasını tutmak isteyebiliriz. Bunları diğer dosyalardan ayrı tutabilir ve bunun yerine sembolik bağlantılarını kullanabiliriz.

Sürüm dosyalarımızı Git deposundan almak için klonlama veya arşivleme komutlarını kullanabiliriz. Bazı insanlar git klonunu kullanır, ancak belirli bir işlemi veya etiketi klonlayamazsınız. Bu, tüm havuzun getirildiği ve ardından belirli etiketin seçildiği anlamına gelir. Bir havuz çok sayıda dal veya büyük bir geçmiş içerdiğinde, boyutu yayın arşivinden oldukça büyüktür. Bu nedenle, üretimde özellikle git deposuna ihtiyacınız yoksa, git archive kullanabilirsiniz. Bu, belirli bir etikete göre yalnızca bir dosya arşivi almamızı sağlar. İkincisini kullanmanın bir başka avantajı da, örneğin testler gibi üretim ortamında olmaması gereken bazı dosya ve klasörleri yok sayabilmemizdir. Bunun için .gitattributes file export-ignore özelliğini ayarlamamız yeterli. OWASP Güvenli Kodlama Uygulamaları Kontrol Listesinde şu öneriyi bulabilirsiniz: "Dağıtımdan önce test kodunu veya üretime yönelik olmayan herhangi bir işlevi kaldırın."

Sürümü kaynak sürüm kontrol sisteminden alıyorsak, git arşivi ve dışa aktarma-yoklama bu gereksinimde bize yardımcı olabilir.

Basitleştirilmiş bir komut dosyasına bir göz atalım (üretimde daha iyi hata işlemeye ihtiyaç duyacaktır):

konuşlandırma.sh

 #!/bin/bash # Terminate execution if any command fails set -e # Get tag from a script argument TAG=$1 GIT_REMOTE_URL='here should be a remote url of the repo' BASE_DIR=/opt/demo # Create folder structure for releases if necessary RELEASE_DIR=$BASE_DIR/releases/$TAG mkdir -p $RELEASE_DIR mkdir -p $BASE_DIR/storage cd $RELEASE_DIR # Fetch the release files from git as a tar archive and unzip git archive \ --remote=$GIT_REMOTE_URL \ --format=tar \ $TAG \ | tar xf - # Install laravel dependencies with composer composer install -o --no-interaction --no-dev # Create symlinks to `storage` and `.env` ln -sf $BASE_DIR/.env ./ rm -rf storage && ln -sf $BASE_DIR/storage ./ # Run database migrations php artisan migrate --no-interaction --force # Run optimization commands for laravel php artisan optimize php artisan cache:clear php artisan route:cache php artisan view:clear php artisan config:cache # Remove existing directory or symlink for the release and create a new one. NGINX_DIR=/var/www/public mkdir -p $NGINX_DIR rm -f $NGINX_DIR/demo ln -sf $RELEASE_DIR $NGINX_DIR/demo

Sürümümüzü dağıtmak için aşağıdakileri yürütebiliriz:

deploy.sh v1.0.3

Not: Bu örnekte v1.0.3, sürümümüzün git etiketidir.

Prodüksiyon üzerine Besteci?

Komut dosyasının bağımlılıkları yüklemek için Composer'ı çağırdığını fark etmiş olabilirsiniz. Bunu birçok makalede görseniz de, bu yaklaşımla ilgili bazı sorunlar olabilir. Genel olarak, bir uygulamanın eksiksiz bir derlemesini oluşturmak ve bu derlemeyi altyapınızın çeşitli test ortamlarında ilerletmek en iyi uygulamadır. Sonunda, üretime güvenle dağıtılabilecek, baştan sona test edilmiş bir yapıya sahip olursunuz. Her derleme sıfırdan yeniden üretilebilir olsa da, bu, uygulamayı farklı aşamalarda yeniden oluşturmamız gerektiği anlamına gelmez. Besteci kurulumunu üretime yaptığımızda, bu gerçekten test edilen yapı ile aynı değildir ve işte yanlış gidebilecek şey:

  • Ağ hatası, indirme bağımlılıklarını kesintiye uğratabilir.
  • Kitaplık satıcısı her zaman SemVer'i takip etmeyebilir.

Bir ağ hatası kolayca fark edilebilir. Komut dosyamız bir hatayla çalışmayı bile durduracaktı. Ancak, üretimde yapamayacağınız testleri çalıştırmadan bir kitaplıktaki bir kırılma değişikliğini tespit etmek çok zor olabilir. Bağımlılıkları kurarken Composer, npm ve diğer benzer araçlar anlamsal sürüm oluşturma-major.minor.patch'e güvenir. Composer.json'da ~1.0.2 görüyorsanız, 1.0.2 sürümünü veya 1.0.4 gibi en son yama sürümünü yüklediğiniz anlamına gelir. ^1.0.2 görürseniz, 1.0.2 sürümünü veya 1.1.0 gibi en son küçük veya yama sürümünü yüklediğiniz anlamına gelir. Herhangi bir önemli değişiklik yapıldığında, kütüphane satıcısının ana sayıyı artıracağına güveniyoruz, ancak bazen bu gereklilik gözden kaçıyor veya takip edilmiyor. Geçmişte böyle vakalar oldu. Composer.json'ınıza sabit sürümler koysanız bile, bağımlılıklarınızın composer.json'larında ~ ve ^ olabilir.

Erişilebilirse, bence daha iyi bir yol, bir yapı deposu (Nexus, JFrog, vb.) kullanmak olacaktır. Gerekli tüm bağımlılıkları içeren sürüm derlemesi, başlangıçta bir kez oluşturulur. Bu eser bir depoda saklanacak ve oradan çeşitli test aşamaları için getirilecekti. Ayrıca bu, uygulamayı Git'ten yeniden oluşturmak yerine üretime dağıtılacak yapı olacaktır.

Kod ve Veritabanı Uyumlu Tutma

Laravel'e ilk görüşte aşık olmamın nedeni, yazarının ayrıntılara çok dikkat etmesi, geliştiricilerin kolaylığını düşünmesi ve ayrıca veritabanı geçişleri gibi birçok en iyi uygulamayı çerçeveye dahil etmesiydi.

Veritabanı geçişleri, veritabanımızı ve kodumuzu senkronize etmemizi sağlar. Değişikliklerinin her ikisi de tek bir işleme, dolayısıyla tek bir sürüme dahil edilebilir. Ancak bu, herhangi bir değişikliğin kesinti olmadan dağıtılabileceği anlamına gelmez. Dağıtım sırasında bir noktada, uygulamanın ve çalışan veritabanının farklı sürümleri olacaktır. Sorun olması durumunda bu nokta bir döneme bile dönüşebilir. Her zaman her ikisini de arkadaşlarının önceki sürümleriyle uyumlu hale getirmeye çalışmalıyız: eski veritabanı – yeni uygulama, yeni veritabanı – eski uygulama.

Örneğin, bir address address2 address1 address2 olarak ayırmamız gerektiğini varsayalım. Her şeyi uyumlu tutmak için birkaç sürüme ihtiyacımız olabilir.

  1. Veritabanına iki yeni sütun ekleyin.
  2. Mümkün olduğunda yeni alanları kullanmak için uygulamayı değiştirin.
  3. address verilerini yeni sütunlara taşıyın ve bırakın.

Bu durum aynı zamanda küçük değişikliklerin dağıtım için ne kadar daha iyi olduğuna dair iyi bir örnektir. Onların geri dönüşü de daha kolaydır. Kod tabanını ve veritabanını birkaç hafta veya ay boyunca değiştiriyorsak, üretim sistemini kesinti olmadan güncellemek imkansız olabilir.

Kubernetes'in Bazı Harikalıkları

Uygulamamızın ölçeği bulutlara, düğümlere ve Kubernetes'e ihtiyaç duymasa da, yine de K8'lerde dağıtımların nasıl göründüğünden bahsetmek istiyorum. Bu durumda, sistemde değişiklik yapmıyoruz, bunun yerine neyi başarmak istediğimizi ve kaç kopya üzerinde çalışması gerektiğini beyan ediyoruz. Ardından Kubernetes, gerçek durumun istenen durumla eşleştiğinden emin olur.

Ne zaman yeni bir sürüm hazırsa, içinde yeni dosyalar olan bir resim oluşturuyoruz, resmi yeni sürümle etiketliyoruz ve K8s'e aktarıyoruz. İkincisi, imajımızı bir küme içinde hızla döndürecektir. Sağladığımız hazırlık kontrolüne bağlı olarak uygulama hazır olmadan önce bekleyecek, ardından trafiği fark edilmeden yeni uygulamaya yönlendirecek ve eskisini öldürecek. Sadece birkaç komutla mavi/yeşil veya kanarya dağıtımları gerçekleştirmemize izin verecek olan uygulamamızın birkaç sürümünü çok kolay bir şekilde çalıştırabiliriz.

İlgileniyorsanız, "Burr Sutter'ın Kubernetes ile Harika Olmanın 9 Adımı" konuşmasında bazı etkileyici gösteriler var.

İlgili: Tam Kullanıcı Kimlik Doğrulaması ve Erişim Kontrolü – Bir Laravel Pasaport Eğitimi, Pt. 1