Docker Base Image with Tomcat+Spring-Boot and config share mechanism - spring-boot

I am a docker newbie seeking ideas.
For a usecase where i need to use tomcat as app server and on top of it add custom spring-boot code and make it a container. Should i be doing that using multi-stage docker build mechanism?
Is it ok to have a base tomcat image and then spring boot image on top of it. OR just put spring boot code into tomcat image and use it in container?
Also i have usecase where spring-boot code will have to connect to external DB (outside image) and want to know best way to have connection pool strategy as i want connections be managed centrally.
Two schools of thoughts -
First is to use docker volumes as i do not want team to use config parameters/environment variables set every time?
Second - have connection pool per docker container so total number of connections are divided by container running (this is risky as autoscaling will take place using Kubernetes)

You have a bunch of questions here - I will start with the most central one.
Deploying Spring Boot Applications in a docker container
If you are deploying Spring Boot applications in docker containers, then there really is no need to use the tomcat image. You just need a java runtime environment in your image, since with Spring Boot you can embed a web server in your fat .jar.
You should be using the spring-boot-starter-web in your project, this will embed the webserver:
Maven example with spring-boot-starter-web - 2.1.3.RELEASE
Add this dependency in your pom.xml (Let spring manage the dependencies by the way, this is just the latest one I am linking here):
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
With this, your Dockerfile will become a lot simpler:
Dockerfile
FROM openjdk:8-jdk-alpine
COPY build/libs/myfatjar.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
Check this guide from spring.io, it goes into the process in detail and outlines your options.
Multistage docker build for Spring Boot application?
I would say that there is little to no need to do this. I will sketch out a few common scenarios here:
Build the fat jar on your dev machine, and then build the image there aswell. Push the image to a registry and deploy from there.
Use a docker image to build your application locally, then build the application image locally, push to a registry and deploy.
If you are using Jenkins, GitLab or some other mechanism to build your image, they will be responsible for building both the application and the final docker image in the same pipeline. There is no need for a multistage build.
Unless you have something specific that requires you to base your application image off of another image - there is no need that I can identify.
Connecting to multiple databases from a Spring Boot application
This is basically no problem. Even though it is considered doubtful practice to simply link external content in an answer - I will do it here. Check this article from Baeldung on multiple databases.
I am not sure what you mean by, that you want the connections managed centrally? Do you have a requirement to have database connections managed outside the Spring Boot application context? That is an antiquated school of thought in my oppinion, at least when dealing with Spring Boot.
But if you are dealing with multiple Spring Boot applications that connect to the same database - then you should consider a distributed cache setup. Like Hazelcast, Infinispan or Memcached.
Binding docker volumes in Spring Boot application container, for configuration
Well, I think I understand what you are talking about here. Generally the preferred mode of injecting configuration into a docker container, and into a Spring Boot application - is to use environment variables. Or Spring Cloud config. Environment variables are particular nice here, because the container can be parameterized with them, and they can be used directly in the properties files that are loaded by your Spring Boot application. And find their way directly into your #Value annotated fields.
However, for a microservice setup with new service instances spawning every now and again, and need to find their configuration - I would advice you to look into Spring Cloud config.
With Spring Cloud cofig, you are essentially introducing a new service into your setup, that is responsible for hosting the configuration of your services. This service is a docker container and a Spring Boot application on its own. And, your other Spring Boot applications will have an easy time utilizing it.
So, basically I would advice against starting to mess around with injecting configuration by mounting it into containers in a docker volume.
I hope I have addressed all of your questions? Otherwise let me know in a comment.

Related

What is value of Docker over Gradle/Maven in Spring Boot Application

Every Tutorial/Guide that I have referred has explained how to build a spring boot application with docker. All those blogs have the same explanation as to why use docker for spring boot application, and it goes something like this
"A container is a standardized unit of software that assembles code, runtime, dependencies, settings, and initialization in a single package that you can run reliably from one computing environment to another."
Wasn't Maven/Gradle built for managing the dependencies? How is Docker responsible to assemble code? As far as I know, Spring boot creates a Fat Jar which runs its own embedded container with the specified JRE. The settings (I understand it as config) is taken from the env file.
Why would one containerize the application? What pain point is docker solving and if possible explain with an example.
Thanks in advance.

Spring Boot REST Deployment: do we need TomCat?

