Maven 부모 POM
Gradle 플러그인의 대응물은 부모 POM `spider-silk-maven-parent`로, 그 `pluginManagement`와 프로파일이 같은 패키징을 담고 있다. Maven은 빌드 컨벤션을 플러그인이 아니라 상속으로 공유한다: Maven 플러그인은 골을 실행하며, Gradle 플러그인처럼 다른 플러그인의 설정을 선언할 수 없다.
<parent>
<groupId>net.benelog.spidersilk</groupId>
<artifactId>spider-silk-maven-parent</artifactId>
<version>1.1.0</version>
</parent>
부모 POM은 Maven이 기본적으로 검색하는 Maven Central에 발행(publication)되므로, <parent> 블록 곁에 저장소나 settings.xml 항목이 필요 없다.
선언으로 옵트인하기
모든 것이 부모의 `pluginManagement`에 들어 있으므로, 자식이 플러그인을 선언하기 전까지는 비활성 상태로 머문다. Gradle 쪽의 `spiderSilk { jte() }`가 그렇듯, 그 선언이 옵트인이다. 컨테이너화하고 jte를 미리 컴파일하는 자식은 둘 다 선언하고, 애플리케이션 자신의 것만 설정한다:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>flashcard.FlashcardApp</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<configuration>
<to>
<image>ghcr.io/benelog/spider-silk-flashcard:${spider-silk.image.tag}</image>
</to>
</configuration>
</plugin>
<plugin>
<groupId>gg.jte</groupId>
<artifactId>jte-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
메인 클래스는 실행 가능한 jar가 어차피 원하는 자리인 jar 매니페스트에 한 번만 선언한다. Jib은 거기서 엔트리포인트를 추론하고, `native-maven-plugin`은 바이너리를 위해 같은 항목을 읽는다. 대신 어느 한 플러그인에 설정해도 동작은 하겠지만, 둘이 어긋나기 전까지다.
선언이 상속하는 것은 Gradle 플러그인의 컨벤션을 그대로 반영한다:
-
Jib은
eclipse-temurin:21-jre위에 빌드하고 포트 8080을 노출한다. `mvn package jib:buildTar`는 Docker 데몬 없이 `target/jib-image.tar`를 써내며, 배포가 설명하는 대로 레이어를 나눈다. -
maven.compiler.release`는 21로 설정되며, 이는 Jib이 베이스 이미지와 대조할 Java 버전을 읽는 자리를 겸한다. Gradle 플러그인이 흡수하는 `targetCompatibility문제는 흡수할 Maven 대응물이 없다. -
jte는
src/main/resources/jte아래의 모든 템플릿을 빌드 시점에 미리 컴파일하며, 네이티브 이미지 리소스도 포함해 템플릿이 설명하는 그대로다. -
네이티브 바이너리는
<fallback>false</fallback>`으로, 대부분 정적으로(--static-nolibc`, 그래서distroless/base컨테이너는 glibc 외에는 아무것도 빚지지 않는다), 그리고 도달 가능성 메타데이터 저장소를 활성화한 채로 빌드한다. 그 이름은 `${spider-silk.native.image-name}`으로, 프로퍼티가 달리 말하지 않는 한 artifactId다.
native 프로파일
`mvn -Pnative package jib:buildTar`는 jar 대신 GraalVM 바이너리를 실어 보낸다. 이 프로파일은 `native:compile-no-fork`를 `package`에 바인딩하고, Jib의 베이스를 `distroless/base`로 바꾸며, 같은 바이너리 이름을 가리키는 Jib의 native-image 확장을 붙인다. 네이티브 이미지 장이 그 전환을 훑어본다.
위 자식의 이미지 이름에 있는 ${spider-silk.image.tag} 자리 표시자가 두 이미지를 구분해 주는 것이다: 부모는 이를 `latest`로 기본 설정하고, 프로파일은 `native`로 바꾸며, 대신 태그를 하드코딩한 자식은 그 구분에서 빠진다.
Dockerfile 워밍업
`mvn dependency:go-offline`은 플랫폼이 Dockerfile을 요구하는 곳에서 Gradle 플러그인의 `resolveDependencies`에 대응하는 Maven 쪽 대응물이다. 이것은 워밍업 레이어를 위해 의존성과 플러그인을 내려받으며, Gradle Dockerfile이 빌드 스크립트를 복사하는 것과 같은 방식으로 pom만 복사한 뒤에 실행된다.