JCON EUROPE

Java Container Mastery: Optimizing Images Across Build Tools | Matthias Haeussler (EN)

49:00 · 20 Apr 2026 – 23 Apr 2026 · YouTube

About this talk

In this session, Matias discusses the integration of Java applications within container environments. He explores various methods for creating container images, focusing on Docker files, multi-stage builds, and the use of build packs. Matias highlights the importance of optimizing images for size, security, and performance, particularly within cloud-native ecosystems. The talk also covers the functionality of JLink and JDeps for creating custom Java runtimes, as well as the advantages of tools like Chip that simplify the image-building process. Through examples, he demonstrates how developers can enhance image structure while maintaining efficiency, and the need for consistent base images to ensure security.

Full transcript

[music] Okay, good afternoon. Um, seems like the the conference is kind of winding down a little. This I think this is the the last session here in this um in this room. So, thanks a lot uh for coming. I'm going yeah to close it up with a session about uh Java and containers. The yeah just maybe a few words about myself. I'm from the south of Germany

from the area of Stoutgot. My name is Matias. I work for a company called CGI um in a role where I help a lot of clients in their adoption of a cloudnative journey and the the practices and technologies. Besides that, I'm also um a lecturer at two universities in in the area where I do modern distributed systems. So that basically means distributed systems with modern technologies. Um

and it's probably fair to say that this this talk and many others originated out of that lecture. Um yeah. Oh yeah, this I was asked to to add this. This is that uh slido thing where you can ask questions, but um since we're not so many people in here now anyways. Um and I'm used to to teaching quite a bit. So if you have any things on

the way, just feel free to raise your hand. Um and I'm I'm happy to answer questions. I also make sure we still have a bit of time left at the end if you um if you want to save it until then. All right, so diving in. Um what is this about? I mean um a situation probably which is not like newest state-of-the-art anymore. A lot of people

are facing that already. Um having Java or JVM based code and you want to put that into a container image for running your um for any application either in the cloud or any other container runtime. So what I'm want to talk about today is what kind of options are out there to do that. And for people that have been dealt with it in the past might think

okay um we know options we have things like docker files but actually there are more things around and you might have heard of one or the other um just a question who in here was in the in the talk from uh Katherine Adelise yesterday. Okay a few yeah so um you might have heard about the terms of of build packs already then and um I'll I know

what she's talking about so we'll try to to pitch a bit of different things. So this is not um a repetition but good to see that there is interest and um so why why are there options or why why do am I doing this talk? Um I mean in the end people might have constraints or certain drivers what they what they want to do what they expect

um when when um putting their code into container and there different things where you can optimize I mean you can do it in a very simple way um we will see that and you can do it in a very optimized way which is normally not so simple anymore then um if you want to improve on things like speed for either build the the the envir the thing

or or run it later on memory consump ion size optimization and and most importantly probably security and structure because I think this is not as a fancy new topic as AI but is getting widely adapted across the industry and especially if more like also regulated environments uh adapt to that. This is these are these are things that that needs to be um answered before you before you

turn it live. So I would assume that most of you know what a container is. just a quick repetition also um to go into the um the the structure optimization later on. I mean in the end uh a container is nothing but like an isolated process um which is basically the part on top which contains all the necessary libraries and dependencies that it needs to execute under

the hood. This is being done by namespaces change within croups in a shared Linux kernel. So, if you're very good with those low-level functionality things, which I am not, you don't actually need um container technology because you can build it all by yourself. But for the for the rest of us, there are things like like Docker around um that provide a simple API to um to build

these constructs and um and handle them. Now, an image um is basically the template um that you that you need to instantiate uh container process. So thinking in Java terms you can say like the the the image is the class and the container is the object. So you you run the an image and you get an instance of a container with a bit more focus on Java

and also for the internal structure. It's important to understand that containers are built off layers and the container demon can cache those layers and that's a point where you can uh focus on when when optimizing. So in the end a typical Java application will have some base layer um with some operating system libraries then a Java runtime and in the end an application on top. Um and

if we go back in history um in 2013 uh is when docker became like it wasn't when it became popular but when when it kind of started um I think this was one of the first um log entries in in in git. Um there's that term docker file. So some some of you might not know that before that you actually had to build your images by hand.

So you like either put a commit and a run and layers all on top and assemble your image that way. But a docker file kind of made that easier. So it's like a uh a sequential list of instructions that are being processed. And important to understand is that each call in a docker file will result in a layer of an image later on. So the image is

