Komut dosyalarından kendi platformumuza: CIAN'da geliştirmeyi nasıl otomatikleştirdik

Komut dosyalarından kendi platformumuza: CIAN'da geliştirmeyi nasıl otomatikleştirdik

RIT 2019'da meslektaşımız Alexander Korotkov şunları yaptı: rapor CIAN'da geliştirme otomasyonu hakkında: yaşamı ve çalışmayı kolaylaştırmak için kendi Integro platformumuzu kullanıyoruz. Görevlerin yaşam döngüsünü izler, geliştiricileri rutin operasyonlardan kurtarır ve üretimdeki hata sayısını önemli ölçüde azaltır. Bu yazıda Alexander'ın raporunu tamamlayacağız ve size basit komut dosyalarından açık kaynaklı ürünleri kendi platformumuz aracılığıyla birleştirmeye nasıl geçtiğimizi ve ayrı otomasyon ekibimizin neler yaptığını anlatacağız.
 

sıfır seviye

“Sıfır seviye diye bir şey yok, öyle bir şey bilmiyorum”
"Kung Fu Panda" filminden Usta Şifu

CIAN'da otomasyon, şirketin kurulmasından 14 yıl sonra başladı. O zamanlar geliştirme ekibinde 35 kişi vardı. İnanması zor, değil mi? Elbette otomasyon bir şekilde mevcuttu ancak sürekli entegrasyon ve kod dağıtımı için ayrı bir yön 2015 yılında şekillenmeye başladı. 

O zamanlar, Python, C# ve PHP'den oluşan devasa bir monolit uygulamamız vardı ve bu uygulama platformunda birçok farklı kod türü kullanıyorduk. Linux/Windows Sunucular. Bu canavarı dağıtmak için, manuel olarak çalıştırdığımız bir dizi komut dosyamız vardı. Ayrıca, dalları birleştirirken, hataları düzeltirken ve "derlemede farklı bir görev kümesiyle" yeniden derlerken ortaya çıkan çakışmalar nedeniyle acı ve sıkıntıya neden olan monolit derleme de vardı. Basitçe ifade etmek gerekirse, süreç şöyleydi:

Komut dosyalarından kendi platformumuza: CIAN'da geliştirmeyi nasıl otomatikleştirdik

Bu durumdan memnun değildik ve tekrarlanabilir, otomatikleştirilmiş ve yönetilebilir bir oluşturma ve dağıtım süreci oluşturmak istedik. Bunun için bir CI/CD sistemine ihtiyacımız vardı ve Teamcity'nin ücretsiz sürümü ile Jenkins'in ücretsiz sürümü arasında seçim yaptık çünkü onlarla çalışıyorduk ve her ikisi de işlev kümesi açısından bize uygundu. Biz daha güncel bir ürün olarak Teamcity'yi seçtik. O zamanlar henüz mikro hizmet mimarisini kullanmamıştık ve çok sayıda görev ve proje beklemiyorduk.

Kendi sistemimiz fikrine geliyoruz

Teamcity'nin uygulanması, manuel çalışmanın yalnızca bir kısmını ortadan kaldırdı: Geriye, Çekme İsteklerinin oluşturulması, sorunların Jira'da duruma göre tanıtılması ve yayınlanacak sorunların seçilmesi kaldı. Teamcity sistemi artık bununla baş edemiyordu. Daha fazla otomasyon yolunu seçmek gerekliydi. Teamcity'de komut dosyalarıyla çalışma veya üçüncü taraf otomasyon sistemlerine geçme seçeneklerini değerlendirdik. Ancak sonunda, yalnızca kendi çözümümüzün sağlayabileceği maksimum esnekliğe ihtiyacımız olduğuna karar verdik. Integro adı verilen iç otomasyon sisteminin ilk versiyonu böyle ortaya çıktı.

Teamcity, oluşturma ve dağıtım süreçlerinin başlatılması düzeyinde otomasyonla ilgilenirken Integro, geliştirme süreçlerinin üst düzey otomasyonuna odaklandı. Jira'daki sorunlarla ilgili çalışmayı Bitbucket'te ilgili kaynak kodunun işlenmesiyle birleştirmek gerekliydi. Bu aşamada Integro, farklı türdeki görevlerle çalışmak için kendi iş akışlarına sahip olmaya başladı. 