I've seen Spring Boot Rest project that generates WAR then deployed in a tomcat container. I wonder if this is best practice because I've also read that in Spring Boot, the new final executable JAR file contains embedded server solution like Tomcat too?
Now i've seen a related post that talks about Spring Boot supports both ways but none talked about the pros and cons of each.
Can someone point out the best practice for deploying a spring boot rest project?
I'm thinking of dockerizing the JAR containing embedded server but i'm wondering if there's any drawbacks vs deploying WAR to Tomcat?
A general best practice ( from 12 Factor App ) regarding the application environment and dependencies is "Explicitly declare and isolate dependencies".
A twelve-factor app never relies on implicit existence of system-wide
packages
With that in mind one should gravitate more towards using embedded container as part of explicit dependency instead of a requirement that needs to be fulfilled separately.There are multiple choices for embedded container in the jar artifact (like tomcat, jetty, undertow, netty) and their respective configuration is also extensive, so using these in production environment is recommended ( I have used them a lot). However there might be certain times when you would want to create a war instead, for e.g., a war file will be deployable in any full-fledged EE Application server ( Weblogic, Wildfly etc) which might be mandated by your environment. With a war, your number of options in terms of app server increases. Personally for me, spring boot jar with embedded tomcat has been quite effective. With embedded container option what you need is a virtual machine with OS and Java installed and you are good to go.
However there is a special limitation related to JSP as mentioned here in Spring Boot documentaion which explain a good reason why you might need to package as a war but still run as jar.

What is recommended while using spring boot in production deployment (jar/war)

I have an interesting decision to take for my project.
We use spring boot for our micro services.
The development environment is spring boot wíth tomcat in the embedded mode.
However, I am not sure if there are any advantages/ drawbacks if I choose this way in production too.
The counter argument is to deploy a war in a separate tomcat.
I am not able to think on any buying points for both views
What will be the best choice for a large enterprise production system on cloud(jar/war)?
I saw some recommendations here (but I need more stronger reasons to chosse/ not choose any one): Spring boot embedded container or war file in an external container for production
here are my points to use fat jar for production deployment.
fat jars are simple to build and deploy.
Spring Boot aims to be production ready, by default. This means that
it ships with useful defaults out of the box that may be
overriden, if necessary.
Fat JARs are good for running as the microservices as managing
microservices is already a burden then why one more step to
configure and deployment should be considered.
fat jar can also run as a java service easy to manage by a single command, restart server/jvm can be managed automatically.
Spring boot is Embedded with- Tomcat, Jetty and Undertow so changing
app server for any micro services is not a big deal.

What is the best container for an integration/pipeline system written with Camel?