not a big blob. So it these these layers are independent artifacts um that can independently be cached and processed. Now this one would basically as I say take a base layer install the Java copy the char file in and tell the tell uh docker to say whenever I do docker run please execute that command. Um if you look at things like which base image with b java

base environment am I am I running my things? I took this screenshot today on the Docker hub from the um Eclipse Teamarine website. You will see a very simple Docker file. Um this will actually run and this will actually work. But I want to come to a point that you also understand same as I that this is not the the best optimization format you can get and

also why this is that way. Unfortunately, I mean I need to say um a lot of people don't especially if you're like from a developer background, you don't really want to worry about that. I mean you worry about your code, your functionality and you want to wrap things in a container and make it run and if it does that what should be wrong right um and what

I encounter a lot in the industry is a lot of the docker files are actually built exactly that way now a couple of things for those let's say simple docker files first thing you need to choose is your base um base layer you either can combine an operating system layer with a Java runtime or put it in separate layers that's up to you And this is already

kind of a choice which one are you about to pick. There is something you need to take care of. Um if if a certain layer or a base image deprecates, you're not going to see that when you execute um the Docker file. You see that and the deprecation notice um on the Docker hub. But this can be dangerous if you don't update your Docker files since they

have been running so fine all the time. So in I just had this as an example still in the in the code repo. um this will still work. This will still compile. Um but um you basically are running on a on a Java runtime which is far too old anyway, but you're also running on a base image which is not uh supported anymore and might expose of

course security risks with that. Now I'm going to come to security later. Um the next evolution of docker files was a so so-called multi-stage um functionality so to say where you say you we have two from clauses in that docker file the first one and the second one in the end only the second one will be the image that you use later on so with the first

stage uh you do you basically build a different container for a different purpose in this case I'm using that as an um as a [clears throat] build container so basically I I pull a maven an image and then I uh compile my code. As a result, I get a char file and I copy that over um to the um to the final uh run image. That is

of course a good thing because you basically ensure consistency in the in the in the files I showed before this they leave completely open where this jar file comes from that you copy in. So this is not can be seen as a as a as a um a vulnerability of let's say robustness. Um uh you can handle it in your pipeline but it's unclear basically given from

the docker file where is that coming from. With this one you kind of ensure that whenever you do that build it will always be built using the specified um uh build environment um and it will always be embedded in an image with the right runtime environment. So you just have to declare this one as the build stage and then you can copy over from that stage to

the um to the later run environment. The evolution continued in 2018 to a thing called build kit um which talked about improved caching, smaller images, uh different stages and so on. So this was kind of when Docker became more popular or container became more popular and um it was a thing to to make that um that evolution better. Also this kind of I mean you could stay

now and you do different parallel stages assemble all your things in different way to a certain point it turns the docker in a bit of a programming language and added more complexity to a point where it wasn't really necessary. So I'm sure I'm not using all of the features in there and I'm I'm pretty sure most people don't uh as well. One of the helpful features though

for um uh especially in development is this kind of mount cache where you can say if I use that multi-stage environment I'm I'm continuously building my code um if I redo that I always have to download all my dependency chars again. So um a container doesn't really cache. So you build run from scratch and with this one you basically reference a point in your file system where

you put in all your downloaded jar files and subsequent builds will be much faster. I wouldn't recommend to do this in production but um for development purposes that this is a really helpful thing that can speed up your process. Now with these initial things um and the development up to that point we can say what makes it makes an image good what are criterias I've already listed

a couple of them before like speed size structure simplicity security and maybe standardization so what do I mean with that in reality things still look like that um so it's not super standardized and it's not super secure so what can we do to make this better. Um, a couple of configuration uh configurations considerations there. I just I already said the image consists of layers and um the

overall size of an image is like the sum of all the layers. So so far so easy to understand and when you rebuild your applications it should probably be the case that the application layer is much often replaced than the than the base operating system layer. If that one changes every time, you have a different problem. But um what I see unfortunately that a lot of people

try to optimize on the base layer um and take things out of an operating system image and build their custom images and so on. Um this is okay, but this becomes a problem if different teams do it in different ways. The point I'm trying to make is um this base OS layer has to be loaded by the container demon only once and if multiple different teams use

