Daripada skrip ke platform kami sendiri: cara kami mengautomasikan pembangunan di CIAN

Daripada skrip ke platform kami sendiri: cara kami mengautomasikan pembangunan di CIAN

Di RIT 2019, rakan sekerja kami Alexander Korotkov membuat lapor tentang automasi pembangunan di CIAN: untuk memudahkan kehidupan dan kerja, kami menggunakan platform Integro kami sendiri. Ia menjejaki kitaran hayat tugas, melegakan pembangun daripada operasi rutin dan mengurangkan dengan ketara bilangan pepijat dalam pengeluaran. Dalam siaran ini, kami akan melengkapkan laporan Alexander dan memberitahu anda bagaimana kami beralih daripada skrip mudah kepada menggabungkan produk sumber terbuka melalui platform kami sendiri dan perkara yang dilakukan oleh pasukan automasi kami yang berasingan.
 

Tahap sifar

"Tiada perkara seperti tahap sifar, saya tidak tahu perkara itu"
Master Shifu dari filem "Kung Fu Panda"

Automasi di CIAN bermula 14 tahun selepas syarikat itu diasaskan. Pada masa itu terdapat 35 orang dalam pasukan pembangunan. Sukar untuk dipercayai, bukan? Sudah tentu, automasi memang wujud dalam beberapa bentuk, tetapi arah yang berasingan untuk penyepaduan berterusan dan penghantaran kod mula terbentuk pada tahun 2015. 

Pada masa itu, kami mempunyai monolit besar Python, C# dan PHP, digunakan pada pelayan Linux/Windows. Untuk menggunakan raksasa ini, kami mempunyai satu set skrip yang kami jalankan secara manual. Terdapat juga pemasangan monolit, yang membawa kesakitan dan penderitaan akibat konflik apabila menggabungkan cawangan, membetulkan kecacatan, dan membina semula "dengan set tugas yang berbeza dalam binaan." Proses yang dipermudahkan kelihatan seperti ini:

Daripada skrip ke platform kami sendiri: cara kami mengautomasikan pembangunan di CIAN

Kami tidak berpuas hati dengan ini dan kami mahu membina proses binaan dan penggunaan yang boleh diulang, automatik dan terurus. Untuk ini, kami memerlukan sistem CI/CD, dan kami memilih antara versi percuma Teamcity dan versi percuma Jenkins, kerana kami bekerja dengan mereka dan kedua-duanya sesuai dengan kami dari segi set fungsi. Kami memilih Teamcity sebagai produk yang lebih terkini. Pada masa itu, kami belum lagi menggunakan seni bina perkhidmatan mikro dan tidak menjangkakan sejumlah besar tugas dan projek.

Kami datang kepada idea sistem kami sendiri

Pelaksanaan Teamcity hanya mengalih keluar sebahagian daripada kerja manual: yang tinggal ialah penciptaan Permintaan Tarik, promosi isu mengikut status dalam Jira dan pemilihan isu untuk dikeluarkan. Sistem Teamcity tidak lagi dapat menangani perkara ini. Ia adalah perlu untuk memilih jalan automasi selanjutnya. Kami mempertimbangkan pilihan untuk bekerja dengan skrip dalam Teamcity atau beralih kepada sistem automasi pihak ketiga. Tetapi pada akhirnya kami memutuskan bahawa kami memerlukan fleksibiliti maksimum, yang hanya boleh diberikan oleh penyelesaian kami sendiri. Ini adalah bagaimana versi pertama sistem automasi dalaman yang dipanggil Integro muncul.

Teamcity berurusan dengan automasi pada tahap pelancaran proses binaan dan penggunaan, manakala Integro memfokuskan pada automasi peringkat atas proses pembangunan. Ia adalah perlu untuk menggabungkan kerja dengan isu dalam Jira dengan pemprosesan kod sumber yang berkaitan dalam Bitbucket. Pada peringkat ini, Integro mula mempunyai aliran kerja sendiri untuk bekerja dengan tugasan pelbagai jenis. 

Disebabkan peningkatan dalam automasi dalam proses perniagaan, bilangan projek dan larian dalam Teamcity telah meningkat. Jadi masalah baharu datang: satu contoh Teamcity percuma tidak mencukupi (3 ejen dan 100 projek), kami menambah satu lagi contoh (3 lagi ejen dan 100 projek), kemudian satu lagi. Akibatnya, kami berakhir dengan sistem beberapa kelompok, yang sukar untuk diurus:

