ProHoster > Bloc > Administració > Cercles de l'infern amb GitHub Actions (creació d'un pipeline CI/CD per a un projecte Java)
Cercles de l'infern amb GitHub Actions (creació d'un pipeline CI/CD per a un projecte Java)
Sovint he de construir un pipeline per construir projectes a Java. De vegades és de codi obert, de vegades no. Recentment he decidit provar de moure alguns dels meus dipòsits de Travis-CI i TeamCity a GitHub Actions, i això és el que en va sortir.
Què automatitzarem?
Primer, necessitem un projecte que automatitzarem, fem una petita aplicació a Spring boot / Java 11 / Maven. Als efectes d'aquest article, no ens interessarà gens la lògica de l'aplicació; la infraestructura al voltant de l'aplicació és important per a nosaltres, de manera que ens serà suficient un simple controlador d'API REST.
Podeu consultar les fonts aquí: github.com/antkorwin/github-actions Totes les etapes de la construcció d'un gasoducte es reflecteixen a les sol·licituds d'extracció d'aquest projecte.
JIRA i planificació
Val la pena dir que normalment utilitzem JIRA com a rastrejador de problemes, així que creem un tauler separat per a aquest projecte i afegim els primers problemes allà:
Una mica més tard tornarem a quines coses interessants poden oferir JIRA i GitHub en combinació.
Automatitzem el muntatge del projecte
El nostre projecte de prova es construeix a través de Maven, de manera que construir-lo és bastant senzill, tot el que necessitem és el paquet mvn clean.
Per fer-ho utilitzant Github Actions, haurem de crear un fitxer al repositori que descrigui el nostre flux de treball, això es pot fer amb un fitxer yml normal, no puc dir que m'agrada "programar yml", però què podem fer - ho fem al directori .github/ workflow/ file build.yml en el qual descriurem les accions a l'hora de construir la branca mestra:
on — Aquesta és una descripció de l'esdeveniment en què es llançarà el nostre guió.
a: pull_request/push — indica que aquest flux de treball s'ha de llançar cada vegada que es fa una empenta al mestre i es creen sol·licituds d'extracció.
A continuació es mostra una descripció de les tasques (llocs de treball) i passos d'execució (passos) per a cada tasca.
s'executa - Aquí podem seleccionar el sistema operatiu objectiu, sorprenentment, fins i tot podeu triar Mac OS, però als dipòsits privats això és bastant car (en comparació amb Linux).
utilitza us permet reutilitzar altres accions, per exemple, utilitzant l'acció actions/setup-java que instal·lem l'entorn per a Java 11.
Mitjançant amb podem especificar els paràmetres amb els quals engeguem l'acció, bàsicament aquests són els arguments que es passaran a l'acció.
Només queda executar la construcció del projecte a Maven: run: mvn -B clean package bandera -B diu que necessitem un mode no interactiu perquè l'expert de sobte no ens vulgui preguntar res
Genial! Ara, cada vegada que us comprometeu amb el mestre, comença la construcció del projecte.
Automatització dels llançaments de proves
El muntatge és bo, però en realitat, un projecte es pot muntar amb seguretat, però no funciona. Per tant, el següent pas és automatitzar les proves. A més, és bastant convenient mirar els resultats de la superació de les proves quan feu una revisió de relacions públiques: sabeu del cert que les proves passen i ningú s'ha oblidat d'executar la seva branca abans de fer una fusió.
Farem proves quan creem una sol·licitud d'extracció i fusionarem amb el mestre, i al mateix temps afegirem la creació d'un informe sobre la cobertura del codi.
Per cobrir les proves, faig servir codecov juntament amb el connector jacoco. codecov té la seva pròpia acció, però necessita un testimoni per treballar amb la nostra sol·licitud d'extracció:
${{ secrets.CODECOV_TOKEN }} — Veurem aquesta construcció més d'una vegada, secrets és un mecanisme per emmagatzemar secrets a GitHub, hi podem escriure contrasenyes/tokens/hosts/urls i altres dades que no s'han d'incloure al codi base del repositori.
Podeu afegir una variable als secrets a la configuració del repositori a GitHub:
Podeu obtenir un testimoni a codecov.io Després de l'autorització mitjançant GitHub, per afegir un projecte públic només cal que seguiu un enllaç com aquest: Nom d'usuari de GitHub/[nom del repositori]. També es pot afegir un repositori privat; per fer-ho, heu de donar drets de codecov a l'aplicació a Github.
Ara el bot codecov introduirà cadascuna de les nostres sol·licituds d'extracció i afegirà un gràfic de canvi de cobertura:
Afegim un analitzador estàtic
En la majoria dels meus projectes de codi obert faig servir el núvol de sonar per a l'anàlisi de codi estàtic, és bastant fàcil connectar-se a travis-ci. Per tant, és un pas lògic quan es migra a GitHub Actions per fer el mateix. El mercat d'acció és una cosa genial, però aquesta vegada em va decepcionar una mica, perquè per costum vaig trobar l'acció que necessitava i la vaig afegir al flux de treball. Però va resultar que el sonar no admet treballar mitjançant una acció per analitzar projectes a maven o gradle. Això sí, això està escrit a la documentació, però qui ho llegeix?!
No és possible mitjançant una acció, així que ho farem mitjançant el connector mvn:
SONAR_TOKEN - es pot obtenir a sonarcloud.io i cal registrar-lo en secret. GITHUB_TOKEN - aquest és un testimoni integrat que genera GitHub, amb l'ajuda del qual sonarcloud[bot] podrà iniciar sessió a Git per deixar-nos missatges a les sol·licituds d'extracció.
Dsonar.projectKey — el nom del projecte al sonar, el podeu veure a la configuració del projecte.
Dsonar.organització — nom de l'organització de GitHub.
Fem una sol·licitud d'extracció i esperem que arribi sonarcloud[bot] als comentaris:
Gestió de llançaments
S'ha configurat la compilació, s'han executat les proves i podem fer un llançament. Vegem com GitHub Actions pot fer que la gestió de llançaments sigui molt més fàcil.
A la feina, tinc projectes el codi base dels quals es troba a bitbucket (tot és com en aquella història "Escric a bitbucket durant el dia, em comprometo a GitHub a la nit"). Malauradament, bitbucket no té eines de gestió de llançaments integrades. Això és un problema, perquè per a cada llançament has de crear manualment una pàgina en confluència i llençar-hi totes les característiques incloses en el llançament, buscar pels palaus de la ment, tasques a jira, commits al repositori. Hi ha moltes possibilitats d'equivocar-se, podeu oblidar alguna cosa o introduir alguna cosa que ja es va publicar l'última vegada, de vegades simplement no està clar com cal classificar una sol·licitud d'extracció: és una característica o una correcció d'errors, o proves d'edició, o quelcom d'infraestructura.
Com ens poden ajudar les accions de GitHub? Hi ha una gran acció: el redactor de la versió, us permet establir una plantilla de fitxer de notes de llançament per configurar categories de sol·licituds d'extracció i agrupar-les automàticament al fitxer de notes de la versió:
Exemple de plantilla per configurar un informe (.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
Afegiu un script per generar un esborrany de llançament (.github/workflows/release-draft.yml):
Totes les sol·licituds d'extracció a partir d'ara es recolliran automàticament a les notes de la versió: màgia!
Aquí pot sorgir la pregunta: què passa si els desenvolupadors s'obliden de posar etiquetes al PR? Aleshores, no està clar en quina categoria posar-lo, i de nou l'hauràs de tractar manualment, amb cada PR per separat. Per solucionar aquest problema, podem utilitzar una altra acció, el verificador d'etiquetes, que comprova la presència d'etiquetes a la sol·licitud d'extracció. Si no hi ha etiquetes necessàries, la comprovació fallarà i veurem un missatge sobre això a la nostra sol·licitud d'extracció.
Ara qualsevol sol·licitud d'extracció s'ha de marcar amb una de les etiquetes: type:fix, type:features, type:documentation, type:tests, type:config.
Anotació automàtica de les sol·licituds d'extracció
Com que vam tocar un tema com el treball eficaç amb les sol·licituds d'extracció, val la pena parlar d'una acció com l'etiquetador, posa etiquetes a PR en funció dels fitxers que s'han canviat. Per exemple, podem marcar com a [build] qualsevol sol·licitud d'extracció que contingui canvis al directori .github/workflow.
No he aconseguit emparellar l'acció que col·loca automàticament etiquetes a les sol·licituds d'extracció amb l'acció que verifica la presència d'etiquetes necessàries; match-label no vol veure les etiquetes afegides pel bot. Sembla més fàcil escriure la teva pròpia acció que combini ambdues etapes. Però fins i tot en aquest formulari és bastant còmode d'utilitzar; heu de seleccionar una etiqueta de la llista quan creeu una sol·licitud d'extracció.
És hora de desplegar
Vaig provar diverses opcions de desplegament mitjançant accions de GitHub (mitjançant ssh, via scp i utilitzant docker-hub), i puc dir que, molt probablement, trobareu una manera de pujar el binari al servidor, per molt que sigui el vostre pipeline. és.
Em va agradar l'opció de mantenir tota la infraestructura en un sol lloc, així que mirem com implementar-los als paquets GitHub (aquest és un repositori de contingut binari, npm, jar, docker).
Script per crear una imatge Docker i publicar-la als paquets GitHub:
En primer lloc, hem de crear el fitxer JAR de la nostra aplicació, després del qual calculem el camí al registre docker de GitHub i el nom de la nostra imatge. Hi ha alguns trucs aquí que encara no hem trobat:
una construcció com: echo “::set-output name=NAME::VALUE” us permet establir el valor d'una variable en el pas actual, de manera que es pugui llegir en tots els altres passos.
podeu obtenir el valor de la variable establerta al pas anterior mitjançant l'identificador d'aquest pas: ${{ steps.global_env.outputs.DOCKERHUB_IMAGE_NAME }}
La variable estàndard GITHUB_REPOSITORY emmagatzema el nom del dipòsit i el seu propietari ("propietari/nom-repositori"). Per tal de tallar-ho tot d'aquesta línia excepte el nom del dipòsit, utilitzarem la sintaxi bash: ${GITHUB_REPOSITORY#*/}
A continuació, hem de construir la imatge de Docker:
Per indicar la versió de la imatge, utilitzem els primers dígits del hash SHA del commit - GITHUB_SHA també hi ha matisos aquí, si feu aquestes compilacions no només quan us fusioneu amb el mestre, sinó també segons la creació de la sol·licitud d'extracció. esdeveniment, és possible que SHA no coincideixi amb el hash que veiem a l'historial de git, perquè l'acció d'accions/checkout fa el seu propi hash únic per evitar accions de bloqueig al PR.
Si tot va funcionar bé, obrint la secció de paquets (https://github.com/antkorwin/github-actions/packages) al repositori, veureu una nova imatge de Docker:
Allà també podeu veure una llista de versions de la imatge de Docker.
Només queda configurar el nostre servidor perquè funcioni amb aquest registre i reiniciar el servei. Probablement parlaré de com fer-ho mitjançant systemd una altra vegada.
Seguiment
Vegem una opció senzilla sobre com fer una comprovació de salut de la nostra aplicació mitjançant GitHub Actions. La nostra aplicació d'arrencada té un actuador, de manera que ni tan sols necessitem escriure una API per comprovar-ne l'estat; ja ho hem fet tot per als ganduls. Només heu de treure l'amfitrió: SERVER-URL:PORT/actuator/health
Tot el que necessitem és escriure una tasca per comprovar el servidor mitjançant cron, i si de sobte no ens respon, enviarem una notificació via telegrama.
Primer, anem a esbrinar com executar un flux de treball cron:
Comprovem l'estat del servidor manualment mitjançant curl:
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"
Primer, guardem en una variable el que el servidor ha respost a la sol·licitud, en el següent pas comprovem que l'estat és ACTIU i, si no és així, sortim amb un error. Si necessiteu "aclaparar" una acció amb les mans, aleshores exit 1 - arma adequada.
- 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 }}
Enviem a telegrama només si l'acció ha fallat al pas anterior. Per enviar un missatge fem servir appleboy/telegram-action; podeu llegir com obtenir un testimoni de bot i un identificador de xat a la documentació: github.com/appleboy/telegram-action
No us oblideu d'escriure els secrets a Github: URL per al servidor i fitxes per al bot de telegram.
Bonus track - JIRA per als ganduls
Vaig prometre que tornaríem a JIRA i hem tornat. Centenars de vegades he observat una situació als stand-ups quan els desenvolupadors van crear una funció, van fusionar una branca, però vaig oblidar arrossegar el problema a JIRA. Per descomptat, si tot això es fes en un sol lloc, seria més fàcil, però de fet escrivim codi a l'IDE, fusionem branques a bitbucket o GitHub i després arrossegueu les tasques a Jira, per a això hem d'obrir noves finestres. , de vegades torneu a iniciar sessió i etc. Quan recordeu perfectament què heu de fer a continuació, no té sentit tornar a obrir el tauler. Com a resultat, al matí en un standup cal dedicar temps a actualitzar el tauler de tasques.
GitHub també ens ajudarà en aquesta tasca rutinària; per començar, podem arrossegar els problemes automàticament a la columna code_review quan enviem una sol·licitud d'extracció. Tot el que heu de fer és seguir la convenció de nomenclatura de branques:
[имя проекта]-[номер таска]-название
per exemple, si la clau del projecte "Accions de GitHub" és GA, aleshores GA-8-jira-bot podria ser una branca per implementar la tasca GA-8.
La integració amb JIRA funciona a través d'accions d'Atlassian, no són perfectes, he de dir que algunes d'elles no m'han funcionat gens. Però només parlarem d'aquells que funcionen definitivament i s'utilitzen activament.
Primer heu d'iniciar sessió a JIRA amb l'acció: atlassian/gajira-login
Extraïm l'identificador de la tasca del nom de la branca:
- 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}}
Si cerqueu al mercat de GitHub, podeu trobar una acció per a aquesta tasca, però vaig haver d'escriure el mateix amb grep amb el nom de la branca, perquè aquesta acció d'Atlassian no volia treballar en el meu projecte de cap manera. , per esbrinar què passava allà, més que fer el mateix amb les mans.
Només queda moure la tasca a la columna "Revisió del codi" quan es crea una sol·licitud d'extracció:
Hi ha una acció especial per a això a GitHub, tot el que necessita és l'ID del problema obtingut al pas anterior i l'autorització a JIRA que hem fet anteriorment.
De la mateixa manera, podeu arrossegar tasques quan us fusioneu al mestre i altres esdeveniments del flux de treball de GitHub. En general, tot depèn de la teva imaginació i ganes d'automatitzar processos rutinaris.
Troballes
Si mireu el diagrama DEVOPS clàssic, hem cobert totes les etapes, excepte potser operar, crec que si ho proveu, podeu trobar alguna acció al mercat per a la integració amb el sistema d'assistència, així que suposarem que el pipeline va girar. que sigui exhaustiu i es puguin extreure conclusions basades en el seu ús.
Pros:
Mercat amb accions preparades per a totes les ocasions, això és molt xulo. En la majoria d'ells, també podeu mirar el codi font per entendre com resoldre un problema similar o publicar una sol·licitud de funció a l'autor directament al repositori de GitHub.
La selecció de la plataforma objectiu per al muntatge: Linux, mac os, windows és una característica força interessant.
Github Packages és una cosa fantàstica, és convenient mantenir tota la infraestructura en un sol lloc, no cal navegar per diferents finestres, tot està en un radi d'un o dos clics del ratolí i està perfectament integrat amb GitHub Actions. El suport del registre de Docker a la versió gratuïta també és un bon avantatge.
GitHub amaga secrets als registres de compilació, de manera que utilitzar-lo per emmagatzemar contrasenyes i fitxes no fa tanta por. Durant tots els meus experiments, mai vaig poder veure el secret en la seva forma pura a la consola.
Gratuït per a projectes de codi obert
Contres:
YML, bé, no m'agrada. Quan treballo amb aquest flux, el missatge de confirmació més comú que tinc és "fixar el format yml", de vegades t'oblides de posar una pestanya en algun lloc, de vegades l'escrius a la línia equivocada. En general, asseure's davant d'una pantalla amb un transportador i un regle no és l'experiència més agradable.
DEBUG, depurar el flux amb commits, executar una reconstrucció i sortir a la consola no sempre és convenient, però és més de la categoria "estàs exagerat"; estàs acostumat a treballar amb IDEA convenient, quan pots depurar qualsevol cosa. .
Podeu escriure la vostra acció en qualsevol cosa si l'emboliqueu a Docker, però només s'admet javascript de manera nativa, és clar que això és una qüestió de gustos, però preferiria una altra cosa en lloc de js.
La setmana vinent actuaré amb informe a la conferència Heisenbug 2020 Piter. Us explicaré no només com evitar errors en preparar les dades de prova, sinó que també compartiré els meus secrets per treballar amb conjunts de dades en aplicacions Java!