Generator-jhipster: Feature request: deploying outside of the WAR

Created on 12 May 2017  Â·  28Comments  Â·  Source: jhipster/generator-jhipster

I like JHipster, but would like to have more deployments options.

Overview of the issue

Currently, JHipster packages Angular app inside the WAR file:
https://jhipster.github.io/production/

Motivation for or Use Case

An Angular app is a static resource and I don't think that every user's request should go to the Spring Boot or any app server. I'd rather deploy an Angular app under a high-performance Web server like NGINX, and one or more Spring Boot instances would run behind it. This would allow configuring proxies on NGINX so some of the requests wouldn't even hit Spring Boot. I created a diagram showing what I'd like to be able to do.

ng

Thank you!

Most helpful comment

+1 for this feature. There are many advantages having the angular app outside the java application. For example serving the angular app via CDN or via docker container scaled over different docker-hosts and so on.

All 28 comments

There is a microservice architecture already developed just for that purpose.

https://jhipster.github.io/microservices-architecture/

yes please use the microservice architecture for such use cases for monolith we want it to be simple as possible

  • For me this is totally valid to do this with monoliths. I know people doing the same kind of thing using Varnish, for example.
  • From a performance point of view, I'm not sure it's such a good idea : serving static files with Spring Boot is very fast, and adding one layer on top of each REST request will slow them a little bit. So I'm not sure here.
  • From a scalability point of view this is a good idea, and something I would like to push, at least for monoliths (otherwise you can't scale them, and parts of the work we did with Hazelcast is useless)
  • This is in fact a pattern I wanted to have with AngularJS 1 (not sure how it will work with Angular 4, but shouldn't be very different). I also wanted to be able to serve static assets through a CDN. We should be able to document it, as basically all the front end is in one folder, so you just need to move it around. You could also do the opposite: all REST requests start with "/api/" so that should be easy to filter.

Re-opening, at least so we document this.
We could also generate a Docker Compose file that configures Nginx for a monolith.

@jdubois >serving static files with Spring Boot is very fast, and adding one layer on top of each REST request will slow them a little bit.

Nginx is blazing fast but it's not only about speed. Some third party services may offer private API keys that are not safe to use in the browsers. We could store them in the Nginx layer, which will be adding these keys while proxying requests to such services.

@jdubois : Maybe we should add an option to not package static files into war and let users to copy paste static files from a prod build (from target/www) into there nginx configuration. I already did that on a project on AWS (serving static files on S3 and Cloudfront) and using war as backend only.

And with a docker-compose file we could do it quickly. But this could be a submodule on marketplace I think

So, with docker-compose, the idea would be:

  • if monolith without discovery, no change on app.yml
  • if monolith with discovery, or microservices

    • add nginx to app.yml

    • no mapping port on gateway (see this line)

    • load balancing by nginx to all gateways, so we can scale the gateway without port conflict

    • the hard part is to correctly config nginx with dynamic gateways

  • I would only do this for monoliths: for microservices, the gateways are supposed to be the "edge servers", so putting an NGinx in front of it is not the idea
  • Anyway, NGinx support should be optional: I am not totally sure it is a good idea (at least it is not always a good idea), and I'm sure some people will want to replace it with something else (there are lots of competing technologies).

So:

  • Having a "nginx.yml" file is great, for monoliths (and maybe microservices)
  • I would not reference it inside the "app.yml", it's preconfigured but not mandatory

So I got this working with Nginx, and in fact it's pretty simple: just serve the front end from target/www and do a proxy to the backend on /api.

However, I have a hard time to "automate" everything with JHipster, I still need to find a good workflow for both dev and prod profiles.

I still can't find a good workflow here.... So for the record:

My Docker Compose configuration for Nginx:

web:
  image: nginx:1.13-alpine
  volumes:
   - ./../../../../target/www:/usr/share/nginx/html
   - ./nginx/site.conf:/etc/nginx/conf.d/default.conf
  ports:
   - "8000:80"

My site.conf:

server {
    listen 80;
    index index.html;
    server_name localhost;
    error_log  /var/log/nginx/error.log;

    location / {
        root /usr/share/nginx/html;
    }
    location /api {
        proxy_pass http://application:8080/api;
    }
}

To have this working fine, my current solution is:

  • Generate the front-end separately from the back-end. We already have those options in the generator (those are flags, --skip-client and --skip-server).
  • Generate the NGinx conf only on the client side, and put the front end inside (in the conf above I'm just mounting a volume, we should have a specific Dockerfile like the one today in src/main/docker/Dockerfile where we ADD the application inside)
  • Use the docker-compose sub-generator to have a full Docker Compose configuration with both front-end and back-end

-> however, I find it quite complex, and very close to our current micro-services architecture, so I'm not totally convinced

Julien, what about generating this setup only when skipServer option is
passed and we can add a dedicated documentation with steps to do this as
well. I think it could be a good middle ground

On 21 Jun 2017 8:22 am, "Julien Dubois" notifications@github.com wrote:

I still can't find a good workflow here.... So for the record:

My Docker Compose configuration for Nginx:

web:
image: nginx:1.13-alpine
volumes:

  • ./../../../../target/www:/usr/share/nginx/html
  • ./nginx/site.conf:/etc/nginx/conf.d/default.conf
    ports:
  • "8000:80"

My site.conf:

server {
listen 80;
index index.html;
server_name localhost;
error_log /var/log/nginx/error.log;

location / {
    root /usr/share/nginx/html;
}
location /api {
    proxy_pass http://application:8080/api;
}

}

To have this working fine, my current solution is:

  • Generate the front-end separately from the back-end. We already have
    those options in the generator (those are flags, --skip-client and
    --skip-server).
  • Generate the NGinx conf only on the client side, and put the front
    end inside (in the conf above I'm just mounting a volume, we should have a
    specific Dockerfile like the one today in src/main/docker/Dockerfile
    where we ADD the application inside)
  • Use the docker-compose sub-generator to have a full Docker Compose
    configuration with both front-end and back-end

-> however, I find it quite complex, and very close to our current
micro-services architecture, so I'm not totally convinced

—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
https://github.com/jhipster/generator-jhipster/issues/5754#issuecomment-309975337,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABDlF7h3qvoxeYCjlieg1RJhnis_V3wzks5sGLakgaJpZM4NZ0Wa
.

@jdubois, @deepu105, I have been doing the following in my current project with great success:
Basically we have a simple pom.xml file in the front-end only project that uses the frontend-maven-plugin and docker-plugin to do the build. This way building the front-end app is similar to building any microservice (mvn package -Pprod docker:build).

I also think we would need some kind of templating for the nginx configuration so that the proxy_pass URL can be changed by environment variables but then it adds some more complexity.

  • Yes @deepu105 that might be only a documentation issue. What people don't see is that our front-end and back-end are already totally separated (that's how we can support AngularJS 1 and Angular 4 at the same time, and that's how the gateway/microservices work). And that's because we don't document this anywhere! Then, it's mostly a matter of copying the right directory in the right place, when you know where everything is.
  • Another solution with my current setup: only use NGinx as a proxy, including for serving the front-end application. I know this isn't the "spirit" of this ticket, but there's a huge gain here: JHipster provides the correct caching tags (something NGinx can't do), so in the end the application should be much more efficient.
  • @PierreBesson not sure I understand everything completely, can you show me your setup next time we meet?

@jdubois It's simply a pom.xml that contains only the front-end maven plugin setup. We initially added this because we were struggling to get the front-end to build in our corporate Jenkins but now I would not do any front-end project without it.

I think we're overcomplicating things here. On the frontend, all we'd need is the ability to specify an API prefix in a single file. By default, it'd be an empty string. It could be customized to point to a different port or a different server altogether.

On the backend, we just need a single property that specifies where the frontend is located (e.g. http://localhost:4200) for CORS. Of course, it might be needed for emails as well.

I don't think we need to use Docker containers for any of this to work.

@mraible The idea is not to force users to use docker but just to provide a way to connect everything with docker-compose for integration testing. It might be useful when having multiple front-ends. Of course we can implement both solutions.

@jdubois are we still doing this?

No, not currently.

  • I have something that works fine for me
  • But it's really hard to transform this into a template, and I'm not sure everybody will agree

-> I plan to write some documentation on this first (it's really easy to do, as that was planned from the start), and then see how we could industrialize it

Hi,

I already deployed a frontend to a sparate web server. As I understand i just need a way to tell it where the backend is and maybe something on a backend side regarding CORS. I'm i right? Can someone help with an advice. I don't see any config for that. Thanks

Hi

What you need to have is a front service with nginx or apache for example
who will serve your static pages (html and javascript) on your front files
be sure to reference your backend server on service url. Enable CORS to
allow traffic from your front to backend. Then I think this should work
fine. For security purpose and if you dont need your backend to provide
service to other application you can authorize only traffic from your front
and block the others. @pbesson should confirm but i think this is all what
you need
Le mar. 8 août 2017 à 20:06, Nenad Djordjevic notifications@github.com a
écrit :

Hi,

I already deployed a frontend to a sparate web server. As I understand i
just need a way to tell it where the backend is and maybe something on a
backend side regarding CORS. I'm i right? Can someone help with an advice.
I don't see any config for that. Thanks

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/jhipster/generator-jhipster/issues/5754#issuecomment-321035973,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ARWTrVdKT6ug9a9eUfryRtRU3sN71elnks5sWKOwgaJpZM4NZ0Wa
.

Thanks for the quick answer. The front is already on some AWS nginx, the jhipster generated one for a test, I pulled the www out of target folder from a prod buiild, but all the api calls target the same host. I guess there should be a way to tell the front where the back is, the url.

Currently all calls to the API expect the API on the same host. I'm also in favor of adding an apiPrefix or baseUrl variable so the frontend can reach a backend hosted elsewhere. This is what @mraible suggested above.

@ndjordjevic For now this change requires manual work, you will need to edit each service file that makes a call to the API (there's 14 places in a default project with no entities, found with grep -R 'this.http' ./src/main/webapp/app/).

Nenad if you use aws you can deploy your front on S3 bucket with server
function and use cdn for better performance
Le mar. 8 août 2017 à 21:23, Jon Ruddell notifications@github.com a
écrit :

Currently all calls to the API expect the API on the same host. I'm also
in favor of adding an apiPrefix or baseUrl variable so the frontend can
reach a backend hosted elsewhere. This is what @mraible
https://github.com/mraible suggested above.

@ndjordjevic https://github.com/ndjordjevic For now this change
requires manual work, you will need to edit each service file that makes a
call to the API (there's 14 places in a default project with no entities,
found with grep -R 'this.http' ./src/main/webapp/app/).

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/jhipster/generator-jhipster/issues/5754#issuecomment-321055949,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ARWTrUJYLPfIf5WPAqNFUa4PvuAiPYWfks5sWLWjgaJpZM4NZ0Wa
.

+1 for this feature. There are many advantages having the angular app outside the java application. For example serving the angular app via CDN or via docker container scaled over different docker-hosts and so on.

I spent a few hours on this, and for me we have in fact 3 different use cases:

  • People who just want the "performance enhancement" of putting the front-end in a CDN, but code the front-end and back-end as one single application. This should already work - in fact it's already working with Google App Engine (I checked this with the Google developers last week in NYC). It's mostly a (simple) configuration in your infrastructure -> I will document that.
  • People who want to code the front-end and back-end separately, but in the end will deploy everything as a single application -> for me this is what @yfain wants, and this needs Nginx/Docker... As discussed here it's quite complex, and varies a lot depending on what people want, so it's hard to automate. My best solution at the moment is also to document that, and give my Nginx configuration. An example of the complexity: I'm basically doing this at the moment, by I use Apache and not Nginx (as the Let's Encrypt bot works automatically with Apache), so that's yet another use case (oh, and that's also a nice config I need to share)...
  • People who want 2 separate applications, using CORS. This is what @mraible wants. I have coded 99% of this (and of course I'm blocked at the last 1% and can't guarantee when this will work).

Please also note that in dev mode you can do wonders with the BrowserSync proxy, and solve a lot of those issues - so for me the biggest question is the prod mode.

I got the CORS part working, I will commit and link it here - then I'll do a specific documentation part for this, and close the ticket.

The documentation is written and will be linked here just after the next documentation release.

I'm closing this, as I want this ticket to be in the next generator release (the generator release is done a few seconds before the the documentation release).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

shivroy121 picture shivroy121  Â·  3Comments

pascalgrimaud picture pascalgrimaud  Â·  3Comments

dronavallisaikrishna picture dronavallisaikrishna  Â·  3Comments

edvjacek picture edvjacek  Â·  3Comments

kaidohallik picture kaidohallik  Â·  3Comments