Daripada skrip ke platform kami sendiri: cara kami mengautomasikan pembangunan di CIAN

Apabila persoalan tentang kejadian ke-4 timbul, kami menyedari bahawa kami tidak boleh terus hidup seperti ini, kerana jumlah kos untuk menyokong 4 kejadian tidak lagi dalam sebarang had. Timbul persoalan mengenai pembelian Teamcity berbayar atau memilih Jenkins percuma. Kami membuat pengiraan pada contoh dan rancangan automasi dan memutuskan bahawa kami akan hidup di Jenkins. Selepas beberapa minggu, kami beralih kepada Jenkins dan menghapuskan beberapa sakit kepala yang berkaitan dengan mengekalkan berbilang contoh Teamcity. Oleh itu, kami dapat menumpukan pada membangunkan Integro dan menyesuaikan Jenkins untuk diri kami sendiri.

Dengan pertumbuhan automasi asas (dalam bentuk penciptaan automatik Permintaan Tarik, pengumpulan dan penerbitan liputan Kod dan semakan lain), terdapat keinginan kuat untuk meninggalkan keluaran manual sebanyak mungkin dan memberikan kerja ini kepada robot. Di samping itu, syarikat itu mula beralih kepada perkhidmatan mikro dalam syarikat, yang memerlukan keluaran yang kerap, dan secara berasingan antara satu sama lain. Beginilah cara kami secara beransur-ansur mencapai keluaran automatik perkhidmatan mikro kami (kami sedang mengeluarkan monolit secara manual kerana kerumitan proses). Tetapi, seperti biasa berlaku, kerumitan baru timbul. 

Kami mengautomasikan ujian

Daripada skrip ke platform kami sendiri: cara kami mengautomasikan pembangunan di CIAN

Disebabkan oleh automasi keluaran, proses pembangunan telah dipercepatkan, sebahagiannya disebabkan oleh melangkau beberapa peringkat ujian. Dan ini membawa kepada kehilangan kualiti sementara. Kedengarannya remeh, tetapi seiring dengan pecutan keluaran, adalah perlu untuk menukar metodologi pembangunan produk. Adalah perlu untuk memikirkan tentang automasi ujian, menanamkan tanggungjawab peribadi (di sini kita bercakap tentang "menerima idea di kepala", bukan denda kewangan) pemaju untuk kod yang dikeluarkan dan pepijat di dalamnya, serta keputusan untuk melepaskan/tidak melepaskan tugas melalui penempatan automatik. 

Menghapuskan masalah kualiti, kami membuat dua keputusan penting: kami mula menjalankan ujian kenari dan memperkenalkan pemantauan automatik latar belakang ralat dengan tindak balas automatik terhadap lebihannya. Penyelesaian pertama memungkinkan untuk mencari ralat yang jelas sebelum kod dikeluarkan sepenuhnya ke dalam pengeluaran, yang kedua mengurangkan masa tindak balas kepada masalah dalam pengeluaran. Kesilapan, sudah tentu, berlaku, tetapi kita menghabiskan sebahagian besar masa dan usaha kita bukan untuk membetulkannya, tetapi untuk mengurangkannya. 

Pasukan Automasi

Pada masa ini kami mempunyai kakitangan sebanyak 130 pemaju, dan kami meneruskan untuk berkembang. Pasukan untuk penyepaduan berterusan dan penghantaran kod (selepas ini dirujuk sebagai pasukan Deploy and Integration atau DI) terdiri daripada 7 orang dan bekerja dalam 2 arah: pembangunan platform automasi Integro dan DevOps. 

DevOps bertanggungjawab untuk persekitaran Dev/Beta tapak CIAN, persekitaran Integro, membantu pembangun menyelesaikan masalah dan membangunkan pendekatan baharu untuk menskalakan persekitaran. Arah pembangunan Integro memperkatakan kedua-dua Integro sendiri dan perkhidmatan yang berkaitan, contohnya, pemalam untuk Jenkins, Jira, Confluence, dan juga membangunkan utiliti dan aplikasi tambahan untuk pasukan pembangunan. 