the same base environment then these layers will be cached and your and your um your processing will be a lot faster. If you have a lot of small and customized base layers and which change often then you have on the one side of security risk which I'm going to bring up in a second but also you don't improve your overall um your overall speed. Um if we

take that consideration for like forward and say okay the application layer will change with every build and in the way that we've seen it before in a Java environment it would probably produce a new char whenever I changed a single line of code. This can also be optimized because also a char file has a structure where where it has like the class files inside resource files and

the dependency jars and as you can probably imagine the class files are the smallest amount but also the ones that change most often. This is also be also possible to take advantage of. Um in this case this is a spring boot example where I say after I have built my application I kind of extract that jar and I extract that jar into like directories of dependencies the

spring boot loader snapshot dependencies and the actual application and I copy that extracted char over uh in that segmented way that means that if the dependencies and and all uh and spring boot loader and so don't change it's only that fourth line which has the application class files getting updated and that and all the other things can be cached. So this is normally in in a build

step it will only take a couple like a couple of microsconds because it's it's very um very small. I mean these are optimizations on a top end. People might say they they don't need that but yeah I try to go a bit into into the details here and what you can also see from this starting from that four two threeline docker file now to the one where

I built inside the the docker file and I extract the the code and I put it into layers. Um of course the thing is the more you optimize the less simple it is. So this is not as easy to understand as the one we saw in the beginning. You can even take this further. So I talked about the base layer and I talked about the application layer.

Now let's talk about the Java layer. Um what I only learned in 2023 even though it was there from I think um Java 11 um are the two tools called Jlink and J deps. They don't they don't really interact with the application side. They focus on building a custom Java runtime. So the Java runtime is also a modular structure and by default you get like the full

thing but your application might not always need the full thing. So you can assemble your Java runtime by just putting those modules into it that you actually need and also from a security point of view it's of course what is not in a container can't be exploited. I mean keeping an image small doesn't only pay off for the for the speed of processing or for your like

disk space it also has less attack surface um where you can do damage. So this is basically being completed by a thing called J deps and J deps actually looks at your application and rep and returns the dependent modules that your JRE needs in order to execute it. So with the combination of J deps and J link you basically can get a custom Java runtime which is

like tailored to your um specific application and putting that all together makes the file of course um even more complex. So we have a build step now. Um we have the Japs and Jailing to create the custom JRE. Um we have the extract part where we split things into layers and later on we pull it all together. And this doesn't even do anything about uh for example

using a non-root user and and other things. So this is kind of the the thing with the Docker files. I mean the Docker files, they certainly give you most granular control um over building your container images, but it's like they either have two versions. Either they are simple, but then they're not very optimized, or they're optimized, but then they're not very simple anymore. And somebody also um

needs to maintain that. Sure. No. Okay. >> Um, so the the question was, if understood it correctly, um, would this one build faster than an image where you just put like the char file in? Um, definitely not. I mean, um, with the when when you just copy the jar file in, the build time is actually outside the scope of your container build. So, it's it's kind of

difficult to measure. So you already arrive with a pre-built jar. In this case, you basically have a section where you compile your application and that takes as long as the basically as big as the application is. The actual executions for JDAPS, JLink and this extraction tool, they're almost neglectable. I mean you this is something you don't really feel. Um and um this will not slow down your

process. But of course taking the the compile part into the docker file will will change the things and ideally you don't basically execute this in in forms of of a pipeline. But as I said before um it works works of course locally as well. All right. So um I want to go into that direction a bit further. So we just talked about that considerations and the optimization

of the base layer and what I also said before if if something is not in the container it can't be exploited and out of that reason people try to do optimizations um in that way to make something better but often they are not fulfilling that goal. So for example, if you have multiple different development teams and they all write softwares maybe not only in Java, maybe in

in other programming languages and frameworks as well and they have the task to deliver that in a container image. Most likely you're going to end up with very with a with a collection of of many different base images because there's a diff many different examples and sources. Um and technically what they're doing for them individually is not wrong but as soon as they also start maybe optimizing

on that Ubuntu layer or that Davian layer or whatever else you get a very fragmented landscape of base images. Now if some vulnerability comes up, so the news in the morning would say there is this um this vulnerability has been detected. What would people normally try to do in the first place is of course try to figure out am I affected and having such a like scattered

landscape of different base layers doesn't help to identify that problem quickly. So what I normally suggest is try to keep like the base layers up to a certain point as consistent as you can. Um and then you can either say well I have this either even if this Ubuntu image is way bigger than for example that Alpine just the fact that you know that everyone um is