I know the question is very general and the answer is too biased to the scale, scope, type, etc. of the the target system. Hence, actually I want to know what is the pros and cons of using various containers such as spring-boot, single-main, karaf, etc. and also when/why I should to use a container for such a system.
In our previous project my colleagues used apacha-karaf but they had a lot of troubles such as building the project, settings to allow components export jmx, poor documentation, etc. with it. Since the current system is a spring-based application maybe using spring-boot makes more sense. Any thoughts?
The main questions you have to ask is what are your requirements regarding:
How many integration (micro?)services you will have to support?
Will you need to support independent configuration of these services?
Will you need to support independent branching/versioning of these services?
Will you need to have "hot deployment" (i.e. deploying/ updating/ re-configuring one does not inherently affects the operation of the others) of these services?
If the answer is yes to all, then you have two main alternatives:
Go the JBoss Fuse way (RedHat branded version of Apache Karaf). This means that each of your integration (micro)services will be an OSGi bundle in Fuse.
Go with a non OSGi container, but in this case in order to satisfy your requirements you need another layer of managing the life-cycle of your services. E.g. you can take a look at Fabric8 (https://fabric8.io/).
This will mean that you will ideally have one (micro)service per Docker container (instead of a micro-service per OSGi bundle) and Fabric8 will provide you will the Web UI (plus many other tools, like Kubernetes commands, maven commands) to manage the deployment of your service to a Docker container. As a result, a service may be using spring boot/ tomcat, another one may be just a jvm standalone process or another one may be an OSGi bundle running inside Karaf container, deployed inside a docker container. So option (1) can also be deployed to option (2).
Depending what path you follow you have to be savvy with different technologies, e.g.:
Fuse: osgi/ Fuse container, camel, maven, ..
Fabric: your on demand container (e.g. spring-boot/ tomcat, java process, Fuse, python process, scala process etc..), Docker, Kubernetes, Fabric8, OpenShift, maven, ..
Hope this help :-)
I use the java dsl of Camel together and deploy it inside apache-karaf wrapped inside a docker container. The key is to use feature descriptors and a maven repository. Then you can create custom distributions of a camel project which are loaded in your karaf distribution. This means you can work towards a really cool microservice approach where services are deployed as individual docker containers.
The biggest difficult was getting the custom distribution of Karaf working. Once that was done the rest was pretty ok. I don't use spring so can't speak about spring-boot.
Inside Karaf/docker you can deploy hawtio and from hawtio do monitoring, see metrics and do all kinds of other stuff. Karaf also has decanter which has a kibana dashboard and alerting feature.
The answer should totally depend on what container technologies you are most familiar with and what you'd like to do with the Camel application.
I think Spring Boot is best when you'd like to create a MSA application with Camel and you are familiar with Spring already. The good news is that Camel now fully supports Spring Boot: http://camel.apache.org/spring-boot.html
On the other hand, if you have a preference to the classical-style standalone approach Karaf would be a rock-solid option since commercial products like JBoss Fuse (https://developers.redhat.com/products/fuse/overview/) use Karaf as the primary container. Plus, if you are an OSGi lover then no doubt you choose Karaf ;-)
Finally, don't forget that you can also run Camel applications on a JEE application container. Basically you can package them as .war and deploy them to any JEE container, but it should be worth noting that WildFly has an extended integration support for Camel: http://wildfly-extras.github.io/wildfly-camel/ With the WildFly-Camel subsystem you can deploy Camel applications as simple .jar as you do on Karaf.
Actually I have the same question, here is my conclusion:
Karaf
pros:
1. OSGI based, hot deploy and support multiple version.
2. Maven support, can continuously deploy from maven repo.
Cons:
1. Legacy jars are not support OSGI, need to recreate the jars
2. Dependency conflicts are really hell.
3. Split functions into bundles, it will take more time to develop and test.
Spring Boot
pros:
1. Spring is like a glue, can integration different libraries easily.
2. Spring boot make it much easier to startup, develop and test efficiently.
3. Spring boot + docker, will make the deployment much easier in cloud environment
cons:
1. If you want to support multiple version at same time, need double your infra.
So my suggestion is to use camel in Spring boot. My architecture design is like Spring Boot + Camel + Docker + Consul + Registrator

Does spring boot needs a WAS (Websphere Application Server)?

In my theory spring boot is capable of running java web application stand-alone. It says it has a own embedded servlet container and can use JNDI itself.
I built a war file before (spring-mvc, security, gradle built), but Spring boot assemble jar file and it runs on any machine which has JVM.
So my question is, if I made a spring boot based web app (contained JSP files & JNDI for looking up datasource), although it has own embedded servlet container and packaged jar file for running standalone, do I still need to package it as WAR file and deploy it in WAS (Websphere Application Server) or servlet containers for any reasons such as performance, stability, scaling-out etc?
WAS is an full blown Java Enterprise Application Server, on the other hand you have Spring that only requires a Servlet Container (Servlets are a part of full JEE).
Servlet Containers are for example: Tomcat, Jetty, but also WAS.
Spring Boot is able to package the complete application TOGETHER with the code of Tomcat in an JAR, so that this jar contains the Servlet Container and your Application.
Do I need a additional WAS for performance, stability, scaling-out etc?
Performance: No - There should be no important performance differerence between Tomcat and WAS when you run a Spring-Application. (Only that Tomcat needs less memory for itsself)
Stability: Tomcat and WAS are both very mature products.
Scaling: You can build a cluster of Tomcats by your own.
The main features of WAS over Tomcat are:
- WAS supports EJB and CDI (Tomcat would need TomEE for this), but Spring will not use it, because it is its one Dependency Injection container
- WAS has more Monitoring features, but this does not matter, because Spring Boot has Actuator
#See Difference between an application server and a servlet container? for more details
Simple answer is No. You do not need any Full blown application servers for any of the reasons that you mentioned (for performance, stability, scaling-out). You can just do fine with tomcat
Edit
Looks like you are using only JNDI feature from the Application server. Do you really need JNDI when you pack your servlet container along with your application ? I don't think so. That days are long gone.
JNDI really shines when you have to move an application between
environments: development to integration to test to production. If you
configure each app server to use the same JNDI name, you can have
different databases in each environment and not have to change your
code. You just pick up the WAR file and drop it in the new
environment.https://stackoverflow.com/a/7760768/6785908
(If you still need JNDI to be used to look up your data source refer: https://stackoverflow.com/a/24944671/6785908).
No, still I do not really see a reason for packaging your application as WAR and deploy it to traditional application server. That being said, if you have some existing infrastructure lying around and you are being forced to deploy to existing WAS (or WebLogic or JBoss any application server for that matter) server, then I rest my case :).

Resources