Pasukan DI bekerja secara kolaboratif dengan pasukan Platform, yang membangunkan seni bina, perpustakaan dan pendekatan pembangunan secara dalaman. Pada masa yang sama, mana-mana pembangun dalam CIAN boleh menyumbang kepada automasi, contohnya, membuat automasi mikro untuk memenuhi keperluan pasukan atau berkongsi idea hebat tentang cara menjadikan automasi lebih baik.

Kek lapis automasi di CIAN

Daripada skrip ke platform kami sendiri: cara kami mengautomasikan pembangunan di CIAN

Semua sistem yang terlibat dalam automasi boleh dibahagikan kepada beberapa lapisan:

  1. Sistem luaran (Jira, Bitbucket, dll.). Pasukan pembangunan bekerjasama dengan mereka.
  2. Platform Integro. Selalunya, pembangun tidak bekerja dengannya secara langsung, tetapi itulah yang memastikan semua automasi berjalan.
  3. Perkhidmatan penghantaran, orkestrasi dan penemuan (contohnya, Jeknins, Konsul, Nomad). Dengan bantuan mereka, kami menggunakan kod pada pelayan dan memastikan perkhidmatan berfungsi antara satu sama lain.
  4. Lapisan fizikal (pelayan, OS, perisian berkaitan). Kod kami beroperasi pada tahap ini. Ini boleh sama ada pelayan fizikal atau maya (LXC, KVM, Docker).

Berdasarkan konsep ini, kami membahagikan bidang tanggungjawab dalam pasukan DI. Dua peringkat pertama berada dalam bidang tanggungjawab arah pembangunan Integro, dan dua peringkat terakhir sudah berada dalam bidang tanggungjawab DevOps. Pemisahan ini membolehkan kami memberi tumpuan kepada tugas dan tidak mengganggu interaksi, kerana kami rapat antara satu sama lain dan sentiasa bertukar pengetahuan dan pengalaman.

Utuh

Mari fokus pada Integro dan mulakan dengan timbunan teknologi:

  • CentOS 7
  • Docker + Nomad + Consul + Vault
  • Java 11 (monolit Integro lama akan kekal di Java 8)
  • Spring Boot 2.X + Spring Cloud Config
  • PostgreSql 11
  • RabbitMQ 
  • Apache Ignite
  • Camunda (terbenam)
  • Grafana + Grafit + Prometheus + Jaeger + ELK
  • UI Web: React (CSR) + MobX
  • SSO: Jubah kunci

Kami mematuhi prinsip pembangunan perkhidmatan mikro, walaupun kami mempunyai warisan dalam bentuk monolit versi awal Integro. Setiap perkhidmatan mikro berjalan dalam bekas Docker sendiri, dan perkhidmatan berkomunikasi antara satu sama lain melalui permintaan HTTP dan mesej RabbitMQ. Perkhidmatan mikro mencari satu sama lain melalui Konsul dan membuat permintaan kepadanya, memberikan kebenaran melalui SSO (Keycloak, OAuth 2/OpenID Connect).

Daripada skrip ke platform kami sendiri: cara kami mengautomasikan pembangunan di CIAN

Sebagai contoh kehidupan sebenar, pertimbangkan untuk berinteraksi dengan Jenkins, yang terdiri daripada langkah berikut:

  1. Perkhidmatan mikro pengurusan aliran kerja (selepas ini dirujuk sebagai perkhidmatan mikro Aliran) mahu menjalankan binaan dalam Jenkins. Untuk melakukan ini, dia menggunakan Konsul untuk mencari IP:PORT perkhidmatan mikro untuk penyepaduan dengan Jenkins (selepas ini dirujuk sebagai perkhidmatan mikro Jenkins) dan menghantar permintaan tak segerak kepadanya untuk memulakan binaan dalam Jenkins.
  2. Selepas menerima permintaan, perkhidmatan mikro Jenkins menjana dan membalas dengan ID Pekerjaan, yang kemudiannya boleh digunakan untuk mengenal pasti hasil kerja. Pada masa yang sama, ia mencetuskan binaan dalam Jenkins melalui panggilan API REST.
  3. Jenkins melaksanakan binaan dan, selepas selesai, menghantar webhook dengan hasil pelaksanaan kepada perkhidmatan mikro Jenkins.
  4. Perkhidmatan mikro Jenkins, setelah menerima webhook, menjana mesej tentang penyiapan pemprosesan permintaan dan melampirkan hasil pelaksanaan padanya. Mesej yang dijana dihantar ke baris gilir RabbitMQ.
  5. Melalui RabbitMQ, mesej yang diterbitkan mencapai perkhidmatan mikro Flow, yang mengetahui tentang hasil pemprosesan tugasnya dengan memadankan ID Pekerjaan daripada permintaan dan mesej yang diterima.

