Problem: bir nəfərin noutbukundan asılı olan deploy

Komanda Spring Boot servisini belə göndərir: jar developer-in maşınında qurulur, serverə kopyalanır və restart edilir. Bir gün build adi halda olmayan başqa Java versiyası ilə işləyir, bir test "bu dəfəlik" atlanır, rollback isə əvvəlki jar-ı kiminsə yükləmələr qovluğunda axtarmaq deməkdir. Kodda problem yoxdur; zəif nöqtə çatdırılma prosesidir.

Continuous integration (CI) hər dəyişikliyin təmiz mühitdə avtomatik qurulması və test olunması deməkdir. Continuous delivery (CD) isə yoxlamadan keçən hər dəyişikliyin təkrarlanan prosesla buraxıla bilməsidir. Məqsəd sürətin özü deyil, darıxdırıcı release-dir: eyni addımlar, eyni nəticə, asan geri qaytarma.

Əsas fikir: bir dəfə qurun, eyni artefaktı irəli aparın

Çatdırılma pipeline-ının ən vacib qaydası: test etdiyiniz artefakt deploy etdiyiniz artefaktdır. Bir image qurun, onu dəyişməz tag ilə (latest yox, commit SHA) işarələyin və məhz bu image-i test, staging və production üzərindən keçirin. Hər mühit üçün yenidən build etmək production-da heç kimin test etmədiyi şeyin işləməsi deməkdir.

Mühitlər arasındakı fərqlər build-də yox, konfiqurasiyada olmalıdır. Eyni image hər yerdə fərqli datasource URL və fərqli sirlər alır.

Mərhələlər və məqsədləri

commit -> build -> test -> checks -> image -> deploy staging
                                          -> smoke test
                                          -> approve -> deploy prod
  1. Build. Bərkidilmiş JDK versiyası və wrapper (mvnw və ya gradlew) ilə kompilyasiya edin ki, CI və noutbuk eyni build alətindən istifadə etsin.
  2. Test. Əvvəlcə sürətli unit testlər, sonra daha yavaş integration testlər, məsələn Testcontainers ilə. Tez uğursuz olun: ən ucuz mərhələni birinci qoyun ki, developer-lər rəyi tez alsın.
  3. Statik yoxlamalar. Format, linter və ya statik analiz, asılılıqların zəiflik skanı. Hansı tapıntıların build-i dayandıracağına qərar verin; hamının ignor etdiyi skan heç olmamasından pisdir.
  4. Image. Container image-i Dockerfile-dan qurun, commit SHA ilə tag-layın, registry-yə push edin.
  5. Deploy və yoxlama. Staging-ə deploy edin, health endpoint və bir-iki kritik axın üzərində qısa smoke test işlədin, sonra irəli aparın.

GitHub Actions üslubunda nümunə

name: cion:  pull_request:  push:    branches: [main]jobs:  build-test:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v      - uses: actions/setup-java@v        with:          distribution: temurin          java-version: 21          cache: maven      - run: ./mvnw -B verify  image:    needs: build-test    if: github.ref == 'refs/heads/main'    runs-on: ubuntu-latest    permissions:      contents: read      packages: write    steps:      - uses: actions/checkout@v      - run: docker build -t registry.example/app:${{ github.sha }} .      - run: docker push registry.example/app:${{ github.sha }}

Sintaksis CI məhsulları arasında fərqlənir, amma struktur hər yerdə eynidir: trigger-lər, asılılıqlı job-lar, keş və job-un yalnız ehtiyac duyduğu səlahiyyətlərlə məhdudlaşan permissions. Üçüncü tərəf action və ya plugin-ləri yoxladığınız versiyaya bərkidin; bərkidilməmiş kod çəkən pipeline supply-chain riskidir.

Keşləmə

Hər işə salınmada asılılıqları yenidən yükləmək vaxt itkisidir. Maven və ya Gradle repository-ni build fayllarının (pom.xml, lock faylları) hash-i ilə açarlayıb keşləyin. CI dəstəkləyirsə, Docker layer-lərini də keşləyin. Keşlə ehtiyatlı olun: köhnəlmiş və ya zədələnmiş keş təmiz maşında uğursuz olacaq build-i keçirə bilər, ona görə keşsiz işlətmək imkanı saxlayın və sirləri və ya təzə olmalı build nəticələrini heç vaxt keşləməyin.

Mühitlər arası promotion və rollback

Staging production-a vacib cəhətlərdə oxşamalıdır: eyni baza mühərriki və versiyası, eyni deploy mexanizmi, oxşar konfiqurasiya forması. Baza miqrasiyaları xüsusi diqqət tələb edir. Sütunu silən miqrasiya əvvəlki tətbiq versiyasını sındırır, buna görə kodu geri qaytarmaq artıq təhlükəsiz deyil. Adi yanaşma expand and contract-dır: əvvəlcə yeni sütunu əlavə edin və hər ikisinə yazan kodu deploy edin, sonra heç nə oxumadıqdan sonra köhnəni silin.

Rollback yenidən build yox, əvvəlki məlum image tag-ının deploy-u olmalıdır. Bunu bir əmr və ya düymə ilə edə bilirsinizsə və məşq etmisinizsə, rollback qorxulu olmaqdan çıxır. Platforma dəstəkləyirsə, onu progressiv buraxılış üsulları ilə birləşdirin: rolling update, əvvəlcə trafikin kiçik hissəsi (canary) və ya blue/green. Hər biri faydalı olmaq üçün yaxşı health check və observability tələb edir, bax observability: log, metrik və trace.

Feature flag-lar başqa vasitədir: kodun deploy-unu davranışın aktivləşdirilməsindən ayırır, belə ki, riskli funksiyanı yenidən deploy etmədən söndürə bilərsiniz.

CI-da sirlər

  • Sirləri CI platformasının secret store-unda və ya xarici vault-da saxlayın, repository-də və ya image-də heç vaxt.
  • Hər job-a lazım olan minimum çıxışı verin. Fork-dan gələn Pull Request deploy kredensiallarına çıxış əldə etməməlidir.
  • Uzunömürlü açarlar əvəzinə federasiya ilə (CI ilə bulud arasında OIDC) alınan qısamüddətli kredensialları üstün tutun.
  • Sirləri log-larda çap etməyin. Maskalama kömək edir, amma bütün dəyərləri tutmaya bilər, ona görə mühit dəyişənlərini echo etməyin.
  • Sirr log-da və ya commit-də göründüsə, dərhal rotasiya edin.

Pull Request-lər, branch-lər və rəy sürəti

Hər Pull Request-də build və testləri işlədin və keçən pipeline-ı əsas branch-a merge üçün şərt edin. Bu, komandanın ən ucuz keyfiyyət qapısıdır, çünki hər dəyişikliyi kimin yazmasından asılı olmayaraq eyni qaydada yoxlayır. Əsas branch-ı həmişə buraxıla bilən saxlayın: qırılarsa, onu düzəltmək komandanın birinci prioritetidir.

Qısaömürlü branch-lar və kiçik dəyişikliklər pipeline-ı faydalı saxlayır. Həftələrlə yaşayan branch merge konfliktləri və sürprizlər toplayır. Hədəf developer-in dəyişikliyin məqbul olub-olmadığını dəqiqələr ərzində öyrəndiyi rəy dövrüdür; bu xeyli uzandıqda insanlar işlərini yığır və CI-ın faydaları azalır. Test hesabatlarını və log-ları pipeline artefaktı kimi dərc edin ki, uğursuzluğu lokal təkrarlamadan anlamaq mümkün olsun.

Tez-tez edilən səhvlər

  • Hər mühit üçün artefaktı yenidən qurmaq.
  • Image-ləri latest tag-lamaq və production-da nəyin işlədiyini bilməmək.
  • Pipeline-ı keçən "testləri atla" bayraqlarına və ya əl ilə merge-lərə icazə vermək.
  • İnsanların yan keçməyi öyrəndiyi yavaş pipeline-lar. Uzun rəy dövrünü qəbul etməzdən əvvəl bölün, paralelləşdirin, keşləyin.
  • Yaşıl olana qədər təkrar işlədilən qeyri-sabit testlər. Onları sahibi və son tarixi ilə düzəldin və ya karantinə alın.
  • Baza miqrasiyalarını əl ilə və ardıcıllıq pozulmaqla işlətmək.
  • Yoxlaması və rollback planı olmayan deploy addımı.

Güzəştlər

Hər merge-dən sonra production-a tam continuous deployment güclü testlər, yaxşı observability və sürətli rollback tələb edir. Bu etibar yaranana qədər bir çox komanda əl ilə təsdiq addımı olan continuous delivery ilə daha yaxşı xidmət görür. Digər tərəfdən ağır təsdiq qapıları dəyişikliklərin böyük yığınlarını yaradır, böyük yığınlar isə çoxlu kiçik dəyişikliklərdən daha risklidir. Mərasim miqdarını sisteminiz üçün uğursuzluğun dəyərinə görə seçin və sistem yetkinləşdikcə yenidən nəzərdən keçirin.

Yoxlama siyahısı

  • Bərkidilmiş JDK və build alət wrapper-i.
  • Ucuz testlər birinci, integration testlər ayrı mərhələ kimi.
  • Image commit SHA ilə tag-lanıb və dəyişdirilmədən irəli aparılır.
  • Asılılıq keşi build fayllarının açarı ilə.
  • Sirlər store-dan, minimum səlahiyyətlə və qısamüddətli kredensiallarla.
  • Geriyə uyğun miqrasiyalar və məşq edilmiş rollback.
  • Hər deploy-dan sonra smoke test.

Növbəti addım