 So every talk needs a structure, and this is how this talk is going to go. I'm going to complain for about 10 or 15 minutes, I'm going to have a good moment, I'm going to complain about everything I can think about, and then for the rest of the talk, Jules is going to solve all of our problems. Okay. So I'm not going to complain about build packs because I love build packs. Does everyone love build packs? Yes. I love being able to do CF push and just worry about my app code and not have to care about shell shock and Heartbleed and pseudo and all that kind of stuff. Build packs are fantastic. They're one of the best things. I am going to complain about writing build packs. Who here has written a build pack? You're heroes. That's fantastic. Did you enjoy the experience? I tried to write a build pack once. Sure. Your question answers itself. I tried to write a build pack once because I'm an enormous beardy hipster. I tried to write a build pack for Haskell. Everyone loves Haskell, right? Yeah, you do. Yeah. One of the many beautiful things about Haskell, it's a lesser-known thing, but it's fantastic. One of the many beautiful things about Haskell is that it's impossible to get an integer overflow using your basic integer type in Haskell. The Haskell language, there's no such thing on the default integer type as max int. So the language is completely happy. If you want to write a program that calculates a single number that fills the whole memory of your computer, the language is fine. You do that. That's great. Okay? This is brilliant. This means you never have to worry about it when you're reasoning about your programs, and that's fantastic. In order to do this, the Haskell compiler needs to rely on a library, a C library, called libgmp, which is an arbitrary-precision math library, right? So when I want to run my Haskell compiler, I'm going to need libgmp to be there. And then the Haskell compiler is going to produce a binary, and that binary is going to be dynamically linked to libgmp because the integer's in it. They're a data structure provided by libgmp. Okay, so I'm going to need libgmp to be in wherever it is that my build pack runs and does the compilation, and I'm also going to need it to be wherever my app runs, all of the many millions of instances of my app. So I'm going to need it to be in both places. Now, fortunately, there is a thing that exists in both places. There's the root FS, we call it at the bottom there. The CF Linux FS. So what do you think? Is libgmp in the CF Linux root FS? No, of course it's not. And this sucks. And it sucks that I even have to know what a CF Linux root FS is in order to write a thing that compiles a Haskell program, right? But okay, it's probably not as bad as all of that. I can just, I can work around it somehow while I'm writing my build pack. So what am I going to have to do? Well, remember that I'm an enormous hipster, so I'm not going to write an offline build pack because I'm just always online. So the first thing I'm going to do is I'm going to, I'm going to W get my library. I'm just going to get it from the internet somewhere. This thing only has to work once. Once I've got my library, what am I going to do next? I'm going to have to copy it into the droplet there. Does everyone know what a droplet is? Yeah, is it tiny piece of a cloud? It's very clever. So I'm going to copy my library into my droplet there because I need that to be there when my app is running. And then I'm going to do a whole bunch of crazy stuff with the LD library path because I'm going to need to be able to access this library when I run my compiler fine. So now I'm going to go get my compiler and that's great. Once I've gotten my compiler, now I can compile a binary and that's fantastic. Now I've done my job. All I have to do is stick the binary into the droplet there and I'm done, right? Except that I forgot that the binary needs to be called with the LD library path magic that I just did, right? So I can't just put the binary in the droplet there and make it work. I'm going to have to wrap it in some kind of shell script. So okay, let's start doing that. And the shell script is going to have to have this kind of this magic, but it's going to have to be subtly different magic for the LD library path in the previous thing because the droplet there appears in two different relative locations, depending on whether I'm actually in the build pack or whether I'm in the droplet and running the thing. Okay, so I need to do that. And then I can call the binary and I have to remember to pass all the arguments along otherwise bad things will happen. And now I'm done. All right, so that wasn't so bad at all, right? That was fine. All right, but at least, oh yeah, remember what I wanted to do, what I really wanted to do instead of all of that stuff is I wanted to get a compiler, compile a program, put the program in the place where I'm going to run it, done, right? That's what I wanted. What I actually did was all of, yeah. Okay, so that's, that kind of sucks, but at least what I've done now, that's the end of the problem, right? I did the work as the build pack author. I was a hero just like you folks who've written build packs, right? I did it and now no one else ever has to worry about it ever again, except for the performance implications of what I just did. So it's slow, how is it slow? This library that I got, right, that's now in the droplet and that droplet, I need to download it into every Diego cell that's ever going to run my app, right? So I'm gonna download it over and over again and I can't cache it anywhere, right? And maybe for one little C library like this, that's not such a problem, but if I were writing a Java build pack, then what we're talking about is the JVM, right? We're talking about whole language runtimes that you download over and over again every time you scale your app up, right? And what's worse is after you've downloaded it, well, what the droplet is, is it's a tarball. So now you've got to extract that tarball and you've got to do it for every container that you spin up, every instance. And what's even worse than that is that you're extracting it onto a layered file system, which has its own performance implications, that's slow. That's, we're making every app instance pay. All right, well, I'm almost done complaining now. That's basically it. Jules is just about to solve all of our problems, but because this is CF Summit and we're all moral, upstanding people, we're gonna give him an opportunity to get some bonus points. And the bonus points are if he solves our problems using open standards, because we care about open standards here. Okay, so here's what we want. Here's the goal. So here's what we want. Here's the goal. I wanna be able to do this. I don't wanna have to do that crazy business that I did before with the LD library path and all that stuff. I just wanna get my compiler, compile my thing, and copy it into a place. And on top of that, I want it to be a whole lot faster than it is right now. And I wanna make use of this OCI standard that we keep talking about in Garden and Diego and all this kind of business. All right, fix it. Okay, so everyone now hates BuildPacks, so we've succeeded. But we remember that we love the BuildPack model, but we wanna just make it faster, use open standards, maybe knock some of the edges off. So let's talk about how staging works today. How does Cloud Foundry work today? This is going to get technical, but I have pictures. So here's my app.code, so bit of code. How does that work today? We've staged that. Let's look inside the staging process. How do we do that staging? Well, if we zoom in, you have this droplet. You have this BuildPack, right? The BuildPack runs on your code, right? And then it puts the outputs of staging into a directory. I call that dropletizing, right? And then we take that tar file, the results in that directory, and we put it off somewhere into a blob store, right? We call that a droplet, right? And then to run that, what do we do? We create a new container, right? From a root file system, and we tar that back in, right? So we re-untar that whole droplet right into the thing, right? So that's a copy of that thing, which may have a big JVM in it, and then we run it. We run app, run or whatever it script is, right? Animation is a super slide. They need to use OCI images. So then we just keep doing that again and again and again, right? So if you have multiple instances, we have to re-extract that droplet with the whole JVM in it again and again and again. So tar files, it's no metadata, they're just a tar file. We keep extracting them again and again and again, and you're limited to this one directory and you can't run those routes, right? Because we have to have everything end up in this one directory because we're doing everything with tar files, right? So, layered images, right? This is this technology. Docker has hugely popularized this technology. It's extremely powerful technology. And we actually have open standards around this technology now. We've got the OCI image spec. So instead of using tar files, we have this way of describing a set of layers, which can be added on top of each other. So you can have a layer which represents maybe a base root FS, like a bun two, a layer maybe with the difference to add go to that base root FS, maybe a layer for like code or something, right? I mean, you can just describe that in an image. Might look something like this, my app image, right? Got a base layer, a bun two, some go code, and then maybe your app on top, right? And all of the things in yellow, most of the things can share, right? Lots of things will be reusing those things. And your bit is just the purple bit on the top, right? So when I create a second image, right? A second go app somewhere else on the platform, we've got all those layers which are in common. You've got your one, which is different. We can just copy across those layers, right? They're in a cache and put yours on top. How does that work? Well, we have these layered file systems which do copy on writes, right? So I can create a directory that's a copy of an existing directory and I can just do that instantly. And I can use that to put these layers on top of each other very quickly, right? So put your app on top, we, okay. So what would this look like if we use this for staging, right? Well, we could instead of having a build pack step and then the dropletize step, we could just run the build pack and then we throw the result out as an image, right? So an image that describes exactly what I want to do with that runtime. So as the whole flexibility of OCI images and we get rid of the tar files. And so we run it, we just run that image, right? Which, and that could be a Docker format image, could be an OCI format image, it doesn't really matter, right? So the interesting thing is we already support running Docker images on Cloud Foundry, right? We already support the run step of this, but we also have this other run step which happens if you staged with a droplet, right? So depending on whether you staged from an image or from a droplet, we either replace the whole root of that and get the whole state of your container from the image and run it, or we get this standard root file system and untie your stuff. Well, actually, all we need to do to make this work is we kill that step. We get rid of that step, right? And now everything we run in the platform, we run from OCI images. How does that work? Well, actually, we then just have two ways of producing those OCI images, right? You've got the way people use today, right? Docker files to create those images, right? It can run that Docker file, create an image, ship it up, or I can use build packs, right? Because the whole library of maintain things that know how to convert my code into an image that someone else is going to patch and do all that stuff with, and it also creates an image. So you end up with a completely standard way to run things and just multiple ways to create these shippable images. So no tar ink, right? Standards all the way and we can actually start to think about relaxing some of those restrictions. We might not initially, we might want to keep the user experience the same, but we'd no longer be forced to have restrictions like not running as routes or being limited to a specific directory. So that'd be pretty cool, right? Now, some of you are probably thinking there are some problems with this. And I think I can name the three top problems. There, what about patching? Probably with exclamation marks. What about existing build packs? And then probably what about patching again? Because you just thought about that again, but like louder. So what happens when we need to patch one of these things? Because one of the great things that Cloud Foundry Platform gives you with build packs is we can take care of all of that. We just roll the new root file system out, put your droplet back on top and everything works. That's how it works today, because these are separate, because we've got the droplet and the root file system, we can put a new version of root file system, re-extract and we're all patched and up to date. Well, okay, what happens when Ubuntu 14.04 goes bad? Okay, I have to patch it. So what do I do? Well, actually an image is a thing with a grid, right? And it's a set of layers. If I want to create a new image with the patched version of Ubuntu, right? So okay, I've got a new image with the patched version of Ubuntu and I want the image that has your code on top, I can actually quite easily create that image, right? I've just created a new image. It's got your code on the top level, on the top layer and it describes what I want that patched application container to look like. You might be thinking this doesn't work, but what I'd like to suggest is this is exactly what we're doing today, because actually untarring the droplet on the new root FS is exactly the same as what this OCI image instructs the container engine to do, right? Let's take this new set of layers and place this tar file back on top, right? And as long as you maintain the build pack contract, so the build pack's guaranteeing that it's gonna set up the files that it's made so that it can still patch, we can still make the same guarantees about patching, but now we can do them in the platform so you can control when you do and don't want to patch those things. So maybe you have a production environment where we shouldn't do that patching automatically, we can now do that because it's no longer a side effect of the Bosch deploy, it's something that we choose to do at the high level and roll out, right? So I just run that, I've got my new container and it's all patched. So what would this mean, right? Well, we get all the power of build packs, right? You still have all this nice maintained functionality, you don't have to worry about writing your own docker files, doing all that stuff. You still get all the patching that we had before, right? But we no longer pay the price of copying these tar files all around, re-extracting them, and we can start to think about relaxing or changing some of the build pack contracts because we're now choosing to have this contract even though the technology allows us to do more things. OCI images throughout, there are still edges that there's still things we have to figure out so we still want to make sure that we can put out a new root FS in a way that we're confident we can keep everyone secure and up to date, right? That's important. But at least you're not gonna have to use docker files when you wanna do a Haskell build pack, right? Today we have a lot of times where people get frustrated with doing it and go, well, let's just run as a docker file, right? This should avoid that. We can actually start to make build packs a supercharged way of writing images and then you can use whatever you like and the platform works consistently. So where are we with this? Well, it's still not definitely happening but we are putting our feet in the water already. So we have a couple of stories in Garden's backlog to try out the first couple of steps. We're running some experiments to see if we can actually prove the performance gains that we think we're gonna have. We put a proposal to CF Dev for the work so you can see much more details with words and details on how all this actually works in practice and how we think we can get that. Feedback is very, very useful for us because this is, although I think it's a very good idea, it's a lot of work and so we need feedback on whether this is something that you think will help with your use cases and is important or not to be able to justify the work that we wanna do on this. And with that, we have intentionally less time for you to ask us any questions. So we would happily answer any questions. Apart from from Doug. Doug. So we're just kind of assuming that the environment which you pile is the same environment you wanna run. And that may not necessarily true in the sense that you don't need to pile anymore when you run. You need to talk about how you may sort of remove the extra board, right? I think you're under just that problem. Is that what happened yet? All right, so we're thinking of this in two steps. So the first step is let's keep the exact same bill pack model but just do it based on those CI images. So in the first step, nothing changes, right? You still have droplets exactly where they are and that's why we know we can still patch them in the exact same way. It's just instead of it being a droplet with a JVM inside, we can start having file system layers and caching stuff. That then I think opens us up to start thinking about ways we can change that UX a little bit. So for example, one thing we've been discussing is you could have in your bin release file, in your bill pack, you could name a set of dependencies which you'd like us to make sure in the final image, right? And that doesn't, that means we don't have to have them all already in the one Uber Franken-Root FS that everything has to have but you can opt into having it and then we can potentially even keep that patched. So you can say I want Haskell, right? Or I want the JVM and we keep that layer there for you and patch it for you and keep putting your code on top. So that might be a way that we can let people do some things that are hard today like getting Haskell because they can just say I want the deb file, right? I want Haskell from the maintained repository without needing to put it in a root FS and without needing to complicate the existing bill pack contracts. So that's just one idea but I think a lot of the value is we can first make it faster and then we can set ourselves up to start experimenting with ways to relax some of the existing contracts and maybe make some of these things easier. That jumped out to me with this notion of swapping out lower layers and I was the item that scared the jeepers out of me because in a general sense a lot of times when we install a higher layer the steps you take to install a higher layer are based very much on the lower layer. Right, so this, so I should say this only works with the bill pack contract because we keep the bill contract the same, we know it's safe. Right, right. It only works as long as it's equivalent to doing the untar, right? As you relax it, the bill pack, this only works if the bill pack designs itself in a way that they can make that guarantee. But actually as long as the bill pack designs itself in a way that it can make that guarantee you can actually do this and you still get all the power and all the patching as long as it does this. So in the plan that we have at the moment what we want to do to start with is we don't actually change anything. So we have the droplets where they are essentially and the root FS and where it is although we might pull the root FS into a blob store. And then we generate the OCI images. So we generate an image that names the root FS and names the droplet. So the droplet is already a tar file. So the droplet is already in the format but you want a layer to look like. So we can actually just keep that where it is and just basically refer to that and just do a little proxying translation to actually create those images. Once you have that in place then maybe you start to think about more complex things if you want to have multiple layers and other things. But because we want to keep the patching in there we don't necessarily want to use like one of the registries that's out there because then we'd have to like go and update each of the images if you want to do the patching. So we think it's actually better for us to generate the image and use that as a communication format but it's sort of CGI if you like, right? We're not, there's not actually an image. There's a thing that we generate as the here's the latest version of your app, right? There's a URL which gives you here's the current patch version of this app that we can then schedule around. Do you see what I mean? We have four minutes. They are now yours. Thank you very much. Thank you.