 Okay, can everybody hear me? Am I coming through okay? Perfect. Okay, so let's go ahead and get started so we can get done. I'm the last talk before you guys have beer and it's gonna be a good talk, so let's go. So we're gonna talk today about using service brokers with Kubernetes. So we've heard a lot today about combining Kubernetes and Cloud Foundry in different ways, how they can be compatible, how they could be cooperative. This is a way that we've taken a piece of Cloud Foundry and brought it to Kubernetes and given you a little bit of that experience. So first off, oops, I'm Jeremy. I work at Microsoft Azure and I work on the open service broker for Azure, which is our implement or one of our implementations of the OSB API for doing things with Azure Cloud Services. I also work on service catalog, which is the implementation of the OSB API from a platform perspective for Kubernetes. I also work on a bunch of other things in the space like Virtual Cubelet that was mentioned in the last talk. You can find me on GitHub and Twitter here. If you want to talk about anything that I talk about today or any other Azure-related things, feel free to reach out to me at my Microsoft e-mail. So again, we've heard a lot today, and I think this is a good way to cap things off, about how Cloud Foundry and Kubernetes can be cooperative. I think the things that are happening with the containerization in ARI are super cool and I'm super excited to go home and play with that myself because I used to use Cloud Foundry quite a bit and I like the developer experience a lot, and that's really missing in Kubernetes. When you think about what Kubernetes really is, Kubernetes is an extensible platform. So I think somebody mentioned in one of the previous talks that Joe Beta called it a platform for platforms, or a platform platform. And really, that's what it is. We treat Kubernetes as a thing that people like to just deploy things directly to, but it's pretty low-level. It doesn't have the same experience that you get with Cloud Foundry or other PaaS-like solutions. But what it is, is something that's very extensible, and you can see that with some of the things we're going to talk about today, with Service Catalog, other things that are coming down with CRDs that were mentioned in the last talk as well. But it's for running containerized workloads, so it's pretty specific about that. But because it's extensible, you can use it to do quite a bit of other things. And the last point is that it's declarative, so all the configuration you use with it is defined in a really standard way. It looks something like this. You have different types of resources. So here we have a pod, and that's kind of like the basic unit of deployment or scale to Kubernetes. Inside of that, you've got a spec, and that's really the desired state. So you say that you want to run a container called nginx, and you're going to use an image from Docker Hub called nginx. And you want to have it expose a certain port 80. And when you use this thing and tell Kubernetes that you want to deploy this pod, what ends up happening is it takes the desired state, and it makes the actual state happen. And then it reconciles those two things. So if you make changes to the desired state over time, it updates the actual state. If things in the actual state happen over time, it reports that back to the resource, so you can see the spec and status of both of those things. That means when you're going to deploy something to Kubernetes, if you're going to try to abstract away and look at what that CF push experience looks like, you build a container, then you write some YAML or JSON that goes along with that, and then you post to the API and say, deploy this thing. And then it's responsible for making that happen. It does run this container. I want two replicas of it. It's going to go on these two nodes wherever they're going to go. And that makes a lot of sense for the single point. I want to run this specific little application. When you get to a bigger, more complicated environment or deployment scenario like this, there's a couple more questions here. So I've got these four services, the online store, the customer service, the inventory service, and the order service. Those things are containerized applications running on my Kubernetes environment. The email service is some external thing. And then MySQL, Neo4j, and MongoDB could be run on the cluster, they could be run externally. But using that spec and status model, how do you define what those things look like? And then how do you connect those things to your application? Kubernetes doesn't have something that necessarily gives you the ability to say provision me and MySQL out of the box. So really, how do you handle that? And once you have them provisioned, how do you connect them to your applications? So we'll talk about how you connect them to your applications first, because it's going to kind of set some groundwork. So most things, when you're talking about deploying applications to Kubernetes, you're going to think of it as something like a 12-factor application, where you're going to pass configuration either via environment variables or maybe by reading a configuration file that's mounted from the file system, like a config map or something like that. It's one of the resource types that's available. But the most common way, I think, is my preferred way is to use environment variables. So here's an example, right? We're going to have this order service that's going to talk to MongoDB, and inside of the spec for that, we say that we want to populate an environment variable called MongoDB URI, and we're going to give it some URI, right? It's going to just be a value. And it's really easy to put that into your YAML file. You can declare that in the scheduler and Kubernetes make that happen for you. But that's not the greatest thing. You're hard coding that value. Probably want to take advantage of something else. So another thing you can do is reference a secret. So this is taking a little bit more of a declarative approach and saying that I've got some secret to find, and the secret is kind of like the way you would store sensitive information versus a config map on the cluster, and you say that I want to reference a certain key from that secret and populate that into that environment variable. So this is a good way. You can update the secret as time goes on. You can restart your application, set up any kind of automation around that you want, and then the value is just going to get populated into your container, and that works pretty nicely. But again, you're still populating that secret somehow, or editing that YAML file to add the value somehow. It would be better if there was a way for us to do something more like bind in the CF world. It'd be really great if we could do something like CF create service and then CF bind service directly to the Kubernetes API and not have to worry about, do I need to go use Terraform or Azure Resource Manager to spin up some external resource or some custom CRD that only works for Amazon and not for everything else on my cluster? It'd be great to have that experience and just have that talk to an existing broker that we already used from Cloud Foundry. So if we're gonna maybe deploy some applications using Cloud Foundry, the cool containerized stuff on Kubernetes, but also have some Kubernetes native applications, it'd be great to be able to reuse those brokers between those. And that's really what service catalog is striving to do. And service catalog kind of harks back to this concept of extensibility. So Kubernetes provides you the foundation and it provides you a couple of ways of doing extensibility. In the case of service catalog, we've built an aggregated API. So you have a second API server that runs in parallel to your regular API server and then it creates a bunch of new resources. So we've talked about a couple of resources so far like pod or secret. It introduces a few new things that really map closely to the OSB API. And those would be the cluster service broker. So that's the model of what a service broker looks like. And then that gives you a couple of additional things called the service class and the service plan. And you can think of those directly from what your experience with CF brokers would be like. And then again, using the service class and the plan, you can make service instances and that's what's gonna do the provision operation to the broker. Once an instance is provisioned, you can bind to that thing using a service binding resource. Once you've had service catalog to your cluster, it now knows about service brokers and it knows how to talk to service brokers using the OSB API. So you can define what a broker looks like like this. So you make a definition of what that broker looks like. You get a URL, any of the authentication information is necessary to talk to it. And then Kubernetes knows that it needs to reconcile that desired state with an actual state. So it'll go and talk to that broker and list all of the services and classes in plans. And make those available into your cluster. So just like that picture that I showed earlier where you had desired state and actual state and there's a reconciliation thing happening in the middle, that's what's happening. Part of the service catalog implementation is a controller that knows how to operate on those things. And it reconciles the state of your desired content or your desired configuration with reality. And that means listing the classes and plans when you register a broker. But it also means invoking the provision API and the bind API when you're doing those operations to correspond to those resources in Kubernetes. So with all that in mind, you can say, I want to provision an instance of Cosmos TV, which is an Azure service, or MySQL. And you define that in the same way you define everything else you do in Kubernetes. You define a YAML file that has whatever provisioning parameters are necessary. You reference the account or the class and the plan. And then you post that to Kubernetes and the API server says, I've got a new thing. Controller is watching that. Controller makes it happen. And eventually, you have a service instance available via Kubernetes. You can then bind to that. And the output of the binding is a secret. So if we go back to that pod definition, one of the ways you could pass environment, like the things to your application, was to use a secret. And that's exactly what happens when you create a binding in service catalog. So this was kind of cool. We've added this experience to Kubernetes. But one of the downsides to this, I think, and some of us have agreed, is that the experience isn't the greatest. Using the CF tool to provision services and bind to them is pretty nice. And from a developer standpoint, it's really great. Doing this is not so great. This is just kind of a funny slide, right? So in the Kubernetes world, you write so much YAML. You might use something like Helm that's been mentioned a couple of times. But you're still writing YAML files in the end. And the experience on top of that is not great. And everybody talks about how the experience on Kubernetes isn't the best, and it could be better. So we thought about how could we make the service catalog experience better. And we built a CLI that's domain-driven to do these sort of things for you. It's heavily influenced by the experience you get with CF. So as an example, if you want to provision a service, we can do things like SVCAT provision service instance, and then give it the class and the plan. And then whatever parameters are necessary. Running this command in the end generates the exact same API objects that you would get if you did that YAML definition. But it's giving you a better experience to do that. You can do operations like register broker and provision services and bind services, update services, and then all the corresponding removes along with that. So we're at this point now where we've got something for Kubernetes that interacts with service brokers and gives you that cool experience of not having to worry about external tooling to provision stuff, or leveraging existing brokers that maybe do stuff in house that's not migrated to Cloud Foundry or Kubernetes. But the experience there gets a little bit murky after that. It's a little bit tricky. So Kubernetes obviously has a different way of doing things than Cloud Foundry does. And some of those things bleed through when you look at how you actually use these things in the end. So I mentioned that binding will create a secret for you. And that secret ends up looking something like this. It's got whatever fields come back from the binding response from the broker, dumped directly basically into a secret. And there is no VCAP services concept. So you're really responsible for mapping these things directly into your application by yourself. So that experience, not so great. There are some things you can do. Service Catalog has a couple of extra features that allow you to do transformations on these things. So if you have a couple of different services and the credentials don't look exactly the same, you can apply transformations to them so that they look similar. Say if you're running MySQL locally from a broker and then MySQL from Amazon, you can make the credentials look more similar. You still don't get that VCAP services experience, though. So it's not exactly the same. And then another concept in Kubernetes that didn't make it directly into how the broker or the catalog was implemented is how to deal with namespaces correctly. So if you looked at those slides before I mentioned, some of the new resources were Cluster Service Broker and Cluster Service Class and Cluster Service Plan. Those things originally were created at the cluster level, which meant everybody had access to them and there wasn't really a way to apply role-based access control to them. It's kind of a bummer. So you may, in the Cloud Foundry world, you do CF enable service to give certain orgs or spaces access to certain classes and plans. You couldn't necessarily do that in Kubernetes because of the way that RBAC works and the way that these resources were created. So we did add a second set of resources that were namespace scoped. And using some additional things we'll talk about in the next slide, you're able to get that same kind of experience. But it does complicate things a little bit because now you have two kind of equal set of resources that are really just different on how they're packaged. One is at the cluster level. One is at the namespace level. So you can get that CF enable service access like experience if you're using namespace broker resources. I've included the links to the documentation here. And then another feature that we allow you to do is to use catalogs restrictions. One of the concepts in Kubernetes is something called a label selector. So when you're trying to target a service to some pods or you wanna list things in a certain way, you can do filters really. Think of them like I have a label, this is the value, only show me the things that look like that. So we added that concept to service catalog as well. So you can do things like say give me only the basic plans or give me only the free plans. And it will list those things back as a filtered subset. And then combining the namespace broker resources and those catalog restrictions, they're able to get that same kind of functionality. But there are also some Kubernetes only features. So one of the things that we've kicked around a little bit is the difficulty in using different brokers. The Azure broker, for instance, requires a resource group and a location for every request. It's kind of annoying to have to provide those things. The structure of requests aren't all the same. So if I'm gonna use one broker and then possibly switch to another broker on another cloud, it's not transparent to me as a developer. I have to know things about what the structure of those requests look like. So to address that, we are adding a new feature to service catalog that allows you to define defaults. So you can take a class or a plan and you can essentially fork it and say that using this thing as a template, I wanna define some default parameters. So in this case, instead of having to provide a resource group, I know that this is always gonna go into my resource group in Azure. And then when the broker sees that you wanna make a service instance using this class, it's gonna resolve it down to whatever the original thing from the broker was and populate those things so that when the request goes to the broker, it's fully fledged. So user experience deviates some from the Cloud Foundry experience. But it's giving you that same kind of behavior and feel. So we've talked about it a little bit. I think the best way to hammer it home is to really do a couple of demonstrations. This will all be available on GitHub. I have not pushed it yet because I was just finishing it yesterday. But it will work locally and it will also work using Azure resources if you wanna use Azure resources. Locally, you can use MiniCube and you can use something called MiniBroker that will deploy Helm charts under your cluster for you automatically. It's pretty cool. Okay, so I'm gonna jump over from this PowerPoint presentation and do some demo now. Okay, let's minimize this. So I have a cluster already built and this is just a Kubernetes cluster. It's got some nodes. Oh, you gotta change the screen. Sorry, thank you, dog. There we go, how's that? Great. Okay, so I've got a three node cluster here. It's pretty basic. It does have service catalog running already. I'm gonna do kubectl, get pods, dash in catalog. It's got the API server which is gonna provide that footprint for you to talk to. And then the controller manager which I mentioned does that reconciliation between things. And I also have a broker registered already. So I do fccat, get brokers. Oops, all namespaces. So we tried to make this tool work pretty closely to how kubectl works. Like the experience is not exactly the same. So we tried to meld what CF and the kubectl command looks like. So using all namespaces there as an example that comes from kubectl. This actually will work as a kubectl plugin. So if you feel like typing extra characters you can do kubectl, plug in svcat, get brokers. But you can use the tool directly like this. So in this case I have a broker running and registered already called osba. And it's in the CF summit demo namespace. By default this kubectl session is using the default namespace. So if I do something like svcat, get plans. I shouldn't get anything back because I don't have any. But if I do the same thing, svcat, get classes or plans in the CF summit namespace. I can see all the things that come back there. It's quite a few. And this is cool because I can define RBAC policies directly on that namespace to say that I'm not allowed to provision anything in this namespace but my coworker is. Or I'm allowed to view them but not actually do anything with them from a provisioning standpoint. So you can do really fine grain control over that. And if you try to reference something in another namespace, it will fail because you won't have access to it. So I'll show you, you don't see it there, but if I run this command to provision, probably don't have it here, do I? Nope, okay, we'll just type it. Okay, so here we go. svcat, provision, cosmos two. And the class is azure, cosmos db, Mongo account. And the plan is account. So we'll just verify that real quick. I'm scrolling up here. Azure, Cosmos, db, Mongo account is the name of the class. Make sure I type that right. Cool. So if I run this command, it's gonna say that it sent the request. Obviously it made all the API objects to do that. But if I do svcat, get instances now. Oops, if I type it. You see it references the non-existent service class. So it failed to provision, and I have prohibited anybody using the default namespace, you can see default right here, from provisioning anything using that broker because it's not exposed into this namespace. So I'll just delete that so it's gone from the list. And that really just removes it from the catalog and from the cluster. Okay, now I can actually register that thing. And I can also register another broker. So we'll just install mini broker really quickly. This will use Helm to do an installation of the broker. And it'll create things like the service broker resource and the secrets associated with that. And it'll spit everything out for you. So service account, pod, a cluster service broker. And if I do svcat, get brokers, all namespaces. Cool, there's one right there. It's not, it hasn't been picked up yet, but it'll get there in a second. We can do the same thing and register Osba a second time. And because these things are constrained in the namespaces, you can register the broker any number of times without having to run it again. So I can just create a secret. I think I already did, but we'll just run this anyway. Cool, so we have a secret there now. And if we run this register command, and if I look now, my cluster just died. Cool, there it goes. It's back. It's coming. So the Osba default broker is gonna be registered in that default namespace. It hasn't been picked up yet. Let's see if we can, can we watch that? Nope. Okay, I can kick it. We can do kubectl, get pod, stash, and catalog. There's a bug in my cluster right now. So if I just kill this, this'll restart the controller manager and it'll actually just go pick up all that information again. So it's running again. If I do svcat, get brokers. Cool, they're already now. So that got picked up and it works now. If I do svcat, get instances. We don't have any in this namespace, but we do have one in that CF summit demo in this namespace already. So just like you would create the broker, you can use svcat to do that. You can also use a yaml file to do that. And we can run that really quickly. We'll just actually use kubectl so you can see what that looks like. kubectl, create dash f, osba, cosmos dpe. And we'll put it in the namespace. That will put it in the default namespace. Cool, so it's provisioning now. It's made that request to the broker and the broker is asynchronously gonna go do that. If I run this command, it'll take like five minutes for it to happen, but eventually it'll be ready and it'll look exactly like the other one. Cool, so let's see what it looks like to use that now. So I could run the svcat bind command. This window's pretty small, but I can run the bind command and I can pass any kind of parameters that I want. I just reference the instance. There's just a few ways to do that and you can customize a lot of things like what secret it's gonna end up in, but the simplest thing to do is just do svcat bind service and you end up with a secret. You don't have to have the application deployed already to do that because it's a little bit of a disconnected process. So you can do those at the same time if you want and that's what we usually do with Helm. So a lot of the examples we have and when I use service catalog myself, I usually package these things into Helm charts because it makes it easier for me to deploy my application and then say, also go provision me the service, also bind to the service. And then you can do different parametries or permutations of that, right? So you can say, I already have an existing Cosmos DB instance but I wanna be able to provision my service and have it bind to that and we'll show you that really quickly right now. So I have a Helm chart that wraps up the Spring Music Cloud Foundry sample application and it runs really well on Kubernetes. I just containerized it, made a Docker image, pushed it to my registry and then I wrote a Helm chart to take care of that and that looks a little bit like this. So let's look at Spring Music, templates, it's got a binding, it's got a deployment and the deployment is really that unit of scale so it's gonna define what the template looks like for the pod and how many replicas I want. The ingress is kind of like the route that will get to that service and the service itself is how you collect all the nodes. So if you say you want five instances of the Spring Music application, it'll get collected together via that service. The binding looks very, very similar, just templated to the ML that we saw for creating a service instance or for a broker. Inside of it, you're gonna reference the class you wanna use, like the instance ref. So the name of that thing, so Cosmos DB, probably the name we use and then what secret you wanna populate. So now we can just run that command and see what happens right here. Forgot to delete it, hold on one second. Cool, now we're running it. So we just did a whole bunch of things because those YAML files had to find things like the service, the secret that's associated with that binding, the binding itself and the deployment and the pods. If we scroll up, we can see those things. Here is the pod that got created. Here is the binding that got created. Here is the deployment. Here is the service. And there's the binding. So we can look at those things now. So if I do SVcat, oh sorry, just kubectl. Kubectl, get secrets. Hasn't happened yet. Let's take a look at the binding. So SVcat, get bindings. Oh, wrong namespace. That's my problem. CFSummitDemo. So there is the spring music, spring music Cosmos DB secret. And then if we look at what that looks like, CRKgetSecret-nCFSummitDemo. And we say we wanna look at the YAML. Let's shrink this down. So I got back a big old YAML. The secret has a few things in it. It's got a connection string. It's got a host, a port, a password, a URI, a username. These are just the things that our broker returns. And you see them here as just base64 encoded. You can obviously configure Kubernetes to do more crazy things like encrypt them, but the default is just to base64 encode them. If we look at what the deployment looks like, though, that's gonna be where the interesting thing that maps this secret up to that application. So we can do kget deployments. CFSummitDemo. There's our deployment. And we wanna look at what that looks like. So let's do a srk describe deployment. Okay, we can see inside of that thing that it has an environment variable called Cosmos DB URI. And that's set to the connection string field or key in the secret spring music, spring music Cosmos DB secret. So that secret got created because I did the binding request. Once service catalog got the binding response from the broker, it created that secret. And then this container was able to start up successfully because the secret existed and it populated that URI. And if we look at the logs of this thing, we get the pods, do klogs dash f. You know, this is just like the exact same thing you would see if you were tailing the logs, if it was running in Cloud Foundry. And if we scroll up a little bit, we should see that it's using that URL. So this is the decoded view of that thing. And I can port forward to it now. Okay, I'm port forwarding to it now. And if I go to the browser, let's open browser window up. Hey, it's spring music and it's got all the data loaded in it. And it's coming from that Cosmos DB that was provisioned in the cloud. And the experience there was so much better than having to go externally and define something or use the Azure resource manager to make these things or click into the portal and have to manually copy those things over. It's given you that similar experience, but not quite the same experience, adapted to Kubernetes. And I think this works out well in that hybrid future that we're kind of seeing now. Where maybe you're running some of your applications in the containerized CF. Maybe you're running some of them on Kubernetes, but you're getting the same broker experience from both of those. So time's up now. If anybody has any questions, I can ask, I'll stand down here and you can talk to me or go enjoy the welcome reception. Thanks. Thank you.