ProHoster > Blog > Uprava > Peklenski krogi z GitHub Actions (gradnja cevovoda CI/CD za projekt Java)
Peklenski krogi z GitHub Actions (gradnja cevovoda CI/CD za projekt Java)
Pogosto moram zgraditi cevovod za gradnjo projektov v Javi. Včasih je odprtokoden, včasih ne. Nedavno sem se odločil, da poskusim premakniti nekaj svojih skladišč iz Travis-CI in TeamCity v GitHub Actions, in to je tisto, kar je nastalo.
Kaj bomo avtomatizirali?
Najprej potrebujemo projekt, ki ga bomo avtomatizirali, naredimo majhno aplikacijo v Spring boot / Java 11 / Maven. Za namene tega članka nas logika aplikacije sploh ne bo zanimala, pomembna nam je infrastruktura okoli aplikacije, zato nam bo zadostoval preprost REST API krmilnik.
Vredno je povedati, da običajno uporabljamo JIRA kot sledilnik težav, zato ustvarimo ločeno tablo za ta projekt in vanjo dodamo prve težave:
Malo kasneje se bomo vrnili k zanimivostim, ki jih lahko ponudita JIRA in GitHub v kombinaciji.
Avtomatiziramo montažo projekta
Naš testni projekt je zgrajen prek maven, zato je njegova izdelava precej preprosta, vse kar potrebujemo je paket mvn clean.
Če želite to narediti z uporabo Github Actions, bomo morali ustvariti datoteko v repozitoriju, ki opisuje naš potek dela, to je mogoče storiti z običajno datoteko yml, ne morem reči, da mi je všeč "programiranje yml", ampak kaj lahko storimo - naredimo v datoteki .github/ imenik workflow/ build.yml, v kateri bomo opisali dejanja pri gradnji glavne veje:
on — to je opis dogodka, na katerem bo zagnan naš skript.
na: pull_request/push — označuje, da je treba ta delovni tok zagnati vsakič, ko je na glavni strani izveden pritisk in so ustvarjene zahteve za vlečenje.
Sledi opis nalog (delovna mesta) in koraki izvedbe (koraki) za vsako nalogo.
nalet - tukaj lahko izberemo ciljni OS, presenetljivo lahko izberete celo Mac OS, vendar je to na zasebnih repozitorijih precej drago (v primerjavi z Linuxom).
uporablja vam omogoča, da ponovno uporabite druga dejanja, na primer z uporabo dejanja actions/setup-java namestimo okolje za Javo 11.
S z lahko določimo parametre, s katerimi zaženemo dejanje, v bistvu so to argumenti, ki bodo posredovani dejanju.
Vse, kar ostane, je zagnati gradnjo projekta z Mavenom: run: mvn -B clean package zastava -B pravi, da potrebujemo neinteraktiven način, da nas maven nenadoma noče nekaj vprašati
Super! Zdaj se vsakič, ko se zavežete masterju, začne gradnja projekta.
Avtomatizacija testnih zagonov
Montaža je dobra, a v resnici se lahko projekt varno sestavi, ne pa tudi deluje. Zato je naslednji korak avtomatizacija testnih voženj. Poleg tega je zelo priročno pogledati rezultate opravljenih testov, ko opravite pregled PR - zagotovo veste, da so testi uspešni in nihče ni pozabil zagnati svoje veje, preden je izvedel združitev.
Teste bomo izvajali pri kreiranju pull request-a in se zlivali v master, hkrati pa bomo dodali izdelavo poročila o pokritosti kode.
Za pokrivanje testov uporabljam codecov v povezavi z vtičnikom jacoco. codecov ima lastno dejanje, vendar potrebuje žeton, da deluje z našo zahtevo po vleku:
${{ secrets.CODECOV_TOKEN }} — to konstrukcijo bomo videli več kot enkrat, secrets je mehanizem za shranjevanje skrivnosti v GitHub, tja lahko zapišemo gesla/žetone/gostitelje/url-je in druge podatke, ki ne smejo biti vključeni v bazo kode repozitorija.
Skrivnostim lahko dodate spremenljivko v nastavitvah repozitorija na GitHubu:
Žeton lahko dobite na codecov.io Po avtorizaciji prek GitHub morate za dodajanje javnega projekta samo slediti povezavi, kot je ta: Uporabniško ime GitHub/[ime skladišča]. Dodate lahko tudi zasebno skladišče; za to morate aplikaciji v Githubu dati pravice kodiranja.
Zdaj bo bot codecov vnesel vsako od naših zahtev za vlečenje in dodal graf spremembe pokritosti:
Dodajmo statični analizator
V večini svojih odprtokodnih projektov uporabljam sonar oblak za analizo statične kode, povezati se s travis-ci je zelo enostavno. Zato je pri selitvi na GitHub Actions logičen korak storiti enako. Akcijski trg je kul zadeva, ampak tokrat me je malo razočaral, ker sem iz navade našel akcijo, ki sem jo potreboval, in jo dodal v potek dela. Izkazalo pa se je, da sonar ne podpira dela prek akcije za analizo projektov na maven ali gradle. Seveda to piše v dokumentaciji, le kdo to bere?!
To ni mogoče prek akcije, zato bomo to storili prek vtičnika mvn:
SONAR_TOKEN - dobite na sonarcloud.io in ga morate registrirati v skrivnostih. GITHUB_TOKEN - to je vgrajeni žeton, ki ga generira GitHub, s pomočjo katerega se bo sonarcloud[bot] lahko prijavil v Git, da bi nam pustil sporočila v vlečnih zahtevah.
Dsonar.projectKey — ime projekta v sonarju, lahko ga vidite v nastavitvah projekta.
Dsonar.organizacija — ime organizacije iz GitHub.
Naredimo zahtevo za vlečenje in počakamo, da se sonarcloud[bot] oglasi v komentarjih:
Upravljanje s sprostitvijo
Zgradba je bila konfigurirana, testi so bili izvedeni in lahko izdamo. Poglejmo, kako lahko GitHub Actions močno olajša upravljanje izdaj.
V službi imam projekte, katerih kodna baza je v bitbucketu (vse je kot v tisti zgodbi »podnevi pišem v bitbucket, ponoči se zavežem GitHubu«). Na žalost bitbucket nima vgrajenih orodij za upravljanje izdaj. To je težava, ker morate za vsako izdajo ročno ustvariti stran v sotočju in tja vreči vse funkcije, ki so vključene v izdajo, iskati po palačah uma, opravilih v jiri, zavezah v repozitoriju. Možnosti za napako je veliko, lahko kaj pozabite ali vnesete nekaj, kar je bilo že objavljeno zadnjič, včasih enostavno ni jasno, v kaj uvrstiti zahtevo po vleku – ali je funkcija ali popravek napake, ali testi urejanja, oz. nekaj infrastrukturnega.
Kako nam lahko GitHub dejanja pomagajo? Obstaja odlična akcija - osnutek izdaje, ki vam omogoča, da nastavite predlogo datoteke z opombami ob izdaji, da nastavite kategorije zahtev za vlečenje in jih samodejno združite v datoteko z opombami ob izdaji:
Primer predloge za nastavitev poročila (.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
Dodajte skript za ustvarjanje osnutka izdaje (.github/workflows/release-draft.yml):
Vse zahteve za vlečenje bodo od zdaj naprej samodejno zbrane v opombah ob izdaji - čarobno!
Tukaj se lahko pojavi vprašanje: kaj če razvijalci pozabijo vstaviti oznake v PR? Potem ni jasno, v katero kategorijo ga uvrstiti, in spet se boste morali ukvarjati ročno, z vsakim PR posebej. Za odpravo te težave lahko uporabimo drugo dejanje - preverjanje oznak - preveri prisotnost oznak na zahtevi za vlečenje. Če zahtevanih oznak ni, preverjanje ne bo uspelo in v naši zahtevi za vlečenje bomo videli sporočilo o tem.
Zdaj mora biti vsaka zahteva za vlečenje označena z eno od oznak: type:fix, type:features, type:documentation, type:tests, type:config.
Samodejno označevanje zahtev za vlečenje
Ker smo se dotaknili takšne teme, kot je učinkovito delo z zahtevami za vleko, je vredno govoriti o takem dejanju, kot je oznaka, v PR postavlja oznake glede na to, katere datoteke so bile spremenjene. Kot [build] lahko na primer označimo vsako zahtevo za vleko, ki vsebuje spremembe v imeniku .github/workflow.
Ni mi uspelo združiti dejanja, ki samodejno postavlja oznake v zahteve po vleku, z dejanjem, ki preverja prisotnost zahtevanih oznak; match-label ne želi videti oznak, ki jih je dodal bot. Zdi se, da je lažje napisati lastno dejanje, ki združuje obe stopnji. Toda tudi v tej obliki je uporaba zelo priročna, pri ustvarjanju zahteve za vlečenje morate izbrati oznako s seznama.
Čas je za razporeditev
Preizkusil sem več možnosti uvajanja prek GitHub Actions (prek ssh, prek scp in z uporabo docker-hub) in lahko rečem, da boste najverjetneje našli način za nalaganje binarne datoteke v strežnik, ne glede na to, kako ukrivljen je vaš cevovod je.
Všeč mi je bila možnost ohranjanja celotne infrastrukture na enem mestu, zato si poglejmo, kako namestiti v pakete GitHub (to je repozitorij za binarno vsebino, npm, jar, docker).
Skript za izdelavo docker slike in njeno objavo v paketih GitHub:
Najprej moramo sestaviti datoteko JAR naše aplikacije, nato pa izračunamo pot do registra dockerjev GitHub in ime naše slike. Tukaj je nekaj trikov, na katere še nismo naleteli:
konstrukcija, kot je: echo “::set-output name=NAME::VALUE” vam omogoča, da nastavite vrednost spremenljivke v trenutnem koraku, tako da jo je nato mogoče brati v vseh drugih korakih.
lahko dobite vrednost spremenljivke, nastavljene v prejšnjem koraku, prek identifikatorja tega koraka: ${{ steps.global_env.outputs.DOCKERHUB_IMAGE_NAME }}
Standardna spremenljivka GITHUB_REPOSITORY shrani ime repozitorija in njegovega lastnika (»lastnik/ime-repoja«). Da bi iz te vrstice izrezali vse razen imena repozitorija, bomo uporabili sintakso bash: ${GITHUB_REPOSITORY#*/}
Za označevanje različice slike uporabljamo prve števke iz zgoščene vrednosti SHA objave - GITHUB_SHA, tukaj so tudi nianse, če takšne gradnje naredite ne samo pri združevanju v master, ampak tudi glede na ustvarjanje zahteve za vlečenje dogodka, se SHA morda ne bo ujemal z zgoščeno vrednostjo, ki jo vidimo v zgodovini git, ker dejanje dejanja/odjave naredi lastno edinstveno zgoščeno vrednost, da se izognemo dejanjem zastoja v PR.
Če je vse potekalo dobro, potem odprete razdelek s paketi (https://github.com/antkorwin/github-actions/packages) v skladišču in boste videli novo sliko dockerja:
Tam lahko vidite tudi seznam različic docker slike.
Vse kar ostane je, da konfiguriramo naš strežnik za delo s tem registrom in znova zaženemo storitev. O tem, kako to narediti prek systemd, bom verjetno govoril kdaj drugič.
Spremljanje
Oglejmo si preprosto možnost, kako s pomočjo GitHub Actions opraviti pregled zdravja naše aplikacije. Naša zagonska aplikacija ima aktuator, zato nam sploh ni treba napisati API-ja za preverjanje njenega statusa; naredili smo že vse za lene. Samo potegniti morate gostitelja: SERVER-URL:PORT/actuator/health
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"
Najprej v spremenljivko shranimo, kaj nam je strežnik odgovoril na zahtevo, v naslednjem koraku preverimo, ali je status UP in če temu ni tako, izstopimo z napako. Če morate dejanje »prevladati« z rokami, potem izhod 1 - primerno orožje.
- 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 }}
V telegram pošljemo samo, če dejanje v prejšnjem koraku ni uspelo. Za pošiljanje sporočil uporabljamo appleboy/telegram-action; o tem, kako pridobiti žeton bota in ID klepeta, lahko preberete v dokumentaciji: github.com/appleboy/telegram-action
Ne pozabite zapisati v skrivnosti na Githubu: URL za strežnik in žetone za telegram bot.
Bonus skladba - JIRA za lene
Obljubil sem, da se bomo vrnili na JIRA, in vrnili smo se. Na stotine krat sem opazil situacijo na stand-upih, ko so razvijalci naredili funkcijo, združili vejo, a pozabili povleči zadevo v JIRA. Seveda, če bi vse to naredili na enem mestu, bi bilo lažje, a dejansko pišemo kodo v IDE, združimo veje v bitbucket ali GitHub in nato povlečemo naloge v Jira, za to moramo odpreti nova okna , včasih se znova prijavite itd. Ko se popolnoma spomnite, kaj morate narediti naslednje, potem nima smisla znova odpirati table. Posledično morate zjutraj ob standupu porabiti čas za posodabljanje plošče opravil.
GitHub nam bo pomagal tudi pri tej rutinski nalogi; za začetek lahko težave samodejno povlečemo v stolpec code_review, ko oddamo zahtevo za vleko. Vse kar morate storiti je, da sledite konvenciji o poimenovanju vej:
[имя проекта]-[номер таска]-название
na primer, če je ključ projekta "GitHub Actions" GA, potem GA-8-jira-bot bi lahko bila veja za izvajanje naloge GA-8.
Integracija z JIRA deluje preko akcij iz Atlassiana, niso popolne, moram reči, da mi nekatere sploh niso delovale. Vendar bomo razpravljali le o tistih, ki zagotovo delujejo in se aktivno uporabljajo.
Najprej se morate prijaviti v JIRA z dejanjem: 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}}
Če iščete na tržnici GitHub, lahko najdete dejanje za to nalogo, vendar sem moral napisati isto stvar z uporabo grep z imenom veje, ker to dejanje iz Atlassiana nikakor ni želelo delovati na mojem projektu , da bi ugotovili, kaj je bilo tam narobe - dlje, kot če bi isto stvar počeli z rokami.
Vse, kar ostane, je, da nalogo premaknete v stolpec »Pregled kode«, ko ustvarjate zahtevo za vlečenje:
Za to obstaja posebno dejanje na GitHubu, vse, kar potrebuje, je ID težave, pridobljen v prejšnjem koraku, in avtorizacija v JIRA, ki smo jo naredili zgoraj.
Na enak način lahko povlečete naloge pri združevanju v glavni del in druge dogodke iz delovnega toka GitHub. Na splošno je vse odvisno od vaše domišljije in želje po avtomatizaciji rutinskih procesov.
Ugotovitve
Če pogledate klasični diagram DEVOPS, smo pokrili vse stopnje, razen morda operacije, mislim, da če poskusite, lahko na trgu najdete nekaj dejanj za integracijo s sistemom službe za pomoč uporabnikom, tako da bomo domnevali, da se je cevovod obrnil temeljito in na podlagi njegove uporabe je mogoče sklepati.
Profesionalci:
Tržnica z že pripravljenimi akcijami za vse priložnosti, to je zelo kul. Pri večini od njih si lahko ogledate tudi izvorno kodo, da razumete, kako rešiti podoben problem, ali objavite zahtevo za funkcijo avtorju neposredno v repozitoriju GitHub.
Izbira ciljne platforme za sestavljanje: Linux, mac os, windows je precej zanimiva funkcija.
Github Packages je odlična stvar, priročno je, da celotno infrastrukturo obdržite na enem mestu, ni vam treba brskati po različnih oknih, vse je v radiju enega ali dveh klikov miške in je popolnoma integrirano z GitHub Actions. Dobra prednost je tudi podpora registra Docker v brezplačni različici.
GitHub skriva skrivnosti v dnevnikih gradnje, zato njegova uporaba za shranjevanje gesel in žetonov ni tako strašljiva. Med vsemi mojimi poskusi nikoli nisem mogel videti skrivnosti v njeni čisti obliki v konzoli.
Brezplačno za odprtokodne projekte
Cons:
YML, no, ne maram ga. Ko delam s takšnim tokom, je najpogostejše sporočilo o objavi, ki ga imam, »popravi format yml«, potem pozabiš nekam postaviti zavihek ali pa ga napišeš v napačno vrstico. Na splošno sedenje pred ekranom s kotomerom in ravnilom ni najbolj prijetna izkušnja.
DEBUG, razhroščevanje toka s potrditvami, zagon vnovične gradnje in izpisovanje na konzolo ni vedno priročno, vendar je bolj v kategoriji »pretiraval si«; navajeni ste delati s priročno IDEA, ko lahko razhroščite karkoli .
Svoje dejanje lahko napišete na karkoli, če ga zavijete v Docker, vendar je izvorno podprt samo javascript, seveda je to stvar okusa, vendar bi raje kaj drugega namesto js.
Naslednji teden bom nastopal s poročilo na konferenci Heisenbug 2020 Piter. Povedal vam bom ne le, kako se izogniti napakam pri pripravi testnih podatkov, ampak tudi deliti svoje skrivnosti dela z nizi podatkov v aplikacijah Java!