Kini kami mempunyai kira-kira 30 perkhidmatan mikro, yang boleh dibahagikan kepada beberapa kumpulan:

  1. Pengurusan konfigurasi.
  2. Maklumat dan interaksi dengan pengguna (utusan, mel).
  3. Bekerja dengan kod sumber.
  4. Penyepaduan dengan alat penempatan (jenkins, nomad, konsul, dll.).
  5. Pemantauan (keluaran, ralat, dll.).
  6. Utiliti web (UI untuk mengurus persekitaran ujian, mengumpul statistik, dsb.).
  7. Integrasi dengan penjejak tugas dan sistem yang serupa.
  8. Pengurusan aliran kerja untuk tugasan yang berbeza.

Tugas aliran kerja

Integro mengautomasikan aktiviti yang berkaitan dengan kitaran hayat tugasan. Dalam istilah yang dipermudahkan, kitaran hayat tugasan akan difahami sebagai aliran kerja tugas dalam Jira. Proses pembangunan kami mempunyai beberapa variasi aliran kerja bergantung pada projek, jenis tugasan dan pilihan yang dipilih dalam tugasan tertentu. 

Mari lihat aliran kerja yang paling kerap kami gunakan:

Daripada skrip ke platform kami sendiri: cara kami mengautomasikan pembangunan di CIAN

Dalam rajah, gear menunjukkan bahawa peralihan dipanggil secara automatik oleh Integro, manakala angka manusia menunjukkan bahawa peralihan dipanggil secara manual oleh seseorang. Mari lihat beberapa laluan yang boleh diambil oleh tugas dalam aliran kerja ini.

Ujian manual sepenuhnya pada DEV+BETA tanpa ujian kenari (biasanya begini cara kami mengeluarkan monolit):

Daripada skrip ke platform kami sendiri: cara kami mengautomasikan pembangunan di CIAN

Mungkin terdapat kombinasi peralihan lain. Kadangkala laluan yang akan diambil oleh isu boleh dipilih melalui pilihan dalam Jira.

Pergerakan tugas

Mari lihat langkah utama yang dilakukan apabila tugasan bergerak melalui aliran kerja "Pengujian DEV + Ujian Canary":

1. Pembangun atau PM mencipta tugasan.

2. Pembangun mengambil tugas untuk bekerja. Selepas selesai, ia bertukar kepada status DALAM SEMAKAN.

3. Jira menghantar Webhook ke perkhidmatan mikro Jira (bertanggungjawab untuk penyepaduan dengan Jira).

4. Perkhidmatan mikro Jira menghantar permintaan kepada perkhidmatan Aliran (bertanggungjawab untuk aliran kerja dalaman di mana kerja dilakukan) untuk memulakan aliran kerja.

5. Di dalam perkhidmatan Aliran:

  • Penyemak ditugaskan kepada tugas (Perkhidmatan mikro pengguna yang mengetahui segala-galanya tentang pengguna + perkhidmatan mikro Jira).
  • Melalui perkhidmatan mikro Sumber (ia tahu tentang repositori dan cawangan, tetapi tidak berfungsi dengan kod itu sendiri), carian dibuat untuk repositori yang mengandungi cawangan isu kami (untuk memudahkan carian, nama cawangan itu bertepatan dengan isu itu. nombor dalam Jira). Selalunya, tugas hanya mempunyai satu cawangan dalam satu repositori; ini memudahkan pengurusan baris gilir penempatan dan mengurangkan ketersambungan antara repositori.
  • Untuk setiap cawangan yang ditemui, urutan tindakan berikut dilakukan:

    i) Mengemas kini cawangan induk (perkhidmatan mikro Git untuk bekerja dengan kod).
    ii) Cawangan disekat daripada perubahan oleh pembangun (perkhidmatan mikro Bitbucket).
    iii) Permintaan Tarik dibuat untuk cawangan ini (perkhidmatan mikro Bitbucket).
    iv) Mesej tentang Permintaan Tarik baharu dihantar ke sembang pembangun (Beritahu perkhidmatan mikro untuk bekerja dengan pemberitahuan).
    v) Membina, menguji dan melaksanakan tugas dimulakan pada DEV (perkhidmatan mikro Jenkins untuk bekerja dengan Jenkins).
    vi) Jika semua langkah sebelumnya berjaya diselesaikan, maka Integro meletakkan Approvenya dalam Permintaan Tarik (perkhidmatan mikro Bitbucket).

  • Integro menunggu Kelulusan dalam Permintaan Tarik daripada pengulas yang ditetapkan.
  • Sebaik sahaja semua kelulusan yang diperlukan telah diterima (termasuk ujian automatik telah lulus secara positif), Integro memindahkan tugas ke status Test on Dev (perkhidmatan mikro Jira).