using the same thing uh you can quickly say well I'm affected so I have to rebuild everything or I'm not affected so I don't have to worry. That's a lot faster and a lot safer than digging through all the different um stacks and figuring out if things are good and bad. And I'm not trying to make a point for Ubuntu here. This is just an example. Important

is more like the consistent thing and use something which is basically coming from a reliable source. Um, right. So these are the things that I would say are the learnings that you can take away from from uh what we've seen with with Docker files. As I said from the bottom, keep it simple and consistent. Don't be too experimental on that uh on that side. um if it's

a a JVM based thing try to optimize with JLink and JDAPS remove everything from the Java runtime that you don't need and on the um on the application side separate the build and run stages and try to apply that layout structure this is from my understanding almost as good as you can go of course there are final like individual different tweaks um but this is kind of

the message that I normally also tell to my students and my clients now there is more Um there's a a friend of mine has once drawn this kind of timeline of different technologies revolving around um container stuff and a couple of things you should probably he like um I want to I want to bring up first off the term build packs. Build packs um I'm going to

talk about in a second is something which originated from Heroku and Cloud Foundry basically as a built-in component into a pass layer. Um, then Spotify brought up a Docker Maven plugin. So, you could basically generate images out of a Maven build. Um, there's this cool tool chip that I want to talk about. Um, and this kind of shows how things evolved. I mean, today, I think when

this image was made, today was 2022. Now, it's 2026. It's still relevant. It's still right. And so, I'm the next thing I'm going to talk about is chip. By the way, what I should probably mention um and I'm going to show give this to you later. I'm not going to code much, but everything in that presentation is based on a git repo where I have all the

various docker files for each of the different examples in there. Same as the commands to execute chip and build packs later on. So if you want to try this yourself, um I'm going to give you the git link um after this talk. So chip is um a development or like a built tooling which comes from the uh from from Google and this is basically works as a

maven or gradal plug-in. The very good thing with chip is that it doesn't require a docker demon. So um as the container image has a standard and the layers have a a standard how they how they are supposed to be built, they can be generated without running a container demon. So this is a a pretty good advantage if you say you have an environment where you're not

allowed like in a built pipeline or so to run a docker demon for whatever reason. This will still give you the option to build um images directly. Another side effect is it's it's really fast. Um the downside is it of course works only for um JVM based uh components since it's built on Maven and Gradel. What you do with your image later on is your thing. You

can push it directly to um to Docker Hub. Uh you can export it as a tar file or if you do that locally and you have a Docker demon running, you can basically of course also push it to the local registry there. Um chip is basically just of course one command. um you add it as as a as a maven uh command line switch or put it

into a pom file um and then you save all the things uh around your docker file and some of the stuff that I've talked about before especially the slicing the Java file into different layers is automatically built into chip so you don't have to specify that explicitly um and um you have like a a clean image with a consistent base um and a very well structured applications

side out of the box with little effort. So, this is normally my my my go-to solution um when when I'm sure I'm I'm completely in a in a Java environment. All right. And then finally to the topic of build packs. Now the way build packs work or where they come from is the the pass world or originally Heroku and as I said Cloud Foundry where people had

the idea so you push code to a certain platform and then the platform automatically transforms it into like a running application that you can scale and and and um and restart. Just think as an blackbox kind of Kubernetes without writing any kind of YAML files. And um this life cycle works in a way that the the build pack would detect um what kind of application is it

then build it change it into like a runnable kind of format which we would call a container image nowadays and and execute it. The advantage with build packs is this isn't limited to one programming languages. So the build packs exist uh for a for a couple of different um frameworks and and languages. So it means you can use the same command invocation um for for different things

and the build peg itself will basically work out how the component is built and structured and it doesn't leave the task to you. I mean of course you can configure it. Of course you can even write your own build packs but the standard is normally pretty good. So I said it started from Heroku went to cloud foundry. This was all a long time ago and then suddenly

there docker came around and kubernetus came around and it was people suddenly were in the role of having to build their own container images like as we are in today and then um the people from heroken cloud foundry said well why don't we take this out of the platform and basically make a proper external project out of it so they created cloudnative build packs as like a

