Introduction In this showcase demo today, I'm going to show you how you can use Cilium and KubeVirt together to provide micro-segmentation for virtual machines, as well as all the other great features that Cilium provides to cloud-native workloads. What is KubeVirt Before we dive into this, what is KubeVirt? KubeVirt is a virtual machine add-on for Kubernetes. It's deployed on top of a Kubernetes cluster that already exists and gives you a way to run virtual machines side by side with your Kubernetes-native workloads. Because KubeVirt uses the underlying CNI, Cilium can be used straight away with essentially no additional changes, and you can take advantage of the same features you use for your hosts and containers and transfer those across into your virtual machine workloads as well. We hear from a number of customers today that they're looking at the various technologies and hypervisors available in the market, especially when they're not natively looking to use one of the big three hyperscalers, and they may also be looking to move away from an incumbent hypervisor solution. That's one of the reasons to look at KubeVirt's offering. It's got a number of integrations, and as an open source project it has a number of investors as well, including Red Hat, and it's the underlying project that powers OpenShift Virtualization, for example. In the showcase demo, we're going to show communication between containers and virtual machines running inside the same platform. We're going to show how we can use Hubble for observability of traffic for that virtual machine that's been deployed. Then we're going to use the Gateway API features for ingress access from outside the cluster to the resources running on that cluster. We're going to host some basic websites there, look at how we could implement the ideas and concepts of zero trust by using Cilium network policies to create those security boundaries, and then finally take advantage of one of the cool features of KubeVirt, which is the ability to migrate a running virtual machine instance between two Kubernetes nodes. We'll show how communication still traverses across to that virtual machine as that happens. I'm going to move into my demo environment for this, and straight away I'm going to create a namespace for my KubeVirt demo today. Demo walkthrough First and foremost, let's create a DNS visibility policy so we get some more interesting traffic data using Hubble in my environment. All we're doing here is capturing anything running in the KubeVirt demo, so all endpoints going to kube-dns for any particular DNS location, and then we're going to proxy that traffic so I can see it in the results of a Hubble observe command. Now we're going to create a virtual machine inside my environment. We're going to create that from a YAML file, and we're going to start that using the virtctl command line, which is used to control resources with KubeVirt. Then I'm going to show you everything that's running inside that namespace at the moment. We can now see a couple of things that have happened. First and foremost, we have a pod and we have a Service that I've also created. The Service is how we're going to communicate into that virtual machine. I've got a little diagram to show you that as well. Then we've got a virtual machine instance, which is the actual virtual machine itself. The pod launcher pod is created by KubeVirt to enable communication, and it does that by attaching the pod to the CNI and then creating a bridge to the virtual machine instance itself. In my bottom terminal here, we'll just connect to that virtual machine's console and then we can see that booting up in the bottom as well. Use Hubble for observability of virtual machine traffic While we wait for that to come online, let's have a look at some of the traffic through my environment. We can now see some traffic going between our pod instance. Bear in mind all the traffic will go through that pod because of the way KubeVirt networking works, and we can see the virtual machine reaching out to repositories as it runs updates and so forth in the background. Let's have a look at the configuration of this virtual machine that I've deployed as well. Again, we deploy this using a YAML file, very similar to how we deploy our workloads in Kubernetes today for pods. We attach to the network using the default Kubernetes network, and then we specify an interface for the virtual machine NIC itself and tell it what it's being connected to. Further down, I've configured the virtual machine to run a script to create something interesting so we can test connectivity and so forth. Finally, we've got that Service, and all that Service is doing is targeting the KubeVirt label that we apply to both the pod and the virtual machine for forwarding traffic. We can see the virtual machine is still just finishing off its last updates, so we'll wait for that to finish. Now that the machine is fully booted and the scripts I ran on first boot have completed, let's test connectivity to this virtual machine from a pod in my environment. I'm going to run everyone's favorite tool, netshoot, and from there let's call the Service I created. That comes back, so that's great. Let's also get some information from the additional page I created. I created a details page on that virtual machine, and it gives me the virtual machine name, the IP address, and some local information so we know it's that particular host and operating system that we're trying to hit. Finally, I also created a secret page. Nothing major on there, but we're going to look at how we create security boundaries around that as well using Cilium. If I now go back to Hubble, we can also see communications from my shell to the KubeVirt pod that backs that virtual machine, and then we can see those DNS queries as well. Access VM resources externally with Gateway API Now inside my environment we're going to look at how I can access this from my own local machine, and we're going to use Gateway API as the feature for that. This is a diagram I've created of my Gateway API setup. Gateway API is the new replacement for Ingress inside Kubernetes. It deploys a Gateway itself, which is tied to a load balancer, and that load balancer is actually provided by Cilium as well. I'm advertising the load balancer IP address using Layer 2 announcements inside my Gateway and then specifying an HTTPRoute that tells it how to pass that traffic through to my Service, and that Service backs it off to the pod itself. Previously I was accessing using the temporary shell and the nginx Service. Externally we're going to go through the HTTPRoute. Again, we've set up a path prefix of slash to match anything for that Service, pass it through to the nginx Service, and then the Service will pass that off to the pod launcher and then to the VM instance itself. So we're going to create that Gateway, we're also going to create the HTTPRoute resource, and I'm just going to label that for my Layer 2 announcements. The Gateway is really simple. We just tell it to listen on port 80 for HTTP requests, and the HTTPRoute tells it exactly where to send those requests. Because I'm only using the one Service, I'm just going to send everything from that path prefix back to that nginx Service, but if needed we can split that across multiple VMs or pods inside our environment with a very simple rule as well. Now from my local machine, rather than a pod running inside the cluster, we're going to try and access the same resources inside that virtual machine. We can get the Gateway IP address and then curl straight to that address, where we can see the nginx welcome page. We can also look at the details page and then finally the secret page as well, and we see our secret page there. Now we've got external communication from outside the cluster to my virtual machine as well, so now let's start thinking about those security boundaries I talked about. Zero Trust policy enforcement We can use Cilium network policies the same way we use them for containers and apply them to our virtual machine as well. We're going to create a simple Layer 4 policy that basically just allows port 80 to that endpoint, and again we're selecting that endpoint by using the label. Here we're allowing traffic from any endpoint inside of the cluster, or anything coming from the ingress controller resources, which is where Gateway API lives, so external-to-cluster traffic via that ingress resource is allowed as well. We're just going to try and hit this from my local machine. We can see it works, and again we're going to go to the details page, and we can see that come through in Hubble here as well, captured from my local machine. Now if I try to hit this from my temporary shell, you're going to see that it times out and it's denied. The reason for that is if we go back to the policy that we created, inside that policy we block a particular label, app equals client, and my pod today doesn't have that label. To fix that very simply, I could apply the correct label. Then if we try it again, we'll see in a moment that this now works and the traffic is forwarded. Unfortunately though, that policy is still pretty open and we want to be a little bit more restricted, so we're going to upgrade this to a Layer 7 policy. We've now added Layer 7 details. We're allowing the GET method on the normal path and also the /details path, but we've not specified /secret, so that will be blocked. The same again we've done for the ingress controller as well, so anything that comes through that ingress controller from the outside world will also be subject to the same security boundaries. We can see again this is allowed, the details page is allowed, and again that's from my local machine to the virtual machine. Then finally if I go to the secret page, we'll see that's failed, and we can see the reason is that it was dropped by that policy. If I try this from the demo pod, we'll see the same again. It gets dropped. The final feature I wanted to show from KubeVirt itself is the ability to live-migrate virtual machines between running hosts inside of our Kubernetes environment. I'm going to run a script which basically just calls out to my virtual machine and prints whether it's 200 in green. Any other code will give me a red color. We're still going to see that tick up. We're going to see where my virtual machine is running at the moment, see that it's live-migratable, issue migrate, and watch the migration happen. At the bottom we're also going to see the status codes and whether there is any change there as well. Okay, the migration finished. We can see that it succeeded, and all of those codes were 200, so we didn't miss anything. Essentially I'm just calling that same HTTP endpoint because we don't have ICMP traffic enabled. Finally, if I check, we now have this virtual machine running on the second worker node within my cluster because it's completed that migration. If you want to learn more about using Cilium in these hybrid environments, then head over to the Isovalent website. You can also check out our labs, where you can get hands-on with a real-world environment using the various Cilium features and play about with everything you've seen here today, especially those Gateway API features. Thank you very much.