 All right, everyone, I'm going to go ahead and get started. Thank you all for coming to the session today. My name is Dan Taylor. I'm a Program Manager for our Python Developer Tools at Microsoft. This is a sponsored session, so I'm going to be going through how you can deploy a Python application to Azure in a Docker container using Visual Studio Code. Together with Azure and Visual Studio Code, you get a really productive developer experience. I'm basically going to show how we start with just these prerequisites here on the screen. If you have an Azure subscription, Visual Studio Code and get command line tools and Docker, how you can deploy an app starting from basically a command line. The steps we're going to run through today, we're going to create an application and run it in a local Docker container running on this local machine. Then we're going to deploy this to Azure Web Apps for Containers using VS Code. Then we're going to add some data to a Cosmos DB database using our Azure Notebooks, and then we're going to update the code and redeploy it. Just a quick summary of some of the key services in Azure that you might be thinking of if you're a Python developer. We've got Web App Hosting and App Service and Azure Kubernetes. We'll be using Azure Notebooks, but there's also things like Azure Machine Learning and Batch AI for doing training of ML. Then we've got various data services like Hosted Redis and Azure Database for Postgres, and then we've got Cosmos DB, which we'll be going through today. Then finally, we'll be using Visual Studio Code, which is Microsoft's free cross-platform and open-source editor. It's very lightweight and fast, and it's got a very rich extension ecosystem, and the extensions that we'll be using today are the Python extension, which is actually what my team builds at Microsoft, the Docker extension, and then some of the Azure extensions that make it really easy to package up and deploy this application. So let's go ahead and dive right in and get started from zero. All right. So I've got a command line here. So Visual Studio Code is a very lightweight editor. As I mentioned, it's meant to work with a command line plus editor. So I usually start out from the command line, and the first thing I do is just make a new folder. I'll make a new folder called zero to Azure. I'm going to change CD into that folder, zero to Azure. Then from here, I'm going to type code dot. So one of the things, if you install Visual Studio Code on Windows, it automatically puts VS Code on the path. On Mac or Linux, there's a simple command that you can run to put VS Code on the path, and it just makes it nice and easy for you to type code dot, and then it opens up in the folder, and then I can start working with Visual Studio Code in the folder. Alternatively, you can come in here and click open folder to open up that folder. So the first thing I want to do is define my entry point for my application. So I'm going to click this new file button. When I click that, it lets me name the file, and I'm going to put my file into a folder called app, and I'm going to name it main.py. So what's really cool about this, if I just hit enter here, it's going to create a folder called app and put a Python file in that folder. So really neat little shortcut trick there. Can everyone see okay on the screen? Great. The first thing I'm going to do is go to write a basic Flask application. How many people here are familiar with Flask as a web service? Great, looks like 60% or so of the room. I'm going to use a little snippet that I've written, Flask app tab, that I've just customized my user snippets here on my VS Code, so you don't have to watch me type this out. But this command has to save. Here just the most basic Flask application you can write. We import the Flask object, we define our app, we define a homepage route there, we render a template index.html, and then this little piece of code here, if you run this main.py file directly, it will run the web server. Alternatively, web servers typically grab this app variable and then use that to run the host, which is how we're going to run it in the Docker container. Okay, so now I need to add this index.html file that I have here. So I'll create another file here and I'll use that same trick where I'll put templates slash index.html. That's where this render template function expects it to be, and I'll use another cool trick in VS Code. Here we have integration with emit, so I can type exclamation mark and press enter, and it'll give me some template, some boilerplate.html code, which does some nice things like sets the device width and the scaling so that it'll render nice on a mobile application. So we'll call this Hello, EuroPython, and then we're gonna say Hello Flask plus Docker plus EuroPython plus, any one that got Edinburgh, what was that? Plus Kitty, and then all the things. Okay, great. So this is our application here, very fancy. This is what we're gonna go ahead and deploy to Azure. So I mentioned this is with Docker, I could go ahead and just right click and run this file locally, but I'm actually gonna run it inside of a Docker container. So what do I need to do? I need to add some Docker files to my workspace here. So far I actually haven't installed any extensions yet. This is just with vanilla VS Code. So let me go ahead and install all the extensions I need from here. Actually, I've got these all saved offline in case the Wi-Fi drops out on me. I've actually got Wi-Fi in my pocket because this is a very connected demo. So the first thing I'm gonna do is search for the Python extension. Normally you'd install it. For me, I just need to enable it. So we'll enable that Python extension. We're gonna turn on the Docker extension as well. I'll come in here and click enable on that. And then as I mentioned, we've got some Azure extensions that we want to turn on. So we'll add the Azure App Service extension. So we're deploying to Azure Web Apps, which is part of App Service. And this is gonna turn on our Azure account extension. And then later in the talk, I'll need Cosmos DB. So I'm gonna turn on the Cosmos DB extension. Great. So let's reload VS Code. So I just clicked that reload button. Every time you install an extension, you need to reload VS Code so that it can start up with all the extensions turned on and those things. Great. Okay, so now that I've installed particularly the Docker extension, I can use command shift P or control shift P if you're on Windows to bring up this command palette. And one of the things that the Docker extension does is it adds a bunch of Docker commands to this command palette. The one that I'm going to use is the add Docker files to workspace command. So when I run that command that was at the top there, it's got some templates for different languages, one of those languages being Python. So if I select the Python application platform, it will have some boilerplate stuff there. And it's asking me which port my app listens on. It listens on port 8,000. So that's important. Okay, so this adds some Docker files here. I'm gonna go in and actually customize these Docker files. They don't know anything about Flask or anything like that just yet. So if you're not familiar with Docker, it's composed of various layers, right? So the first thing you define is what is the base image that you want to depend upon and then you just add the little pieces of code that your application depends on. So one of the neat things, I'm gonna use a Docker image base that's publicly published on Docker Hub. And one of the cool things about this Docker extension is it actually has autocomplete for the base images so that as I type, I'm actually gonna use this one by this member of the community, user Tiangolo, that's created a really good Docker image for hosting Flask applications. So I'm gonna use this Uwizgi Nginx Flask. This puts Flask behind a production web server so that it's nice and fast. And then as I type out my tags here, it gives me autocomplete for the tags. So I want this to run in Python 3.6 using Alpine Linux, because Alpine Linux is very small. Makes the Docker image much smaller than a full Ubuntu or Debian image. This just makes everything faster as you're deploying and running your application. So a couple other quick customizations that I wanna make to this file. It's exposing this port on this Docker container so when it runs, you can connect in to port 8000. But I also am gonna set an environment variable, listen port, which basically tells the base image to start the Flask application up on port 8000 so those things are aligned. And then I'm going to make one other customization here. I'm going to add, I wanna add this app folder into the app folder of the Docker container. And then I'm just gonna comment out these commands because this would install additional packages but the container already has Flask built into it and has a startup script so I don't need these, right? So if I look at the Docker compose file here, this has some like local build time, runtime parameters here so it tells the tools on my local machine for the most part what to do. It has the image name that I want to run this at and then it has the port to map this to. So when I run this locally, it'll be available on port 8000. So I've set up those containers, those files to have what I need. I'm just going to run compose up which is a command added by the Docker extension. So if I run compose up, it's going to, that was pretty quick. It'll create a Docker image, building that Docker file. It actually runs, it starts up the Docker container running on port 8000 locally. And if I go into my Docker tab over here, I can see that it's actually started up a Docker container here called zero to Azure and I can actually manage these containers. I can start, stop, remove. And one of the other things is that I can show logs. So if I right click and show logs, I can actually see the log of the running Nginx web server inside of this container here. I can see that it started up, it ran a bunch of commands. And then of course I can also run, I can also connect to port 8000 locally. And there we go, we've got hello all the things including the kitties, cool. Right, so we just created our app from scratch and ran it in a local Docker container. So quick review, we made a folder, we launched VS code with code dot, we installed the Azure and Python and Docker extensions. We created a hello world Flask app using some snippets that are available. We added the Docker files and we made some changes to the base image including setting, using one of the images from Docker hub and changing the listen port and just copying the right files over. And then we used compose up to build and run the container locally, showed the logs and browsed it to it on local host. All right, so the next thing that we want to do is take this container and shove it up into Azure, right? We want to host this as a web application that the public internet can see because this is the best website in the world. All right, so let me just minimize this, that's for later in the talk. So the first thing I'm going to do is go to the Azure portal and create an Azure container registry. So when you publish a Docker container, it has to live in a registry somewhere and you can publish it to Docker hub. That's sort of the default container registry. You can also create an Azure container registry for hosting that Docker image, so that's what I'm going to do. So I went to portal.azure.com and I'm going to sign in to the Azure portal. This is where the Azure subscription comes in. You can get a free subscription, you can get $200 in free credits if you want to just play with Azure and try out all these steps. So when you come into the portal, I've got some resources here created already, but the first thing I want to do is create a resource and for that I want to create a container registry. So I'll select that, there we go. So here's the container registry. I'll select create. It's going to put this into, so this is going to create a registry. I'll just call it my new registry and this will create a registry that's available at azurecr.io. And I get to create a new resource group. So a resource group is basically a set of folders for all your Azure resources. So I'll just say my new resource group. We'll put it in North Europe because I think that's pretty close to where we are. And then I'll pick the basic SKU because that's the cheapest and I'm just a developer playing with things, right? So all these things you can do with the free credits that you get with the Azure trial. So I will select create here. And at this point, just to minimize potential, again, Wi-Fi gotchas, I'm going to switch over to a zero to Azure resource group that already has a container registry created and it's called EP Registry. So I'm going to go into the access keys and copy the password here so that I can log into this registry with VS Code. So let's hit control C here, stop this container. So the first thing I'm going to log in to that registry from the command line. So Docker log in EP Registry.AzureCR.IO. The default username works and then press Command V to paste that password that I just copied with the portal. And then that's going to allow me to push this container image over to Azure. So if I come back to this file here, I need to change the image name so that it's prefixed with the location where this container is going to be pushed. So I will prefix it with, that's the registry I want to push this to and we'll throw a version number tag on it just for it's just a good practice. So now if I go and run that compose up command, it'll rebuild this container. I'll select that Docker compose file. So it'll rebuild this container. And then if I go and see the images that I have on my local machine, there's the container image that we just built. I can right click this and say push. So if I push that container, it'll, it knows where to push it using the Docker command line. And because I've prefixed the image name with the registry URI. And so it's gone ahead and pushed that up to my container running in Azure. Now I can also browse my container registries that are running into Azure, but now I need to sign in for this step, right? So if I click here to sign in, VS code has this really nice sign in experience where it just has this code that it copies to the clipboard and I can click copy and open and it gives me a login prompt in the browser. So I can just paste this code into that browser, hit continue and it just asks me to sign in to confirm who I am. And then that should be it. And I should now be signed into Azure with VS code. So we can see there says Python demos at outlook.com. I'm signed into Azure with VS code. And now VS code can see my Azure resources, including the Azure registry. This is the one I just created. This is the one that we're actually using. I can actually expand this and browse through all the containers and version numbers that are deployed. So if I had multiple versions, I could see them here, but this is the zero to Azure container that I just pushed. And then this is the version that I just deployed. And so I can right click this and from here I can just deploy this container directly to a new website web app running in Azure. So I'll select deploy image to Azure app service. It's gonna take me through a set of questions here. I've got a resource group, again, that's a folder for all of my different Azure resources called zero to Azure. I'll select that. We're gonna create a new app service plan. So a plan is the actual physical VM on which the container runs. You can host multiple containers running on the same plan and you only pay for the one plan. So if we will call this the zero to Azure plan, hit enter. And we'll pick again the B1, the basic pricing tier. This actually allows us to run three containers on the same set of resources. So if you have a dev staging and prod site, you can host them all on one set of resources. And then let's call this your Python app. And so this is the actual location where the app is gonna be available. So in the output window, it's creating the app service plan that I have there. And if I switch back to the portal and back to this resource group here, I'll actually be able to see these resources come in as they're being created by VS Code. So it says the plan's been created. So if I refresh, there's the host for the web app. And then it says that the web app's been created there. So there's the actual website there, EuroPython app. Now one final thing that I need to do before this website will be available is I need to tell the app service which port my container's listening on. So that was port 8000, that's what I had used. So if I go to, I went to the Azure tab here, which is added by the app service extension. There's the EuroPython app that I just created. Here is the different application settings, which are all my environment variables. So if I right click here, add a new setting, say websites, port, put 8000 in there, this container will now be available. So now I'll browse to the website. So the first time the website gets hit, it actually takes about a minute to load because it's downloading that Docker container from the Azure registry. So I thought right now I'd just take any quick questions. I have like time for one question if anyone is sort of lost or has anything. Yes sir. Yeah, so the question was, can we do it in different locations and can we isolate it from the outside web? So yes, so I deployed this one to Northern Europe. We have locations all around the world. Actually there was a point where I could pick which region to deploy to. So yeah, you would just pick which region that you want it to go to. And yes, there is a way to configure things behind virtual networks and VLANs and stuff like that. Just the default is that it's publicly exposed because that's the easiest thing to get started with. But yeah, I'd be happy to talk to you afterwards about how to get it behind a virtual network. Cool, so I said I had time for one question. There's the app now deployed. EuroPythonApp.azurewebsite.net. You can all hit this on your phones if you feel like confirming that we actually live out there online. All right, so moving along. So just a quick recap. So we signed into Azure with VS Code using the Azure Sign In command. We posted that code into the browser to authenticate it. We created an Azure Container Registry so that we could actually host our Docker container. As part of that, we created a resource group which would hold all of the other resources that we have for this web app. We then logged in using Docker login and then we built the image and we gave it a new tag and pushed it to that registry. And then finally we right clicked. I deployed the image to Azure App Service and then we set the website port to 8,000 there. Cool, so now we're gonna add some data to this website using our hosted Jupyter Notebook Service Azure Notebooks and Cosmos DB, which is a globally distributed document storage database with very configurable trade-offs between throughput, latency, and things like that. So it provides a lot of different flexibility for the schema you need so you can sort of get guaranteed performance and you can trade-off performance for various other factors. Okay, so the first thing I'm going to do is I've got this, if you go to notebooks.azure.com, I have, again it's a hosted Jupyter Notebook Service but one of the cool things that allows you to do is make notebooks available publicly. So I've got a notebook where I've done some analysis of some Stack Overflow surveys over the various years and so we're gonna take this data and we're actually going to put it into a database and then render a chart with our web app. I'm gonna pull down the code for the chart stuff, I'm not gonna type all that here. So this is a public library, you can actually clone this and then start running this code locally and so if you do that, you should probably uncheck it just so that if you put some connection, you can clone it as a private notebook so that if you put any connection strings or anything like that in there, people won't be able to get your credentials. So I'll switch, I would click this clone button here but I'm gonna switch over to one that I've already got cloned. How many people here are familiar with Jupyter Notebooks? Great, so I don't need to tell you too much about them but for people who are new to them, basically it allows you to run interactively and you can run code cells one at a time and view the output. So I'm not gonna spend too much time on how this works but basically I've got some code in here that downloads Stack Overflow Survey data. It's one of my favorite demos to do because the data's all public for the last eight or so years and it grabs the totals of people who have indicated they're using all the different languages. So one of the neat things here is that you can kind of view the intermediate data one cell at a time and so I kind of take you through how I actually go through and analyze and crunch this data to get to basically this language and percent by year information. At the very end it's all in this totals dictionary which has the years, the counts and the percents. So this dictionary is what I actually wanna push into Azure Cosmos DB. So this is kind of where we're gonna start with this demo is pushing this data from this notebook into Cosmos. So let me switch over here to VS Code. So the first thing I'm going to do is open up this Cosmos DB tab. You can create a new Cosmos database in here by clicking again the plus sign. Close DB, one, two, three, four. So we give the database a name. We pick the API schema that we want to use. Microsoft has a document DB SQL query language. We also support MongoDB. So if you want geo distributed Mongo you can use this Mongo API and we have a few other ones. But we're gonna use the SQL one in this case and we put that in that same zero to Azure resource group. We'll all put it in this my new resource group and here we pick the location. So I'm gonna put this one in North Europe where the other ones are. But I already have this Euro Python database here that I've created and just for expediency I'm gonna use this because it takes about a minute to create this database. So the first thing I'm gonna do is copy the connection string. So I'll just run this cell that imports the Cosmos DB libraries and I'm gonna paste the connection string here into these variables. So there's the key, put the key there and there's the host name. So we'll put that in there and then I've got about five minutes to get this all out the door. So run this, this defines our variables. This cell here creates a client to the document DB or to the Cosmos DB. This one creates a database. In this case we're gonna create a database called stack overflow and then this one will create a collection. We'll call the collection the results collection. So we're gonna create basically a place to shove our pre-computed results from these surveys and then finally this query actually takes this totals dictionary that we had from above and inserts it as a document. And then, okay, so it's inserted that into Cosmos DB and just to make sure that we have it, I've got a query here that selects basically from that database and shows the result down here. Okay, so now I'm gonna switch over to an, now we want to actually display this information within the app so I'm gonna switch over to an app which has a little bit more code in it. So I'll go back to the command line here and go to zero to Azure Flask Cosmos. And again, I'll run code dot which I showed you earlier so that will just open up this version. I've got this code on GitHub. Same app with just a little bit more code. And the main difference here is that we've added an API that reads the information from Cosmos DB. So the other thing is we've got the host and the key are read from environment variables here. So what I want to do is go back to my, well the first thing is I'm just gonna rebuild this container, compose up, we had there. And then we'll go to the Azure tab and add those keys to the Cosmos DB. There's the EuroPython app. And the first one is Cosmos DB host. Sorry, I did that wrong. We'll copy that from our database. And there is the key to add Cosmos DB. So we'll set that there. Okay, so we've built our container locally. We just want to repush. So if we want to update code and redeploy, all we need to do is push a new version of the container. And that will just only push the Delta layers that we've added. And this time it actually should load faster. So I'll just give it a quick restart to make sure it picks up the latest container. And then I will browse to that site. I caught it in the middle of the restart there. So with any luck crossing my fingers, we'll see a nice chart here. There we go. We've pulled data from Cosmos DB and deployed it to the app. You weren't expecting that to work, were you? Thank you. So just a quick recap and then we'll wrap up here. We created the Cosmos DB account from within the Azure extension. We ran code in our Jupyter Notebook to push that document into Cosmos DB. And then we added some environment variables to our application settings, rebuilt the container, pushed and restarted. Thanks for coming to the talk. That's everything. The code is available, including slides and everything on this GitHub URL. If you want to know more about anything we're doing at Microsoft with Python, aka.ms slash Python blog. And I'm available here if you have more questions. Thank you.