reference our um implementation and many subsequent implementations followed. So there's a there's a Google implementation, there's a Heroku implementation there um one is called Pakto. This is was from the original cloud foundry part. So these are things that you can use um to automate your builds without writing docker files and with handling all your all your needs. The way how that works um you just basically execute

a command called pack and um this will download a very big image which is called builder image that contains all those build packs and then basically is putting your code through that life cycle. So it's analyzing the code and in the end it's um building your application depending on what uh what what code it is and also optimizes the layer structure in your container. The good thing

is it only needs one command. Um the downside as you can say you will have to download one additional image but you have a very standardized procedure in the end. Another very important feature in those build packs is that rebasing functionality. Um so in the beginning of the presentation told I told you you normally like the top side of your container is the one that should change

more often. Now I'm telling you that you can also basically update your base layer without touching the top layers. And that's exactly the situation I was talking about before when I said try to keep your base images consistent. This is what the build packs do automatically. They have one base image for everything. And of course um and that's was the same thing as it was in Heroku

and Cloud Foundry. So whenever there was a vulnerability they could quickly say okay we're not affected then we're fine and or we are affected either we have to rebuild everything or we have to patch it with a certain uh command. So for example when the lock 4J vulnerability was exposed all of the things in cloud foundry were running again in within minutes because they could say sure

okay we're affected everywhere. Um so we just put in that fix and then everything is fine again because we know we have all we we have all the systems um safe again in particular for that uh vulnerability. And that rebasing step is just basically exchanging all the base layers in the image creates new images and then you can continue with that without a lot of overhead. That's

basically the thing I said before. You can do this manually um of course um with with Docker files or you can use mechanisms that that do that for Now for PTO um um as I said if you use that for a Java application you probably have already guessed it that structure of like class files resource files and dependency chars is already given there out of the box

you don't need to specify that um individually if you I think if you have a spring boot application I'm not sure if this going to come yeah you can also use this as a maven or cradle plugin so um that's very convenient. I normally prefer the pack command. So I'm not dependent and say okay I'm I make a different a different approach for Java and non-Java application.

I just want to mention it's there. Also the part that I mentioned before with JLink and J deps is not a default setting in those build packs but you can enable it. So if you switch it on then your code is going to be analyzed and the um like the custom or tailored JRE is going to um pop out and being added as the central layer in

your final image. All right. Um but that's we still have a bit of time then. Yeah, I'm going to do this first and then maybe um show a couple of steps live. I mean why am I all doing this? Um I as I said before I don't want to like say I'm an advocate for this solution or this one is better than the other. All of them

have their strengths and with all with all of them that I have shown you can get to the same goal. But if you have certain like different kind of constraints one solution might be better from the other or you can also take the like um the approaches from one solution and apply it with the others. Um of of course very important as I said keep your base

images and layers as consistent optimize on top. Try to avoid wild growth because that will um will hit you in the end. Automate and standardize as much as possible. And again there is no universally best solution. There might be a best thing depending on if you want to go for control for speed for standardization and so on. So I tried to make this kind of chart even

though I'm not super happy with it because you I'm a consultant and each of those things has a certain it depends factor to it. Um but still I mean what is important to say if you want it very simple um a docker file can be very simple but then it's not going to be very optimized. Um the more you optimize the basically the simpler it gets but

of course you have super granular control then about your security settings um size structure and so on. With chip the big advantage is it's like very simple super fast. Um the downside is yeah it is kind of limited to the world of of Java. Um the the build packs um they are super in in this standardization and and structurization also supporting multiple frameworks and multiple languages. It's

just yeah um they add you you need the um an additional component to do it. In the end it's just another container that you download to execute it. So it's not a big deal but it's it's at least something that you need. And um yeah so this is kind of this the stuff I I wanted to make sure um I I tell you now I actually have

given a very initial version of this talk at JCON I think during the COVID phase so it was a remote talk back then so a lot of the things I mean it's interesting to see it's still a very relevant topic and things are also changing. So questions I get often is um how do things work with um with other frameworks? I mean I didn't show much of

the demo. Um it's just a very simple spring boot application and all of the docker files that I have here are basically targeting that application. Um I got asked how are things like for quarkus and for micronode with I mean the important thing is most of the things especially for chip and build packs they work across all frameworks. So this is there there's nothing like is something

targeted just only for for the world of spring um in in caucus it's already caucus and and micro came a little later to the game. So um when when spring boot became popular docker wasn't really there yet. was just about to emerge when when when Quarkus and Micronode came, Kubernetes was already a big thing and you could see that people would want to use containers. So they

