
Di RIT 2019, kolega kami Alexander Korotkov membuat
laporan tentang otomatisasi pengembangan di CIAN: untuk menyederhanakan kehidupan dan pekerjaan, kami menggunakan platform Integro kami sendiri. Ini memonitor siklus hidup tugas, menghilangkan operasi rutin dari pengembang, dan secara signifikan mengurangi jumlah bug dalam produksi. Dalam posting ini kami akan melengkapi laporan Alexander dan memberi tahu Anda bagaimana kami beralih dari skrip sederhana menjadi menggabungkan produk open source melalui platform kami sendiri dan apa yang dilakukan oleh tim otomasi terpisah.
Tingkat nol
"Tidak ada level nol, saya tidak tahu ini"
Shifu master dari film "Kung Fu Panda"Otomasi di CIAN dimulai 14 tahun setelah pendirian perusahaan. Kemudian ada 35 orang di tim pengembangan. Sulit dipercaya, bukan? Tentu saja, otomasi memang ada dalam beberapa bentuk, tetapi area terpisah dari integrasi berkelanjutan dan pengiriman kode mulai terbentuk pada tahun 2015.
Pada saat itu, kami memiliki monolit besar dari Python, C # dan PHP yang digunakan pada server Linux / Windows. Untuk penyebaran monster ini, kami memiliki satu set skrip yang kami jalankan secara manual. Ada juga majelis monolit, menyebabkan rasa sakit dan penderitaan karena konflik ketika menggabungkan cabang, mengedit cacat dan membangun kembali "dengan serangkaian tugas yang berbeda dalam pembangunan." Proses yang disederhanakan tampak seperti ini:

Ini tidak cocok untuk kami, dan kami ingin membangun proses pembangunan dan penyebaran yang berulang, otomatis, dan terkontrol. Untuk melakukan ini, kami membutuhkan sistem CI / CD, dan kami memilih antara versi gratis dari Teamcity dan Jenkins gratis, karena kami bekerja dengan mereka dan keduanya cocok kami untuk serangkaian fungsi. Kami memilih Teamcity sebagai produk yang lebih baru. Kemudian kami tidak menggunakan arsitektur microservice dan tidak mengandalkan banyak tugas dan proyek.
Kami sampai pada ide sistem kami sendiri
Implementasi Teamcity hanya menghapus sebagian dari pekerjaan manual: masih ada penciptaan Permintaan Tarik, promosi tugas berdasarkan status di Jira, pemilihan tugas untuk dirilis. Teamcity tidak bisa lagi mengatasinya. Itu perlu untuk memilih jalur otomatisasi lebih lanjut. Kami mempertimbangkan opsi untuk bekerja dengan skrip di Teamcity atau beralih ke sistem otomasi pihak ketiga. Tetapi pada akhirnya, kami memutuskan bahwa kami membutuhkan fleksibilitas maksimum yang hanya diberikan oleh solusi kami sendiri. Jadi versi pertama dari sistem otomasi internal yang disebut Integro muncul.
Teamcity terlibat dalam otomatisasi pada tingkat awal proses perakitan dan penyebaran, dan Integro telah berfokus pada otomatisasi tingkat atas dari proses pengembangan. Itu perlu untuk menggabungkan pekerjaan dengan tugas-tugas di Jira dengan memproses kode sumber terkait di Bitbucket. Pada tahap ini, Integro mulai memiliki alur kerja sendiri untuk bekerja dengan berbagai jenis tugas.
Karena peningkatan otomatisasi dalam proses bisnis, jumlah proyek dan berjalan di Teamcity telah meningkat. Jadi masalah baru muncul: satu instance Teamcity gratis tidak ada (3 agen dan 100 proyek), kami menambahkan contoh lain (3 agen lebih dan 100 proyek), lalu satu lagi. Akibatnya, kami mendapat sistem beberapa kluster, yang sulit dikelola:

Ketika muncul pertanyaan tentang instance 4, kami menyadari bahwa kami tidak bisa hidup seperti itu lagi, karena total biaya untuk mendukung 4 instance tidak lagi sesuai dengan kerangka kerja apa pun. Muncul pertanyaan untuk membeli Teamcity berbayar atau memilih Jenkins gratis. Kami melakukan perhitungan pada mesin virtual dan rencana untuk otomatisasi dan memutuskan bahwa kami akan hidup dengan Jenkins. Setelah beberapa minggu, kami beralih ke Jenkins dan menyingkirkan bagian sakit kepala yang terkait dengan mendukung beberapa instance Teamcity. Oleh karena itu, kami dapat fokus pada pengembangan Integro dan menyelesaikan Jenkins untuk diri kita sendiri.
Dengan tumbuhnya otomatisasi dasar (dalam bentuk pembuatan Permintaan Tarik otomatis, pengumpulan dan publikasi cakupan Kode dan cek lainnya), ada keinginan kuat untuk menolak rilis manual sebanyak mungkin dan memberikan karya ini kepada robot. Selain itu, perusahaan mulai pindah ke layanan microser, yang membutuhkan rilis sering, dan terpisah satu sama lain. Jadi kami secara bertahap sampai pada rilis otomatis dari layanan microser kami (untuk saat ini, kami merilis monolith secara manual karena kerumitan prosesnya). Tetapi, seperti biasanya, kompleksitas baru telah muncul.
Pengujian Otomatis

