Im zweiten Teil der Reihe wurden die notwendigen Werkzeuge vorgestellt und installiert. Nun werden wir den Build-Prozess für Java-Projekte und die Erstellung der Docker-Images zusammenführen.
Teil 3: Der Build-Prozess
Build von Java-Projekten mit Apache Maven
Apache Maven ist neben Apache Ant mit Ivy und Gradle ein Standard-Werkzeug, das zum automatisierten Erzeugen von Java-Archiven benutzt werden kann. Allen Werkzeugen gemeinsam ist das Dependency Management: Projekt-Abhängigkeiten werden in einer Konfigurationsdatei abgelegt und vom Build-Werkzeug automatisch aus einem Artefakt-Repository geladen. Repositories werden von verschiedenen Anbietern frei zugänglich im Internet betrieben. Maven Central ist das wahrscheinlich bekannteste Beispiel.
Um die selbst erzeugten Artefakte selbst verwalten zu können, werden im Unternehmen meistens eigene Server betrieben. Dazu existieren sofort einsetzbare Produkte wie Sonatype Nexus, JFrog Artefactory oder Apache Archiva.
Entscheiden wir uns für einen Maven-basierten Build-Prozess erfolgt die allgemeine Konfiguration des Build-Prozesses mit zwei Dateien:
- Die
settings.xml
enthält die URL des Artefakt-Repositories und gegebenenfalls Authentifizierungs-Informationen
<settings> <mirrors> <mirror> <id>nexus</id> <mirrorOf>*</mirrorOf> <url>http://xxxxx/repository/maven-public/</url> </mirror> </mirrors> <repositories> <repository> <id>central</id> <url>http://central</url> <releases><enabled>true</enabled></releases> <snapshots><enabled>true</enabled></snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>central</id> <url>http://central</url> <releases><enabled>true</enabled></releases> <snapshots><enabled>true</enabled></snapshots> </pluginRepository> </pluginRepositories> <servers> <server> <id>nexus</id> <username>xxx</username> <password>xxx</password> </server> </servers> </settings>
Ein Parent-POM enthält neben allgemeinen Informationen für alle Build-Prozesse auch die Informationen zum Ausbringen der Artefakte in das Repository
<distributionManagement> <repository> <uniqueVersion>false</uniqueVersion> <id>nexus</id> <name>Corporate Repository</name> <url>http://…</url> </repository> <snapshotRepository> <uniqueVersion>true</uniqueVersion> <id>nexus</id> <name>Corporate Snapshots</name> <url>http://…</url> </snapshotRepository> </distributionManagement>
Nach all diesen Vorbereitungen ist der Build-Prozess eines eigenen Projekts sehr einfach: Es wird ein Projekt-POM definiert, das im einfachsten Fall nur den Parent angeben muss.
<project> <modelVersion>4.0.0</modelVersion> <groupId>org.javacream.training</groupId> <artifactId>org.javacream.training.business</artifactId> <version>1.0</version> <parent> <groupId>org.javacream.training.docker</groupId> <artifactId>org.javacream.training.docker.parent</artifactId> <version>1.0</version> </parent> </project>
Trotz dieser wirklich sehr einfachen Konfiguration kann das Java-Projekt sofort bis hin zu verschiedenen Phasen gebaut werden:
compile
: Das Projekt wird kompiliertpackage
: Ein Java-Archiv wird im target-Verzeichnis des Projekts erzeugtdeploy
: Das Archiv wird in das Unternehmens-Repository ausgebracht
So einfach funktioniert Maven!
Maven und Docker
Auch Docker definiert einen Build-Prozess: Images werden aus dem Dockerfile erzeugt. Was liegt also näher, als diesen Prozess mit Maven zu integrieren? Diese Idee wird durch Maven-PlugIns für Docker umgesetzt. Hierzu stehen sogar verschieden Produkte zur Auswahl:
- Durch das Parent-POM ist die Integration dieser PlugIns für den Entwickler vollkommen transparent! Wird beispielsweise das Spotify-PlugIn in den Parent aufgenommen
<plugin> <groupId>com.spotify</groupId> <artifactId>docker-maven-plugin</artifactId> <version>0.4.11</version> <configuration> <imageName>${docker.namespace.prefix}/${project.artifactId}</imageName> <dockerDirectory>src/main/docker</dockerDirectory> <resources> <resource> <targetPath>/</targetPath> <directory>${project.build.directory}</directory> <include>${project.build.finalName}.jar</include> </resource> <resource> <targetPath>/</targetPath> <directory>${project.build.directory}</directory> <include>libs/*.jar</include> </resource> </resources> <imageTags> <imageTag>${project.version}</imageTag> <imageTag>latest</imageTag> </imageTags> </configuration> </plugin>
so stehen nun neue Maven-Befehle zur Verfügung, insbesondere
docker:build
: Erzeugen des Images aus dem Dockerfile des Projektsdocker:push
: Pushen des Images in ein Docker-Repository
Damit ist die gewünschte Integration der Build-Prozesse durchgeführt. Und nachdem Nexus oder Artefactory neben Java-Artefakten auch Docker-Images verwalten können, ist unser System praktisch fertig! Dass die Quellcodes, das POM und das Dockerfile in einem Versionsverwaltungssystem abgelegt werden und auf ein Build-Server wie Jenkins die Builds automatisiert ablaufen lassen wird, ist selbstverständlich.
Die vollständige Parent-POM kann hier angezeigt werden:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.javacream.training.docker</groupId> <artifactId>org.javacream.training.docker.parent</artifactId> <version>1.0</version> <packaging>pom</packaging> <properties> <docker.namespace.prefix>javacream</docker.namespace.prefix> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.8</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>3.0.0</version> <executions> <execution> <id>copy-dependencies</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/libs</outputDirectory> <overWriteReleases>false</overWriteReleases> <overWriteSnapshots>false</overWriteSnapshots> <overWriteIfNewer>true</overWriteIfNewer> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.6.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>com.spotify</groupId> <artifactId>docker-maven-plugin</artifactId> <version>0.4.11</version> <configuration> <imageName>${docker.namespace.prefix}/${project.artifactId}</imageName> <dockerDirectory>src/main/docker</dockerDirectory> <resources> <resource> <targetPath>/</targetPath> <directory>${project.build.directory}</directory> <include>${project.build.finalName}.jar</include> </resource> <resource> <targetPath>/</targetPath> <directory>${project.build.directory}</directory> <include>libs/*.jar</include> </resource> </resources> <imageTags> <imageTag>${project.version}</imageTag> <imageTag>latest</imageTag> <imageTag>localhost:5000/${project.build.finalName}</imageTag> </imageTags> </configuration> </plugin> </plugins> </build> <distributionManagement> <repository> <uniqueVersion>false</uniqueVersion> <id>nexus</id> <name>Corporate Repository</name> <url>http://10.44.1.101:8081/repository/maven-releases/</url> <layout>default</layout> </repository> <snapshotRepository> <uniqueVersion>true</uniqueVersion> <id>nexus</id> <name>Corporate Snapshots</name> <url>http://10.44.1.101:8081/repository/maven-snapshots/</url> <layout>legacy</layout> </snapshotRepository> </distributionManagement> </project>
Im vierten und letzten Teil wird dann programmiert: Wir erstellen einen Microservice auf Basis von Spring Boot!
Seminare zum Thema