 Hi, welcome to Visual Studio Toolbox. I'm your host, Robert Green, and today we're going to talk about containers, and joining me to do that is Aditi Dugar. Hey, everyone. How are you? Good. Thanks for coming on. Thank you. We've done containers a few times in the show. We've had episodes on Docker. We just did as part of the Smart Hotel 360 Series dive on the back-end services, which are all containerized microservices. But what I wanted to do is start from scratch. I'd go back to the beginning, if you will, and talk about what containers are and what some of the tooling is in Visual Studio to help, because there is quite a bit of tooling that helps, and then approach it from a different angle. Not so much the fancy modern microservices, where some are in .NET Core and others are in Java and they're orchestrated in Kubernetes and all that, which is good stuff to know. But what if I'm just somebody who's building and maintaining, has built and is maintaining, right? Classic.NET applications, ASP.NET, web forms or MVC or a WinForms or WPF app that talks to WCF, that talks to a SQL Server, right? Exactly. What do containers have to do with me? Because it turns out the answer is a lot. Yeah, for sure. Yeah, that's a great point. Let's take a look here at what the term modernization actually means and where containers really fits into that. So really, we're talking about here existing apps and services as you were talking about. So applications built with .NET Framework, usually on-prem and we want to make sure that we can move those to the Cloud. Right. Without necessarily having to rewrite it as a .NET Core app. Exactly. Which you can do if you want. But it's not a requirement. No, and there's much easier ways to move it to the Cloud. If you don't want to spend the time rewriting it in .NET Core. So the first option you could do would be to migrate it. So this really means making it Cloud infrastructure ready, which is really just re-hosting in VMs. So here you have, don't code changes, really easy but you use VMs, which is the more traditional route. Right. When we're talking about modernizing, you can do this in a couple of different ways. One is making it Cloud DevOps ready and this is where containers come in. So containers really make it more portable, lightweight, easy to deploy, and more DevOps ready. Here again, minimal, very minimal code changes. So you don't really have to re-architect your app at all. It's really just adding some extra few lines for container support, which is pretty easy to do and I'll go through that in a little bit. Or you could Cloud Optimize your app and that's what you were talking about before with re-writing your app, re-architecting your app into .NET Core, maybe utilizing microservices, but obviously that will require a lot more work. So containers can be more of an easy step in between that. Okay. It's the first step, it may be the only step you need to take. Yeah, exactly. You don't have to go fully to microservices if you don't want to. Okay. Let's take a second and talk a little bit about VMs versus containers, just so people can get a sense of what the differences are between the two. So in a container, what's different is that you're sharing an operating system kernel, and you're really deploying the containers with the binaries, the libraries, and the application, and that's what makes it so lightweight and so portable. Versus a VM, you actually have the operating system for each one. Right. It's called a virtual machine for a reason. It's an entire machine virtualized. So it's everything from the base operating system on up. So they're huge, they require huge amounts of disk space. There's certainly scenarios where that's good, but not exactly portable, not exactly lightweight. The container is, you take the application and all of its dependencies, and that's what's in the container, and then it runs on the operating system which already exists. Exactly. Windows Server or of course, sitting in Windows Server in the Cloud. Yeah. So you could have Linux and Windows. So today we're focusing on Windows just because we're talking about.NET Framework applications. So you'll have to use Windows containers, but you can also have- Get to use Windows containers. Get to use Windows containers, exactly. But if you wrote a.NET Core application and wanted to containerize that you could pick if you want to choose. Windows containers, Linux containers, whatever you actually want to use. Yeah. Linux containers are a little bit more lightweight. They can be faster at the moment. A little bit, they work a little bit better with Kubernetes, although great Windows support is coming. On the other hand, I don't know nothing about Linux. I know a lot about Windows. So there's a benefit to choosing the container that's the operating system you know about. Very true. Very true. So let's go into talking a little bit about Docker, just so people are familiar with Docker. So Docker is basically a container platform provider, and it helps you automate your containerization, so you can easily deploy your apps to some containers. So Microsoft actually has a set of images hosted on Docker that makes this really easy for you. So if you go to Docker Hub here, you can see that Microsoft has published all sorts of images. So you have your Windows Server Core image, your .NET images, you have your ASP.NET images. So here's where you can find all of the images. And these are starting points. Exactly. Take that image and then you add things to it, like your application or additional functionality that you want to add it. You can start out with a stripped down container and then add more things to it. You could just choose the ASP.NET or the ASP Core image, which already has ASP.NET Core running, and then you can just do nothing more and then put your app into it. And then of course you can make any of the changes you need to it to add functionality or restrict functionality. Right. But you don't have to start from scratch. No, you don't have to start from scratch, which is great. And all of these have documentation associated with them, which is even better because it makes it even easier to get up and run quickly. And they're updated on a fairly regular basis. Correct, definitely. So let's talk first before we go into the demos about why you want to containerize your app. Because it's the cool thing. Everybody is doing it. Exactly. That's the only reason you should do it. So modernization in general can be useful for improving agility, growing your applications, lowering your IT costs. Say you have an on-prem database that you want to move to the cloud. Really, modernization in general is about lowering your total cost of ownership. Containers in particular are useful because, as I mentioned before, you don't have to re-architect your code. So that makes things a little bit easier for you. There's less of a learning curve, less code required. Lower deployment costs improve productivity, improved DevOps agility, and portability, which is what we talked about with containers versus VMs. They also give you some act as kind of a firewall between you and the rest of the machine. So you could have a web app running on a machine that you wrote on .NET 3.5, and you're leaving it there because it works fine. But then people keep making changes to that machine, and new versions come on, or new libraries come in, and now your app is subject to whatever is going on on that machine. So how many times is your app broken because somebody fiddled with the server? Exactly. You stick it in a container, it's fixed. That container runs on that machine, and people can do whatever they want to that machine as long as they don't take away the ability to run a container, and your app will never be affected by that. And if you need to make changes to your app in the container, then you go ahead and do that, whether it's update to a new version of the framework, or apply different patches or whatever, but you get this isolation. That's the word I was looking for. You get an isolation, and the ability to move it around, right? Oh, this machine's going down for three weeks. We're going to replace it with a new machine. Can you get your app up and running on this new machine? Yeah. If you have to then go and install on that machine, I mean, that could be a bit of a nightmare, or you say, yeah, here's the container, run it, done. Easy. Yeah, I mean, another point there is really dev test environments as well. So you hear a lot of people who are like, ah, it worked in testing, worked on my machine, but somehow this just doesn't work in production. Right. That's great. So that probably is also solved. We use this app twice a year, right? Because we have our annual poll, or we have our annual raffle twice a year. So you just want to, you don't necessarily want that app having to run all year. You spin it up when you need it, and you take it down. Containers make it really easy to do that as well. But there's a lot of benefits. Agreed. So let's get into some demos, so I can actually show how this works in Visual Studio. So let's take a look at this first scenario here. So a common scenario might be to have a web application, and this could be an MVC app. This could be a web forms app. And you could containerize this. You could have it talk to a SQL server, also in a container. For the purposes of the first demo, we're just going to stick with containerizing just the MVC portion of the app. You have to put in some additional dependencies in to talk to the SQL server, which I'll show you in the second demo, which is a little bit more complex. But let's start with the basics. All right. So if we go to our legacy MVC app. I love the word legacy. Legacy means existing apps that are running the business today. Exactly, existing line of business applications. Yeah. So I've started this up already, and this is basically an eShop, which has a bunch of different catalog items, and you can manage the catalog from this web app here. So you could create new items, you could edit, delete, do whatever you need to the catalog. Frameworks 3, 5, 4, 4, you know? Probably 4 something, probably 4, 7, I think. Oh, is that recent? It's okay. Yeah, we just made these recently. I think we update them pretty regularly, but it could be older if it needed to be. Doesn't matter what framework version, per se. So as you can see, this is running locally, just on my machine here. So if we go back to the application in Visual Studio, and I wanna add Docker support, all I need to do is right click here and say add. Now before you click that, not that this hasn't happened to me like every day. First of all, you need Docker installed on your local machine, and you need it running. Yes, that's a great point, yeah. So if I had a dollar for every time I either built this project or tried to add Docker support before I had actually started Docker, I could retire. Yeah, that's a really good point. I automatically have it up and running all the time, so I forget that that's a critical step in the process. You can see by this little icon down here, it's up and running. Another point there is that you see here, it says switch to Linux containers, so right now I'm running Windows containers and you have to make sure you're running Windows or Linux containers, whichever one you wanna choose. Okay. So if we go into here and say add Docker support, it's gonna auto generate a few files for us and we can walk through each of them and talk a little bit about what they're doing. So this first is the Docker file and this is basically describing the environment that your app is running in. So the important point here is that it's using this Microsoft ASP net image. Yeah, so this is basically the recipe for how you build this container. Exactly. It says if you haven't already downloaded it to your computer, which can take a while, go to Docker Hub and get this particular image. Windows Server Core version 1709 with ASP.net, 4.7.1, that's pretty new. So go get that file, which is large. It is pretty large. So the first time you run this, it actually takes a little bit of time to download that image and make sure it's on your machine. Once it's already there, unless you delete it, then it's pretty quick to start up. But yeah, the first time it'll be a little bit lengthy. You also have this Docker compose node that was created and this really has all of the assets to build and configure your containers when you actually run it. So you have this Docker compose file here and this is really just saying get that image, that eShop legacy MVC image, and it uses that Docker file that I just showed you for context. And you also have an override file and this is just defining some additional environmental variables to help it run. So for example, exposing port B. So the cool thing, which is why we love Visual Studio, is it wraps all the plumbing for me. You can do this from the command prompt and many, many people do. Or you can right click and have Visual Studio do it for you. Yeah, and the other cool thing is these are all text files. So instead of having to install a bunch of things on your VM, you can just go and make some changes in these text files and it's pretty easy to add dependencies, add new things or configure how you need to. Which is very cool. And you haven't touched the app? Nope, haven't touched the app. The app is exactly the same. All I did was add Docker support. So now if I start up with adding Docker. Oops. I want it to start without debugging. So you can debug into your container if you need to. But for a faster startup, I just started without debugging here. And you can see down here, it's getting these images. It's making sure all the containers are ready. And it'll start up the same web app now at an IP address. So this is the IP address of the container itself. And if that's something that you want to find out later, you can even go to your command prompt say and say first you'd have to find out what the name of the container is. So Docker PS is a good way to do that. So that'll give you all the containers that are currently running on your machine. So once you have that container ID, you can say Docker inspect. And this is gonna give you all that information about the container, including what that IP address is. So you now have this app running in a Docker container locally on your Windows 10 machine. Correct, exactly. Very cool. And it's running at this IP. As you can see, it's the same exact catalog as I showed before. Yep. Talking to SQL server. Not yet. Not yet. For this one, we didn't implement. So if you see the Docker PS, only brings up your one container for this eShop legacy MVC. But if this app was talking to a SQL server, then the container can talk to that machine too. Exactly. Since it's essentially, it's equivalent of a Windows machine running on your network. Yeah. Right. Exactly. And we'll show that in the next example too. So you don't have to do anything with the SQL server. No. No. It'll be in its own container. It'll come down. It doesn't have to be in a container though. You could containerize it. You could just leave it where it is. You could. Exactly. It could be either way. Right. Okay. Cool. That's pretty easy. Yeah. And then another thing you can do is type Docker images. And this is gonna show you that you have that image on your machine. So we have that ASP.NET Core image right here. Mm-hmm. And we also have that eShop legacy MVC. Okay. Right. Which is so the basic image, ASP.NET running on Core, seven and a half gigs. This ASP.NET one is, they take a bit of space. They do take a bit of space. The Windows containers take a bit of space. So if you are sitting there with like 12 gig left on your hard drive, then you're gonna have a hard time running on that machine. If you wanted to delete these images though, you could also do that. And you wouldn't affect things on your machine. So it's pretty simple. There's also a way to, there's a Docker command to take the image and put it in a tar file. Which you could then move to a different computer, wipe all the images off if you needed the disk space. Right. Because you were just playing around with it. And then take the tar file and rehydrate it as images. So I discovered that one a while ago. Yeah. It's pretty cool. That's a good one too. Yeah, I have quite a few images on here just because I play around with this a lot. But I'll probably have to clean them out at some point. Cool. So let's get into the second scenario. Which is a little bit more complex, but pretty similar. So in this one, so you have a three tier scenario. And for this you have a windforms front end. You have a WCF middle tier and a SQL server back end. Okay. So this might be a little bit more traditional, three tier and end tier app that you might have in your line of business application. So this is based on the same eShop example. Again, we go back to Visual Studio. I have this up and running, just so we can show you. It is gorgeous, right? And in 4.7.1, you got the high DPI support, so it doesn't get all crazy. It doesn't get all crazy, yes. So this is a high DPI monitor itself, which is why it looks a little funky here. But if you had a high DPI monitor, it would automatically adjust. Exactly. So we can do the same thing here and right click on this WCF service and say add Docker support. And again, it's gonna auto-generate some files here, but we're gonna have to make some modifications this time. And that's because this is only generating files just for the WCF service, since that's what I right clicked on and added Docker support for. So now I wanna put that SQL server in a container too and say, okay, now we have two containers and I wanna make the service actually talk to the SQL server. So if you're gonna leave it that the WCF service talks to the same SQL server sitting somewhere else, then you wouldn't need to make these additional changes, right? There's a few changes in this base file that you need to make, which is documented on the site for the WCF. The question is, what WCF services does this have? Does it have all of them, right? You need WS transport, WS this, that, the other thing. Exactly. You might need to add some additional things. Yep, so first we're gonna add those additional things just for the WCF portion. And all we're doing here is adding some additional things to make the environment full and this is all documented online and something you have to do when you add the WCF. And you're exposing port 83, that's what that exposes. Yes, it exposes port 83. Got it. And then if we go to the compose file, here's where we're gonna add the dependency on the SQL server. So we'll take this and this now depends on SQL.data and this here is referring to the SQL server image. So now it's gonna pull both that WCF image and the SQL image onto your machine. So again, the first time you run this it's gonna take quite a bit of time because you have to pull both of these images. And on that container, you've got SQL server but you'd have to put your database on and then set up your users and your security the same way you do any SQL server because again, it is a SQL server. Exactly, yeah. The last step is to actually put that connection string info. Oh, you get to do all that in your override file. Oh, that's cool. Yes. So. I thought you'd haul out SQL management studio. No. But it's easier this way. Actually, I can just put it in the text file. So I have my connection string. I have my password here. I have all the credentials here and I'm talking to that port 83 that I exposed. Okay. And that's really just these and additional environmental variables right here. And that's actually it. So even to add support and dependency for the SQL server container, there was a little bit of work but it wasn't re-architecting my code. Yeah, definitely. So I went to my app and changed it all. Now it's all set up to run in Docker. Okay. So let's start Docker. And this one will take a little bit more time just based on the facts that you have these two containers that need to start up. So you started without the debugging which is faster but if you start with the debugging then you actually can set the break points and debug the app while it's running in the container. Yes, yeah, you can do that as well. If that's something that you need to look into. Right. I mean, presumably the app's been tested locally and works just fine but. Hopefully. You never know. You never know. Yeah. It's always useful to have that option. Right. Exactly. And so you can see here we created, what's creating the SQL container now and now it's moving on to the WCF container. You can see in the output here. So if I go back here and I type in Docker PS you'll see that I have, I still have that container from before because I didn't do anything with it but now I have this new SQL container and when the WCF container is done that will show up here as well. Now in the WinForms app you need to point it to the WCF service running somewhere else? No, so I didn't have to make any changes to the WinForms front end. So the WinForms was already talking to the WCF service just locally and you just had to containerize the WCF service and it can still talk to you. But isn't it running on a different host? Yeah. Oh, yes, yes. Okay, that's what you're saying. Yeah, to reset the service reference. Yes, exactly. Point in the web, not the web here, the app config is pointed to a different server. Yes, exactly. Which you can again get by the IP address, right? Exactly. So now we have this starting up here and we have the service. So this is the service itself and exactly we're gonna take this IP address and we're gonna put this into the app config file here. And so right now it had the endpoint as local host because that's what we were talking to before. So this is what you'll replace with the IP address. And... Do you get to assign names or do you always have to use IP address? You have to use IP address, unfortunately. I don't know if there's a way to do it with the ID of the container or not. I haven't looked into that at all, but IP is definitely the easiest way to go. So now if we start... Yep. It's so sterile. It's so not impersonal. It's true. You can't name your container something. Something interesting. So now I've started up an instance of the WinForms front end again and that's gonna be talking to the IP address here. A few seconds. This is so cool because you didn't have to change any of the app. You just had to basically change where the pointer to the service. Exactly. And you... Visual Studio... Obviously you need to learn more about Docker, right? But it's not that hard to learn how to do things. Yeah, exactly. Where the image is. What does it mean? How do you start and stop a container? This is really good documentation on the Docker site. There's inexpensive books you can get. But you've taken this application and containerized it in 20... Well, we talked about 16 minutes, right? That was easy. Yeah. Not counting the time it takes to download the images. Right, yeah. So that would take a little bit more time, sure. Now, so a question I had, we talked about some of the benefits of containers. There's to modernize, to cloud enable these things, you could have taken that NBC app and published it to an Azure web app. You could take this WCF service and publish it to an Azure web app. So talk about when you might do one versus the other. Yeah, I think there's a couple of key points. So the first is about deployment. So as we were talking about before, you don't know what framework version this is running in. And say you publish this to app service and this is running in the latest framework version, but app service doesn't yet support the latest.net framework version. So there's sometimes a gap there. So with containers, that's not an issue because your framework's gonna come with your container and all those dependencies are kind of baked in. In addition to framework, it could be another third party dependency. So a lot of existing line of business applications have things like ComPlus components or other dependencies. And so all of those dependencies are really packaged in for you and you don't have to worry about installing them separately or worrying about them. The second is really to improve DevOps and improve DevTest environments. So you can start up a DevTest environment really easily, like we talked about before. So you can set up your DevTest environment using the container. In this case, you don't have to even install SQL Server on your machine, right? Because you have it in the container, the container's gonna come down to your machine and that's much easier than say, installing all of that from the ground up. So- Which would really help if this app was using SQL Server 2010, for example, and we weren't going to touch it, but I've got 2017 on my machine, right? Exactly. And in addition, you could test it into your DevTest environment and you could be a lot more certain that it's actually gonna work in production. So I think those are kind of the key things I would point out. And I guess also, you can run containers locally. You don't need- You don't have to. If they run on a Windows Server, just fine. Yep, you can run them locally. You can deploy them to the cloud if you want to. We obviously, when we talk about containers, we're typically deploying them into Azure for a couple reasons. One, because we also want to talk about Azure. But two, none of us are lugging around Windows Server machines, so it's just a heck of a lot easier to put it in Azure, right? Right, exactly. Yeah, that's actually what we can talk about the next time that we chat. So I think in the next session, we can talk a little bit more about, okay, now we have them running in containers locally, but how do we get this to the cloud? What are all the different ways you can get there? How do you scale out your application? We can talk about orchestrators, which you may have talked about in your microservices episode as well. A little bit, yeah. Yeah, so I think those are kind of the next steps in this scenario. But this is really the basics in the first part of getting towards there. Cool, so this is a good stopping point. And we will pick this up again in the next one. Sounds great. On Visual Studio Toolbox. Bye.