Karena otomatisasi rilis, proses pengembangan telah dipercepat, sebagian karena melewatkan beberapa tahap pengujian. Dan ini menyebabkan hilangnya kualitas sementara. Kedengarannya klise, tetapi seiring dengan percepatan rilis, perlu untuk mengubah metodologi pengembangan produk. Itu perlu untuk berpikir tentang otomatisasi pengujian, menanamkan tanggung jawab pribadi (di sini kita berbicara tentang "menerima gagasan di kepala", dan bukan denda moneter) dari pengembang untuk kode yang dirilis dan bug di dalamnya, serta tentang keputusan untuk mengeluarkan / tidak mengeluarkan tugas melalui penyebaran otomatis.
Menghilangkan masalah kualitas, kami sampai pada dua keputusan penting: kami mulai melakukan pengujian kenari dan menerapkan pemantauan otomatis latar belakang kesalahan dengan respons otomatis terhadap kelebihannya. Solusi pertama memungkinkan untuk menemukan kesalahan yang jelas sebelum kode sepenuhnya masuk ke produksi, yang kedua mengurangi waktu respons terhadap masalah dalam produksi. Kesalahan, tentu saja, memang terjadi, tetapi kita menghabiskan sebagian besar waktu dan energi kita bukan pada koreksi, tetapi pada minimalisasi.
Tim otomasi
Sekarang kami memiliki staf dari 130 pengembang, dan kami terus
berkembang . Tim untuk integrasi berkelanjutan dan pengiriman kode (selanjutnya disebut sebagai tim Deploy and Integration atau DI) terdiri dari 7 orang dan bekerja dalam 2 arah: pengembangan platform otomasi Integro dan DevOps.
DevOps bertanggung jawab atas lingkungan Dev / Beta dari situs web CIAN, lingkungan Integro, membantu pengembang untuk memecahkan masalah dan mengembangkan pendekatan baru untuk meningkatkan skala lingkungan. Lini bisnis Integro berkaitan dengan Integro sendiri dan layanan terkait, misalnya, plug-in untuk Jenkins, Jira, Confluence, dan juga mengembangkan utilitas bantu dan aplikasi untuk tim pengembangan.
Tim DI bekerja bersama dengan tim Platform, yang mengembangkan arsitektur, perpustakaan, dan pendekatan pengembangan dalam perusahaan. Pada saat yang sama, setiap pengembang di dalam CIAN dapat berkontribusi untuk otomatisasi, misalnya, membuat mikroautomasi dengan kebutuhan tim atau berbagi ide keren bagaimana membuat otomasi menjadi lebih baik.
Otomatisasi puff pie di cyan

Semua sistem yang terlibat dalam otomasi dapat dibagi menjadi beberapa lapisan:
- Sistem eksternal (Jira, Bitbucket, dll.). Tim pengembangan bekerja dengan mereka.
- Platform Integro. Paling sering, pengembang tidak bekerja dengannya secara langsung, tetapi dialah yang mendukung pekerjaan semua otomatisasi.
- Jasa pengiriman, pembuatan dan penemuan (mis. Jeknins, Konsul, Nomad). Dengan bantuan mereka, kami menyebarkan kode pada server dan saling memberikan layanan.
- Lapisan fisik (server, OS, perangkat lunak terkait). Pada level ini, kode kita berfungsi. Ini bisa berupa server fisik atau virtual (LXC, KVM, Docker).
Berdasarkan konsep ini, kami membagi bidang tanggung jawab dalam tim DI. Dua level pertama berada di area tanggung jawab area pengembangan Integro, dan dua level terakhir sudah berada di area tanggung jawab DevOps. Pemisahan ini memungkinkan Anda untuk fokus pada tugas dan tidak mengganggu interaksi, karena kami bersebelahan dan terus bertukar pengetahuan dan pengalaman.
Integro
Mari fokus pada Integro dan mulai dengan tumpukan teknologi:
- CentOs 7
- Docker + Nomad + Konsul + Vault
- Java 11 (monolith Integro lama akan tetap ada di Java 8)
- Spring Boot 2.X + Spring Cloud Config
- PostgreSql 11
- Rabbitmq
- Apache terbakar
- Camunda (tertanam)
- Grafana + Grafit + Prometheus + Jaeger + ELK
- UI Web: React (CSR) + MobX
- SSO: Keycloak
Kami mematuhi prinsip pengembangan layanan-mikro, meskipun kami memiliki warisan dalam bentuk monolit dari versi awal Integro. Setiap microservice berputar dalam wadah buruh pelabuhannya, layanan berkomunikasi satu sama lain melalui permintaan HTTP dan pesan RabbitMQ. Layanan Microsoft menemukan satu sama lain melalui Konsul dan melaksanakan permintaan untuk itu, melewati otorisasi melalui SSO (Keycloak, OAuth 2 / OpenID Connect).