already come with predefined Docker files here in an example of Quarkus and since they have a high focus on building native applications, you kind of get a get Docker files if you do a native build or if you do like um a standard um JVM build. Here you can also see they they split it into layers, copy the individual layers in. So it's the same thing there.

Um yeah, native images. I just mentioned that. That's another question I get fairly often. Um I mean for those of you not familiar with um Grav VM native images, in this case you build your Java code into like a a native binary which kind of contains all the information. It sounds a bit similar to a container image, but it it's only from a very certain point of

view. I mean, in the end, with a native image, you optimize for a certain underlying um architecture. With a container, you more like try to be independent of that architecture. Nevertheless, you can put native images also into container images. What you unfort what you can't do is basically to say I am optimizing within the native image and separate it in the same way as we did with

a char file. However, what you can do is of course still try to to follow the same principles and say no matter if I have a traditional build or if I have a native build, I'm trying to keep those layers uh um like in sync that I have um on on the bottom layer. And if you use something like build packs which can of course also compile

uh native images again you get this just out of the box. Um yeah something which is also changing um especially as I said before since the topic of containers is more coming into like a regulated world of big enterprises um the security and supply chain security um aspects. So, espawns is a thing to not just to say um yeah, how how good and efficient is my image

also what's inside of that image. Can I have like a verified statement of all the components which are contained or basically where was it built, how was it built and and what was involved to make your image basically traceable um and more trustworthy than just to say yeah I put this from the Docker Hub and it should be fine. Uh we all know this can be a

dangerous statement. So Docker has built that into um generate sbomb and define that kind of provenence layer build packs automatically generate sbombs for for chip. I need to say I I don't know that I have to figure that out. Also in that kind of evolution um you might have heard of things like secure base images or hardened images. I mean Docker is still the um the the

number one name I would say around the the container technology. They have had this offering of Docker hardened images around for a while. They just released this as an as a free kind of um offering at the end of 2025. also bellsoft and chain guard have um such so-called hardened images which in the end are im images which have done a lot of the optimization I was

talking about. So they try to reduce the footprint they try to reduce the the CVE exposure and put in that a lot of this prominence to say okay this is where it comes from and this is how it has been built. um additional things like of course nonroot execution um are um are given in those images as well and so the docker hardened images is the one

I've just recently started using at a client and the the pitch they're basically making is that you can say you have just like this drop in adoption so you say what whatever was your your previous image you have like a hardened images so you see it's a different image registry dh iio U which has all those hardened images and um at at the moment there are about

thousand images available. So they have been built with a certain standard. They come with an asbond. Um they have all they they have a detailed list of what's what what are the CVEs in there. So you you know pretty well what you are doing. And I'm kind of hope that this will become also the new standard. It doesn't need to be the the Docker one, but if

you if you look to that that that diagram I'm coming back to again, um you can just now say I'm taking this Ubuntu layer out and using that standard hardened image either from Doco or from Belloft or from Jangot or wherever else. The important thing is just I'm using one of these for all and then I can be pretty pretty sure um this is fairly safe and

I get frequent updates on that. All right. Um, yeah, I it's I have five minutes left, so I don't think it's a lot of a big point to like start doing a demo now. Um, I mean, the demo is not so super exciting because I basically just execute Docker files. What I can show you of course is um these are my docker images and these are all

the Java images that I have built using um the the docker files in in in that ripple and you can um let's maybe have a look if we so from the from the size perspective I mean they vary from like the most of them are in 300 megabytes but you can see there are really small ones 93 3 185 139 these are the ones where this JLink

um functionality is applied. So the the basically the um the JRE is stripped down to the to the part which is only needed with an alpine you have a super small layer of a base image and then you then there's your application on top um and there's no other um things made. So I can look at the um the docker file for you quickly again. Um so

this is the one um we basically use a heavy image of Maven to build the code. Um then we use that tarine 25 to do the ch the tabs and jlink but in the end um the alpine is like a small base image. Then we copy in the JRE that we've built as a custom JRE with that JLink command here. And then I'm copying. In this case,

I didn't even optimize on the layers. Please apologize. Um, so I copied over the entire char file. This is a step that I could potentially still optimize. I think I have it in another file. Um, yeah, here. So, um, there's an additional stage for extraction and then basically copying all the the components over. If you look um let's just um compare the two things for those who