İş süreçlerinde otomasyonun artması nedeniyle Teamcity'deki proje ve çalıştırma sayısı arttı. Böylece yeni bir sorun ortaya çıktı: Bir ücretsiz Teamcity örneği yeterli değildi (3 temsilci ve 100 proje), başka bir örnek ekledik (3 temsilci ve 100 proje daha), sonra bir tane daha. Sonuç olarak, yönetilmesi zor olan birkaç kümeden oluşan bir sistem elde ettik:

Komut dosyalarından kendi platformumuza: CIAN'da geliştirmeyi nasıl otomatikleştirdik

4. örnek sorunu ortaya çıktığında bu şekilde yaşamaya devam edemeyeceğimizi anladık çünkü 4 örneği desteklemenin toplam maliyeti artık herhangi bir sınır dahilinde değildi. Ücretli Teamcity satın alma veya ücretsiz Jenkins'i seçme sorusu ortaya çıktı. Örnekler ve otomasyon planları üzerinde hesaplamalar yaptık ve Jenkins'te yaşamaya karar verdik. Birkaç hafta sonra Jenkins'e geçtik ve birden fazla Teamcity örneğini sürdürmenin yarattığı baş ağrısının bir kısmını ortadan kaldırdık. Bu nedenle Integro'yu geliştirmeye ve Jenkins'i kendimize göre özelleştirmeye odaklanabildik.

Temel otomasyonun büyümesiyle birlikte (Çekme İsteklerinin otomatik olarak oluşturulması, Kod kapsamının toplanması ve yayınlanması ve diğer kontroller şeklinde), manuel sürümlerden mümkün olduğunca vazgeçilmesi ve bu işin robotlara verilmesi yönünde güçlü bir istek vardır. Ayrıca şirket, sık sık sürüm gerektiren ve birbirinden ayrı mikro hizmetlere şirket içinde geçiş yapmaya başladı. Mikro hizmetlerimizin otomatik olarak yayınlanmasına bu şekilde yavaş yavaş ulaştık (sürecin karmaşıklığı nedeniyle şu anda monoliti manuel olarak yayınlıyoruz). Ancak her zaman olduğu gibi yeni bir karmaşıklık ortaya çıktı. 

Testleri otomatikleştiriyoruz

Komut dosyalarından kendi platformumuza: CIAN'da geliştirmeyi nasıl otomatikleştirdik

Sürümlerin otomasyonu nedeniyle, kısmen bazı test aşamalarının atlanması nedeniyle geliştirme süreçleri hızlandı. Bu da geçici bir kalite kaybına yol açtı. Önemsiz gibi görünüyor, ancak sürümlerin hızlanmasıyla birlikte ürün geliştirme metodolojisini değiştirmek gerekliydi. Testin otomasyonu, geliştiricinin yayınlanan kod ve içindeki hatalar için kişisel sorumluluğunu aşılamak (burada para cezalarından değil, "kafadaki fikri kabul etmekten" bahsediyoruz) ve ayrıca karar verme kararı hakkında düşünmek gerekiyordu. otomatik dağıtım yoluyla bir görevi serbest bırakın/serbest bırakmayın. 

Kalite sorunlarını ortadan kaldırarak iki önemli karara vardık: Kanarya testi yapmaya başladık ve hata arka planının otomatik olarak izlenmesini ve fazlalığına otomatik yanıt verilmesini uygulamaya koyduk. İlk çözüm, kodun tamamen üretime sunulmasından önce bariz hataların bulunmasını mümkün kıldı, ikincisi ise üretimdeki sorunlara yanıt verme süresini kısalttı. Elbette hatalar olur, ancak zamanımızın ve çabamızın çoğunu onları düzeltmek için değil, en aza indirmek için harcıyoruz. 

Otomasyon Ekibi

Şu anda 130 kişilik geliştirici kadromuz var ve çalışmalarımıza devam ediyoruz. büyümek. Sürekli entegrasyon ve kod teslimi ekibi (bundan sonra Dağıtım ve Entegrasyon veya DI ekibi olarak anılacaktır) 7 kişiden oluşur ve 2 yönde çalışır: Integro otomasyon platformunun ve DevOps'un geliştirilmesi. 

DevOps, CIAN sitesinin Dev/Beta ortamından, Integro ortamından sorumludur, geliştiricilerin sorunları çözmesine yardımcı olur ve ortamları ölçeklendirmeye yönelik yeni yaklaşımlar geliştirir. Integro geliştirme yönü, hem Integro'nun kendisi hem de Jenkins, Jira, Confluence eklentileri gibi ilgili hizmetlerle ilgilenir ve ayrıca geliştirme ekipleri için yardımcı araçlar ve uygulamalar geliştirir. 

