DockerDuke

Docker und Java – Teil 3: Der Build-Prozess

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 NexusJFrog 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 kompiliert
  • package: Ein Java-Archiv wird im target-Verzeichnis des Projekts erzeugt
  • deploy: Das Archiv wird in das Unternehmens-Repository ausgebracht

So einfach funktioniert Maven!

Ein Maven System
Ein Maven System

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 Projekts
  • docker: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

 

Dr. Rainer Sawitzki / Dr. Rainer Sawitzki

Nach seinem Studium der Physik und anschließender Promotion Wechsel in die IT-Branche. Seit mehr als 20 Jahren als Entwickler, Berater und Projektleiter vorwiegend im Bereich Java und JavaScript unterwegs. Parallel dazu in der Entwicklung und Durchführung von hochwertigen Seminaren für die Integrata im Einsatz.

Schreibe einen Kommentar