haven't seen it yet. So this the tamarine let's look at the tamarine. so if I say docker history and in this one you can basically see this is probably the base layer of the application. This is the 198 megabyte is basically where the the the the Java runtime comes in and the 23 is basically the char file as one big package. And if we compare that to

like um a layered one which is the layered call it JVM flags No, that was I must have taken the wrong one. Give me a second. I'll take that one. Yeah, I mean you see that mess if you have too many um Docker images. So here you can see that um that copy step of that individual layers and we had about what do we have 23.3 megabytes

before now you can see 23.1 are only in dependency chars and only 4 kilobytes are basically the the application code which has changed so this is a small char file in general but you see the relation and that's even going to be more if you have um large larger char files so that change becomes um pretty pretty small and all the other things are getting cached chip

and and and um build packs are doing that out of the box and I think yeah let's just wait since we have one or two more minutes um so I have the pto jl link here so I'm just make make sure I use could take the right one so if I do a docker history here I could also use a tool called dive um to analyze the

individual layers but here you can see Um yeah, we have a a pretty small base layer. Um here we have that JLink created Java runtime which makes about the still the biggest portion of that of that container image. And here on top we have the application also sliced in this time being done by the by the build pack. And again we have 23 megabytes of code and

only six kilobytes uh of of of dependencies and only six kilobytes of the application code. And it comes along um with some more information and esbomb information putting into the application. So it's just a little better cleaned up than than a typical docker file. All right. So with that, um, I want to say, um, thank you for listening and I still have time for a few questions.

In meantime, I leave this open so you can check out the repo if you're interested. Yes, >> I meant JVM. I mean, basically pretty much everything you can build with Maven or Gradel, you can use Chip Forb since it is a plug-in there. So of course um cotlin is not a problem either. So >> that's a good question. I cannot answer that. I'm I'm sorry. I also

can check on slido if you have put anything in there. Um where is my link? how would you try to find the trade-off between a standardized Java base image maintained by a platform team and trailing optimization per application. This is yeah I mean this is hard. This is a typical it depends question. Um if you have um a platform team which takes care of that and of

course this makes makes it uh it comes with with a certain size of your organization and um let's say breadth of applications then it makes sense to say okay uh if it's under a certain limit we just use um a typical um provided image from a verified publisher and I also need to say the the hardened images, they also have um hardened images with Java runtimes in

there. So that's something I would suggest there. Um and if you have a a bigger team like and and people maintaining that, it can of course make sense to optimize like build your own custom base layer at your um at at JLink and Japs to optimize on that um on that Java runtime. I mean in the end it's really hard to say um because this is kind

of the middle layer ways where where I would say this is where like should end and customization would basically start. So it's it's pretty much up to you. Also if you say I don't see the the chance of vulnerabilities popping out of the JRE itself. It's normally on the on the level of the operating system. you're probably true and in the end um this layer will then

be cached and can be used for many different applications as well. So the the efficiency optimization is just like having a smaller image on on on the disk. Um I can recommend either side. So it's it's really hard to say where to make that trade-off. Uh, I just wanted to make sure I show you both ways to be aware that this is actually this is actually possible.

And I mean I would probably say um in a in a build pack variant you have this all covered. I mean um you have uh you can specify as just one command line flag uh when this getting invoked um optimize the the Java runtime and then you have the full consistency in place. So you have a standardized base image, you have the optimized runtime in the middle

and the also the the sliced So I hope this answers the question and I think I saw another one. Uh I have a feature complete micros service that only gets dependency updates. Could I use chip build packs for a reversed layer sequence? Yeah, you can do that. I so it's just like a different build mechanism that you basically set to the to the same to the to

the same source repo. I mean, it's of course one of the points that I'm trying to make is try those things out. I mean, obviously they're not as well known as Docker files are for um for obvious reasons. Um, but yeah, it's it's it's not it doesn't mean you have to start with them and continue with them all over. A lot of people have started with Docker

files and then adopted those things uh on the longer run. I even had customers that uh wrote their own build pack implementations according to their company standards with also makes sense on on at a certain level of um of dimension. All right. So if there are not more questions then I would just say thanks for listening and thanks for being at the conference and still have a

a nice evening. >> [applause]

From event

JCON EUROPE

20 Apr 2026 – 23 Apr 2026

All event videos
Back to Watch