DI ekibi, mimariyi, kitaplıkları ve geliştirme yaklaşımlarını şirket içinde geliştiren Platform ekibiyle işbirliği içinde çalışır. Aynı zamanda, CIAN içindeki herhangi bir geliştirici otomasyona katkıda bulunabilir, örneğin ekibin ihtiyaçlarına uygun mikro otomasyon yapabilir veya otomasyonun nasıl daha iyi hale getirilebileceğine dair harika bir fikir paylaşabilir.

CIAN'da otomasyonun katman katmanı

Komut dosyalarından kendi platformumuza: CIAN'da geliştirmeyi nasıl otomatikleştirdik

Otomasyona dahil olan tüm sistemler birkaç katmana ayrılabilir:

  1. Harici sistemler (Jira, Bitbucket vb.). Geliştirme ekipleri onlarla çalışır.
  2. Integro platformu. Çoğu zaman geliştiriciler doğrudan onunla çalışmazlar, ancak tüm otomasyonun çalışmasını sağlayan şey budur.
  3. Teslimat, orkestrasyon ve keşif hizmetleri (örneğin, Jeknins, Consul, Nomad). Onların yardımıyla kodu sunuculara dağıtıyoruz ve hizmetlerin birbirleriyle çalışmasını sağlıyoruz.
  4. Fiziksel katman (sunucular, işletim sistemi, ilgili yazılım). Kodumuz bu seviyede çalışır. Bu, fiziksel bir sunucu veya sanal bir sunucu (LXC, KVM, Docker) olabilir.

Bu konsepte dayanarak DI ekibinin sorumluluk alanlarını paylaştırıyoruz. İlk iki seviye Integro geliştirme yönünün sorumluluk alanındadır ve son iki seviye halihazırda DevOps'un sorumluluk alanındadır. Bu ayrılık, birbirimize yakın olduğumuz ve sürekli bilgi ve deneyim alışverişinde bulunduğumuz için, görevlere odaklanmamızı sağlar ve etkileşimi engellemez.

Bozulmamış

