 Hello, everyone. My name is James Faulkner. I'm a technical marketing for Red Hat, focusing on app servers and developer tools. Today, we're going to talk about fat jars. And we're going to compare and contrast a couple of popular fat jar technologies and frameworks that utilize fat jars to deploy applications onto your production environment. So we'll look at Spring Boot, Eclipse Vertex, Drop Wizard, and Wildfly Swarm. So how many of you have heard of fat jars before? OK, good. Well done. So fat jars, I probably need this slide. They're easily portable. They're easily runnable, especially in IDEs. You specify the main class, and it loads it up in the JVM, and off you go. And you have all your dependencies inside the jar file. You have no downloads. You have no initialization of app containers. It just runs. Everybody supports it. It's been supported actually since about 2011. Drop Wizard was the first. A lot of people think that Spring Boot kind of popularized the use of fat jars, but actually Drop Wizard was first. So kudos to them. Yes, thank you, Ver. So essentially, everything is packaged in a single jar. All your dependencies are resolved at build time so that at runtime, you have no resolution required. Everything's there. It starts up relatively quickly, and you can't run into problems where, oh, it can't find this jar file or this other dependency somewhere else, and the thing fails at runtime. That's the last thing that you want in production. If you're using Linux containers, like for example, Docker, everything in the fat jar is in a single container layer, because it's actually in a single file put into the Docker container layer using your Docker file that you build. And so that also means that when you change one line of code in your 200 megabyte fat jar, the entire 200 megabytes gets recreated and re-added to the Linux container layer, meaning if you then redeploy that container image out somewhere else, all 200 megabytes are transferred over the network and stored in your S3 bucket in AWS and is reflected in your AWS bill. So one prime example of this is a company called HubSpot. They do marketing automation. HubSpot started building fat jars. They have over 100 developers doing a number of commits per day, probably a couple of hundred pushes to production, and they were using fat jars. Every single one of those developers was building a fat jar and pushing that into their corporate repository every single time they did a build. Every time they did a deployment, every single one of those megabytes in their fat jars were being pushed out to their nodes. This resulted with one to 2,000 builds per day and a couple of hundred production pushes per day, they were generating around 100 gigabytes of new bits per day. Now you can imagine 100 gigabytes times the cost of storing, computing, and transferring that across the network resulted in a huge AWS bill. So they started to look at some alternatives and started to get away from fat jars. And they came up with a homegrown solution where they built their dependencies independent of the application itself, pushed those dependencies out to Amazon, to S3, and then when the application was deployed to production, it would pull those dependencies and cache them locally so that all the applications deployed on that particular node could reuse those same dependencies locally and not have to pull those dependencies down. So they essentially created a homegrown solution of what Spring Boot, Wildfly Swarm, Vertex, and DropWizard do today. So I'm gonna show you some of the standard tools that you can use to kind of essentially recreate what HubSpot has done using supported technologies from Red Hat. Okay, so in a typical Docker container, if you're not using containers, this doesn't apply to you, but for Docker containers, they are built up by a number of layers. So when you build a container image, the first thing you do is you add an operating system, the user land bits from the operating system. And you can see that down here, this is using CentOS, it's around 190, almost 200 megabytes. The next layer up is Java. So the JDK or the Java runtime environment with all of its dependencies, all of its tooling, all of its compilers, all of the things that you need to run a Java application is in that next layer up. That comes out to be around 200 megabytes or so. Then the top layers are some, so in this case for you, this is an S2I build of a Java EE application. S2I is a technology in Red Hat OpenShift for doing source to image, that's what it stands for, for taking your source code, combining it with a runtime and then packaging that up as a Linux container image. So this is an S2I build. There are a couple of very small build scripts, essentially negligible in size. And then the last layer at the top there you can see is around 209 megabytes. That is the app server, in this case it was JBoss EAP, along with the application itself. So the app server was around 150 megabytes, something like that, and the app was around 50 megabytes. So this is something you typically see in a Java EE app server Docker image. Compare and contrast that with, say, Spring Boot, and its Fat Jar technology. So in this case, we still have the same kind of layers, we have an OS, we have Java, and we have the app, but they're much smaller. The operating system is Alpine Linux, it's a very, very small, very highly optimized for running in containers. Java is still pretty sizable. It's been minimized somewhat in this image, but it's around 100 megabytes. But then the application itself, this is the Fat Jar, it's around 14 megabytes. So that's a little bit of an improvement. So let's take another example. So Wildfly Swarm, Wildfly Swarm is a Java microservice framework for Java developers. Traditionally, Java EE developers have had access to a number of functionalities in Java EE app servers. Wildfly Swarm makes those same functionalities available, but allows you to package it into just enough app server. So only the bits that you need from the app server along with your application. So, and the result is, again, a Fat Jar. So this is the same exact application except it's built with a Wildfly Swarm. It's essentially the same, so we still have the same small operating system, the same smallish Java. But then we have two other layers here. And in the demo, you'll see how these are constructed. But there's a, what we call a hollow jar, that's the Wildfly Swarm runtime. And then the application sits on top of that. So it's very similar to the Spring Boot example, except in the Spring Boot example, everything is packaged in one. We, in the Wildfly Swarm example, there are two different layers. There's a nuance of why that difference is, but it actually turns out it's not all that important when talking about Fat Jar. So you see the very, very small application. This is literally only the bits that you type into your IDE is two kilobytes, right, really small. So the benefit here with Linux containers is if you change any of the layers at the bottom, every single layer above it has to be rebuilt and redeployed and transferred across the network. If all you change is the top layer, that's the only thing that needs to actually participate in a build. Everything else is cached. You don't need to pull those other layers down when you want to deploy this to production. So putting small things at the top layer and the very fast changing things, the things that you change every single day in the highest layers is very, very beneficial in the world of Linux containers and container orchestration platforms like OpenShift. Okay, so let's look at the Fat Jar kind of Hello World plus one library. So keep in mind this application that I built and then generate these numbers from this is not a real world application, right? This is a Hello World app. It has Jaxrs in the case of Wi-Fi Swarm and Spring. It's a very, very simple application that just outputs one line of code, nothing you'd ever seen production. It's very instructive to look at that because that is where you kind of filter out all of the noise from real world applications to get to the technology itself and to compare them and contrast them and show how you can build them in different ways. So you can see the sizes of this Hello World Fat Jar across the different technologies here. So Wi-Fi Swarm comes in at around 45 megabytes, Spring Boot 17, Drop Wizard 15 and Vertex at a very attractive four megabyte. Again, for Fat Jar, this ICE difference is actually important, right? Because you're transferring more bits over the network every time you rebuild the Fat Jar. These technologies come with additional features that people may not know about. Moving from the Fat Jar to away from Fat Jar makes a lot of sense in the containerized world because of the layering and because of the amount of change that goes into building applications, say microservice applications, they're built and deployed hundreds of times per day in a real scaled production environment. So again, getting those bits at the topmost layer is super important. So let's see about how we can do that. So before doing that, I want to explain some of the technology I've been using like hollow and skinny and fat and thin. We all know what Fat Jar is, right? That's everything. It includes the application runtime. It includes the application's dependencies and the application itself. So the application itself, the red box, this is the bits that you type into your IDE and you compile and they turn into dot class files in the Java world. The application dependencies, the direct application dependencies are things that your app needs that the app runtime doesn't supply. So things like database drivers or some library you may be using. In this case, in my Hello World example, I had a time library that made sense of the crazy Java dot util dot date fiasco in the previous JDKs or Java versions. And then finally, the app runtime are the things that are necessary, kind of the final mile or final kilometer to get the application running on the JVM. So in the traditional Java EE world, this would be the app server. This would be the thing that Java EE, either JBOS, EAP or WebLogic or WebSphere or whatever. So all of those combined is the Fat Jar. The thin jar or thin ward, depending on the technology you're using, that contains the app and app dependencies but not the application runtime. The thin war or jar is not runnable on its own. You cannot run it without this other glue to actually make it run. If you try and run it, it's gonna fail with some class not found exception. And then the skinny package, this is the app itself. This is a two kilobyte example in the wildfire swarm. Again, not runnable on its own but also not runnable without its dependencies and with the runtime that it needs to run. Okay, so that's Fat, Skinny and Thin. And then the term hollow, that's essentially the application runtime itself. So in a traditional sense, the hollow application is the app server, is the Java EE app server, right? That's the app server. If you run this by itself, it will run but it will do absolutely nothing other than initialize itself. It needs applications to make actual business sense. But packaging it on its own has a lot of value, especially in the world of Linux containers. It's had value in the past because now you have this prepackaged thing from a vendor like Red Hat. You can ship it around, you can patch it independently of the applications themselves. So it makes a lot of sense to be able to package that separately for a number of reasons. Okay, so here's the grid of supported options. And after this slide, we'll do a demo. So everybody supports Fat. That's been around forever and that's a well-known. It's very easy to understand for developers and for IT operators. The ability to separate the application from the application runtime is what we call Thin. Those are also supported by all four of these technologies via different mechanisms. So in the Spring Boot case, there's a thing called Spring Boot Thin Launcher. This is an experimental library written by some of the Spring Boot engineers. I hope hopefully we'll see that actually supported and put into the next version of Spring Boot, next major version of Spring Boot, which is Spring Boot 2, which is I think coming out, I heard later this year or sometime in the very near future. Wildfly Swarm actually, because of its Java EE heritage, Wildfly Swarm supports Thin jars or Thin Warfiles natively. This is kind of the default way you create applications in Java EE. When you build a Java EE application, the output is a Warfile, which is generally pretty small. It doesn't include the app server itself. That's exactly what Wildfly Swarm does as well. And you'll see that in the demo. Vertex and DropWizard don't have kind of first-class support for Thin, the ability to separate them out, but it is possible to do that via some Maven plugins and some Maven support. So Maven has the ability to just generate the dependencies for the app and put them in a separate directory. Then you can use Docker to kind of build those layers independently and do it yourself. So Vertex and DropWizard don't necessarily have first-class knowledge or support for it, but you can certainly do it. Then the Skinny Hollow is kind of a super-efficient packaging mechanism. And again, Boot, Swarm, and Vertex all support this via different technologies. So for Boot and Vertex, they support it through essentially Docker itself, being able to create a Docker layer image with the dependencies separated because Spring Boot and Vertex both know how to separate their dependencies. They just don't know how to package them up. So they use Docker to do that. Swarm has a packaging mechanism within it called Fractions. Via Fractions, you can separate the application from its direct dependencies, from the application runtime itself, and truly create all three of those layers independently with first-class knowledge in the tooling for the technology. You could do all of this with Swarm without Docker, for example. So it knows about Thin, it knows about Skinny, and Hollow. These concepts are built into the project. Let's do the demo. So what we're gonna do is basically just walk through all of these technologies that I just kind of gave an outline for and show you how it works in the real world. Okay, so I have a number of projects here. Apologies if this is a bit small on the left, but these are just a list of a number of projects I created to demonstrate this stuff. So let's start with Fat Jar. Everyone knows Fat Jar. We'll start with Wildfly Swarm here. I have a very simple application. So it's a RESTful application. It has an endpoint, which essentially just outputs that. So if I build that, Maven Clean Package, so what this is gonna do is invoke Wildfly Swarm. It's gonna look at, find all the dependencies, package them all up into a single Fat Jar. Okay, so it's up here now. Hopefully a little big enough to read. So if I look at the result of that build, I see my Fat Jar here. Wait-1.0-swarm.jar, if I run it, Java-jar-target-wait-1.0-swarm.jar. It'll essentially run this very basic service and I can hit it with API slash hello. So, curl, HTTP, PS, or local host, if I can type, 880, API, hello. Right, very simple. It's also using that time library, which I'll be using in a moment to show you how to separate the dependencies from the app itself. But there's a basic, yeah, so this is local date.now.getstring. This is that Jota time library that I was telling you about. So a dependency separate from the app, but not part of the app server. Okay, so that's the Fat version of a Wildfly swarm app. So let's take a look at DropWizard. So DropWizard, I also have a very simple application here. It's, I think it's on API saying, so if we build that, so let's go to DropWizard, Maven Clean package. So that built and the resulting Fat Jar, as you can see here, is about 15 megabytes if I run it. So Java-jar, oops. That's jar, if I can type again. I got to kill this one first because it's sitting on the same board. Target, target slash, blah, blah. Oh, I got to run it this way. It has a bit of a different way to start it up, but it's essentially the same thing, right? Fat Jar from DropWizard, very well-known technology again, the first to do Fat Jars. And if I run it here, I can just do curl, I should be local, host, maybe 80. I think it's greeting. Yeah, so there's the Fat Jar from DropWizard. Again, about 15 megabytes, right? Much smaller than the Swarm version, but let's keep going. So after DropWizard, let's look at Spring Boot. So Spring Boot, very popular. Actually, kind of the Docker of Fat Jars, right? Docker made Linux containers really cool. Spring Boot made Fat Jars really cool, although again, they weren't first. So I have a very simple application here. It is sitting on, I believe, on the root, okay. Or maybe it's greeting, I don't know. So let's build that one, we can stop this one. So let's go ahead and build the Spring Boot Fat Jar. Spring Boot, Fats, Maven Clean Package. So there's my Spring Boot Fat Jar, it's about 14 megabytes. And if I run that, Java.shar.target.bat. So that comes up, and I can hit that as well. Local host, I believe it's local host. Yeah, it's just on the root. So there's my Spring Boot Fat Jar, again, about 14 megabytes. And then the last one is Vertex. So let's take a look at Vertex. So I have a very simple vertical here, just basically just outputs again, a very simple message. So let's build that one. So Vertex, Fats, Maven Clean Package. So there's my Vertex Fat Jar coming in at a very small size, about almost four megabytes. So Java.shar.target.bat. So it's up and running, and I can hit that with, I believe it's also on the root, right here. So that's our application. Okay, so that's the easy stuff, right? Now let's look at the more interesting things. So let's look at the Thin War, or Thin Jar. So this is the ability to separate the application, bits you type in from the application runtime. So here, again, with Wildfly Swarm, we'll start with Wildfly Swarm. Actually there's nothing to do with Wildfly Swarm because, as I mentioned, it already natively creates that Thin Jar file, or War file. So you can see here, it's already created this weight-1.0.war, right? This is the Thin app. It only contains the application. It also contains the application's dependencies. So if we look at what's inside of that, I only, it's like a three line application, but it's still about 500 and something kilobytes. So what takes up the space? Well, in this case, it's the Jota Time Library, right? It's sitting in there, although I've created my Fat Jar and it's less than a megabyte, it's still way bigger than it really should be because I only typed in one line of code, yet I have a huge file that's gonna be uploaded. Every single time I push that, every single time I change that one line in the code, it's gonna repush those bits. So we'll take a look at what we can do to separate that in a moment. So, but that's the concept of Thin in Wildfly Swarm. So what is the difference? What is the concept of Thin in, say, Spring Boot? So I have, again, an application, a simple Spring Boot application with, it just outputs, it's exactly the same application, but it's built slightly differently. So let me build it and I'll show you what happens here. So Maven Clean Package. So again, it's building the application with Spring Boot, but it's doing it in a slightly different way. And if we take a look before I show you the application, or the result, if we take a look at the POM file in the Thin version of Spring Boot, let me make this a bit bigger here. So we have the traditional dependencies for Spring Boot. We have, we pull in the starters that we need, we have the web starter here, we have our JotaTime library there. We also have the Spring Boot Maven plugin, but we also have a dependency within that Spring Boot Maven plugin, which creates what's known as a new layout for the resulting application using what we call the Spring Boot Thin layout, or Spring Boot Thin plugin. So that's essentially all I've added to my POM file. And so what happened when I built that, if we go into the directory where the thing is created, you can see I now have a Thin JAR file, I don't have the Fat JAR file. It's about 11 kilobytes. The dependencies themselves are actually in a directory here called Thin. What this actually is is a Maven repository, a local Maven repository. So if you look at what's in that directory, it's essentially a Maven repository with all of its dependencies from the application itself. So if I run this Java-JAR greeting Spring Boot Thin, it's a runnable Thin JAR, right, which is slightly different from Wildfly Swarm. Oh, I think I have something already on running here. I gotta kill that one, try that again. So it's actually resolving its dependencies from that local Maven repository that was created as part of this plugin. So the application runs, I can hit it on Curl, I can show you that, but I assume you believe me by now. But it's resolved those dependencies. So what you can do is to create a Docker image is take that Thin layer, combine it with the application itself, Docker in a Docker file. So I have a Docker file here, which is very simple. It basically adds two files to the Docker image. It adds the dependencies from this Thin directory, and then it adds the application itself. So if I Docker build this, Docker, say Docker build, I'll call it Spring Docker build. So you can see it actually, because I haven't actually made any changes to the application, it used the cached version of the dependencies. So the Docker build was very fast. The only thing that was added to the directory here was my actual application itself. If I make a change to this application, say from Java one, save that and rebuild it, Maven clean package, rebuild the application, which rebuilds everything, the dependencies and the application. But then when I rebuild the Docker image, it goes very fast. And the only thing that was added, that was not cached, was the application itself. The dependencies haven't changed. It was able to use the cache within the Docker registry and then rebuild it very quickly. And then I can run it using run-p8080 to expose the port. It's like run this within the Docker image and then essentially do the, we'll do exactly the same thing. It'll expose that on a port and I can hit that on local host 8080. And I get my Spring Boot Thinjar. Did I change the wrong file here? Yes. Okay. I believe that I changed the wrong file. Yeah, this is the one I needed to change from Java one. So that was the default. Yeah. Let me rebuild this Spring Boot Thin. Docker build, rebuilds and then I'll rerun it. Hopefully and I will get the message I was expecting which has the Java one string in it. I just changed the wrong file here. So let's hit it again and it didn't work. Okay. So what did I not do right here? Spring Boot Thin, Docker build, Docker run. Oh, I didn't rebuild it. That would help. So you actually have to build the application itself to compile the bytecode into the Thin layer and then rebuild the Docker image and then rerun it. Okay, let's see if this works. This doesn't work, then I'll give up. Okay, so there's the image. So essentially I made a one line change to the file. It only resulted in about 11 kilobytes of change instead of the 15 or 16 megabytes of change that would have resulted if I was building a fat jar. So very, very powerful mechanism for saving a lot of sanity in IT departments. Okay, so that's Spring Boot Thin. Now let's take a look at Vertex Thin and then we'll go get to Wildfly Swarm which is a very interesting use case. Okay, so for Vertex Thin, so if you remember from the graph, Vertex Thin is actually supported through Docker. So what that means is I actually have a Docker file which is pulling from a pre-built Docker image. This is a Docker image that the Vertex project makes available to me. This is essentially representing the app runtime, right? This is Vertex Core plus a couple of other dependencies. This is how I get the notion of a Thin application in Vertex. So when I built this, I just built it, the actual application itself is only about four kilobytes or three kilobytes, very small. The fat jar again, if you recall, is four megabytes. So there's a pretty significant order of magnitude difference between the Thin jar of my application and the fat jar in Vertex World. So to realize this with Docker, again, I have this Docker file. It essentially just adds the vertical. Because it's getting Vertex from the base image, it's only adding the jar file itself, the application itself. So if I then build this one, Docker build, HT, Vertex, latest, dot. So again, it's just adding my application here. Then I can run that, Docker run dash IT dash P 8080. And then I got something running. So I still have my Spring Boot app running. So let me kill that, run this again. So it's already up and running. It's super fast. Vertex is one of the fastest starting applications in the world in my opinion. Then if I can hit it on local hosts, so there's my Vertex Thin jar application. Again, if I were to make a single line change to the application and rebuild it, the exact same thing from Spring Boot would happen. I would only get a couple of kilobytes of change in the Docker layer. Everything else would be cached and saving me network compute and storage and saving my AWS bill. Okay, so that's Vertex. So let's take a look at, the last one we're gonna look at is a wildfire swarm. So we already talked about wildfire swarm fat jars. That's pretty clear. We talked about wildfire swarm Thin wars, which is essentially coming from its Java EE heritage. So let's talk about skinny and hollow. So in the wildfire swarm case, it has this concept of fractions. So if you recall from the earlier discussion, in the, when I built the Thin jar, or the Thin war of wildfire swarm, it contained 500 kilobytes of bits. That's way too big, right? This should be very small, .0, .jar. Oops, jar. So target. So there's, oh man, let me try that again. There. Okay, so here's my Thin application in wildfire swarm, right? Here's my application itself, which is like one kilobyte. And then here's this humongous library, 630 kilobytes, right? That's pretty expensive when you scale to the scale of HubSpot or Google, who does two billion deploys per week. That adds up quickly. Not only that, this is a hello world application. In a real world application, you're gonna have fat jars they get up to. In the HubSpot case, they're fat jars. Real world application, right? Successful company, 200 megabytes was their fat jar size. That's one of the reasons why their bill was so huge. So you can really easily get up to large fat jars. It makes a lot of sense for developers, but it is a death knell to, yeah, two minutes. All right, cool. So it's bad for IT departments. So with swarm, what we can do is do what's called a skinny. So let me build it and just describe what's happening here. So actually, in order to get rid of that library and all the libraries that I eventually add, I need to create a fraction. This is a first-class citizen in swarm. So I actually created a fraction for this JodaTime library. So I do Maven clean package install, and while it's building, I'll quickly show you what it looks like. It's a very simple, it's got very little code in it. In fact, it has almost no code in it. It has a single kind of class that tells, well, if I swarm that this is a fraction, it sends from this fraction class, and then it has a module file which describes its class dependencies itself. This is a JBoss module. This is a technology coming from the JBoss world, brought into while if I swarm, makes it possible to create these fractions. So if I look at the, if I then, so I've built my fraction, I've installed it, now I want to go ahead and build the application using that fraction. So I have a skinny application here. If we look at the POM file, it's got a dependency on my Joda fraction that I created. This is separate from my application. It's not built with the application. It's brought in as part of the swarm runtime. So let's go ahead and build that. So if I go to skinny, maven, clean package, what I'm gonna get is I'm gonna get that hollow jar file. It's runnable, but it doesn't do anything on its own. So I just built it. Now you can see I have this hollow swarm file. This is the original, this is the, this is the wild fly swarm minus the application, but adds that Joda fraction that I talked about. So now I've packaged all of my apps dependencies plus the runtime into this hollow swarm file. I can then run this, this tiny, tiny, tiny application. This is the bits that I've typed into my IDE. That's only two kilobytes, right? I've now separated them out. So now I can then, again, with Docker, I can build Jchefs swarm latest. I can then put, oh boy, Docker build dash T. I can then put those separate bits into separate layers. So here you can see the hollow swarm was added as one layer and then my application itself was added as a separate layer. When I make a one line change to the application, that is the only thing that's gonna change. Nothing else will change. The application runtime, wild fly swarm in this case, will not change. It will not be re-downloaded, it will not be redeployed. It will always be cached and you save a ton of money on network compute and disk again. So last thing, I'll just run it. Actually, let me go ahead and run it real quick and then we'll finish up. Docker run dash IT dash P, 8080, 8080. Okay, I got something else running. So let me kill that, try it one more time. Oops, I just built it again. Okay, last one here. This is the money shot here. So it's running a wild fly swarm but then bringing in that application separately because the application is now split from the application runtime. By then curl it, API hello. So it's there. This is the skinny jar using that externalized library put into a separate Docker layer and it's very powerful. So that's kind of the rundown. Last thing is the kind of packaging recommendations. So fat apps, fat jars work well. People understand those. For small applications it makes sense but you very quickly, if you're building a real world application at scale, you're gonna get into a situation where you have 100 megabytes of a fat jar. That multiplied by the number of nodes that you have and the resulting storage necessary and network transfers costs a lot of money. So that's when you're gonna start wanting to consider splitting the application out of a fat jar into a thin or hollow jar or war file and separating those into separate layers so that you can save money. HubSpot is a great example of this. They actually did their homegrown solution but with wild fly swarm and spring boot and Verdex and Drop Wizard, you have kind of options in the projects themselves, supported options from the projects and in Red Hat's case, we're supporting these through the Red Hat OpenShift application runtimes. You can do this on your own using support from a vendor like Red Hat. So that's it. Thanks for hanging out. If you have any questions, I'll be around. But thank you.