00:06
Today, data is the lifeblood of every organization. It needs to be instantly accessible to the right person at the right time, and always protected from the moment it's born. And given the significance and scale of AI, your data needs Kontxtual and intelligence so your business can thrive.
00:23
So how are you managing your data? Everpure, data management so simple it feels like second nature. Hi, everyone. I'm Dan Bunch, a systems engineer for Everpure here in the UK, and I'm joined today by Andrew Pruski, and he's a Microsoft MVP and a principal field solutions architect here at Everpure.
00:53
Now, in today's EdTech talk, we're gonna be exploring how to achieve faster, safer database operations. Now, while containers offer speed and agility, enterprises really need high availability and data services to run those mission-critical SQL Server workloads on Kubernetes.
01:17
So in this session, we're gonna be looking at the why and the benefits of in containers, specifically with Kubernetes. We'll look at the deployment, using StatefulSets and configuring guaranteed, QoS performance. We're gonna be looking at the migration, and comparing the paths for SQL Server, on Linux,
01:41
versus, on Windows. We'll be, we'll be looking at cloning, and also we'll look at KubeVirt, which allows the running of virtual machines alongside containers in one environment. But before we dive into these technical details and a demo, I'm gonna hand over to Andrew, and he's gonna share some exciting news about an upcoming event, where you can
02:04
actually meet the two in person. So over to you, Andrew. Thank you, Dan, and good morning, everyone. Yes, we are going to be at SQLBits in Newport, the ICC in Wales next week. Come and join us and have a chat with us about everything we can do to help And we have a little competition as well.
02:24
For those that want wish to, for a free entry ticket to attend a paid day for SQLBits, the first three people to email Olga will be selected, and her the slide. So three, two, one, go. And now on to the session. So welcome, everyone, to this session.
02:42
It is Running SQL Server on Kubernetes for Faster, Safer Database Operations. My name is Andrew Pruski, and as Dan said, I'm a principal field solutions architect here at Everpure. Joined back in, oh, September 2022. Time is ticking on. And before that, I was a SQL Server DBA
03:01
working with databases for around fifteen years. I'm a Microsoft Data Platform MVP, Docker captain, basic all-round SQL Server nerd. So let's dive in and see what we're gonna be doing today. And before we go anywhere, we should think about the platforms that we have to run SQL Server on. So we have our physical machines, big, beefy
03:22
boxes that give us the high performance, low latency. If we are looking at those high-performance OLTP systems, we have our physical machines. Then we have our virtual machines with this flexible environment, things like vMotions, the ability to provide HA, the ability to move from host to host, giving us all that flexibility for our SQL instances.
03:42
But the platforms that we're gonna focus on today are SQL Server containers. Now, this has been around for a while, since around SQL Server 2017. It gives us the ability to instantaneously spin up an SQL Server instance that is fully configured to how we want it to be. I must admit, the first time I saw this, I was kind of blown away.
04:03
The ability to get an instance of SQL Server up and running in less than a second is very, very powerful. And we'll have a look at taking containers from just a standalone box that's for dev and test into a production today with an orchestrator such as Kubernetes. And then to round off the session, we'll have a look at KubeVirt, the ability to run virtual
04:27
machines in Kubernetes. So here's the agenda. We're gonna start off with the why. Why would we wanna deploy SQL Server to Kubernetes? Then we'll have a look at deploying SQL Server to Kubernetes.
04:38
What are the gotchas that we need to be aware of when we run SQL Server in this Then we'll have a look at two different methods of taking, say, our existing SQL databases in our environment and migrating them to Kubernetes. And finally, to round off the session, we'll have an overview of KubeVirt. Just have a look at some of the performance testing I've been doing for SQL Server in a
05:03
Windows VM running in Kubernetes. So let's talk about SQL Server in containers. This is an article that I wrote based on some work I did when I first moved to Ireland. I'm originally from Swansea in Wales, moved to Ireland, oh, way years ago now. Moved for a job, never left.
05:22
But what I did was I was working with my QA department, and my QA department every month had a process of refreshing their environment. This meant blowing away VMs, rebuilding them, installing SQL, creating databases, pumping data in. Now, this wasn't exactly the most it wasn't the quickest process in the world.
05:41
The hosts that the VMs were running on were about ten years old at the time of writing. And so this process for one VM took around forty-five minutes to an hour. It's a long time if you're doing this every month. There are about forty of these things. Now, of course, we could do some of them in parallel, but still, it was a time-consuming
06:00
process, and it also wasn't exactly reliable. It was built on a whole bunch of PowerShell scripts that sometimes would fail, and they'd have to go and work out why an install of SQL had failedSo we decided to blow all that away, get rid of the SQL instances on the VMs, and have them running as containers on a remote host.
06:18
So that meant the VM's resources could be scaled down because SQL wasn't sitting there just gobbling up all the CPU and memory. And what would happen would we build a new VM, kick off a connection to the host running Docker, spin up a container running SQL from a custom image that would give us databases which they could then pump the data in.
06:38
Now, we timed this process, and it went down from, say, 45 minutes to an hour to get one VM up and running down. The longest it took us was two minutes. That's a huge saving. We actually worked this out, and it saved us about a month's worth of dev time per year.
06:54
So great, we, A real successful project. However, we were running SQL Server in containers on a standalone host in just using Docker. One day I came in, that host was down, and I became all of a sudden the most popular person in the office, purely for the fact that none of the QA people could do any work until we
07:17
got that host up and running and got all the containers up and running again. So this is why we have container orchestrators. We get all the benefits of containers. We get instant creation of an image of Sorry, of a container from a known image customized to how we want it to be.
07:35
We can separate the storage from the compute, which is a real big one here. SQL Server DBAs are generally used to of our physical machines, our VMs as all-in-one storage and compute. But do we really care about the compute if we think about it? Not really, as long as something can access it.
07:54
What we actually care about is the data on the storage. We care about our databases. As long as something can come along, access it, we don't mind whatever that is. We don't fix a broken container or pod in Kubernetes. We blow it away, spin up a new one.
08:11
It's a different way of thinking about SQL Server instances, and that gives us other benefits. Things like the ability to upgrade to a new CU of SQL Server and then roll back pretty much instantaneously if something goes wrong. Now, things have happened. The first CU of SQL Server 2025 had an issue,
08:27
and we had to go off and uninstall in our dev and test instances in Windows. And uninstalling a CU on Windows is a bit of a kerfuffle. Not with containers. All we do is roll back the image in our manifest and boomph, we are rolled back. So we get all those benefits with a container orchestrator.
08:44
But the key to running a container orchestrator is we get high availability built in. If I'd been running SQL Server in my containers in Kubernetes as pods, it wouldn't have mattered if one host had gone down. All those pods would have failed across to another host.
09:01
Everyone could continue working, and I could have come in at my, you know, strolled in at my usual half nine, rock-up time, and then fixed it in the background, everyone none the wiser. So that is why we use container orchestrators. And of course, if we are talking about a stateful application in Kubernetes, we need
09:21
a stable performant storage net, data platform, I should say, to provide To provision storage for, say, persistent volumes and then persistent volume claims. And this is where Portworx by Everpure comes in. It's a Kubernetes data platform providing enterprise-grade storage, data protection, and mobility for our containerized applications.
09:42
And we have two offerings with Portworx. We have PX-CSI and Portworx Enterprise. Portworx CSI is our lightweight CSI-based integration that exposes native functionality from, say, a FlashArray or FlashBlade for, say, smaller scale clusters. It gives us a simple on-ramp for containers on Pure, so we can get up and running with, say,
10:04
SQL Server and Kubernetes really, really quickly. And we get all the benefit of, say, the underlying storage like FlashArray. There's six nines of uptime, stable performance, the snapshot capabilities which will come into key in the demos when we have a look later. And then of course we have Portworx Enterprise, which is our full container
10:25
platform for large mission-critical Kubernetes and DB platforms. With advanced automation built in, HAD after the storage backup, and u- the ability to unify heterogeneous on-prem and cloud storage. So let's go have a look at how we can this and deploy SQL Server to Kubernetes, because there are a couple of things we need to be aware of when we are running SQL Server in Kubernetes.
10:53
So when we deploy SQL Server to Kubernetes, we have the options of running it as a deployment or a stateful set. Deployment's okay. They were out there for a while. They are really for stateless applications. So we're gonna go with stateful sets instead of deployments, and we get the benefits of that. We get the ability to define our storage in
11:10
our manifest, our YAML file. We get stable network identity, stable pod names, and we get the ability to configure other things in there as well, like we have to configure things like tolerations. Now, there are no native HA technologies available to us in SQL Server, so we don't get the ability to have Well, we can have them, but we don't get things
11:32
like automatic failover. So we can build AGs, and we'll see that coming up. We can use mirroring, but we don't get that auto failover. So we are going to have to rely on the built-in HA capabilities within Kubernetes itself.
11:47
So we need to do things like ensure tolerations are set within our stateful set. And that means, well, when a node, say, in Kubernetes reports as unreachable or not ready, Kubernetes will automatically move them over after a set period of time, and I think the default is five minutes. Five minutes is way too long for something like SQL Server, so we need to update those in
12:09
our manifest. Now, you can do it at the cluster level. I like more granular control and having it in our stateful set there. So we need to set toleration for not ready and nodes unreachable. We can bring those down, and we'll have at the YAML in a second.And then finally, we need to configure guaranteed quality of service.
12:27
We need to set the CPU limits and res- and requests in our manifest to the same value, and this ensures predictable performance for our application, SQL Servers, you know. And that pod is least likely to face eviction as well when the node becomes So enough of me talking. Let's get straight into labs. I want this to be a very demo heavy session because I have to show
12:49
people how we can do things. So let's go over to our lab. And here we are. We are in Visual Studio Code, and I'm just gonna make sure that I am in the right location. Let's clear that up. And I'm connected to the correct cluster.
13:07
It will always help. And we'll test connection. There we go. Okay. So this is a pretty typical cluster. It is one control plane node. Oh. Where's my mouse gone? There we go. One control plane node and three worker nodes
13:25
down here running version one three five. OS image, twenty-two O four. Probably need to upgrade that to twenty-four O four at some point, and my container runtime containerd. All good. Okay.
13:40
So let's configure make sure Portworx CSI is installed and configured correctly. Status of running, always good. Controller and node plugin. I didn't enable any telemetry here, and I've got my back end here, my FlashArray back end connected in, and that is an X90, so pretty beefy here. Okay.
14:01
So let's go ahead and let's deploy SQL Server. Now, the first thing I need to confirm is I have a storage class, and I'm gonna use built-in storage class that comes with Portworx CSI, and that's Portworx PFA direct access. I'm gonna go straight down to my FlashArray.
14:14
It gives me all the benefits of all the features of FlashArray. I can provision storage automatically through this storage class. But before we go anywhere near there, SQL Server needs a password to connect. We need to configure our SA passwords. So we're gonna create a secret because we don't wanna have our SA password in plain text
14:34
in, say, our stateful set YAML file. We need to obfuscate it. So we can use it with, say, a little secret here, and there's my password. Rocking. Okay. Now if I deploy that, have a look at it, we can see, yes, obfuscated.
14:54
But there is a gotcha here, and I just wanna point this out. I always point this out when I'm working with SQL Server and Kubernetes, and it's ge- in general for secrets. Secrets in Kubernetes by default are encoded. They are not encrypted, which means it's really easy to get at those values.
15:12
So yes, it's really good. We can see. There we are. Nice and simple. Couple of lines of code. So yes, it's good to have and use secrets to obfuscate away the values. Just remember that they're not as secure as that you might think they are.
15:27
They're really easy to get to. There are options to encrypt secrets, and there are other options as well to use, say, you know, pull from a secret store, but just something to be aware of. Anyway, let's clear that out, and let's have a look at our SQL Server YAML file. Deploying SQL Server to Kubernetes as a stateful set.
15:47
So we've got a s- pretty much, typical stateful set here. We have our kind stateful set. Oh, one thing I wanna mention here is replicas of one. Now, of course, you can have more than one replica in a stateful set, but none of these SQL Server instances are gonna be linked.
16:05
I'm not gonna have them in AG with automatic failover here. So do I want more than one re- more than one instance of SQL Server managed by this StatefulSet YAML? Because remember, if I upgrade this, I'm gonna have to upgrade both of them at the same time, all of them at the same time if I want to. Now you can do that. That's not a problem to do that.
16:23
But again, I like that granular control. So I like to have that one stateful set, one instance of SQL Server per stateful set. It's just a personal preference. It's why I do it. So that means the parallel pod management policy really doesn't kick in here. But let's kick on, and let's have a look.
16:36
Here we go. Our tolerations. So when a node becomes unreachable or not ready, I'm setting toleration seconds to ten. Now that might be too aggressive. Like with anything I'm going to show you here, your mileage may vary. Test, test, test, test, test in your environment.
16:54
Come up with the values that work for you. When I'm testing here, yes, ten seconds is good enough because remember we have to wait for that node to report it's not ready as well. So there is a little bit of lag time as well between them. Then we have our container image, 2025 CU three.
17:10
All our environment variables including our SA password, and then we have our limits and requests set to the same value, guaranteeing that quality of service. And then finally, volumeMounts. We're gonna go with /var/opt/ms SQL for one of our SQL Server, the default location for all of our SQL Server system databases, so msdb, model, tempdb, master.
17:35
And then a location for my ooh, location for my user databases data files and my user databases log files, and then specifying in my volumeClaimTemplates. We're gonna go with ReadWriteOnce pod. We used to only have the option for ReadWriteOnce, so any pod on a node could access the volumes.
17:55
We don't want that for SQL Server. We want one pod accessing these volumes. PFA direct access, our storage class. I'm gonna go with twenty GB for my system databases, hundred GB for my user databases data files, and fifty GB for my user databases log files.
18:13
Three, two, one. Let's go and deploy. Excellent stuff. Okay. Let's have a look at our storage. Have we got them there?Aha. Okay, getting a little bit messy 'cause I've increased the font size here, but we have them.
18:30
We have our volumes one, two, and three all bound already up and going, automatically provisioned from a FlashArray via Portworx CSI. So let's see if that's We can also Ah, we can grab the volumes here, and we can get the back-end volume image. Let's go and have a look at it, shall we? Let's see if we can grab that one, and I'll log into my X90.
18:55
This is why I don't type in demos. And let's go storage, volumes, and there it is. Excellent stuff. Connect it to my host. Okay. Cool. Okay. So automatically provision STaaS FlashArray for my SQL Server instance via Portworx CSI.
19:21
Let's have a look and see if that stateful set is actually up and running and if the pod is there. Yep, one of one is ready, and there's my pod, mssql-stateful-set-zero. Let's make sure we've got our quality of service. That's guaranteed. Fantastic.
19:44
And then let's deploy a service. Let's go and do this quickly, shall we? And all I'm doing here is creating a load balancer service that's listening on port 1 four three three, connecting to port, four three three on my pod, the default that SQL Server listens on. And for my cluster here, I'm using metal LB as
20:02
a provisioner for my external IP for my service because I don't have a load balancer available. If you are doing a demo and test cluster, very much check out metal LB. Finally, let's grab that IP address, one thirty, and let's test that connection to SQL.
20:24
Hey, nice and quick. And we also Let's drop it into Management Studio here and have a look. One thirty, connect. Oh, there we go. We're in. And bec- well, let's try that again.
20:36
And because we're SQL Server on Linux, we get a little NuX icon next to our Lovely stuff. So that is how simple it is. Just need to watch out for the tolerations, quality of service, and then provisioning our storage background. We've got up and running with SQL Server, a new instance of SQL Server up and seconds that has that high availability for
20:54
Kubernetes all built in. Okie dokie. So we'll clean that up, and let's jump back into the slides, and let's have a look at migrating SQL Server to Kubernetes. So say, what if we have a whole bunch of databases in traditional SQL Server instances that we want to migrate to Kubernetes?
21:16
I wanna get a copy of my production database into Kubernetes for my dev and test environment. How do we do that? Well, okay. Since 2017, we have the ability to run SQL Server on Linux. Now, I appreciate it's not the most common option out there. SQL Server on Windows is by far always the
21:36
most popular way of deploying SQL Server. But SQL Server on Linux out there, I have customers running it. And so how can we get a databases in a instance of SQL Server on Linux into a Kubernetes cluster? Well, really simply, actually.
21:52
We have our fo- we have our volumes with our databases on, and we need to get them into our Kubernetes cluster. Well, all we need to do is leverage capabilities of a FlashArray, take a snapshot, create a PVC from that snapshot, and create a stateful set from that PVC, and we have our databases migrated into our Kubernetes cluster.
22:16
And that is it. And once we are in that Kubernetes cluster, we can snap and clone again, and again, and again, and again, over and over, and over. We also get the data reduction FlashArray as well. Clones will pretty much deduplicate one hundred percent until we start writing into them.
22:35
So if I copy, say, a five hundred GB in and provision it five times, I'm not five timing that five hundred GB. It will deduplication down. Okay. So all right, all right. That is SQL Server on Linux.
22:47
We have people out there using it, nice and simple. But what about migrating from SQL Server on Windows? How do we get from there? Well, it's a little bit more complicated, I'm afraid. We can't just snap a volume on Windows and provision it to a pod in Kubernetes, purely
23:05
for the fact that most, nearly all Windows are running NTFS file system. So we can't snap an NFS file system and mount an NFS file system into a pod running SQL Server on Linux. Now we can run things like NTFS fix over the top of it, but it's, it's not a f- it's n- not really automatable, if I'm honest. The best way of doing it is leveraging availability groups.
23:28
Now we don't get automatic failover in Kubernetes, but we can build what's known as a read scale replica or clusterless group and use the auto seeding a database from Windows into Linux. So we have our SQL Server on Windows with our databases. We have our Kubernetes cluster.
23:47
We then create a stateful set, and from that stateful set running an instance of SQL, no databases, we create an availability group between the SQL Server on Windows and the pod running in the stateful set. And that means we can then seed the databases. Now, okay, this is a size of data operation, I'm afraid, which does mean SQL is migrating
24:12
sorry, copying data across from Windows to Linux. But just let it run. It won't affect the production instance as long as we configure our AG correctly. Let it run, and once we're in there, we can then snap and clone, and again, and again, and again.
24:25
And again, data reducing down. We can provide multiple instances of our SQL Server sorry, multipleCopies of our SQL Server databases and multiple pods in Kubernetes once we have the databases over there. So let's go ahead and let's have a look at, first of all, cloning from Linux and then migrating from Windows.
24:46
We have Andrew, we have a, we have a question just before you- Yes, of the demo. And we've got a question that's just come in from, Home, and that just kind of relates to what you were just talking about. His question is, "Can we migrate or clone from a Windows SQL Server to a Linux SQL Server?" That's exactly what we're about to do using this clusterless
25:08
availability group. Snapshots won't work here, but there of doing it, but it's not It's a very manual process. You have to go in and run a whole bunch of, commands to, like, strip out all the NTFS stuff and then mount it in. It's easier- Yeah to use a clusterless availability group and use the auto seeding
25:26
function or backup and restore into it, and once But once The key is once you're on the Linux instance, you can then snap clone, snap clone, snap clone. And we're gonna do two different methods here of cloning. We're gonna use our Pure Storage PowerShell SDK because remember we're using Portworx CSI, so we get all the native features of FlashArray here for cloning.
25:45
And then for the migrating, we'll do the snap and cloning all the way through, through Portworx using, manifests to provision our snapshots and leveraging that functionality the other way. So we'll see the differences. Cool. So let's go ahead and I'm just making sure I'm always in the right cluster and my right connection just in case Visual Studio goes pop
26:08
on me and I need to reset everything back up. But here we are, we're all connected in, and we just do K get all. We should have nothing running. Excellent. Okay. So I have a SQL Server on Linux instance. Let's get rid of this because we deleted it, and here we go.
26:22
Where is it? There. AP Linux 01. I'm great at naming things. This is my server, and it's a Linux box. There we are, AP Linux 01, and of course it's Linux, so we have the Linux icon. What we're gonna do is we are gonna migrate this database from Linux into a
26:38
pod running in our Kubernetes cluster. So let's scroll down, and let's import our Pure Storage PowerShell SDK module. Now, this is available in the PowerShell gallery. It's just a quick install module, and you'll have it down. I'm going to connect to my Oh, sorry.
26:56
First of all, I'm gonna set up some Let's do our source FlashArray in X70, our target FlashArray. So my production instance, let's say, is on one array, and my dev instance is on another FlashArray. Okay, my production instance isn't on X70 and my dev instance is on an X90.
27:15
But okay, it should be probably the other way around. But anyway, we have a Linux We have our server name, protection group, and we'll have a look at that in a second, and then our volume. Now, the way we get consistent copies of databases in Oh, that's been deleted. FlashArray is via protection groups, and all protection groups are is a logical entity on
27:38
the FlashArray that we drop multiple volumes in. If I go and have a look at it, protection groups. Shared APs. Oh, again, this is why I don't type. There it is. And all a protection group is a logical entity on the FlashArray where we drop multiple volumes in, and when we snap a protection
27:58
group, we get a snapshot that contains a snapshot of both volumes at the same time, and that's how we can get a consistent copy of a database from SQL Server. Because all right, for this demo, all my databases are gonna live on one volume, just Otherwise, you'd be watching me overwrite multiple volumes in the demo, and we really don't have time. We've got a lot to get in.
28:17
But when we snap that protection group, if we are on, say, data on multiple volumes and our log on a separate volume, we get a snapshot of all of them at exactly can then use to provision a copy that gets a consistent database every single time onto the same instance of SQL Server or like this in another instance of SQL Server. So let's go ahead and let's take that snapshot.
28:38
I'm gonna set those variables. I'm gonna connect to my target SQL Server instance, and let's just make sure There Yeah, as I said, they're all on one volume, var opt MS SQL data. We'll take a snapshot of that volume and get it into our pod in Kubernetes. I'm gonna connect to both FlashArrays.
29:00
Now, I'm using a dot cred file here just 'cause as you've seen, me typing in demos is pretty terrible. I don't want to s- you fudge typing in my password over and over. So I'm just importing the credentials there. And now we can take the snapshot using our new PFA protection group FlashArray of our protection group.
29:19
Because I want to replicate from one array to another, I'm gonna specify and I'm gonna apply some attention as well. Retention even. Definitely applying it, attention. There we go. Okay. If we come here and see, I've already got my target set up here.
29:34
So it's literally just a switch to say replicate that snapshot over now. Let's have a look if we got it. There it is with my volume within it. So let's jump back into the code, ensure it's coming across to my target FlashArray.
29:57
And using this command, we can have a look and see, get PFA volume snapshot transfer. Yes, progress of one, which means a hun- 100. And if I come into my other FlashArray, protection, snapshots, there it is replicated across. Excellent stuff. Okay, so we have that on our target FlashArray.
30:20
So now I can create a PVC in Kubernetes that's gonna host my database. Confirm. There it is.I can get the volume name if we can see that on the target FlashArray. And what we're gonna do is if we grab this, Storage, Volumes, we are gonna overwrite this volume with a snapshot we just replicated across that
30:49
contains our SQL Server database. So there we go. Let's overwrite. New PFA volume on our target FlashArray. The name of the volume we just provisioned and the snapshot keyword Three, two, one. Boom.
31:10
Our snapshot technologies are meta database only. So what I've just done essentially is that volume was pointing at these blocks the array, it is now pointing at those blocks on the array, which means if I could provision a StatefulSet now referencing that PVC, hopefully that pod is now up and running. Okay, this always takes just long enough to make me panic,
31:38
every time. And we can check to see if our database files are there. And they aren't. Oh, we've had a problem. Did I actually overwrite that? Okay, let's try this. When you've got a moment, we've got a couple
32:07
of questions that have come in, um- Yes, of course. So yeah, give us a cue and I'll, I'll, let you know what they are. Yeah, ask the questions. No worries. Let's go for it. Okay. We've had an issue. So, Joseph has asked us a
32:20
question, in, in the chat. So once the seeding's complete, do queries get served by both the Windows and Linux instances? No, it'll just be the Windows instance. Okay. There's our volume.
32:40
Okay. And let's make sure we've got both of these set, shall we? We've had an issue here. There we go. And our snapshot name. Yeah, that's correct. Three, two, one. There we go. Did I actually write that?
32:55
Let's try again. Container creating, okay. No, it is just the Windows instance. There we go. Okay, panic over. I obviously didn't o- actually hit the overwrite command when I
33:19
went to overwrite that. So again, carried away with myself. There are my data files. Let's try that again, shall we? Connecting in, and let's actually attach that database this time. So this is just a create database from the database files.
33:44
And there is our database migrated over. And of course, if I go in and connect now, there is our database migrated over using snapshots on our FlashArray provisioning. And now that we're on that array, we can snap clone, snap clone, snap clone as much as we want, provisioning multiple copies for our, say, developers, giving them a full instance,
34:09
a full-blown copy of that database pretty much instantaneously. Think about on provisioning on-demand SQL Server instances for your dev, QA, and test environments. Really, really powerful. But it's I'm wondering, would you, would you say that this, the use case of running SQL
34:25
within containers, it- it's very much sort of addressed the problem or challenge of, of having to, having to provision many, many multiples of SQL instances, often, often quite small instances as well? Yes, absolutely. This is exactly what it's designed for. The ability to have an instantaneous copy of your database up and running.
34:45
Say, "Oh, I need to do some testing on this. Can I have that there?" Boom, up you go, there you are. Instead of having to, say, send in a ticket to the IT help desk, wait a week for it to get provisioned- Yeah then it's up and running and you need to make a change, go. It's literally boom. You could even have it as self-service.
35:00
And I've done this in the past where we've had an environment where our developers could enter in some details, hit a button, it would go off, hit the database, spin up a container, do some configuration for it if we wanted to pump data in for test and provision it back. And it can happen in We're going down from, say, hours to seconds.
35:19
Yeah. Very, very powerful. And, and all those, that, that provisioning is very consistent. It's consolidating the management of those instances. And I guess standardizing and, avoid, avoiding disparate sort of like versions and, deployments. Yep.
35:35
It's, you're building from a known instance. Yeah. So you're building Every container built from that instance will be a carbon copy of every single container in that instance. Yeah. So yeah, 100%. All right. Now let's go and do this again, but let's use
35:51
Windows instance. So let's connect into my Windows instance. There we go. Where are we? SQL Server 01. So again, Windows instance SQL 01. And what we're gonna do is we're gonna create an AG, get that database from that Windows instance into a Linux instance where we can then snap clone, snap clone, snap clone.
36:12
Now bear with me. There is some setup required here to get this AG up and running, but we're gonna do it from scratch pretty much. So the demos so far have all worked, touch wood. Let's see how we get on.
36:28
So I've just con Let's confirm that we've got everything good to go. Okay. So I'm not gonna mess around here. I'm just gonna deploy my StatefulSets. We have that up and running.And we're gonna view our pod. Container creating, yep.
36:44
We'll wait for that to come up. And four. Oh, a little bit longer. There we go. All righty. We're up and running, and we've got our volumes. Let's deploy the service. I'm skipping a little couple of things here
37:01
because those are just checks. We can get the SQL instance up and running. Let's make sure we can connect into that instance there. Excellent. Okay. So here we go, connected in. Nothing in it, just an empty instance of SQL.
37:19
What we're gonna do is create a clusterless AG from this instance to this SQL Server instance here and get that database across. So we're gonna ensure we can connect to our SQL Server on Windows and create a session on our target VM, just a PowerShell session, again, using these cred files so I don't have to type in my password each time.
37:45
And then we need to set up the auth. Now because this is Windows to Linux, I'm gonna use cert-based authentication. So I need a login user and a certificate, they should already be there on the Windows instance already set up, login user and certificate. What we need to do is create the same login and user on the Linux instance and get that
38:03
certificate into the Linux instance as well, so the two endpoints of the AG can authenticate against each other and connect. So I'm gonna backup that certificate on my Windows instance, and if anything's about to go wrong, it will go wrong here because I'm going to grab those files from our SQL instance, copy them locally, and push them up to my sorry, I'm gonna backup them on my
38:34
Windows instance, grab them from Windows, pull them locally so I can push them up into my pod ready for my SQL Server instance to use them, and I have to deal with, ooh, do so, and that works straight away. So are they there? Let's have a look. E:\Temp\certs.
38:53
Yes. Excellent. Okay, we have them there. So let's create our login and user in our target instance in our pod. And because we're using certs, we need to create an encryption hierarchy starting off with a master key in our database. I'm gonna fire those certs up into my pod using kubectl cp,
39:17
and then let's confirm that they're there. Okay. All right. That was a bit of groundwork there, but we're just setting up in the background the user login certificate start building out this AG. Remember, we haven't touched the Linux- Windows instance here.
39:32
All we've done is backup that certificate. So I can now create that certificate from the backup files in my Linux instance, and then I'm gonna confirm I've got my endpoint for my SQL instance on my Windows box running. Yep. And we'll do the same, we'll create the same on our Linux instance.
39:55
So we're nearly there. Little bit of setup, but we're gonna create our endpoint here. So just saying create endpoint using our certificate here and then granting connection on that endpoint to the login that we've set up. So that's pretty much it.
40:12
What we can do now is create our AG with a cluster type of none, reference in our Windows instance and our Linux instance, seeding mode of automatic so we can get our databases across. Three, two, one. Final thing is just to join the Linux instance.
40:35
This can take a few seconds. Aha! Okay. So if I do a refresh now, we have an AG sitting from our Windows instance to our Linux instance. So nothing Everything's fine on the Windows instance.
41:00
We've not interrupted production at all. We're just building this in the background. Now we need to make sure There's a couple of things here. We don't have automatic failover. It's not available for us in a clusterless failability group, so we
41:09
have to worry about that. Commits on secondaries, we wanna set that to zero. We don't want that happening because if our pod goes down, writes will fail primary Windows instance. We don't want that either. So there are little things we need to configure here, but all we need to do now
41:23
really to get a database across is add our database to that AG. Now, of course, size of data operation, this is auto-seeding. We need to monitor it using the, SQL Server system DMVs, but, and I am using an empty database here, at this point, we have a database in our Linux instance. Okay. It's over and across.
41:48
Now that we have that, we have the ability to snap and clone, and we snapshot classes in Portworx. We don't have to use the PowerShell SDK if we don't want to. We can create a snapshot class and take a snapshot of our persistent volume. There we go. And again, all this is doing really is
42:10
leveraging the snapshot capabilities of the FlashArray. But if we get snapshot, there it is. And if we have a look at our volume and our snapshot Let's clear that out. It's not very nice. Let's have a look. Let's grab our volume name and our snapshot name.
42:27
If we come into the FlashArray, grab that. Am I on the x90? Yes. Reflection, storage, volumes. Here we go. And there's our snapshot. Awesome stuff. Okay, we are done.
42:46
All we can do nowIs we could deploy a PVC from that snapshot. And let's go ahead and let's deploy SQL Server, again, from a stateful set referencing that PVC. Finally, let's c- let's confirm everything is up and running, and we'll connect in. There we go.
43:09
Okay, let's do K, get all. Are we up and running? Yes. Okay, there we are. Grab our service IP address, one three two. Oh, actually let's do it this way. There we go.
43:28
And there is our database. Now, there's a little bit more work to do here. We need to do things like set HADR off and drop the AG, 'cause it still thinks it's in an availability group. And this can take a couple of seconds, so we may not have time, 'cause I do wanna finish off the session by talking about KubeVirt for
43:44
a little bit. But all we need to do here is knock off HADR on that database, and then remove the AG from that development SQL instance, and we have our copy of test database deployed again from snapshots on the FlashArray. So we're At the core base of this, all we're really doing is snapping and cloning, and cloning, leveraging the snapshot capabilities within Pure Storage FlashArray.
44:07
But yes, that does take a few moments to go off, just doing a whole bunch of stuff in the background for that database. So what I think we'll do is, we'll confirm when that's done, we'll jump back into the slides, and we'll have a look at that when we come back in for the final demo. Okay. So let's talk about KubeVirt, because let's be
44:26
honest, what we've done so far is worked with SQL Server running in Kubernetes, and SQL Server in containers is always Linux-based. Microsoft did have SQL Server in Windows containers at one point, but they've dropped them and now focus solely on Linux containers, and the reason for that is stability and image size.
44:49
When they first came out, I worked a lot with SQL Server Windows containers. They weren't great, Windows containers. And you can deploy Windows nodes to Kubernetes and run Windows containers there, but Microsoft will not support SQL Server in a Windows container. Also, this image size, like SQL Server on Linux, the image size is around 1.5
45:10
gig, which for a container image is gigantic. Well, SQL Server on Windows container images were anywhere between ten to fifteen GB. They were massive. So no Windows containers.
45:24
If you want to run SQL Server in Windows in Kubernetes, then we have the option of KubeVirt here. And what KubeVirt does, is gives us the ability to deploy Windows VMs into Kubernetes. Now, SQL Server on Linux and Windows pretty much has feature parity at this point, but there are some out of their cases.
45:45
A couple of my migrations to SQL Server in Linux have been halted up by using custom CLRs, say building C# assemblies that wouldn't run on Linux. So if you have legacy applications that you need to run in Windows, need some features of SQL Server that aren't available in Linux, we have the option for KubeVirt. Running virtual machines-based workloads that cannot easily be containerized.
46:08
So components of KubeVirt. We've spent too long on this. We've got the API, which we connect to using the virtctl to interact with our VM. Virt controller is our control plane component of KubeVirt. Virt handler is our node level component, and the operator, which manages everything
46:23
KubeVirt itself. And it all fits into Kubernetes this way. We can see we have our cluster components there, the KubeVirt controller, the KubeVirt API, and then coming onto the worker nodes, we have the handler, the launcher with QEMU to spin up the containers themselves. But I re- realize we're coming to tight on time.
46:41
Let's jump into the final demo, and let's have a look to see if that actually completed there. It did, and I missed off it. Go. So quickly, let's do connect and 132. There we go. We have our database deployed from a snapshot of a database that was seeded across from Windows via a clusterless
47:10
AG and then provision. And we can do it again, snap clone, snap clone, as many times as we want. But anyway, let's close all this. And I have an instance of SQL running in KubeVirt here. Here it is. Got a database, running TPCC.
47:24
I'll talk about what that is in a second. And here is my KubeVirt VM. It is literally just a VM of Let's do system info, give me some information. This is literally running Windows Server twenty Windows Server twenty twenty-five data center.
47:38
And it's just a VM that I can interact with in any way I would. Like, I've got RDP here, I've got connection to SQL Server. There we go, twenty twenty-five data center. Let's have a look at it. Let's have a look at the components running. I'll close and clear all this.
47:54
And I'll talk about some of the testing that we did when I first got my hands on all of this. So if you want a detailed run through of setting up KubeVirt and SQL Server, check out my blog there, and we will post a whole bunch of resources in the chat at the end of this session. I'm gonna make sure I'm using the correct location and context.
48:13
This is a different cluster. It is a I'm gonna call it a compressed cluster. What this is, is, a physical box. My other cluster, the four-node cluster, was a VMware cluster. And think about what we're doing here.
48:28
If I deployed to that cluster, I would have SQL Server in a VM running in Kubernetes nodes that are also a VM on top of an ESX host. And I was doing performance testing. I didn't even try and attempt to trace that IO path. This is a physical box running Kubernetes, where I can deploy virtual
48:47
machines in via KubeVirt. Makes the, makes it a lot simpler in anyway.So let's have a whole bunch of have a look at a few things. Let's have a look at namespaces, storage classes, and my persistent volumes. So we've got our namespace, we've got Portworx here with all our Portworx components.
49:06
KubeVirt running all the KubeVirt components that we had a look at just in the slide there. I know it was a very quick overview. But then finally, CDI, which is the that allow us to do things like take an ISO file for, say, SQL Server or Windows, import them as a persistent volume. And here we go. We've got a Windows 2025 PVC and a SQL Server
49:27
2025 PVC. Now, when I first built this, I built this as a blank Windows VM, then I manually, and then I installed SQL. But again, now that we have it in there, we have that snap clone functionality available to us through this, through Portworx or directly on the FlashArray.
49:44
If we have a look at the virtual machines and virtual machine instance Well, let's do this. Let's have a look at the pods. We'll have a look at all of it, shall we? Why not? Though I'm aware we are tight on time. So we have our virtual machine and the instance of that virtual machine running. We then have a pod, virt launcher, where it's the actual pod running our virtual machine,
50:06
and then I opened up two services here, and I could have combined them, but again, I like that granular control, so I can just look at a thing and go, "Ah, that's I've got RDP 3389 and SQL 1433. At some point, I'd blow away the RDP one, just have that deployed for, say, any troubleshooting I ever needed to do.
50:24
Okay. All right. So we have that physical machine. We're running Kubernetes, and we have SQL Server deployed as a VM in that machine. Now, what I did, and what this database here is, this TPC-C database, is a database that
50:41
can be automatically provisioned via HammerDB is a performance set, testing suite for SQL Server that can do OLTP testing, or OLAP testing, TPC-H testing. And so what I did was I spun up a StatefulSet running SQL Server on the cluster as my KubeVirt installation, and did side-by-side testing.
51:07
And these are the results I got initially. I got WEKA. We do, we measure it by transactions per minute. So I got a hundred and eight thousand transactions per minute in my StatefulSet result. I got forty-one thousand transactions per minute in my KubeVirt.
51:22
Not great. So I went off and started doing a whole bunch of testing, and there are a whole performance considerations to be taken in, taken into account when you're deploying this. So I won't go through all of these manually because we don't have time. The main ones though were this Hyper-V feature enabled for the Windows V- for
51:44
the VM manifest. This en- enables Hyper-V features for performance and timing, and there's a whole bunch of other ones underneath it. Once I enabled that, set my resources, and re- requests and limits matching the same for that guaranteed quality of service, and then using the specific virtio driver for my
52:05
disks, I then reran the tests and was hitting ninety-eight percent of my StatefulSet. So SQL Server running a StatefulSet and running in a VM, we can get pretty much performance parity. I did a few more tweaks as well, and pretty much got a hundred percent. If you wanna check that out, you can check out the performance tuning KubeVirt for SQL Server,
52:25
and this blog here again will be in the notes for this session. Okay. Jump it back in. As I mentioned, we've got all of these resources for you here, which we'll share. We've got the case study that I wrote for replacing SQL Server instances with SQL Server containers.
52:43
We've got the Portworx CSI documentation, the KubeVirt documentation, getting started with SQL Server and KubeVirt, performance tuning SQL Server and KubeVirt, using snapshots with SQL Server, deploying SQL Server containers on Kubernetes with StatefulSets. That's some Microsoft documentation.
52:59
And then brand new, we have from our own Anthony Ocentino, principal field solutions architect for SQL Server based over in the United States. He has just released a SQL on K8s operator. Now, I know I mentioned right at the start, we don't get any native SQL Server HA features in Kubernetes.
53:18
We don't get any availability groups. This gives us the ability to deploy availability groups in Kubernetes and get automatic failover. Absolutely fantastic stuff, released very recently, and there's a link to it right Go and check it out. Okay.
53:35
Fantastic stuff. We've got a few minutes. Do we have any questions? Yes, we do actually, Andrew. We've got one that came in earlier on, during the session, from Jose. And he wants to know, how are you handling the CPU count mismatch for SQL Server
53:55
in Kubernetes? By default, SQL Server sees all host CPUs, not the pod limit. So max DOP zero means it tries- Yeah to go parallel at host level DOP on a fraction of the actual compute. That means the optimizer picks parallel plans expecting CPU time that isn't there. Yeah. The, the only way around that, and
54:19
a real way around it, is because it will see them all, and it gets limit by CPU cycles when we set in. So we, it's, it's testing, I'm afraid. Test to see how you set in re it's just a brand-new platform that has these little tweaks that we need to go and test. It's, it's one that catches us all out with it because, yeah, you're not
54:37
limiting locking down. It will see all the CPUs, but you're locking down the cycles instead. Yeah. Right. Okay. Thank you. Okay. And, and just a, I guess one question that came to me was, are there any specific SQL Server versions, which support this running,
54:55
within a container?Uh, it started off with SQL Server 2017 and upwards. So, from SQL Server 2017, when they released SQL Server on Linux, you have the ability to deploy on Linux, therefore you'll have a SQL Server container image that you can build. And of course, you can build your own images, but don't try and build SQL Server Windows container images. Talking to someone who once built and deployed
55:18
a SQL Server 2014 on Windows container image that was 20 GB in size, 2017 and upwards. Got that. Okay. So I'll check if any more questions come in. And there's no more questions other than that that's come in. Um- All right. So please if, if anyone does have any
55:41
questions, my, my email address is aprosky@purestorage.com. Please feel free to reach out. I'm always willing to talk about this stuff. Oh, thanks. And, and I, and I'm gonna definitely go look at your blog, 'cause I've been read I read the first section of your running SQL, on a VM
55:56
within KubeVirt, and I got to the point where you've demonstrated that there was a bit of a performance difference. Mm-hmm. Need to read the next section of the blog to prove, how you, how you mitigated that with the- It was, it Yeah, it was really, really surprising. Cause the first time I, I did it, I sort of went, "Well, that makes sense because of the
56:10
virtualization layer. Okay, so we're- Yeah I didn't think it'd be that bad." But yeah, then I, I went and I actually had a chat with some of our engineers here who've got, you know, a little bit more experience with KubeVirt than me because I was just getting to my hands on it, who were saying, "No, there's all these different switches you need and features that you need to go enable.
56:25
If you're just deploying a unconfigured virtual machine, of course the performance is going to be bad." Yeah. You need to go and switch these things on. And I think they did it, bang, you know, straight up to 98% with the Hyper-V ena- enlightenment features there. Really great. And then if you go through- Yeah the blog,
56:39
I'll talk about all the different ones and give you, e- explanations of what each one is doing as well. Yeah. Okay. It stands to reason that should be the case because what with KubeVirt, being, you know, such a key part of, providing an alternative virtualization platform, and, you know, SQL is just one of many work, many workloads that we
56:58
could find on, Windows VMs running within, pods. So yeah, that's great. Well, well, thanks very much, Andrew. And, well, yeah, yeah, as I say, if anyone wants to follow up, you now know who Andrew Prosky is, and, do get in touch, and, hopefully we'll see you
57:16
all at, SQLBits in Wales. Thanks very much. Thank you.