Integro'ya odaklanalım ve teknoloji yığınıyla başlayalım:

  • CentOs 7
  • Docker + Nomad + Konsolos + Vault
  • Java 11 (eski Integro monoliti Java 8'de kalacak)
  • Spring Boot 2.X + Spring Cloud Yapılandırması
  • PostgreSQL 11
  • RabbitMQ 
  • apache tutuşturmak
  • Camunda (gömülü)
  • Grafana + Grafit + Prometheus + Jaeger + ELK
  • Web Kullanıcı Arayüzü: React (CSR) + MobX
  • TOA: Anahtarlık

Integro'nun ilk versiyonunun yekpare bir mirasına sahip olmamıza rağmen, mikro hizmet geliştirme ilkesine bağlı kalıyoruz. Her mikro hizmet kendi Docker kapsayıcısında çalışır ve hizmetler birbirleriyle HTTP istekleri ve RabbitMQ mesajları aracılığıyla iletişim kurar. Mikro hizmetler birbirlerini Consul aracılığıyla bulur ve SSO (Keycloak, OAuth 2/OpenID Connect) aracılığıyla yetkilendirmeyi geçerek ona bir istekte bulunur.

Komut dosyalarından kendi platformumuza: CIAN'da geliştirmeyi nasıl otomatikleştirdik

Gerçek hayattan bir örnek olarak, aşağıdaki adımlardan oluşan Jenkins ile etkileşimi düşünün:

  1. İş akışı yönetimi mikro hizmeti (bundan sonra Flow mikro hizmeti olarak anılacaktır) Jenkins'te bir yapı çalıştırmak istiyor. Bunu yapmak için, Jenkins ile entegrasyon için mikro hizmetin (bundan sonra Jenkins mikro hizmeti olarak anılacaktır) IP:PORT'unu bulmak için Consul'u kullanır ve derlemeyi Jenkins'te başlatmak için ona eşzamansız bir istek gönderir.
  2. Bir istek aldıktan sonra, Jenkins mikro hizmeti bir İş Kimliği oluşturur ve ona yanıt verir; bu daha sonra işin sonucunu tanımlamak için kullanılabilir. Aynı zamanda REST API çağrısı yoluyla Jenkins'teki derlemeyi tetikler.
  3. Jenkins derlemeyi gerçekleştirir ve tamamlandıktan sonra yürütme sonuçlarını içeren bir web kancasını Jenkins mikro hizmetine gönderir.
  4. Web kancasını alan Jenkins mikro hizmeti, istek işlemenin tamamlandığına dair bir mesaj oluşturur ve yürütme sonuçlarını buna ekler. Oluşturulan mesaj RabbitMQ sırasına gönderilir.
  5. RabbitMQ aracılığıyla yayınlanan mesaj, istekteki İş Kimliğini ve alınan mesajla eşleştirerek görevinin işlenmesinin sonucunu öğrenen Flow mikro hizmetine ulaşır.

Artık birkaç gruba ayrılabilecek yaklaşık 30 mikro hizmetimiz var:

  1. Konfigürasyon yönetimi.
  2. Kullanıcılarla bilgi ve etkileşim (mesajcılar, posta).
  3. Kaynak koduyla çalışma.
  4. Dağıtım araçlarıyla entegrasyon (jenkins, nomad, consul vb.).
  5. İzleme (yayınlar, hatalar vb.).
  6. Web yardımcı programları (test ortamlarını yönetmek, istatistik toplamak vb. için kullanıcı arayüzü).
  7. Görev takipçileri ve benzeri sistemlerle entegrasyon.
  8. Farklı görevler için iş akışı yönetimi.

İş akışı görevleri

Integro, görev yaşam döngüsüyle ilgili etkinlikleri otomatikleştirir. Basitleştirilmiş bir ifadeyle Jira'da bir görevin yaşam döngüsü, bir görevin iş akışı olarak anlaşılacaktır. Geliştirme süreçlerimiz projeye, görev türüne ve belirli bir görevde seçilen seçeneklere bağlı olarak çeşitli iş akışı varyasyonlarına sahiptir. 

En sık kullandığımız iş akışına bakalım:

Komut dosyalarından kendi platformumuza: CIAN'da geliştirmeyi nasıl otomatikleştirdik

Diyagramda dişli, geçişin Integro tarafından otomatik olarak çağrıldığını, insan figürü ise geçişin bir kişi tarafından manuel olarak çağrıldığını göstermektedir. Bu iş akışında bir görevin izleyebileceği çeşitli yola bakalım.

DEV+BETA'da kanarya testleri olmadan tamamen manuel test (genellikle bir monoliti bu şekilde yayınlıyoruz):

Komut dosyalarından kendi platformumuza: CIAN'da geliştirmeyi nasıl otomatikleştirdik

Başka geçiş kombinasyonları da olabilir. Bazen bir konunun izleyeceği yol Jira'daki seçenekler aracılığıyla seçilebilmektedir.

Görev hareketi

Bir görev "DEV Testing + Canary Tests" iş akışında ilerlerken gerçekleştirilen ana adımlara bakalım:

1. Geliştirici veya Proje Yöneticisi görevi oluşturur.

2. Geliştirici görevi işe alır. Tamamlandıktan sonra İNCELEMEDE durumuna geçer.

3. Jira, Jira mikro hizmetine (Jira ile entegrasyondan sorumlu) bir Webhook gönderir.

4. Jira mikro hizmeti, iş akışını başlatmak için Flow hizmetine (işin gerçekleştirildiği dahili iş akışlarından sorumludur) bir istek gönderir.

5. Flow hizmetinin içinde:

  • Gözden geçirenler göreve atanır (Kullanıcılar hakkında her şeyi bilen kullanıcı mikro hizmeti + Jira mikro hizmeti).
  • Kaynak mikro hizmeti aracılığıyla (depolar ve dallar hakkında bilgi sahibidir ancak kodun kendisi ile çalışmaz), sayımızın bir dalını içeren depolar için bir arama yapılır (aramayı basitleştirmek için, dalın adı sayıyla örtüşür) Jira'daki numara). Çoğu zaman, bir görevin tek bir depoda yalnızca bir dalı bulunur; bu, dağıtım kuyruğunun yönetimini basitleştirir ve depolar arasındaki bağlantıyı azaltır.
  • Bulunan her dal için aşağıdaki eylem dizisi gerçekleştirilir:

    i) Ana dalın güncellenmesi (kodla çalışmak için Git mikro hizmeti).
    ii) Dalın geliştirici tarafından değişiklik yapması engellendi (Bitbucket mikro hizmeti).
    iii) Bu dal için bir Çekme İsteği oluşturulur (Bitbucket mikro hizmeti).
    iv) Geliştirici sohbetlerine yeni bir Çekme İsteği hakkında bir mesaj gönderilir (Bildirimlerle çalışmak için mikro hizmete bildirimde bulunun).
    v) DEV'de (Jenkins ile çalışmaya yönelik Jenkins mikro hizmeti) oluşturma, test etme ve dağıtma görevleri başlatılır.
    vi) Önceki adımların tümü başarıyla tamamlanırsa Integro Onayını Çekme İsteğine (Bitbucket mikro hizmeti) koyar.

  • Integro, belirlenmiş incelemecilerden Çekme Talebinde Onay bekliyor.
  • Gerekli tüm onaylar alınır alınmaz (olumlu geçen otomatik testler dahil) Integro, görevi Test on Dev (Jira microservice) durumuna aktarır.