Sebagai contoh nyata, pertimbangkan interaksi dengan Jenkins, yang terdiri dari langkah-langkah berikut:
- Layanan microser workflow manajemen (selanjutnya disebut sebagai microservice Flow) ingin menjalankan perakitan di Jenkins. Untuk melakukan ini, ia menemukan melalui Konsul IP: integrasi layanan perangkat lunak PORT dengan Jenkins (selanjutnya disebut layanan perangkat lunak Jenkins) dan mengiriminya permintaan tidak sinkron untuk memulai perakitan di Jenkins.
- Layanan mikro Jenkins, setelah menerima permintaan tersebut, menghasilkan dan memberikan kembali ID Pekerjaan, yang kemudian memungkinkan untuk mengidentifikasi hasil pekerjaan. Bersamaan dengan ini, ia mulai membangun di Jenkins melalui panggilan ke REST API.
- Jenkins membangun dan, setelah selesai, mengirimkan webhook dengan hasilnya ke layanan mikro Jenkins.
- Layanan mikro Jenkins, setelah menerima webhook, menghasilkan pesan tentang penyelesaian pemrosesan permintaan dan melampirkan hasil eksekusi padanya. Pesan yang dihasilkan dikirim ke antrian RabbitMQ.
- Melalui RabbitMQ, pesan yang diterbitkan sampai ke microservice Flow, yang belajar tentang hasil pemrosesan tugasnya dengan mencocokkan ID Pekerjaan dari permintaan dan pesan yang diterima.
Sekarang kami memiliki sekitar 30 layanan mikro yang dapat dibagi menjadi beberapa kelompok:
- Manajemen konfigurasi.
- Menginformasikan dan berinteraksi dengan pengguna (instant messenger, mail).
- Bekerja dengan kode sumber.
- Integrasi dengan alat penyebaran (jenkins, nomad, konsul, dll.).
- Pemantauan (rilis, bug, dll.).
- Utilitas web (UI untuk mengelola lingkungan pengujian, mengumpulkan statistik, dll.).
- Integrasi dengan pelacak tugas dan sistem serupa.
- Kelola alur kerja untuk berbagai tugas.
Tugas alur kerja
Integro mengotomatiskan kegiatan yang terkait dengan siklus hidup tugas. Disederhanakan oleh siklus hidup tugas, maksud kami alur kerja tugas di Jira. Dalam proses pengembangan kami, ada beberapa variasi alur kerja tergantung pada proyek, jenis tugas dan opsi yang dipilih dalam tugas tertentu.
Pertimbangkan alur kerja yang paling sering kita gunakan:

Dalam diagram, roda gigi menunjukkan bahwa transisi disebut oleh Integro secara otomatis, sedangkan sosok manusia berarti bahwa transisi tersebut secara manual disebut oleh orang tersebut. Mari kita lihat beberapa cara agar tugas dapat melalui alur kerja ini.
Pengujian manual untuk DEV + BETA tanpa tes kenari (biasanya kami merilis monolit):