6. Penguji menguji tugasan. Jika tiada masalah, maka tugas itu dipindahkan ke status Sedia Untuk Bina.

7. Integro "melihat" bahawa tugas itu sedia untuk dikeluarkan dan memulakan penggunaannya dalam mod kanari (perkhidmatan mikro Jenkins). Kesediaan untuk pelepasan ditentukan oleh satu set peraturan. Sebagai contoh, tugas berada dalam status yang diperlukan, tiada kunci pada tugas lain, tiada muat naik aktif perkhidmatan mikro ini pada masa ini, dsb.

8. Tugas dipindahkan ke status Canary (Jira microservice).

9. Jenkins melancarkan tugas penempatan melalui Nomad dalam mod kenari (biasanya 1-3 kejadian) dan memberitahu perkhidmatan pemantauan keluaran (perkhidmatan mikro DeployWatch) tentang penggunaan.

10. Perkhidmatan mikro DeployWatch mengumpul latar belakang ralat dan bertindak balas terhadapnya, jika perlu. Jika latar belakang ralat melebihi (norma latar belakang dikira secara automatik), pembangun dimaklumkan melalui perkhidmatan mikro Notify. Jika selepas 5 minit pembangun tidak bertindak balas (diklik Kembali atau Kekal), maka pemulangan automatik bagi tika kenari dilancarkan. Jika latar belakang tidak melebihi, maka pembangun mesti melancarkan penggunaan tugas secara manual ke Pengeluaran (dengan mengklik butang dalam UI). Jika dalam masa 60 minit pembangun tidak melancarkan penggunaan ke Pengeluaran, maka tika kenari juga akan ditarik balik atas sebab keselamatan.

11. Selepas melancarkan penempatan ke Pengeluaran:

  • Tugas dipindahkan ke status Pengeluaran (Jira microservice).
  • Perkhidmatan mikro Jenkins memulakan proses penggunaan dan memberitahu perkhidmatan mikro DeployWatch tentang penggunaan.
  • Perkhidmatan mikro DeployWatch menyemak bahawa semua bekas pada Pengeluaran telah dikemas kini (terdapat kes apabila tidak semua dikemas kini).
  • Melalui perkhidmatan mikro Notify, pemberitahuan tentang hasil penempatan dihantar kepada Pengeluaran.

12. Pembangun akan mempunyai 30 minit untuk mula melancarkan tugas daripada Pengeluaran jika tingkah laku perkhidmatan mikro yang salah dikesan. Selepas masa ini, tugasan akan digabungkan secara automatik menjadi induk (perkhidmatan mikro Git).

13. Selepas berjaya bergabung menjadi induk, status tugas akan ditukar kepada Tertutup (Jira microservice).

Gambar rajah tidak berpura-pura terperinci sepenuhnya (sebenarnya terdapat lebih banyak langkah), tetapi ia membolehkan anda menilai tahap integrasi ke dalam proses. Kami tidak menganggap skim ini ideal dan sedang menambah baik proses pelepasan automatik dan sokongan penggunaan.

Apa yang Seterusnya

Kami mempunyai rancangan besar untuk pembangunan automasi, contohnya, menghapuskan operasi manual semasa keluaran monolit, menambah baik pemantauan semasa penggunaan automatik dan menambah baik interaksi dengan pembangun.

Tetapi mari kita berhenti di sini buat masa ini. Kami membincangkan banyak topik dalam semakan automasi secara dangkal, ada yang tidak disentuh langsung, jadi kami dengan senang hati akan menjawab soalan. Kami sedang menunggu cadangan tentang perkara yang perlu dibincangkan secara terperinci, tulis dalam komen.

Sumber: www.habr.com

Tambah komen