6. Test uzmanları görevi test eder. Herhangi bir sorun yoksa görev, Oluşturmaya Hazır durumuna aktarılır.

7. Integro, görevin yayınlanmaya hazır olduğunu "görür" ve kanarya modunda (Jenkins mikro hizmeti) dağıtımına başlar. Serbest bırakılmaya hazır olma durumu bir dizi kuralla belirlenir. Örneğin, görev gerekli durumda, diğer görevlerde kilit yok, bu mikro hizmetin şu anda etkin yüklemesi yok vb.

8. Görev Canary durumuna (Jira mikro hizmeti) aktarılır.

9. Jenkins, Nomad aracılığıyla kanarya modunda (genellikle 1-3 örnek) bir dağıtım görevi başlatır ve dağıtım izleme hizmetini (DeployWatch mikro hizmeti) dağıtım hakkında bilgilendirir.

10. DeployWatch mikro hizmeti hata arka planını toplar ve gerekirse buna tepki verir. Hata arka planı aşılırsa (arka plan normu otomatik olarak hesaplanır), geliştiricilere Bildir mikro hizmeti aracılığıyla bilgi verilir. Geliştirici 5 dakika sonra yanıt vermezse (Geri Al veya Kal'a tıkladıysa), canary örneklerinin otomatik olarak geri alınması başlatılır. Arka plan aşılmazsa geliştiricinin, görev dağıtımını Üretim'e manuel olarak başlatması gerekir (kullanıcı arayüzündeki bir düğmeye tıklayarak). Geliştirici 60 dakika içinde dağıtımı Üretim'e başlatmazsa güvenlik nedeniyle canary örnekleri de geri alınacaktır.

11. Üretime dağıtımı başlattıktan sonra:

  • Görev, Üretim durumuna (Jira mikro hizmeti) aktarılır.
  • Jenkins mikro hizmeti dağıtım sürecini başlatır ve DeployWatch mikro hizmetine dağıtım hakkında bilgi verir.
  • DeployWatch mikro hizmeti, Üretimdeki tüm kapsayıcıların güncellenip güncellenmediğini kontrol eder (tümünün güncellenmediği durumlar da vardı).
  • Bildir mikro hizmeti aracılığıyla, dağıtımın sonuçlarına ilişkin bir bildirim Üretim'e gönderilir.

12. Yanlış mikro hizmet davranışı tespit edilirse geliştiricilerin, bir görevi Üretimden geri almaya başlamak için 30 dakikaları olacaktır. Bu sürenin sonunda görev otomatik olarak ana (Git mikro hizmeti) ile birleştirilecektir.

13. Ana öğeyle başarılı bir şekilde birleştirme sonrasında görev durumu Kapalı (Jira mikro hizmeti) olarak değiştirilecektir.

Diyagram tamamen ayrıntılı gibi görünmüyor (gerçekte daha da fazla adım var), ancak süreçlere entegrasyon derecesini değerlendirmenize olanak tanıyor. Bu planın ideal olduğunu düşünmüyoruz ve otomatik sürüm ve dağıtım desteği süreçlerini iyileştiriyoruz.

sonra ne

Otomasyonun geliştirilmesine yönelik büyük planlarımız var; örneğin monolit sürümler sırasında manuel işlemleri ortadan kaldırmak, otomatik dağıtım sırasında izlemeyi iyileştirmek ve geliştiricilerle etkileşimi geliştirmek.

Ama şimdilik burada duralım. Otomasyon incelemesinde birçok konuyu yüzeysel olarak ele aldık, bazılarına hiç değinmedik, bu nedenle soruları yanıtlamaktan memnuniyet duyarız. Neleri detaylı ele alacağımız konusunda önerilerinizi bekliyoruz, yorumlara yazın.

Kaynak: habr.com

DDoS korumalı siteler, VPS VDS sunucuları için güvenilir hosting satın alın 🔥 DDoS korumalı, güvenilir VPS ve VDS sunucu barındırma hizmeti satın alın | ProHoster