 My name is Lance Ball. I'm a principal software engineer at Red Hat and the functions architect for OpenShift serverless functions. You can find me on Twitter at Lance Ball and this is Mauricio. I'll let him introduce himself. Yes, so my name is Mauricio Salatino. I do work for VMware. I'm 24-7 there on Knative. And I'm super excited to be working on the functions project we launched. This is exciting stuff. So I think that we can just back on, right? Yeah. Before we start, we build the game using functions and that's kind of what we want to show today. So I will quickly show you how the game works because we will be playing together at the end of the session. So I wanted just to show you how the interaction goes because it's going to go fast. And if you want to play and get some points and get some swag, you will need to understand how it works first. So the first thing that we do is we just create a player name and then we play. And as you can guess, we are going to be playing through a set of questions. And each question is going to be basically triggering a new function as you might guess because we are talking about functions. So when you start the question, you need to know that there is like a timer up here that it's going to run out. And you will score more points if you go fast, right? Like you just need to pick an option there and just move forward. As you can see there, there's some cold stuff. Then you just get the answer from the next level. And there might be questions that ask you to do different things. But the important thing of the game, something that will happen at the end of the timer there, is that you will be able to tweet the scores and also we will be kind of using a hashtag in Twitter just to score different participants and just track who is playing. And I will be using this through KubeCon. So at the end we will be doing some raffle and just getting some swag. When things work and the internet works, there will be a Twitter button there. That's where you can tweet. So we will be playing together at the end of the presentation. And I will be also talking about how we build this game and how this game is kind of evolving. Lance? Okay. Go for it, man. All right. Okay. So that was the quiz game. So brief agenda. We're going to talk about why we did this project. Why we did this project on Knative. Talk a little bit about the characteristics of function projects. I'm going to do a very quick demo just to kind of show you what the developer experience is about when you get started using functions. And then Mauricio is going to talk a bit more about sort of more advanced function patterns and then show you how this game is architected and then how you can extend something like this to go even further. And then finally we'll talk a little bit about our roadmap and plans for the future. So why do we talk about functions? Well, functions are really the single responsibility principle on steroids. When you think about single responsibility principle, usually you think about microservices where you have some sort of object like an order and then you've got a set of services that can create, update, delete this order thing. And that's a single responsibility. But the truth is that there's a lot more going on there, right? As an application developer, you have to open up your network connections. You have to be listening for operating system signals and that sort of thing. Functions sort of narrow all of this down to actually just a single responsibility and that is your business logic, right? Your function receives some input, has some output. That's it. And that's all you have to think about as a function developer. So much so that these functions are meant to be very portable. There's no dependency in the code on Knative itself. So if you write a function in, let's say, Node.js and you package that up as a module, you can deploy it as a function on Knative, but you could also use it just as a module in some other application somewhere else. They're very independent and portable. We provide some pretty powerful tooling, function CLI, as well as the ability to extend that CLI with what we were calling language packs. And there's a contract to extend the sort of capabilities of the function CLI that way through language packs. The main thing for us is developer happiness, right? Making it very easy. Knative already makes it really easy for developers to get started on Kubernetes This just takes that one step further. So why do we do it in Knative? Well, first of all, it already makes things easy for developers. And I like to think of functions as sort of the programming model and Knative as the deployment model, right? So these functions in theory could be deployed any number of places. Right now Knative makes the most sense because it's Kubernetes-based, it's containerized deployment, and Knative serving provides all the things that you need in order for you to receive like HTTP ingress, right? Incoming HTTP connections are handled by Knative serving. You don't have to think about it as a function developer. And then in more advanced cases, when we're talking about reactive type of functions, we get Knative eventing involved where you can get events coming in through Kafka or RabbitMQ and those flow through the Knative eventing system through channels and triggers and brokers and that sort of thing, all in the form of cloud events and the functions that we support can be invoked that way reactively via cloud events as well. The characteristics of Knative functions are this. We've got a handful of languages that we support just out of the box. So to get started, you can write your functions in Node.js, Go, Python, Spring Boot, TypeScript, Rust, Sparkus. And like I said, you can extend that. So if you're a vendor or a large organization, a large company like say American Express, and you've got a bunch of dependencies that all of your developers use in all of their projects, you can use a language pack to sort of customize the developer experience. We don't have a lot of time in this presentation today. To get into the depth of like language packs and customizing, but it is a really neat feature and if you're a vendor or a large organization, you might want to look into that. We support a couple of different build strategies, S2I and build packs for the local experience for the developer on their laptop or pushing to like a development cluster or a staging cluster. And then of course, you don't want developers pushing code directly to a production system. You want to have that part of a CI-CD pipeline. We also support that through Tecton. Typically, your functions are going to be stateless. If you do need to store state, you're going to do that in some sort of external thing like Redis. And we'll see that today. And like I mentioned earlier, there's a couple of different ways that these functions can sort of react to things, imperatively through just sort of standard HTTP invocations as well as reactively through cloud events. So I made it through those slides pretty quickly. I'm going to show you a quick demo of what the developer experience is meant to be like for functions. This big screen, make it a little bit bigger. Okay, so we have, in addition to everything I've mentioned, we also have a plug-in for VS Code and IntelliJ. And it's a little rough around the edges. This is all pretty new stuff, but I was really excited to show it off to you. So I'm going to try and use it today. Hopefully everything will go okay. So the first thing I want to do is create a function. I can do that through the plug-in. It prompts me for the name of a function. I'm going to call this viewer because basically every function out of the box is just an echo function. So we're going to view some cloud events. As you can see, we support all these different runtimes. Node is going to be easy to demonstrate. So we'll do that. And let's look at cloud events since this is a CNCF event. And I'm going to create this in my little demo folder here. So I create a function, and it asks me if I want to add to the workspace. I will do so. And now you can see over here on the left, I've got a project that looks pretty much like any other Node.js project. I've got an index.js. This is where my function lives. And as you can see, this function is less than 40 lines of code. Half of it is comments. And then we've got this dependency here on cloud events. I mentioned that because I want to point out that this is very much like any other Node project. So I can update change dependencies. I happen to know that the invocation framework here, Fast.js runtime, has been bumped to 0.90. So I can do an npm install. And it'll easily just bump up my dependencies. There's nothing sort of unusual about this project in any way. Sorry. Oh, yeah, yeah. Let's fix that. There we go. So yeah. Okay. So the vulnerabilities are gone now. Now, the next thing I want to do is show you sort of what it looks like from this Knative plugin. We can see now that I've got a function here locally. I can do a funk deploy and do it in verbose mode. And it will use picado build packs to create my function. Make it bigger. Is that what you're saying? Yeah. So we're using build packs to build the function. And now it's pushing my... It's already created an OCI container image. It takes that container image, pushes it up to a registry. In this case, it's pushing to quay.io. And yeah, it should already be. I hope I didn't control C that. And now I can run funk invoke. And no, I can't. I have to go into the directory, the project directory here. And from the project directory, I can run funk invoke. And it will send a cloud event. How about funk run? You can run it locally. And then funk invoke. Send a cloud event to my function. The funk invoke knows if my function is running locally or if it's running in the cluster. If it's running locally, it'll prefer that because that is the sort of developer inner loop. The developer inner loop is I'm going to make some changes to my code. I want to build it. I want to test it. I want to build it. I want to test it. Speaking of testing, the other thing that we have is the ability to all of these functions have come out of the box with at least basic unit tests. So there's a test directory here. We've got unit tests. And we think of functions typically as being unit testable. And you don't really need to do integration testing. You can, I suppose, if you want, when you've got a bunch of different functions together. A single function, its input and its output. So unit tests are sort of the name of the game here. So just funk test. No, sorry, NPM test, just like any other NPM or Node.js project. So as a developer, and I'm showing you Node.js, but obviously we have all these different runtimes, as a developer, your developer experience is going to kind of just be like any other developer, any other experience that you have for that given runtime. You don't have to think about YAML. You don't have to think about containers. It just works. I'm going to hand it over to you now. Thank you very much. And show the really cool stuff. Let's do that. So yeah, and I guess that part of the presentation here is to show what the project can do. And building functions, it's a different programming model. And that's why I wanted to quickly go over the interaction patterns here. I don't know if you can see my screen now. Nope. Yes. Loading. Loading. All right. But I have, again, the same thing. Yeah, there you go. So basically, as Lance mentioned at the beginning, we have different interactions. So we can just do synchronous interactions using HTTP. And there are different patterns. And I'm pretty interested in this because the more advanced functions that we build, the more patterns that we will discover. And that's why that was the main reason to build a more large application to start showing this in action. So as you can imagine, you can do an HTTP request and then just execute the function and forget about it. The function will do something, probably store data somewhere. And then you can move forward or you can just be waiting for some results from the function. And most commonly, because the functions are stateless, you will be needing to connect to an external state to read or write data. KN80 is taking care of the auto-scaling, like scaling up based on demand and based on requests and also scaling down. And also buffering the request when there is no instance of a function. But that's pretty nice for developers. But you need to be aware that that's kind of like the behavior when you're building functions. So whatever you are doing inside a function, you need to know that the platform will automatically scale it up. And at some point, your function might be completely downscale to zero. Things that you need to have in mind when you build functions. There are some other interaction patterns that goes more into the async space, like asynchronous interactions, where you might contact a function and the function will need to do a long batch process. And these kind of mechanisms where they are going to post the results somewhere else. So you need to kind of understand how to go and fetch those results or have a channel to be able to get those results back to the application. And then we move to the cloud event-based space where you can have functions that are going to react based on events. You can actually consume an event like reacting when an event happens and then emitting an event as a result, which allows you to go and chain functions together. Like one function can consume the events that other functions are producing, and then you start building these more like event-driven applications. Or you can mix and match all the things that I mentioned before. You can have like HTTP-based functions, emitting events, and then notifying other functions to do some other stuff. And this is actually how we built the quiz game that I showed you at the beginning. The first thing that we built, it's pretty simple, but as you might know, as soon as you start building something that needs to work and that we are all going to be playing together, things get complex. And for this application, we try to keep it as simple as possible. Like the application is built with that idea of each question in the quiz game. It's a different function. We have created a different function to deal with every request. And we are storing a state in radius, right? And as you might think, in this case, because we are doing all synchronous requests, we will need to take kind of like the latency, you know, into account to make sure that, you know, our application can react and can work correctly for all the users, right? Like if we have all this room playing at the same time, we will need to bootstrap this and scale up these functions for that to work. There are different ways of doing this. We done it in this way just to test this approach, this synchronous approach, and then we extended it with events, and we will be seeing that in action. But what this makes, like what this diagram is showing, is that we also have like an orchestrator in this case. So if you have synchronous interactions, you will need to have some component that has the logic on which function to call next. And in this case, that's kind of like the game front end that we have in there. And then we have a react application on the other side. There are some challenges and some good stuff about these building applications in this way, right? When I do not, I haven't been using functions for a long time, and now when I switch to build this application, it's pretty interesting how you need to change, you know, like the mindset on the things that you are going to put there on the function so the platform can take care of all this like upscaling and downscaling. So definitely you need a game, like an orchestrator in this case that I mentioned before, and that's the only reason because you need that, the only reason why you need that is because you need to coordinate which functions are going to be called and in which order. We need to take into account the latency and you will see that the first person playing this game will need to wait for the function to get started, but all of you will need to wait for Redis to write stuff into the database and to read data from it. And yeah, another thing to take into account when you're building this kind of applications is that if you are connecting to the database and your functions aren't going to be scaled up, you might start hitting kind of like bottlenecks on the database if you run out of connections because you will have lots of replicas just trying to connect to the database. For that reason, we decided to also add some reactive stuff on top of this application and in this case, we are using Knative Eventing to deal with cloud events and route cloud events across different components in the application. So each level here, like every time that you are working, like answering a question, it's going to emit a cloud event to a Knative Broker, this kind of cloud events router that it's going to send, you know, the events to the front end and we are going to use our socket to send the events back to the client side, which is pretty nice. Everything is cloud event based, so we are routing events even to the front end, like even to the client side code that it's running into your laptops and that's pretty cool, I think, like because the programming model, again, it's all the same and it works like kind of nice. And going down, doubling down on what Lance mentioned before, I really love the idea of having kind of like functions written in different languages. Oh, sorry about that. I just want to mirror my screen and I cannot do it from here, right? There you go. Let me mirror my screen so I can see what I'm talking about at the same time. This place, I don't know why for some reason, like it was mirroring before, now it is not mirroring again. Now it's mirroring, I guess. There you go. So what I wanted to show is like quickly, two functions that we have here, like one in Go. Again, the same thing that Lance built, but now using Redis and connecting to the database. And what you can see is that we have just a single, you know, entry point for the function. This is kind of like, how are we going to invoke the function once it's deployed. And then, you know, again, like simple, like typical developer stuff in Go, we are connecting to Redis. We are storing some data in there. We are emitting some cloud events from here. And the same thing, just to prove the point, we have built different levels using different languages. We have another function written in Go, sorry, in Spring Boot in this case, which is pretty simple. It's following like Java conventions and Java function interfaces, which is pretty nice, because again, if you are building functions in Java, that's pretty much what you want to use. You can import any other Java function and just expose it as a Knative function pretty easily. Again, same thing. We are connecting to Redis. We are connecting, emitting cloud events. All using kind of like the libraries that the language provides. Both projects were created with funk, as Lance mentioned, so this is pretty nice and pretty straightforward, no matter in which language are you working on. And I think that we don't have any limitations of adding new stacks there, so if you are interested in a language that it's not there, we can definitely add it. Finally, to kind of close that, when you are building with functions with events, you definitely need to take it into account that now you are building a sync communication, so eventual consistency might be a thing. Because we are using cloud events, that basically means that when I'm in Spring Boot or where I'm in Go, I'm using the cloud events SDK just to create and read cloud events, and that's pretty powerful because again, there is no technology stack kind of like locking. You can choose whatever you want and then produce and consume cloud events or create HTTP request in any language. And yeah, and that's kind of like very interesting because you can start extending your synchronous applications with reactive stuff and start adding on top of the things that you already have, like these more event-driven features that I will be showing in the game. Before we go and play together, let's talk a little bit about the roadmap, right? Oh, yeah, yeah. So really excited to announce that Knative Functions is now sort of a full-fledged working group. It began as a task force, and as of this week, I think, we're actually a real working group. So yay, very exciting. Everything is happening very quickly. Things are maturing. We're trying to keep everything backwards-compatible as much as possible. You know, some things might be changing in the next month or two with the new funk.yaml format. We want to improve our on-cluster build capabilities to be able to support multiple build strategies aside from just build packs on the cluster and then dynamic templates, which... We're thinking about it. Yeah, we're thinking about that. Yeah, we don't need to get into that right now. And we're going to continue to build out the plugins for VS Code and IntelliJ. And then these external template repositories are basically examples of the language packs, and we're going to continue to build that stuff out as well. Very excited about what's going on here. Yeah, definitely. Around those templates, as you can see, if I'm building a lot of levels for the application, they are all built in Go or in Spring Boot, it makes a lot of sense to have this external repository where you can put templates that will make your life easier as a developer, and funk allows you just to point to these repositories and get started with something that's not a very empty shell for a function. So I think that it's time to play. If you open your phone, you can go there. I think that there is something missing in the application that it's reporting issues, but we will probably be adding that if the application fails. You can get it there. There you go. So if you open the application, you will be able to start playing there and you will go through five questions. What I want to do while you are open the application, I see everyone playing already, I will just switch to the dashboard here that basically will show me who is playing live, I guess. Let me see. There you go. Let me see if I refresh this. I have no internet. Are you kidding me? Sorry, what? Oh, no. Are you kidding me? Are you kidding me? Look, I need to pay for it. No, but I don't have internet. How can I pay? No, are you kidding me? All right. This is Cloud Native. Thank you very much. And this is how we fail. Live. There you go. Oh, yeah. Let's see. Here we go. Yeah. You can see that this people is playing, right? Some people manage to get into the application and they are playing. Look at that. We have like 24 people playing. 25 now, 26. That's pretty cool. There you go. So we will be looking at the, you know, at the scores and then sharing some prices with you folks. But that's pretty much it. One of the things that we want to do with the demo is just to share it so you can run it on your own environments. That's working progress still, but you know, feel free to get in touch with both of us and I guess that we will be sharing more stuff. Yes. One question? Sure. One question? Go for it. They are answering questions now. I don't think... Question? I think we'll have time for... 36 people. That's good. Damn it. That's me, so don't do me. So we put some easter eggs in the question, so I don't know if people notice. Hi. Thanks for the talk. This is yours. You're welcome. All right, fine. Cold starts are actually a big thing with this. Can you elaborate a bit with the different language packages? Like I know, Quarkus can compile natively, which prevents a cold start due to like sup milliseconds, but can you elaborate a bit on the other languages supported? How cold starts can be managed or should be managed? Yes. Do you want me to answer that? It's about cold starts. I didn't really hear it. Cold starts and how they can be managed and based on languages and language functions? Yeah, so it really depends on the technology stack, right? So if you are using Quarkus as you said, like if you use Grad VM, like the native compilation, you will have a fast cold start because that's kind of like what you're doing. You are compiling natively, so that will start fast. In Spring, we have a Spring native. It does the same thing. You can just do the same thing. In Go, it's pretty fast all the time because again, it's just compiled. So it really depends on kind of like the language that you're using and the technology stack. You should, as a developer, building functions, definitely take care of that in some way or another, and then just making sure that your functions can bootstrap it quickly so, you know, the platform doesn't wait for too long. We have another question. Sure. Can I go start talk later in the day? Go start later, yes. Hey, thanks for the talk. I'm wondering what architectures are supported. What was that? Like system architectures. Does it run on ARM kind of thing? System architectures, does it run on ARM? Uh-huh. Power PC, S390X, Wink Wink, X86. The FUNK binary runs on ARM, AMD, X86, 64. I'm trying to think what else. I think that's it. That's it, yeah. Yeah, and then the builder images, the build pack builder images, I think right now there is not an ARM 64 builder image, but hopefully that's coming soon. We don't produce those. We're using Pequeto builder images. Although it is pluggable, you could use your own if you've got an ARM 64 builder image that you like. It's pluggable. On Pequeto, build packs. Yes. I think we'll have more questions. We'll have a question? Okay, so one more and we finish to give time to the next speaker. Oh, hi. Oh, okay, cool, sweet. So I noticed that you'd mentioned that there was no YAML associated with using your function tool. However, I did see as part of your directory or the file breakdown something called FUNK.YAML. That's correct. What is that for? He said it, not me. So that's metadata for the function itself. And so there is YAML in the project. We try to hide that or not really hide it, but the user doesn't have to interact with that. And in fact, a lot of the values in here you can set using the FUNK CLI. So we have a FUNK config command that you can use to do things like set environment variables on your function and those environment variables may be pulled from a persistent volume or secrets or from something in your environment, you know, itself or a hard-coded value. And that kind of stuff is hidden, the YAML is hidden from the user through the things like FUNK config. Yeah. Or especially Kubernetes YAML, right? There's no Kubernetes in this YAML. No, yeah, exactly. And the idea is that you're not using QtlApply. We are just trying to hide that away from the user in this case. Okay. So, thank you, Marisa and Lance. Thank you for your great talks.