ProHoster > Blog > uprava > Stvaranje optimiziranih Docker slika za aplikaciju Spring Boot
Stvaranje optimiziranih Docker slika za aplikaciju Spring Boot
Kontejneri su postali preferirano sredstvo za pakiranje aplikacije sa svim njezinim ovisnostima o softveru i operativnom sustavu i zatim za njihovu isporuku u različita okruženja.
Ovaj članak pokriva različite načine spremnika Spring Boot aplikacije:
izgradnja docker slike pomoću docker datoteke,
stvaranje OCI slike iz izvora koristeći Cloud-Native Buildpack,
i optimizacija slike tijekom izvođenja odvajanjem dijelova JAR-a u različite slojeve pomoću višeslojnih alata.
Primjer koda
Ovaj članak je popraćen primjerom radnog koda na GitHubu .
Kontejnerska terminologija
Počet ćemo s terminologijom spremnika koja se koristi u članku:
Slika spremnika: datoteka određenog formata. Pretvorit ćemo našu aplikaciju u sliku spremnika pokretanjem alata za izgradnju.
kontejner: Izvršna instanca slike spremnika.
Kontejnerski motor: Daemon proces odgovoran za pokretanje spremnika.
Domaćin spremnika: Glavno računalo na kojem radi spremnik.
Registar kontejnera: Opća lokacija koja se koristi za objavljivanje i distribuciju slike spremnika.
OCI standard: Inicijativa za otvoreni kontejner (OCI) je lagana, otvorena struktura upravljanja formirana unutar Linux Foundationa. OCI specifikacija slike definira industrijske standarde za formate slike spremnika i vremena izvođenja kako bi se osiguralo da svi pogoni spremnika mogu pokretati slike spremnika stvorene bilo kojim alatom za izgradnju.
Kako bismo aplikaciju pretvorili u spremnik, omotamo našu aplikaciju u sliku spremnika i tu sliku objavimo u zajedničkom registru. Vrijeme izvođenja spremnika dohvaća ovu sliku iz registra, raspakira je i pokreće aplikaciju unutar nje.
Verzija 2.3 programa Spring Boot pruža dodatke za stvaranje OCI slika.
Lučki radnik je najčešće korištena implementacija spremnika, a mi koristimo Docker u našim primjerima, tako da će se sve daljnje reference spremnika u ovom članku odnositi na Docker.
Izrada slike spremnika na tradicionalan način
Izrada Docker slika za Spring Boot aplikacije vrlo je jednostavna dodavanjem nekoliko uputa vašoj Docker datoteci.
Prvo stvaramo izvršnu JAR datoteku i, kao dio uputa za Docker datoteku, kopiramo izvršnu JAR datoteku na osnovnu JRE sliku nakon primjene potrebnih postavki.
Kreirajmo našu Spring aplikaciju na Opruga Initializr sa ovisnostima web, lombokи actuator. Također dodajemo kontroler odmora za pružanje API-ja GETmetoda.
Stvaranje Dockerfilea
Tu aplikaciju zatim stavljamo u spremnik dodavanjem Dockerfile:
Naša Docker datoteka sadrži osnovnu sliku iz adoptopenjdk, na koji kopiramo našu JAR datoteku i zatim otvaramo port, 8080koji će osluškivati zahtjeve.
Izrada aplikacije
Najprije morate izraditi aplikaciju koristeći Maven ili Gradle. Ovdje koristimo Maven:
mvn clean package
Ovo stvara izvršnu JAR datoteku za aplikaciju. Moramo pretvoriti ovaj izvršni JAR u Docker sliku za rad na Docker motoru.
Stvaranje slike spremnika
Zatim ovu izvršnu JAR datoteku stavljamo u Docker sliku pokretanjem naredbe docker buildiz korijenskog direktorija projekta koji sadrži ranije stvorenu Docker datoteku:
docker build -t usersignup:v1 .
Svoju sliku možemo vidjeti na popisu pomoću naredbe:
docker images
Izlaz gornje naredbe uključuje našu sliku usersignupzajedno s osnovnom slikom, adoptopenjdknavedeno u našoj Docker datoteci.
REPOSITORY TAG SIZE
usersignup v1 249MB
adoptopenjdk 11-jre-hotspot 229MB
Pogledajte slojeve unutar slike spremnika
Pogledajmo hrpu slojeva unutar slike. Koristit ćemo se alat ronjenje za pregled ovih slojeva:
dive usersignup:v1
Ovdje je dio izlaza iz naredbe Dive:
Kao što vidimo, aplikacijski sloj čini značajan dio veličine slike. Želimo smanjiti veličinu ovog sloja u sljedećim odjeljcima kao dio naše optimizacije.
Stvaranje slike spremnika pomoću Buildpacka
Montažni paketi (Buildpacks) opći je izraz koji koriste razne ponude platforme kao usluge (PAAS) za stvaranje slike spremnika iz izvornog koda. Pokrenuo ga je Heroku 2011., a od tada su ga prihvatili Cloud Foundry, Google App Engine, Gitlab, Knative i nekoliko drugih.
Prednost paketa za izgradnju oblaka
Jedna od glavnih prednosti korištenja Buildpacka za izradu slika je ta Promjenama konfiguracije slike može se upravljati centralno (builder) i proširiti na sve aplikacije pomoću buildera.
Paketi za izradu bili su čvrsto povezani s platformom. Cloud-Native Buildpacks pružaju standardizaciju na svim platformama podržavajući OCI format slike, koji osigurava da sliku može pokrenuti Docker mehanizam.
Korištenje dodatka Spring Boot
Dodatak Spring Boot gradi OCI slike iz izvora koristeći Buildpack. Slike se stvaraju pomoću bootBuildImagezadataka (Gradle) ili spring-boot:build-imagetarget (Maven) i lokalna Docker instalacija.
Možemo prilagoditi naziv slike koju trebamo gurnuti u Docker registar navođenjem imena image tag:
Iz izlaza vidimo da paketo Cloud-Native buildpackkoristi se za stvaranje radne OCI slike. Kao i prije, možemo vidjeti sliku navedenu kao Docker slika pokretanjem naredbe:
Zatim pokrećemo dodatak Jib pomoću naredbe Maven za izradu aplikacije i stvaranje slike spremnika. Kao i prije, ovdje ne koristimo nikakve Docker datoteke:
Nakon izvršenja gornje Maven naredbe, dobivamo sljedeći izlaz:
[INFO] Containerizing application to pratikdas/usersignup:v1...
.
.
[INFO] Container entrypoint set to [java, -cp, /app/resources:/app/classes:/app/libs/*, io.pratik.users.UsersignupApplication]
[INFO]
[INFO] Built and pushed image as pratikdas/usersignup:v1
[INFO] Executing tasks:
[INFO] [==============================] 100.0% complete
Izlaz pokazuje da je slika spremnika stvorena i postavljena u registar.
Motivacije i metode za stvaranje optimiziranih slika
Imamo dva glavna razloga za optimizaciju:
Performanse: U sustavu orkestracije spremnika, slika spremnika se povlači iz registra slika na glavno računalo koje pokreće pogon spremnika. Taj se proces naziva planiranje. Povlačenje velikih slika iz registra rezultira dugim vremenima raspoređivanja u sustavima orkestracije spremnika i dugim vremenima izgradnje u CI cjevovodima.
sigurnosti: velike slike također imaju veliko područje za ranjivosti.
Docker slika sastoji se od niza slojeva, od kojih svaki predstavlja instrukciju u našoj Docker datoteci. Svaki sloj predstavlja deltu promjena u donjem sloju. Kada povučemo Docker sliku iz registra, ona se povlači u slojevima i predmemorira na hostu.
Spring Boot koristi "debela JAR" u kao zadani format pakiranja. Kada pogledamo debeli JAR, vidimo da aplikacija čini vrlo mali dio cijelog JAR-a. Ovo je dio koji se najčešće mijenja. Ostatak se sastoji od zavisnosti Spring Frameworka.
Formula optimizacije usredotočena je na izoliranje aplikacije na zasebnoj razini od ovisnosti Spring Frameworka.
Sloj ovisnosti, koji čini najveći dio debele JAR datoteke, preuzima se samo jednom i sprema u predmemoriju na glavnom sustavu.
Samo se tanki sloj aplikacije povlači tijekom ažuriranja aplikacije i raspoređivanja spremnika. kao što je prikazano na ovom dijagramu:
U sljedećim odjeljcima pogledat ćemo kako stvoriti ove optimizirane slike za Spring Boot aplikaciju.
Stvaranje optimizirane slike spremnika za proljetnu aplikaciju za pokretanje pomoću Buildpacka
Spring Boot 2.3 podržava slojevito izdvajanje dijelova debele JAR datoteke u zasebne slojeve. Značajka slojevitosti onemogućena je prema zadanim postavkama i mora se izričito omogućiti pomoću dodatka Spring Boot Maven:
Koristit ćemo ovu konfiguraciju za izgradnju naše slike spremnika prvo s Buildpackom, a zatim s Dockerom u sljedećim odjeljcima.
Idemo lansirati build-imageMaven cilj za stvaranje slike spremnika:
mvn spring-boot:build-image
Ako pokrenemo Dive da vidimo slojeve na rezultirajućoj slici, možemo vidjeti da je aplikacijski sloj (označen crvenom bojom) mnogo manji u rasponu kilobajta u usporedbi s onim što smo dobili korištenjem debelog JAR formata:
Stvaranje optimizirane slike spremnika za proljetnu aplikaciju za pokretanje pomoću Dockera
Umjesto korištenja Maven ili Gradle dodatka, također možemo stvoriti slojevitu Docker JAR sliku s Docker datotekom.
Kada koristimo Docker, moramo izvršiti dva dodatna koraka kako bismo izdvojili slojeve i kopirali ih u konačnu sliku.
Sadržaj rezultirajućeg JAR-a nakon izgradnje pomoću Mavena s omogućenim slojevitim izgledom izgledat će ovako:
Izlaz prikazuje dodatni JAR pod nazivom spring-boot-jarmode-layertoolsи layersfle.idxdatoteka. Ova dodatna JAR datoteka pruža mogućnosti slojevite obrade, kao što je opisano u sljedećem odjeljku.
Izdvajanje ovisnosti o pojedinim slojevima
Za pregled i izdvajanje slojeva iz našeg slojevitog JAR-a koristimo svojstvo sustava -Djarmode=layertoolsza početak spring-boot-jarmode-layertoolsJAR umjesto aplikacije:
Pokretanje ove naredbe proizvodi izlaz koji sadrži dostupne opcije naredbe:
Usage:
java -Djarmode=layertools -jar usersignup-0.0.1-SNAPSHOT.jar
Available commands:
list List layers from the jar that can be extracted
extract Extracts layers from the jar for image creation
help Help about any command
Izlaz prikazuje naredbe list, extractи helpс helpbiti zadana. Pokrenimo naredbu s listopcija:
java -Djarmode=layertools -jar target/usersignup-0.0.1-SNAPSHOT.jar list
Vidimo popis ovisnosti koje se mogu dodati kao slojevi.
Zadani slojevi:
Naziv sloja
sadržaj
dependencies
bilo koja ovisnost čija verzija ne sadrži SNAPSHOT
spring-boot-loader
Klase učitavača JAR-a
snapshot-dependencies
bilo koja ovisnost čija verzija sadrži SNAPSHOT
application
aplikacijske klase i resurse
Slojevi su definirani u layers.idxdatoteku redoslijedom kojim bi trebali biti dodani Docker slici. Ti se slojevi pohranjuju u predmemoriju na hostu nakon prvog dohvaćanja jer se ne mijenjaju. Samo se ažurirani aplikacijski sloj preuzima na glavno računalo, što je brže zbog smanjene veličine .
Izrada slike s ovisnostima ekstrahiranim u zasebne slojeve
Konačnu sliku izgradit ćemo u dvije faze koristeći metodu tzv višestupanjska montaža . U prvom koraku ćemo ekstrahirati ovisnosti, au drugom koraku ćemo kopirati ekstrahirane ovisnosti u konačnu sliku.
Modificirajmo našu Dockerfile za izgradnju u više faza:
# the first stage of our build will extract the layers
FROM adoptopenjdk:14-jre-hotspot as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
# the second stage of our build will copy the extracted layers
FROM adoptopenjdk:14-jre-hotspot
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
Ovu konfiguraciju spremamo u zasebnu datoteku - Dockerfile2.
Docker sliku gradimo pomoću naredbe:
docker build -f Dockerfile2 -t usersignup:v1 .
Nakon pokretanja ove naredbe dobivamo sljedeći izlaz:
Sending build context to Docker daemon 20.41MB
Step 1/12 : FROM adoptopenjdk:14-jre-hotspot as builder
14-jre-hotspot: Pulling from library/adoptopenjdk
.
.
Successfully built a9ebf6970841
Successfully tagged userssignup:v1
Vidimo da je Docker slika stvorena s ID-om slike i zatim označena.
Na kraju, pokrećemo naredbu Dive kao i prije kako bismo pregledali slojeve unutar generirane Docker slike. Možemo dati ID slike ili oznaku kao ulaz u naredbu Dive:
dive userssignup:v1
Kao što možete vidjeti iz rezultata, sloj koji sadrži aplikaciju sada ima samo 11 KB, a ovisnosti su predmemorirane u zasebnim slojevima.
Izdvajanje internih ovisnosti o pojedinačnim slojevima
Možemo dodatno smanjiti veličinu sloja aplikacije izdvajanjem bilo koje od naših prilagođenih ovisnosti u zasebnu razinu umjesto da ih pakiramo s aplikacijom tako što ćemo ih deklarirati u ymlsličan naziv datoteke layers.idx:
U ovoj datoteci layers.idxdodali smo prilagođenu ovisnost pod nazivom, io.myorgkoji sadrži organizacijske ovisnosti dohvaćene iz zajedničkog repozitorija.
Izlaz
U ovom smo članku pogledali korištenje Cloud-Native Buildpacks-a za izradu slike spremnika izravno iz izvornog koda. Ovo je alternativa korištenju Dockera za stvaranje slike spremnika na uobičajeni način: prvo se stvara debela izvršna JAR datoteka, a zatim se pakira u sliku spremnika navođenjem uputa u Docker datoteci.
Također smo razmotrili optimizaciju našeg spremnika omogućavanjem značajke slojevitosti koja povlači ovisnosti u zasebne slojeve koji se pohranjuju u predmemoriju na glavnom računalu, a tanki sloj aplikacije učitava se u vrijeme zakazivanja u izvršnim strojevima spremnika.
Sav izvorni kod korišten u članku možete pronaći na Github .
Referenca naredbe
Evo kratkog pregleda naredbi koje smo koristili u ovom članku.
Čišćenje konteksta:
docker system prune -a
Stvaranje slike spremnika pomoću Docker datoteke:
docker build -f <Docker file name> -t <tag> .
Izgradite sliku spremnika iz izvora (bez Dockerfilea):
mvn spring-boot:build-image
Pregledajte slojeve ovisnosti. Prije izgradnje JAR datoteke aplikacije, provjerite je li značajka slojevitosti omogućena u spring-boot-maven-pluginu:
java -Djarmode=layertools -jar application.jar list
Izdvajanje slojeva zavisnosti. Prije izrade jar datoteke aplikacije, provjerite je li značajka slojevitosti omogućena u spring-boot-maven-pluginu: