ProHoster > Blog > podávání > Vytváření optimalizovaných obrázků dockeru pro aplikaci Spring Boot
Vytváření optimalizovaných obrázků dockeru pro aplikaci Spring Boot
Kontejnery se staly preferovaným prostředkem pro zabalení aplikace se všemi jejich závislostmi na softwaru a operačním systému a jejich následné dodání do různých prostředí.
Tento článek popisuje různé způsoby kontejnerizace aplikace Spring Boot:
vytvoření obrazu dockeru pomocí dockerfile,
vytvoření obrazu OCI ze zdroje pomocí Cloud-Native Buildpack,
a optimalizace obrazu za běhu oddělením částí JAR do různých úrovní pomocí vrstvených nástrojů.
Příklad kódu
Tento článek je doplněn příkladem pracovního kódu na GitHub .
Kontejnerová terminologie
Začneme terminologií kontejnerů používanou v celém článku:
Obrázek kontejneru: soubor určitého formátu. Spuštěním nástroje sestavení převedeme naši aplikaci na obrázek kontejneru.
kontejner: Spustitelná instance obrazu kontejneru.
Kontejnerový motor: Proces démona zodpovědný za spuštění kontejneru.
Hostitel kontejneru: Hostitelský počítač, na kterém běží kontejnerový stroj.
Registr kontejnerů: Obecné umístění používané k publikování a distribuci obrazu kontejneru.
standard OCI: Open Container Initiative (OCI) je lehký, open-source rámec pro správu vytvořený Linux Foundation. OCI Image Specification definuje průmyslové standardy pro formáty obrázků kontejnerů a běhové prostředí, aby bylo zajištěno, že všechny kontejnerové stroje mohou spouštět obrázky kontejnerů generované jakýmkoli nástrojem pro vytváření.
Abychom aplikaci kontejnerizovali, zabalíme naši aplikaci do obrázku kontejneru a publikujeme tento obrázek do veřejného registru. Runtime kontejneru načte tento obraz z registru, rozbalí jej a spustí v něm aplikaci.
Verze 2.3 Spring Boot poskytuje zásuvné moduly pro vytváření obrazů OCI.
přístavní dělník je nejběžněji používaná implementace kontejneru a v našich příkladech používáme Docker, takže všechny následující odkazy na kontejnery v tomto článku budou odkazovat na Docker.
Vytvoření image kontejneru tradičním způsobem
Vytváření obrazů Dockeru pro aplikace Spring Boot je velmi snadné přidáním několika pokynů do souboru Dockerfile.
Nejprve vytvoříme spustitelný JAR a jako součást instrukcí Dockerfile zkopírujeme spustitelný JAR na základní obraz JRE po použití nezbytných úprav.
Pojďme vytvořit naši jarní aplikaci na Spring Initializr se závislostmi web, lombokи actuator. Přidáváme také řadič odpočinku, který poskytuje API GETmetoda.
Vytvoření souboru Dockerfile
Tuto aplikaci pak přidáváním umístíme do kontejneru Dockerfile:
Náš soubor Dockerfile obsahuje základní obrázek, od adoptopenjdk, na který zkopírujeme náš soubor JAR a poté otevřeme port, 8080který bude naslouchat žádostem.
Sestavení aplikace
Nejprve musíte vytvořit aplikaci pomocí Maven nebo Gradle. Zde používáme Maven:
mvn clean package
Tím se vytvoří spustitelný soubor JAR pro aplikaci. Potřebujeme převést tento spustitelný JAR na obraz Dockeru, aby mohl běžet na enginu Docker.
Vytvořte obrázek kontejneru
Tento spustitelný soubor JAR pak vložíme do obrazu Dockeru spuštěním příkazu docker buildz kořenového adresáře projektu obsahujícího dříve vytvořený soubor Docker:
docker build -t usersignup:v1 .
Náš obrázek můžeme vidět v seznamu příkazem:
docker images
Výstup výše uvedeného příkazu obsahuje náš obrázek usersignupspolu se základním obrázkem, adoptopenjdkspecifikované v našem Dockerfile.
REPOSITORY TAG SIZE
usersignup v1 249MB
adoptopenjdk 11-jre-hotspot 229MB
Zobrazení vrstev uvnitř obrázku kontejneru
Podívejme se na hromadu vrstev uvnitř obrázku. budeme používat инструмент potápět se, pro zobrazení těchto vrstev:
dive usersignup:v1
Zde je část výstupu příkazu Dive:
Jak vidíme, aplikační vrstva tvoří významnou část velikosti obrázku. V rámci naší optimalizace chceme v následujících částech zmenšit velikost této vrstvy.
Vytvoření obrázku kontejneru pomocí Buildpack
Montážní balíčky (Buildpacks) je obecný termín používaný různými nabídkami Platform as a Service (PAAS) k vytvoření image kontejneru ze zdrojového kódu. Byl spuštěn společností Heroku v roce 2011 a od té doby byl přijat společnostmi Cloud Foundry, Google App Engine, Gitlab, Knative a několika dalšími.
Výhoda balíčků Cloud Build Packages
Jednou z hlavních výhod použití Buildpack k vytváření obrázků je to změny konfigurace obrazu mohou být spravovány centrálně (builder) a šířeny do všech aplikací pomocí builderu.
Sestavovací balíčky byly úzce svázány s platformou. Cloud-Native Buildpacks poskytují standardizaci napříč platformami tím, že podporují obrazový formát OCI, což zajišťuje, že obraz lze spustit pomocí modulu Docker.
Použití modulu Spring Boot Plugin
Plugin Spring Boot vytváří obrazy OCI ze zdroje pomocí Buildpack. Obrázky jsou vytvořeny pomocí bootBuildImageúkoly (Gradle) popř spring-boot:build-imagecíl (Maven) a místní instalace Dockeru.
Můžeme upravit název obrázku, který potřebujeme odeslat do registru Docker, zadáním názvu image tag:
Z výstupu to vidíme paketo Cloud-Native buildpackslouží k vytvoření pracovního obrazu OCI. Stejně jako dříve můžeme vidět obrázek uvedený jako obrázek Docker spuštěním příkazu:
Dále spustíme plugin Jib pomocí příkazu Maven k sestavení aplikace a vytvoření bitové kopie kontejneru. Stejně jako dříve zde nepoužíváme žádné soubory Docker:
Po provedení výše uvedeného příkazu Maven získáme následující výstup:
[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
Výstup ukazuje, že obraz kontejneru byl vytvořen a umístěn do registru.
Motivace a metody tvorby optimalizovaných obrázků
Pro optimalizaci máme dva hlavní důvody:
Производительность: V systému orchestrace kontejnerů je obraz kontejneru načten z registru obrazů do hostitele, na kterém je spuštěn kontejnerový stroj. Tento proces se nazývá plánování. Vytahování velkých obrazů z registru má za následek dlouhé doby plánování v systémech orchestrace kontejnerů a dlouhé doby sestavení v kanálech CI.
zabezpečení: velké obrázky mají také velkou oblast pro zranitelnosti.
Obraz Dockeru se skládá z hromady vrstev, z nichž každá představuje prohlášení v našem souboru Docker. Každá vrstva představuje deltu změn v podkladové vrstvě. Když vytáhneme obrázek Dockeru z registru, je stažen ve vrstvách a uložen do mezipaměti na hostiteli.
Použití Spring Boot "tlustý JAR" v jako výchozí formát balení. Když se podíváme na tlustý JAR, vidíme, že aplikace je velmi malá část celého JAR. Toto je část, která se nejvíce mění. Zbytek tvoří závislosti Spring Framework.
Optimalizační vzorec je zaměřen na izolaci aplikace na úrovni oddělené od závislostí Spring Framework.
Závislá vrstva, která tvoří většinu tlustého souboru JAR, se stáhne pouze jednou a uloží do mezipaměti hostitelského systému.
Během aktualizací aplikace a plánování kontejneru se stáhne pouze tenká vrstva aplikace, jak ukazuje tento diagram:
V následujících částech se podíváme na to, jak vytvořit tyto optimalizované obrazy pro aplikaci Spring Boot.
Vytvoření optimalizovaného obrazu kontejneru pro aplikaci Spring Boot pomocí Buildpack
Spring Boot 2.3 podporuje vrstvení extrahováním částí tlustého souboru JAR do samostatných vrstev. Funkce vrstvení je ve výchozím nastavení zakázána a je třeba ji explicitně povolit pomocí pluginu Spring Boot Maven:
Tuto konfiguraci použijeme k vytvoření bitové kopie kontejneru nejprve pomocí Buildpack a poté pomocí Dockeru v následujících částech.
Utíkejme build-imageMaven cíl pro vytvoření obrázku kontejneru:
mvn spring-boot:build-image
Pokud spustíme Dive, abychom viděli vrstvy ve výsledném obrázku, můžeme vidět, že aplikační vrstva (zakroužkovaná červeně) je mnohem menší v rozsahu kilobajtů ve srovnání s tím, co jsme získali pomocí tlustého formátu JAR:
Vytvoření optimalizovaného obrazu kontejneru pro aplikaci Spring Boot pomocí Dockeru
Místo použití pluginu Maven nebo Gradle můžeme také vytvořit vrstvený obraz Docker JAR se souborem Docker.
Když používáme Docker, musíme udělat dva další kroky k extrahování vrstev a jejich zkopírování do konečného obrázku.
Obsah výsledného JAR po sestavení pomocí Maven se zapnutým vrstvením bude vypadat takto:
Výstup zobrazuje další JAR s názvem spring-boot-jarmode-layertoolsи layersfle.idxsoubor. Tento dodatečný soubor JAR poskytuje možnosti vrstvení, jak je popsáno v další části.
Extrahujte závislosti na samostatných vrstvách
K zobrazení a extrahování vrstev z našeho vrstveného JAR používáme vlastnost system -Djarmode=layertoolspro začátek spring-boot-jarmode-layertoolsJAR místo aplikace:
Spuštěním tohoto příkazu se vytvoří výstup obsahující dostupné možnosti příkazu:
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
Výstup zobrazuje příkazy list, extractи helpс helpbýt výchozí. Spusťte příkaz s listvolba:
java -Djarmode=layertools -jar target/usersignup-0.0.1-SNAPSHOT.jar list
Vidíme seznam závislostí, které lze přidat jako vrstvy.
Vrstvy ve výchozím nastavení:
Název vrstvy
Obsah
dependencies
jakákoliv závislost, jejíž verze neobsahuje SNAPSHOT
spring-boot-loader
Třídy nakladačů JAR
snapshot-dependencies
jakákoliv závislost, jejíž verze obsahuje SNAPSHOT
application
aplikační třídy a prostředky
Vrstvy jsou definovány v layers.idxsoubor v pořadí, ve kterém by měly být přidány do obrazu Docker. Tyto vrstvy jsou po prvním načtení uloženy do mezipaměti hostitele, protože se nemění. Na hostitele se stáhne pouze aktualizovaná aplikační vrstva, což je rychlejší díky zmenšené velikosti .
Vytvoření obrazu se závislostmi extrahovanými do samostatných vrstev
Výsledný obraz vytvoříme ve dvou krocích pomocí metody tzv vícestupňová montáž . V prvním kroku vyextrahujeme závislosti a ve druhém kroku extrahované závislosti zkopírujeme do výsledného .
Upravme náš Dockerfile pro vícefázové sestavení:
# 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"]
Tuto konfiguraci uložíme do samostatného souboru - Dockerfile2.
Obraz Dockeru vytvoříme pomocí příkazu:
docker build -f Dockerfile2 -t usersignup:v1 .
Po provedení tohoto příkazu dostaneme následující výstup:
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
Můžeme vidět, že obrázek Docker je vytvořen s ID obrázku a poté je označen.
Nakonec spustíme příkaz Dive jako dříve, abychom zkontrolovali vrstvy uvnitř vygenerovaného obrázku Docker. Můžeme poskytnout ID obrázku nebo značku jako vstup do příkazu Dive:
dive userssignup:v1
Jak můžete vidět z výstupu, vrstva obsahující aplikaci má nyní pouze 11 KB a závislosti jsou ukládány do mezipaměti v samostatných vrstvách.
Extrahujte vnitřní závislosti na samostatných vrstvách
Velikost aplikační vrstvy můžeme dále zmenšit extrahováním jakékoli z našich vlastních závislostí do samostatné vrstvy místo toho, abychom je sbalili s aplikací tak, že je deklarujeme v ymlpodobný soubor s názvem layers.idx:
V tomto souboru layers.idxpřidali jsme vlastní závislost s názvem, io.myorgobsahující závislosti organizace načtené ze sdíleného úložiště.
Výkon
V tomto článku jsme se podívali na použití Cloud-Native Buildpacks k vytvoření image kontejneru přímo ze zdroje. Toto je alternativa k použití Dockeru k vytvoření obrazu kontejneru obvyklým způsobem: nejprve se vytvoří tlustý spustitelný soubor JAR a poté se zabalí do obrazu kontejneru zadáním pokynů v souboru Dockerfile.
Také jsme se podívali na optimalizaci našeho kontejneru zahrnutím funkce vrstvení, která extrahuje závislosti do samostatných vrstev, které jsou uloženy v mezipaměti hostitele, a tenká aplikační vrstva je načtena v době plánování v prováděcích motorech kontejneru.
Veškerý použitý zdrojový kód najdete v článku na adrese GitHub .
Reference příkazů
Zde je souhrn příkazů, které jsme použili v tomto článku pro rychlou orientaci.
Vyčištění kontextu:
docker system prune -a
Vytvoření obrazu kontejneru pomocí souboru Dockerfile:
docker build -f <Docker file name> -t <tag> .
Sestavení obrázku kontejneru ze zdroje (bez Dockerfile):
mvn spring-boot:build-image
Zobrazit vrstvy závislostí. Před vytvořením souboru jar aplikace se ujistěte, že je v modulu spring-boot-maven-plugin povolena funkce vrstvení:
java -Djarmode=layertools -jar application.jar list
Extrahujte vrstvy závislostí. Před vytvořením souboru jar aplikace se ujistěte, že je v modulu spring-boot-maven-plugin povolena funkce vrstvení: