ProHoster > Blog > yönetim > GitHub Actions ile Cehennem Çemberleri (bir Java projesi için bir CI/CD ardışık düzeni oluşturma)
GitHub Actions ile Cehennem Çemberleri (bir Java projesi için bir CI/CD ardışık düzeni oluşturma)
Java'da projeler oluşturmak için sıklıkla bir boru hattı oluşturmam gerekiyor. Bazen açık kaynaktır, bazen değildir. Yakın zamanda bazı depolarımı Travis-CI ve TeamCity'den GitHub Actions'a taşımayı denemeye karar verdim ve ortaya çıkan da bu oldu.
Neyi otomatikleştireceğiz?
Öncelikle otomatize edeceğimiz bir projeye ihtiyacımız var, Spring boot / Java 11 / Maven’de küçük bir uygulama yapalım. Bu yazının amaçları doğrultusunda uygulama mantığıyla hiç ilgilenmeyeceğiz; uygulamanın etrafındaki altyapı bizim için önemli, dolayısıyla basit bir REST API denetleyicisi bizim için yeterli olacaktır.
Kaynakları burada görebilirsiniz: github.com/antkorwin/github-actions Bir boru hattı inşa etmenin tüm aşamaları bu projenin çekme taleplerine yansıtılmıştır.
JIRA ve planlama
Sorun takip aracı olarak genellikle JIRA'yı kullandığımızı söylemekte fayda var, bu yüzden bu proje için ayrı bir pano oluşturalım ve ilk sayıları buraya ekleyelim:
JIRA ve GitHub'un birlikte sunabileceği ilginç şeylere biraz sonra döneceğiz.
Projenin montajını otomatikleştiriyoruz
Test projemiz maven aracılığıyla oluşturuldu, dolayısıyla onu oluşturmak oldukça basit, ihtiyacımız olan tek şey mvn clean paketi.
Github Actions'ı kullanarak bunu yapabilmek için repository'de iş akışımızı anlatan bir dosya oluşturmamız gerekecek, bu normal bir yml dosyası ile yapılabilir, "yml programlamayı" sevdiğimi söyleyemem ama ne yapabiliriz - bunu, ana şubeyi oluştururken eylemleri açıklayacağımız .github/ dizin iş akışı/ build.yml dosyasında yapıyoruz:
on — bu, senaryomuzun başlatılacağı olayın açıklamasıdır.
açık: pull_request/Push — ana makineye her gönderim yapıldığında ve çekme istekleri oluşturulduğunda bu iş akışının başlatılması gerektiğini belirtir.
Aşağıda görevlerin açıklaması bulunmaktadır (iş fırsatları) ve yürütme adımları (adımlar) her görev için.
devam eden - burada hedef işletim sistemini seçebiliriz, şaşırtıcı bir şekilde Mac OS'yi bile seçebilirsiniz, ancak özel depolarda bu oldukça pahalıdır (Linux'a kıyasla).
kullanım örneğin Java 11 için ortamı kurduğumuz eylemler/setup-java eylemini kullanarak diğer eylemleri yeniden kullanmanıza olanak tanır.
Vasıtasıyla ile eylemi başlatacağımız parametreleri belirleyebiliriz, esasen bunlar eyleme aktarılacak argümanlardır.
Geriye kalan tek şey proje yapısını Maven ile çalıştırmak: run: mvn -B clean package bayrak -B ustanın aniden bize bir şey sormak istememesi için etkileşimsiz bir moda ihtiyacımız olduğunu söylüyor
Harika! Artık master'a her taahhütte bulunduğunuzda proje inşası başlar.
Test başlatmalarını otomatikleştirme
Montaj iyidir, ancak gerçekte bir proje güvenli bir şekilde monte edilebilir, ancak çalışmaz. Bu nedenle bir sonraki adım test çalıştırmalarını otomatikleştirmektir. Ek olarak, bir PR incelemesi yaptığınızda testleri geçme sonuçlarına bakmak oldukça kullanışlıdır - testlerin geçtiğinden ve birleştirme yapmadan önce hiç kimsenin şubesini çalıştırmayı unutmadığından emin olursunuz.
Bir çekme isteği oluştururken ve ana öğeye birleştirirken testler gerçekleştireceğiz ve aynı zamanda kod kapsamına ilişkin bir rapor oluşturulmasını da ekleyeceğiz.
Testleri tamamlamak için codecov'u jacoco eklentisiyle birlikte kullanıyorum. codecov'un kendi eylemi vardır, ancak çekme isteğimizle çalışması için bir jetona ihtiyacı vardır:
${{ secrets.CODECOV_TOKEN }} — bu yapıyı bir kereden fazla göreceğiz, sırlar GitHub'da sırları depolamak için bir mekanizmadır, oraya şifreleri/belirteçleri/ana bilgisayarları/url'leri ve depo kod tabanına dahil edilmemesi gereken diğer verileri yazabiliriz.
GitHub'daki depo ayarlarında gizli dizilere bir değişken ekleyebilirsiniz:
adresinden jeton alabilirsiniz. codecov.io GitHub aracılığıyla yetkilendirmenin ardından herkese açık bir proje eklemek için aşağıdaki gibi bir bağlantıyı izlemeniz yeterlidir: GitHub kullanıcı adı/[depo adı]. Özel bir repository de eklenebilir; bunun için Github'daki uygulamaya codecov haklarını vermeniz gerekir.
Şimdi codecov botu her çekme isteğimize girecek ve bir kapsam değişim grafiği ekleyecek:
Statik bir analizör ekleyelim
Açık kaynak projelerimin çoğunda statik kod analizi için sonar bulutu kullanıyorum, travis-ci'ye bağlanmak oldukça kolay. Dolayısıyla GitHub Actions'a geçiş yaparken aynısını yapmak mantıklı bir adımdır. Aksiyon pazarı güzel bir şey ama bu sefer beni biraz hayal kırıklığına uğrattı çünkü alışkanlıktan ihtiyacım olan aksiyonu buldum ve iş akışına ekledim. Ancak sonarın, maven veya gradle üzerindeki projeleri analiz etmek için bir eylem üzerinde çalışmayı desteklemediği ortaya çıktı. Tabii ki, bu belgelerde yazılıdır, ancak bunu kim okur?!
Bir eylemle mümkün değil, bu yüzden bunu mvn eklentisi aracılığıyla yapacağız:
SONAR_TOKEN - şu adresten edinilebilir: sonarcloud.io ve bunu sırlara kaydetmeniz gerekiyor. GITHUB_TOKEN - bu, GitHub'un oluşturduğu yerleşik bir belirteçtir ve bunun yardımıyla sonarcloud[bot], çekme isteklerinde bize mesaj bırakmak için Git'te oturum açabilir.
Dsonar.projectKey — sonardaki projenin adı, bunu proje ayarlarında görebilirsiniz.
Dsonar.organizasyonu — GitHub'dan kuruluşun adı.
Bir çekme isteğinde bulunuyoruz ve sonarcloud[bot]'un yorumlara gelmesini bekliyoruz:
Yayın yönetimi
Derleme yapılandırıldı, testler yapıldı ve bir sürüm yayınlayabiliriz. GitHub Eylemlerinin sürüm yönetimini nasıl daha kolay hale getirebileceğine bir göz atalım.
İşyerinde kod tabanı bitbucket olan projelerim var (her şey şu hikayedeki gibi: "Gündüzleri bitbucket'e yazıyorum, geceleri GitHub'a bağlanıyorum"). Ne yazık ki bitbucket'in yerleşik sürüm yönetimi araçları yoktur. Bu bir sorundur, çünkü her sürüm için manuel olarak bir araya gelerek bir sayfa oluşturmanız ve sürümde yer alan tüm özellikleri oraya atmanız, zihnin saraylarını, jira'daki görevleri, depodaki taahhütleri aramanız gerekir. Hata yapma şansınız çoktur, bir şeyi unutabilir veya daha önce yayınlanmış bir şeyi girebilirsiniz, bazen bir çekme isteğinin neye göre sınıflandırılacağı açık değildir - bu bir özellik mi, bir hata düzeltmesi mi, yoksa düzenleme testleri mi, veya altyapısal bir şey.
GitHub eylemleri bize nasıl yardımcı olabilir? Harika bir eylem var - sürüm taslağı oluşturucu, çekme isteklerinin kategorilerini ayarlamak ve bunları sürüm notları dosyasında otomatik olarak gruplamak için bir sürüm notları dosya şablonu ayarlamanıza olanak tanır:
Rapor oluşturmaya yönelik örnek şablon (.github/release-drafter.yml):
name-template: 'v$NEXT_PATCH_VERSION'
tag-template: 'v$NEXT_PATCH_VERSION'
categories:
- title: ' New Features'
labels:
- 'type:features'
# в эту категорию собираем все PR с меткой type:features
- title: ' Bugs Fixes'
labels:
- 'type:fix'
# аналогично для метки type:fix и т.д.
- title: ' Documentation'
labels:
- 'type:documentation'
- title: ' Configuration'
labels:
- 'type:config'
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
template: |
## Changes
$CHANGES
Taslak sürüm oluşturmak için bir komut dosyası ekleyin (.github/workflows/release-draft.yml):
Artık tüm çekme istekleri sürüm notlarında otomatik olarak toplanacak - sihir!
Burada şu soru ortaya çıkabilir: Peki ya geliştiriciler PR'ye etiket koymayı unutursa? O zaman onu hangi kategoriye koyacağınız belli değil ve yine her PR ile ayrı ayrı manuel olarak ilgilenmeniz gerekecek. Bu sorunu çözmek için başka bir eylem (etiket doğrulayıcı) kullanabiliriz; bu, çekme isteğinde etiketlerin varlığını kontrol eder. Gerekli etiket yoksa kontrol başarısız olur ve çekme isteğimizde bununla ilgili bir mesaj görürüz.
Artık herhangi bir çekme isteğinin şu etiketlerden biriyle işaretlenmesi gerekir: type:fix, type:features, type:documentation, type:tests, type:config.
Çekme isteklerine otomatik açıklama ekleme
Çekme istekleriyle etkili çalışma gibi bir konuya değindiğimiz için, etiketleyici gibi bir eylemden bahsetmeye değer, PR'ye hangi dosyaların değiştirildiğine göre etiketler koyar. Örneğin, dizinde değişiklik içeren herhangi bir çekme isteğini [build] olarak işaretleyebiliriz .github/workflow.
Etiketleri çekme isteklerine otomatik olarak yerleştiren eylemi, gerekli etiketlerin varlığını kontrol eden eylemle eşleştirmeyi başaramadım; match-label, bot tarafından eklenen etiketleri görmek istemiyor. Her iki aşamayı birleştiren kendi eyleminizi yazmak daha kolay görünüyor. Ancak bu formda bile kullanımı oldukça uygundur, çekme isteği oluştururken listeden bir etiket seçmeniz gerekir.
Dağıtım zamanı geldi
GitHub Eylemleri aracılığıyla (ssh aracılığıyla, scp yoluyla ve docker-hub kullanarak) çeşitli dağıtım seçeneklerini denedim ve şunu söyleyebilirim ki, boru hattınız ne kadar çarpık olursa olsun, büyük olasılıkla ikili dosyayı sunucuya yüklemenin bir yolunu bulacaksınız. dır-dir.
Tüm altyapıyı tek bir yerde tutma seçeneği hoşuma gitti, bu yüzden GitHub Paketlerine nasıl dağıtım yapılacağına bakalım (bu, ikili içerik, npm, jar, docker için bir depodur).
Liman işçisi görüntüsü oluşturmak ve bunu GitHub Paketlerinde yayınlamak için komut dosyası:
Öncelikle uygulamamızın JAR dosyasını oluşturmamız gerekiyor, ardından GitHub docker kayıt defterinin yolunu ve imajımızın adını hesaplıyoruz. Burada henüz karşılaşmadığımız birkaç püf noktası var:
Şuna benzer bir yapı: echo "::set-output name=NAME::VALUE", geçerli adımdaki bir değişkenin değerini ayarlamanıza olanak tanır, böylece bu değişken daha sonra diğer tüm adımlarda okunabilir.
önceki adımda ayarlanan değişkenin değerini bu adımın tanımlayıcısı aracılığıyla alabilirsiniz: ${{steps.global_env.outputs.DOCKERHUB_IMAGE_NAME }}
Standart GITHUB_REPOSITORY değişkeni, havuzun ve sahibinin adını (“sahip/depo-adı”) saklar. Deponun adı dışındaki her şeyi bu satırdan kesmek için bash sözdizimini kullanacağız: ${GITHUB_REPOSITORY#*/}
Görüntünün sürümünü belirtmek için, taahhüdün SHA karma değerinin ilk rakamlarını kullanırız - GITHUB_SHA, bu tür yapıları yalnızca ana yapıyla birleştirirken değil, aynı zamanda çekme isteği oluşturmaya göre de yaparsanız burada da nüanslar vardır. Bu durumda SHA, git geçmişinde gördüğümüz karmayla eşleşmeyebilir, çünkü eylemler/ödeme eylemi, PR'deki kilitlenme eylemlerini önlemek için kendi benzersiz karma değerini oluşturur.
Her şey yolunda gittiyse, depodaki paketler bölümünü (https://github.com/antkorwin/github-actions/packages) açtığınızda yeni bir liman işçisi görüntüsü göreceksiniz:
Burada ayrıca liman işçisi görüntüsünün sürümlerinin bir listesini de görebilirsiniz.
Geriye kalan tek şey sunucumuzu bu kayıt defteriyle çalışacak şekilde yapılandırmak ve hizmeti yeniden başlatmaktır. Muhtemelen başka bir zaman bunun systemd aracılığıyla nasıl yapılacağından bahsedeceğim.
İzleme
GitHub Eylemlerini kullanarak uygulamamız için sağlık kontrolünün nasıl yapılacağına dair basit bir seçeneğe bakalım. Önyükleme uygulamamızın bir aktüatörü var, dolayısıyla durumunu kontrol etmek için bir API yazmamıza bile gerek yok; tembeller için zaten her şeyi yaptık. Sadece ana bilgisayarı çekmeniz gerekiyor: SERVER-URL:PORT/actuator/health
Tek ihtiyacımız olan, cron kullanarak sunucuyu kontrol etmek için bir görev yazmak ve aniden bize cevap vermezse telgraf yoluyla bir bildirim göndereceğiz.
İlk önce bir cron iş akışının nasıl çalıştırılacağını bulalım:
Sunucu durumunu curl aracılığıyla manuel olarak kontrol edelim:
jobs:
ping:
runs-on: ubuntu-18.04
steps:
- name: curl actuator
id: ping
run: |
echo "::set-output name=status::$(curl ${{secrets.SERVER_HOST}}/api/actuator/health)"
- name: health check
run: |
if [[ ${{ steps.ping.outputs.status }} != *"UP"* ]]; then
echo "health check is failed"
exit 1
fi
echo "It's OK"
Öncelikle sunucunun isteğe verdiği yanıtı bir değişkene kaydediyoruz, sonraki adımda durumun UP olup olmadığını kontrol ediyoruz ve eğer durum böyle değilse hata vererek çıkıyoruz. Bir eylemi ellerinizle "boğmanız" gerekiyorsa, o zaman çıkış 1 - uygun silah.
- name: send alert in telegram
if: ${{ failure() }}
uses: appleboy/telegram-action@master
with:
to: ${{ secrets.TELEGRAM_TO }}
token: ${{ secrets.TELEGRAM_TOKEN }}
message: |
Health check of the:
${{secrets.SERVER_HOST}}/api/actuator/health
failed with the result:
${{ steps.ping.outputs.status }}
Yalnızca eylem önceki adımda başarısız olursa telgrafa göndeririz. Mesaj göndermek için appleboy/telegram-action kullanıyoruz; bot jetonunun ve sohbet kimliğinin nasıl alınacağını belgelerden okuyabilirsiniz: github.com/appleboy/telegram-action
Github'daki sırlara yazmayı unutmayın: Sunucu için URL ve telegram botu için belirteçler.
Bonus parça - Tembeller için JIRA
JIRA'ya döneceğimize söz verdim ve geri döndük. Yüzlerce kez stand-up'larda geliştiricilerin bir özellik yaptığı, bir şubeyi birleştirdiği ancak konuyu JIRA'ya sürüklemeyi unuttuğu bir durum gözlemledim. Elbette tüm bunlar tek bir yerde yapılsaydı daha kolay olurdu ama aslında IDE'ye kod yazıyoruz, dalları bitbucket veya GitHub'a birleştiriyoruz ve ardından görevleri Jira'ya sürüklüyoruz, bunun için yeni pencereler açmamız gerekiyor , bazen tekrar giriş yapın vb. Bundan sonra ne yapmanız gerektiğini tam olarak hatırladığınızda, tahtayı tekrar açmanın bir anlamı kalmaz. Sonuç olarak, sabahları bir stand-up'ta görev panosunu güncellemek için zaman harcamanız gerekir.
GitHub ayrıca bu rutin görevde bize yardımcı olacaktır; yeni başlayanlar için, bir çekme isteği gönderdiğimizde sorunları otomatik olarak code_review sütununa sürükleyebiliriz. Tek yapmanız gereken şube adlandırma kuralını takip etmektir:
[имя проекта]-[номер таска]-название
örneğin, "GitHub Actions" proje anahtarı GA ise, o zaman GA-8-jira-bot GA-8 görevinin uygulanmasına yönelik bir dal olabilir.
JIRA ile entegrasyon Atlassian'ın eylemleriyle çalışıyor, mükemmel değiller, bazılarının bende hiç işe yaramadığını söylemeliyim. Ancak yalnızca kesinlikle işe yarayan ve aktif olarak kullanılanları tartışacağız.
Öncelikle şu eylemi kullanarak JIRA'da oturum açmanız gerekir: atlassian/gajira-login
- name: Find Issue
id: find_issue
shell: bash
run: |
echo "::set-output name=ISSUE_ID::$(echo ${GITHUB_HEAD_REF} | egrep -o 'GA-[0-9]{1,4}')"
echo brach name: $GITHUB_HEAD_REF
echo extracted issue: ${GITHUB_HEAD_REF} | egrep -o 'GA-[0-9]{1,4}'
- name: Check Issue
shell: bash
run: |
if [[ "${{steps.find_issue.outputs.ISSUE_ID}}" == "" ]]; then
echo "Please name your branch according to the JIRA issue: [project_key]-[task_number]-branch_name"
exit 1
fi
echo succcessfully found JIRA issue: ${{steps.find_issue.outputs.ISSUE_ID}}
GitHub pazaryerinde ararsanız bu görev için bir action bulabilirsiniz ancak ben aynı şeyi grep kullanarak şubenin adını kullanarak yazmak zorunda kaldım çünkü Atlassian'dan gelen bu action hiçbir şekilde projem üzerinde çalışmak istemedi , orada neyin yanlış olduğunu anlamak - aynı şeyi ellerinizle yapmaktan daha uzun.
Geriye kalan tek şey, çekme isteği oluştururken görevi "Kod incelemesi" sütununa taşımaktır:
Bunun için GitHub'da özel bir action var, tek ihtiyacı olan bir önceki adımda alınan issue ID ve yukarıda yaptığımız JIRA'daki yetkilendirme.
Aynı şekilde, ana öğeye birleştirirken görevleri ve GitHub iş akışındaki diğer olayları da sürükleyebilirsiniz. Genel olarak her şey hayal gücünüze ve rutin süreçleri otomatikleştirme arzunuza bağlıdır.
Bulgular
Klasik DEVOPS diyagramına bakarsanız, belki de çalıştırma dışında tüm aşamaları ele aldık, sanırım denerseniz, yardım masası sistemiyle entegrasyon için piyasada bazı eylemler bulabilirsiniz, bu nedenle boru hattının döndüğünü varsayacağız. kapsamlı olması gerekir ve kullanımına bağlı olarak sonuçlar çıkarılabilir.
Artıları:
Her duruma uygun hazır eylemlerin bulunduğu pazar yeri, bu çok hoş. Çoğunda, benzer bir sorunun nasıl çözüleceğini anlamak için kaynak koduna da bakabilir veya doğrudan GitHub deposunda yazara bir özellik isteği gönderebilirsiniz.
Montaj için hedef platformun seçilmesi: Linux, mac os, windows oldukça ilginç bir özellik.
Github Paketleri harika bir şey, tüm altyapıyı tek bir yerde tutmak kullanışlıdır, farklı pencerelerde gezinmenize gerek yoktur, her şey bir veya iki fare tıklaması yarıçapındadır ve GitHub Eylemleri ile mükemmel bir şekilde entegre edilmiştir. Ücretsiz sürümdeki Docker kayıt defteri desteği de iyi bir avantajdır.
GitHub, derleme günlüklerindeki sırları gizler, bu nedenle onu şifreleri ve belirteçleri depolamak için kullanmak o kadar da korkutucu değildir. Tüm deneylerim sırasında, sırrı konsolda hiçbir zaman saf haliyle göremedim.
Açık Kaynak projeleri için ücretsiz
Eksileri:
YML, onu sevmiyorum. Böyle bir akışla çalışırken karşılaştığım en yaygın taahhüt mesajı "yml formatını düzelt" oluyor, sonra bir yere sekme koymayı unutuyorsunuz veya yanlış satıra yazıyorsunuz. Genel olarak, bir iletki ve cetvelle ekranın önünde oturmak pek hoş bir deneyim değildir.
DEBUG, taahhütlerle akışta hata ayıklamak, yeniden oluşturmayı çalıştırmak ve konsola çıktı almak her zaman uygun değildir, ancak bu daha çok "fazla abartıldınız" kategorisine benzer; herhangi bir şeyde hata ayıklayabildiğiniz zaman kullanışlı IDEA ile çalışmaya alışkınsınız .
Docker'a sararsanız herhangi bir şeyin üzerine eyleminizi yazabilirsiniz, ancak yalnızca javascript native olarak desteklenir, elbette bu bir zevk meselesi, ancak js yerine başka bir şeyi tercih ederim.
Gelecek hafta birlikte performans sergileyeceğim rapor Heisenbug 2020 Piter konferansında. Size yalnızca test verilerini hazırlarken hatalardan nasıl kaçınabileceğinizi anlatmakla kalmayıp, aynı zamanda Java uygulamalarındaki veri kümeleriyle çalışmanın sırlarını da paylaşacağım!