Mungkin ada kombinasi transisi lainnya. Terkadang jalur yang akan diambil tugas dapat dipilih melalui opsi di Jira.
Gerakan tugas
Pertimbangkan langkah-langkah dasar yang dilakukan saat memindahkan tugas pada alur kerja "Pengujian untuk pengujian kenari DEV +":
1. Pengembang atau PM menciptakan tugas.
2. Pengembang mengambil tugas untuk bekerja. Setelah selesai, transfer ke status IN REVIEW.
3. Jira mengirimkan Webhook menuju microservice Jira (bertanggung jawab untuk integrasi dengan Jira).
4. Jira microservice mengirimkan permintaan ke layanan Flow (bertanggung jawab atas alur kerja internal di mana pekerjaan dilakukan) untuk memulai alur kerja.
5. Di dalam layanan Flow:
- Peninjau untuk tugas tersebut ditugaskan (Pengguna-microservice yang mengetahui segalanya tentang pengguna + Jira-microservice).
- Melalui microservice Sumber (ia tahu tentang repositori dan cabang, tetapi tidak bekerja dengan kode itu sendiri), ia mencari repositori di mana ada cabang tugas kami (untuk menyederhanakan pencarian, nama cabang cocok dengan nomor tugas di Jira). Paling sering, tugas hanya memiliki satu cabang dalam satu repositori, ini menyederhanakan pengelolaan antrian pada penyebaran dan mengurangi konektivitas antara repositori.
- Untuk setiap cabang yang ditemukan, urutan tindakan berikut dilakukan:
i) Memicu cabang utama (Git microservice untuk bekerja dengan kode).
ii) Cabang diblokir dari perubahan oleh pengembang (Bitbucket microservice).
iii) Permintaan Tarik dibuat di cabang ini (Bitbucket microservice).
iv) Pesan tentang Permintaan Tarik baru dikirim ke obrolan pengembang (Beri tahu layanan mikro untuk bekerja dengan notifikasi).
v) Membangun, menguji, dan menyebarkan tugas ke DEV (layanan mikro Jenkins untuk bekerja dengan Jenkins).
vi) Jika semua paragraf sebelumnya telah berhasil diselesaikan, maka Integro menempatkan Approve-nya dalam Pull Request (Bitbucket microservice). - Integro mengharapkan Pull Request Approve dari pengulas yang ditunjuk.
- Segera setelah semua Approve yang diperlukan telah diterima (termasuk pengujian otomatis telah berhasil dilewati), Integro mentransfer tugas ke status Test on Dev (Jira microservice).
6. Penguji menguji tugas. Jika tidak ada masalah, maka mereka mentransfer tugas ke status Ready For Build.
7. Integro βmelihatβ bahwa tugas tersebut siap untuk dirilis, dan meluncurkan penyebarannya dalam mode kenari (Jenkins microservice). Kesiapan untuk rilis ditentukan oleh seperangkat aturan. Misalnya, tugas dalam status yang benar, tidak ada kunci pada tugas lain, sekarang tidak ada perhitungan aktif dari layanan Microsoft ini, dll.
8. Tugas dipindahkan ke status Canary (Jira-microservice).
9. Jenkins memulai melalui Nomad penyebaran tugas dalam mode kenari (biasanya 1-3 instance) dan memberi tahu layanan pemantauan rilis (DeployWatch microservice) dari perhitungan.
10. DeployWatch-microservice mengumpulkan kesalahan latar belakang dan menanggapinya jika perlu. Jika kesalahan latar belakang terlampaui (laju latar belakang dihitung secara otomatis), pengembang akan diberi tahu melalui layanan microser Notify. Jika setelah 5 menit pengembang tidak merespons (mengklik Kembalikan atau Tetap), maka kembalinya otomatis contoh kenari dimulai. Jika latar belakang tidak terlampaui, maka pengembang harus secara manual meluncurkan penyebaran tugas pada Produksi (dengan menekan tombol di UI). Jika dalam waktu 60 menit pengembang tidak meluncurkan penyebaran dalam Produksi, maka instance kenari juga akan dipompa keluar karena alasan keamanan.
11. Setelah meluncurkan penyebaran ke Produksi:
- Tugas dipindahkan ke status Produksi (Jira microservice).
- Jenkins microservice memulai proses penyebaran dan memberi tahu penyebaran microservice DeployWatch.
- DeployWatch-microservice memverifikasi bahwa semua kontainer diperbarui pada Produksi (ada kasus ketika tidak semua diperbarui).
- Pemberitahuan tentang hasil penyebaran ke Produksi dikirim melalui layanan pemberitahuan mikro.
12. Pengembang akan memiliki waktu 30 menit untuk memulai rollback tugas dengan Production jika terdeteksi perilaku keliru dari layanan microser. Setelah waktu ini, tugas akan secara otomatis dituangkan ke master (Git-microservice).
13. Setelah penggabungan master berhasil, status tugas akan diubah menjadi Tertutup (Jira microservice).
Skema ini tidak berpura-pura terperinci sepenuhnya (pada kenyataannya, bahkan ada lebih banyak langkah), tetapi memungkinkan Anda untuk mengevaluasi tingkat integrasi ke dalam proses. Kami tidak menganggap skema ini ideal dan meningkatkan proses pelacakan rilis dan penyebaran otomatis.
Apa selanjutnya
Kami memiliki rencana besar untuk pengembangan otomatisasi, misalnya, penolakan operasi manual selama rilis monolit, peningkatan pemantauan selama penyebaran otomatis, peningkatan interaksi dengan pengembang.
Tapi untuk sekarang, mari kita berhenti di tempat ini. Kami membahas banyak topik secara dangkal dalam tinjauan otomasi, beberapa tidak menyentuhnya sama sekali, jadi kami akan dengan senang hati menjawab pertanyaan. Kami menunggu saran tentang apa yang akan dibahas secara rinci, tulis di komentar.