jhipster-lite
jhipster-lite copied to clipboard
Add GraalVM support for JHipster Lite
- fix https://github.com/jhipster/jhipster-lite/issues/2819
This adds GraalVM support to JHipster Lite.
To build the native image:
mvn -Pnative clean package spring-boot:build-image -DskipTests
To run it:
docker run -p 7471:7471 -it docker.io/library/jhlite:0.2.1-SNAPSHOT
What still needs to be done:
- Eclipse JGit doesn't support GraalVM, so when the image runs, calling any JGit method will result in a stack trace. Quarkus has a JGit extension at https://github.com/quarkiverse/quarkus-jgit so this is possible to fix.
@pascalgrimaud one important change: this removes Logback as it's not supported by Spring Native.
Codecov Report
Merging #1483 (b1918b4) into main (bd16d9d) will not change coverage. The diff coverage is
n/a
.
@@ Coverage Diff @@
## main #1483 +/- ##
===========================================
Coverage 100.00% 100.00%
Complexity 1597 1597
===========================================
Files 305 305
Lines 5227 5227
Branches 106 106
===========================================
Hits 5227 5227
Continue to review full report at Codecov.
Legend - Click here to learn more
Δ = absolute <relative> (impact)
,ø = not affected
,? = missing data
Powered by Codecov. Last update bd16d9d...b1918b4. Read the comment docs.
wow thanks @jdubois ! I'll try it soon
@pascalgrimaud I added a GitHub Action step to automatically build the image, but it will only push it to GitHub packages if it's merged on the main branch. This is to limit the size this will take, as you need to pay for GitHub packages (the limit is pretty low). Maybe we should look at hosting this with Docker, JFrog, or Azure Container Registry.
I built the image locally and indeed it started very very fast!
Inside the image, we need to install git
, as some generation part needs to use git.
Otherwise, we'll have this error:
org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.Error: java.lang.NoSuchMethodException: org.eclipse.jgit.internal.JGitText.<init>()
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1082) ~[na:na]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[na:na]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[na:na]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[na:na]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) ~[na:na]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[na:na]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[na:na]
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) ~[na:na]
@pascalgrimaud for Git: in fact you're using JGit, which is a Java library and it is not compatible with GraalVM by default. I'm having a look at fixing this, but this will take time and I will need help.
Ok @jdubois : let me think if we can avoid using git, I'll investigate too
I'm converting this PR to draft, until we find a solution for this :-)
What do you think about recoding tech.jhipster.lite.generator.project.infrastructure.secondary.GitUtils
and instead of using JGit (the Java implementation of Git that causes the issue), using an external command for Git like we do in tech.jhipster.lite.generator.packagemanager.npm.infrastructure.secondary.NpmLocalRepository
(using the locally-installed version of NPM)?
It's a little less portable, but if we consider that people need to have NPM installed, we can also consider they should have Git installed. And for cloud-based environments made with Docker, both shouldn't be an issue (we'll add them to the Docker image).
Yes it's a valid solution, I'm fine with this :)
@jdubois @pascalgrimaud I gave it a try as well, currently native image build fails for me. I do have a few suggestions though:
- we probably can use GraalVM's GitHub action: https://github.com/marketplace/actions/github-action-for-graalvm
- use native build tools: https://graalvm.github.io/native-build-tools/latest/index.html
Thanks @alina-yur for trying this and for your suggestions
The quarkus extensions looks quite small, it replaces the work queue and user home implementation (which seems to be the problematic parts, regarding the jgit issue tracker). I can check it, if we can just use the same substitutes in jhipster lite to make it work with graal without doing heavy refactoring or replacing jgit completly.
@atomfrede : after discussing with @DamnClin I think we'll remove jgit. In fact we don't need it. It means we'll have this feature soon ;)
@pascalgrimaud Awesome!
After https://github.com/jhipster/jhipster-lite/pull/2469 we'll be left with 2 jgit usages:
- In dummy feature -> we should totally rework this one (make it a module, generate different files, etc)
- In init (for a git init), let's replace that by an exec (so that mean you'll need to install git on your servers)
cc @jdubois, if you deploy the current main on a computer with git installed it won't using JGit anymore, hope that helps
Thanks @DamnClin this is probably the easiest way to fix this!
I gave a quick try this morning. Here different analysis:
I upgrade spring.native version to 0.12.1
Then, after building and running the image:
I got:
➜ docker run -it paketobuildpacks/builder:tiny git --version
git version 2.17.1
But I think this image is used only for building, and git is not in the final image
I tried to use JGit from quarkus (the implem is secondary is unchanged), and I can't build the image:
diff --git a/pom.xml b/pom.xml
index 0983c82d0..0f012b938 100644
--- a/pom.xml
+++ b/pom.xml
@@ -48,7 +48,7 @@
<jacoco.version>0.8.8</jacoco.version>
<mustache.version>0.9.10</mustache.version>
<guava.version>31.1-jre</guava.version>
- <jgit.version>6.2.0.202206071550-r</jgit.version>
+ <quarkus-jgit.version>2.1.0</quarkus-jgit.version>
<archunit-junit5.version>0.23.1</archunit-junit5.version>
<springdoc-openapi-ui.version>1.6.9</springdoc-openapi-ui.version>
<problem-spring.version>0.27.0</problem-spring.version>
@@ -104,9 +104,9 @@
<version>${mustache.version}</version>
</dependency>
<dependency>
- <groupId>org.eclipse.jgit</groupId>
- <artifactId>org.eclipse.jgit</artifactId>
- <version>${jgit.version}</version>
+ <groupId>io.quarkiverse.jgit</groupId>
+ <artifactId>quarkus-jgit</artifactId>
+ <version>${quarkus-jgit.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
So I added a new class to replace the JGitGitRepository:
class NoGitRepository implements GitRepository {
private final Logger log = LoggerFactory.getLogger(NoGitRepository.class);
@Override
public void init(JHipsterProjectFolder folder) {
log.info("Can't launch git init");
}
}
After updating Bean configuration, I can start correctly the image. But there is a problem when using the "init" button:
This problem is not related to git
but to something else.
I didn't have time to investigate more
For the command part this seems relevant https://github.com/oracle/graal/issues/1185
Following these links:
- https://docs.spring.io/spring-native/docs/current/reference/htmlsingle/
- https://github.com/spring-projects-experimental/spring-native/issues/1152
I manage to make it works
To fix the reflection, related to jackson :
@org.springframework.nativex.hint.TypeHint(
types = { RestJHipsterModuleProperties.class, PersistedProjectHistory.class, ProjectHistory.class, ProjectDTO.class, PersistedProjectAction.class},
access = { TypeAccess.DECLARED_CONSTRUCTORS, TypeAccess.PUBLIC_METHODS }
)
To fix the git configuration :
package tech.jhipster.lite.git.infrastructure.secondary;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tech.jhipster.lite.git.domain.GitCommitMessage;
import tech.jhipster.lite.git.domain.GitRepository;
import tech.jhipster.lite.module.domain.properties.JHipsterProjectFolder;
class NoGitRepository implements GitRepository {
private final Logger log = LoggerFactory.getLogger(NoGitRepository.class);
@Override
public void init(JHipsterProjectFolder folder) {
log.info("Can't launch git init");
}
@Override
public void commitAll(JHipsterProjectFolder folder, GitCommitMessage message) {
log.info("Can't launch git commit");
}
@Override
public void commitAll(JHipsterProjectFolder folder, String message) {
log.info("Can't launch git commit all");
}
}
And GitRepositoryConfiguration
:
@Configuration
class GitRepositoryConfiguration {
private static final Logger log = LoggerFactory.getLogger(GitRepositoryConfiguration.class);
@Value("${application.git:true}")
private boolean applicationGit;
@Bean
GitRepository gitRepository(GitChecker checker) {
if (!applicationGit) {
log.info("Using No git repository");
return new NoGitRepository();
}
if (checker.hasGit()) {
log.info("Using command line git repository");
return new CommandLineGitRepository();
}
log.info("Command line not available, using JGit git repository");
return new JGitGitRepository();
}
}
In application.properties
:
application.git=true
Then to start Docker:
docker run -p 7471:7471 -it -e APPLICATION_GIT=false docker.io/library/jhlite:0.12.1-SNAPSHOT
I don't understand. If we have to remove the git support then let's just delete the command line implementation. The whole goal of this was to be able to use it on graal, if it doesn't work let's just delete it!
BUT, removing git can't be done just like that, this is buggy since users will still have the commit checkbox on the frontend. I think we should either make git works (probably the easiest one to do) or to something to totally remove git options
@DamnClin : no, I don't want to remove git, I just tried to make it works, that's all and as I didn't find a solution for Git in GraalVM image, I disabled it
I can try the Quarkus like jgit replacement if you haven't done it already.
@atomfrede : you can give a try, I already did it but it doesn't work
Since the command line implementation for git manipulation wasn't helping (but still creating some logic duplication) I'm deleting it in https://github.com/jhipster/jhipster-lite/pull/3228
I think the plan for JGit isn't to use the quarkus dependency but to set this configuration in a spring native way: https://github.com/quarkiverse/quarkus-jgit/blob/main/deployment/src/main/java/io/quarkus/jgit/deployment/JGitProcessor.java
Closing this, in favor of https://github.com/jhipster/jhipster-lite/pull/4314
Oh maybe there can be some ideas which can be taken, specially for the build part cc @atomfrede
Yes maybe we can (re)use the github actions configuration