Metode kontinualne integracije – Jenkins
Sadržaj
Šta je kontinualna integracija?
Kontinualna integracija je praksa u softverskom inžinjeringu u kojoj se teži ka tome da se male izmene u kodu integrišu u repozitorijum često u cilju ranog otkrivanja grešaka i bržeg razvoja.
Tradicionalni pristup
Kod tradicionalnog pristupa razvoju softvera, velike celine se razvijaju odvojeno. Iako unit
testovi, odnosno testovi tih celina pokazuju da kod dobro funkcioniše, prilikom integracije može doći do grešaka. Ispravljanje tih grešaka može trajati veoma dugo i dovesti do probijanja rokova i dodatnih troškova.
Ukoliko svako radi na svom delu koda duže vreme, povećava se verovatnoća da će doći do konflikta. Ako ima puno koda, potrošiće se i mnogo vremena na sređivanje konflikta.
Prednosti kontinualne integracije
Zbog navedenih mana tradicionalnog pristupa, bitno je da izmene koje se dodaju budu male. Ovako se štedi vreme i brže se može nastaviti sa radom.
Ako pretpostavimo da postoje testovi za prethodno napisan kod, kada se naprave izmene u repozitorijumu, potrebno je da se izvrši build
projekta i obavi testiranje, kako bi se osiguralo da nove izmene ne kvare postojeće funkcionalnosti. Ovo nekada može da traje dosta dugo i može se desiti da se testovi ne izvrše uvek na isti način, ukoliko se izvršavaju manuelno (na primer, jedna osoba ne uradi nešto na isti način dva puta). Zbog toga je lakše da se testovi automatizuju, jer će se uvek izvršiti brže i na potpuno isti način. Za kontinualnu integraciju neophodno je da build
koda i testovi budu automatski.
Prednosti kontinualne integracije su to što integracija traje kraće, greške se uočavaju ranije, debug
troši manje vremena, pa ostaje više vremena za razvoj. Dalje, nema čekanja da se sazna da li kod radi, smanjuju se problemi integracije, pa se softver može razvijati brže.
Metode CI
- Koristi se jedan repozitorijum.
Build
se izvršava automatski.- Testovi se izvršavaju automatski.
- Za svaki
commit
,build
se vrši na mašini za integraciju. Build
treba da bude brz.- Testiranje se obavlja u kloniranom okruženju produkcije.
- Poslednja izvršna verzija svima treba da bude lako dostupna.
- Svi u timu imaju pregled svih dešavanja.
- Automatski
deploy
.
Faze kontinualne integracije
Kako se radi kontinualna integracija?
Programeri vrše izmene u lokalnom okruženju. Kada završe, commit
-uju kod u repozitorijum. CI
server prati repozitorijum i povlači nove izmene kada se dogode. CI
server pokreće build
i izvršava unit
testove i testove integracije. CI
server pravi instancu projekta spremnu za testiranje. CI
server pridružuje oznaku build
-u. CI
server obaveštava tim o uspešnosti build
-a. Ukoliko je build
neuspešan, tim odmah može da počne sa rešavanjem problema. Ciklus kontinualne integracije se nastavlja, a projekat se testira.
Potrebno je da svi članovi tima prave izmene često, da ne commit
-uju kod koji ne radi, da ne commit
-uju kod koji nije testiran, da ne commit
-uju nove izmene ukoliko build
nije uspešan, i da ne napuštaju radno mesto nakon commit
-a pre nego što saznaju da je build
uspešan.
Dakle, kontinualna integracija podrazumeva dodavanje malih celina u repozitorijum čim se završe. Zatim se pokreće build
, izvršavaju se testovi i ukoliko postoji neka greška to se saznaje veoma rano i može odmah da se ispravi.
Alati za kontinualnu integraciju
Postoje razni alati za kontinualnu integraciju kao što su Bamboo
, Jenkins
, Travis CI
, Circle CI
, Codeship
, Semaphore
, CruiseControl
, TeamCity
, GitLab CI
, Drone
, itd. U nastavku će se govoriti o Jenkins
-u koji je jedan od najčešće korišćenih, besplatan je, ima dobru podršku i veliki broj ekstenzija.
O Jenkins-u
Jenkins
je open source
server za automatizaciju napisan u Javi
. Koristi se u softverskom inžinjeringu da pomogne timovima prilikom automatizacije procesa razvoja softvera. Uklanjanje ljudskog faktora izbacuje mogućnost nastanka greške.
Primer kontinualne integracije
Na Java
projektu biće objašnjeno kako konfigurisati Jenkins
da vrši automatski build
i testiranje nakon što se repozitorijum izmeni. Reč je o jednostavnom kalkulatoru.
Projekat se nalazi na ovom linku (GitHub
), a ispod ce biti dati i konkretni delovi koda.
Na početku imamo klasu Calculator.java
sa metodom za sabiranje 2 broja i klasu sa unit
testom CalculatorTest.java
za njeno testiranje. U pom.xml
fajlu se nalaze podaci neophodni za Maven
. Za izvršavanje unit
testova koristićemo JUnit
.
Calculator.java
package calculator; public class Calculator { public static int add(int a, int b) { return a + b; } }
CalculatorTest.java
package calculator; import org.junit.Assert; import org.junit.Test; public class CalculatorTest { @Test public void add3and7() { int result = Calculator.add(3, 7); Assert.assertEquals(result, 10); } }
pom.xml
4.0.0 ci-demo simple-calculator 0.0.1-SNAPSHOT Simple calculator junit junit 4.12 test 1.8 1.8
Pre svega, biće prikazano kako se instalira i konfiguriše Jenkins
na operativnom sistemu Ubuntu 18.04
.
Instalacija Jave
Update
liste paketa:
sudo apt-get update
Instalacija Jave 8
:
sudo apt install openjdk-8-jdk
Proverimo da li smo uspešno instalirali Javu
:
java -version
Izlaz bi trebalo da bude sličan ovom:
openjdk version "1.8.0_181" OpenJDK Runtime Environment (build 1.8.0_181-8u181-b13-0ubuntu0.18.04.1-b13) OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
U fajl
/etc/environment
dodajemo:
JAVA_HOME="/usr/lib/jvm/java-8-openjdk-amd64"
NAPOMENA: Putanja može biti drugačija. Provera JAVA_HOME
promenljive:
source /etc/environment echo $JAVA_HOME
Izlaz treba da odgovara setovanoj vrednosti.
Instalacija Git-a
Potrebno je pokrenuti komandu:
sudo apt-get install git
Instalacija Jenkins-a
wget -q -O - https://pkg.jenkins.io/debian/jenkins-ci.org.key | sudo apt-key add - sudo sh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list' sudo apt-get update sudo apt-get install jenkins
Korisnik Jenkins
će biti dodat automatski i Jenkins
će biti pokrenut na lokalnoj adresi na portu 8080
.
Konfiguracija Jenkins-a
U browser-u treba otići na adresu:
http://localhost:8080
Pri prvom pokretanju pojaviće se pop-up sa uputstvom za autorizaciju. Komandom:
cat /var/lib/jenkins/secrets/initialAdminPassword
dobijamo lozinku koju koristimo da otključamo Jenkins
. Nakon toga treba da odaberemo koje dodatke (plugins
) hoćemo da instaliramo. Osim prethodno selektovanih odabraćemo GitHub integration
i maven
plugin
. Nakon instalacije plugin
-ova potrebno je napraviti administratorski nalog. Nakon kreiranja naloga, nalazimo se na početnoj strani.
Konfiguracija Git-a i Maven-a
Sa početne strane idemo na stranu Manage Jenkins > Global Tools Configuration
. Za Git name
unosimo
Git
a za Path to Git executable
git
Za Maven name
unosimo
Maven
i čekiramo Install automatically
. Treba da kliknemo da dugme apply
da bi se primenile promene.
Konfiguracija e-mail-a
Sada treba da odemo na stranu Manage Jenkins > Configure system
. Pronađimo sekciju E-mail Notification
. Potrebno je da unesemo odgovarajuće podatke. Možemo testirati konfiguraciju e-mail
-a čekiranjem opcije Test configuration by sending test e-mail
a zatim klikom na dugme Test configuration
. Treba da kliknemo da dugme save
da sačuvamo izmene.
Vratimo se na početnu stranu. Treba da izaberemo new item
.
Unosimo naziv job
-a i biramo Maven
za tip projekta.
Čekiramo GitHub project
i unosimo URL
projekta:
https://github.com/ndukic/simple-calculator
Sada za source code management
treba da odaberemo Git
i unesemo URL
za kloniranje git
projekta, u našem slučaju:
https://github.com/ndukic/simple-calculator.git
Za Build Triggers
ćemo odabrati Poll SCM
a za schedule
ćemo uneti:
* * * * *
Ovo znači da će Jenkins
na svaki minut proveravati da li je bilo promena u repozitorijumu i ako jeste, izvršiće build
. Postoji i elegantniji način za ovo. Možemo odabrati Git hook trigger
. Potrebno je samo da na GitHub
-u napravimo novi Webhook
gde ćemo za Payload URL
da stavimo:
$JENKINS_BASE_URL/github-webhook/
U Build
sekciji za root POM
stavljamo:
pom.xml
a za Goals and options
clean install
Čekiramo E-mail Notification
i unosimo adresu primaoca. Na ovu adresu će se slati izveštaji o statusu build
-ova. Ukoliko hoćemo da navedemo više primalaca, adrese razdvajamo zarezom.
Na kraju treba da kliknemo na Save
dugme da sačuvamo izmene.
Izvršavanje build-a
Sada kada je job
setovan, svaki put kada dodje do izmene na repozitorijumu, Jenkins
će to primetiti i pokrenuti build
. Build
možemo pokrenuti i ručno klikom na Build Now
. Nakon konfiguracije, Jenkins
će primetiti da je došlo do izmena, tj. videće da se lokalni repozitorijum, koji je prazan, razlikuje od onog na GitHub
-u i odraditi build
. Na slici ispod vidimo da je rezultat uspešan.
Sada ćemo proširiti klasu Calculator
metodom factorial()
u kome je namerno napravljena greška.
public static int factorial(int a) {
if (a == 1) {
return 0; // intentional mistake
} else {
return a * factorial(a - 1);
}
}
Napravili smo i unit
test koji očekuje tačan rezultat. U klasu CalculatorTest
dodajemo:
@Test
public void factorialOf5() {
int result = Calculator.factorial(5);
Assert.assertEquals(result, 120);
}
Uradili smo commit
novih izmena u deljeni repozitorijum. Build
se okinuo i u izveštaju imamo da je 1 od 2 testa neuspešan.
Nakon debug
-a, pronašli smo grešku i ispravili kod u klasi Calculator
. U metodi factorial()
liniju:
return 0; // intentional mistake
menjamo u:
return 1;
Nakon commit
-a, ponovo se pokreće build
. Ovog puta, rezultat je uspešan.
Ako proverimo e-mail
, videćemo da imamo obaveštenja o ovim rezultatima.
Zaključak
Na primeru vidimo značaj kontinualne integracije, nakon male izmene, greška je odmah pronađena i brzo se može otkloniti. Da nije bilo automatskog build
-a i testiranja, ova greška bi mogla da prođe neopaženo. Moglo se sakupiti više grešaka i kada bismo prilikom integracije koda primetili da nešto ne radi kako treba, bilo bi potrebno više vremena da se greška pronađe.
Značaj ove prakse je u tome što se za svaku izmenu odmah može saznati da li radi kako je očekivano.
Šta dalje?
Continuous Delivery i Continuous Deployment
Osim mehanizama za automatski build
i testiranje, Jenkins
se može podesiti tako da automatizuje još poslova. Na primer, ako je build
uspešan (svi testovi su uspešni), kod se može dopremiti na produkciju. Ova praksa se naziva Continuous Deployment
i često je usko povezana sa CI
-om. Nju ne treba mešati sa pojmom Countinuous Delivery
. Razlika je u tome što se ovom drugom praksom podrazumeva samo da je kod spreman za puštanje na produkciju u bilo kom trenutku.
Jenkins Pipeline
Set procesa koji se odvijaju u Jenkins
-u može se podesiti pomoću Jenkins Pipeline
-a. Pipeline
predstavlja set plugin
-ova koji omogućavaju integraciju Countinous Delivery
pipeline
-a.
Korisni linkovi
Continuous IntegrationJenkins Pipeline
Wikipedia