{"id":72,"date":"2018-03-27T06:48:21","date_gmt":"2018-03-27T06:48:21","guid":{"rendered":"https:\/\/blogs-staging.imperial.ac.uk\/research-software-engineering\/?p=72"},"modified":"2019-06-11T12:38:54","modified_gmt":"2019-06-11T12:38:54","slug":"cloud-first-rapid-webapp-deployment-using-containers","status":"publish","type":"post","link":"https:\/\/blogs-staging.imperial.ac.uk\/research-software-engineering\/2018\/03\/27\/cloud-first-rapid-webapp-deployment-using-containers\/","title":{"rendered":"Cloud-first: Rapid webapp deployment using containers"},"content":{"rendered":"<p><em>This is the second in a <a href=\"https:\/\/blogs-staging.imperial.ac.uk\/research-software-engineering\/tag\/rse-cloud-computing-award\/\">series of posts<\/a> describing activities funded by our <a href=\"https:\/\/www.software.ac.uk\/rse-cloud-awardees\">RSE Cloud Computing Award<\/a>. We are exploring the use of selected <a href=\"https:\/\/azure.microsoft.com\/en-gb\/\">Microsoft Azure<\/a> services to accelerate the delivery of RSE projects via a cloud-first approach.<\/em><\/p>\n<p>In our <a href=\"https:\/\/blogs-staging.imperial.ac.uk\/research-software-engineering\/2018\/02\/13\/cloud-first-simple-automated-testing-using-drone\/\">previous post<\/a> we described the deployment of a fairly typical web application to the cloud, using an Azure Virtual Machine in place of an on-premise server. Such VMs offer familiarity and a great deal of flexibility, but require initial provisioning followed by ongoing maintenance and monitoring. <a href=\"https:\/\/www.imperial.ac.uk\/admin-services\/ict\/self-service\/research-support\/rcs\/research-software-engineering\/\">Our team<\/a> at Imperial College is increasingly using containers to package applications and their dependencies, using Docker images as our unit of deployment. Can we do better than provisioning servers on a case-by-case basis to get web applications into production, and thereby more rapidly deliver services to our users?<\/p>\n<p>The <a href=\"https:\/\/azure.microsoft.com\/en-gb\/services\/app-service\/\">Azure App Service<\/a>\u00a0provides a solution named\u00a0<a href=\"https:\/\/azure.microsoft.com\/en-gb\/services\/app-service\/containers\/\">Web App for Containers<\/a>, which essentially allows you to deploy a container directly without provisioning a VM. It handles updates to the underlying OS, load balancing and scaling. In this post we&#8217;ll demonstrate how to run pre-built and custom Docker images on Azure, without having to manually configure any OS or container runtime. As previously, we&#8217;ll use the <a href=\"https:\/\/azure.microsoft.com\/en-gb\/features\/cloud-shell\/\">Azure Cloud Shell<\/a>, and arguments that you&#8217;ll want to set yourself are highlighted in <strong>bold<\/strong>.<\/p>\n<h3><strong>Getting started<\/strong><\/h3>\n<p>First of all we create an App Service plan. This only needs to be performed once for your active subscription:<\/p>\n<pre>az group create --name myResourceGroup --location \"West Europe\"<\/pre>\n<pre>az appservice plan create --name myAppServicePlan --resource-group myResourceGroup --sku S1 --is-linux<\/pre>\n<h3><strong>Deploying a pre-built, public container image<\/strong><\/h3>\n<p>It&#8217;s then just one command to run a Docker container. In this case we&#8217;ll deploy <a href=\"https:\/\/www.nginx.com\/\">Nginx<\/a>\u00a0using its <a href=\"https:\/\/hub.docker.com\/_\/nginx\/\">Docker Hub image<\/a>:<\/p>\n<pre>az webapp create --resource-group myResourceGroup --plan myAppServicePlan --name <strong>ic-nginx<\/strong> --deployment-container-image-name nginx<\/pre>\n<p>We can then visit our public site at <a href=\"https:\/\/ic-nginx.azurewebsites.net\/\">https:\/\/<strong>ic-nginx<\/strong>.azurewebsites.net\/<\/a><\/p>\n<p>You can use a custom DNS name by following these <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/app-service\/app-service-web-tutorial-custom-domain\">further instructions<\/a>.\u00a0Note that the site automatically has HTTPS enabled.<\/p>\n<p>Decommissioning the webapp (thereby avoiding any further charges) is similarly straightforward:<\/p>\n<pre>az webapp delete --resource-group myResourceGroup --name <strong>ic-nginx<\/strong><\/pre>\n<h3><strong>Deploying a custom container image<\/strong><\/h3>\n<p>Running your own app is as simple as providing a valid container identifier to <span style=\"font-family: terminal, monaco, monospace\">az webapp create<span style=\"font-family: georgia, palatino, serif\">.\u00a0 This can point to either a public or private image on Docker Hub or any other container registry, including Azure&#8217;s native registry.<\/span><\/span><\/p>\n<p>For demonstration purposes we&#8217;ll build a <a href=\"https:\/\/github.com\/simonw\/datasette\">Datasette<\/a>\u00a0image to publish the UK responses from the <a href=\"https:\/\/github.com\/softwaresaved\/international-survey\">2017 RSE Survey<\/a>. Datasette is a great tool for automatically converting an SQLite database to a public website, providing not only a means to browse and query the data (including query bookmarking) but also an API for programmatic access to the underyling data. It has a sister tool,\u00a0csvs-to-sqlite, that takes CSV files and produces a suitable SQLite file.<\/p>\n<p>First we need to install both tools, download the survey data, and convert it from CSV to SQLite:<\/p>\n<pre>pip install https:\/\/github.com\/simonw\/csvs-to-sqlite\/zipball\/master datasette<\/pre>\n<pre>curl -O https:\/\/raw.githubusercontent.com\/softwaresaved\/international-survey\/master\/analysis\/2017\/uk\/data\/cleaned_data.csv<\/pre>\n<pre>csvs-to-sqlite --table responses cleaned_data.csv uk-rse-survey-2017.db<\/pre>\n<p>Then we can create a Docker image containing the data and the Datasette app with one command, annotating with the appropriate licence information:<\/p>\n<pre>datasette package uk-rse-survey-2017.db\r\n--tag mwoodbri\/uk-rse-survey:2017\r\n--title \"UK RSE Survey (2017)\"\r\n--license \"Attribution 2.5 UK: Scotland (CC BY 2.5 SCOTLAND)\"\r\n--license_url \"https:\/\/creativecommons.org\/licenses\/by\/2.5\/scotland\/deed.en_GB\"\r\n--source \"The University of Edinburgh on behalf of the Software Sustainability Institute\"\r\n--source_url \"https:\/\/github.com\/softwaresaved\/international-survey\"<\/pre>\n<p>Then we push the image to Docker Hub:<\/p>\n<pre>docker push <strong>mwoodbri<\/strong>\/uk-rse-survey:2017<\/pre>\n<p>And, as previously, create an Azure Web App:<\/p>\n<pre>az webapp create --resource-group myResourceGroup --plan myAppServicePlan --name <strong>rse-survey<\/strong> --deployment-container-image-name <strong>mwoodbri<\/strong>\/uk-rse-survey:2017<\/pre>\n<h3><strong>Using Datasette<\/strong><\/h3>\n<p>After a brief delay the app is publicly available: <a href=\"https:\/\/rse-survey.azurewebsites.net\/\">https:\/\/<strong>rse-survey<\/strong>.azurewebsites.net\/<\/a><\/p>\n<p>Note that the App Service automatically detects the right port to expose (8001 in this case) and maps it to port 80.<\/p>\n<p>Datasette enables you to run and bookmark SQL queries, for example <a href=\"https:\/\/rse-survey.azurewebsites.net\/uk-rse-survey-2017-2d3b656?sql=SELECT+%22currentEmp2.+Which+university%3F%22++++++++AS+Institution%2C+%0D%0A+++++++COUNT%28%22currentEmp2.+Which+university%3F%22%29+AS+Respondents+%0D%0AFROM+++responses+%0D%0AGROUP++BY+Institution+%0D%0AORDER++BY+Respondents+DESC%3B\">this query<\/a> which lists the contributors&#8217; organisations in order of the\u00a0number of responses received:<\/p>\n<p><a href=\"https:\/\/rse-survey.azurewebsites.net\/uk-rse-survey-2017-2d3b656?sql=SELECT+%22currentEmp2.+Which+university%3F%22++++++++AS+Institution%2C+%0D%0A+++++++COUNT%28%22currentEmp2.+Which+university%3F%22%29+AS+Respondents+%0D%0AFROM+++responses+%0D%0AGROUP++BY+Institution+%0D%0AORDER++BY+Respondents+DESC%3B\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"833\" class=\"alignnone wp-image-96 size-large\" src=\"https:\/\/blogs-staging.imperial.ac.uk\/research-software-engineering\/files\/2018\/03\/Screen-Shot-2018-03-27-at-07.49.47-1024x833.png\" alt=\"\" \/><\/a><\/p>\n<h3><strong>Private registries<\/strong><\/h3>\n<p>If you&#8217;re hosting your images on a publicly accessible that requires authentication then you can use the previous <span style=\"font-family: terminal, monaco, monospace\">az webapp create<\/span> command into two steps: one to create the app and then to assign the relevant image. In this case we&#8217;ll use the <a href=\"https:\/\/azure.microsoft.com\/en-gb\/services\/container-registry\/\">Azure Container Registry<\/a>\u00a0but this approach is compatible with any Docker Hub compatible registry.<\/p>\n<p>First we&#8217;ll provision a container registry. These steps are unnecessary if you already have one:<\/p>\n<pre>az acr create --name <strong>myrepo<\/strong>\u00a0--resource-group myResourceGroup --sku Basic --admin-enabled true<\/pre>\n<pre>az acr credential show --name <strong>myrepo<\/strong><\/pre>\n<p>Then we can login to our private registry and push our appropriately tagged image:<\/p>\n<pre>docker login <strong>myrepo<\/strong>.azurecr.io --username <strong>username<\/strong>\r\n\r\ndocker push <strong>myrepo<\/strong>.azurecr.io\/uk-rse-survey:2017<\/pre>\n<p>Finally we can create our webapp and configure it to be created using the image from our private registry:<\/p>\n<pre>az webapp create --resource-group myResourceGroup --plan myAppServicePlan --name <strong>rse-survey<\/strong><\/pre>\n<pre>az webapp config container set --resource-group myResourceGroup --name <strong>rse-survey<\/strong> --docker-custom-image-name <strong>myrepo<\/strong>.azurecr.io\/rse-survey --docker-registry-server-url https:\/\/<strong>myrepo<\/strong>.azurecr.io --docker-registry-server-user <strong>username<\/strong> --docker-registry-server-password <strong>password<\/strong><\/pre>\n<p>The end result should be exactly the same as when using the same image but from the public registry.<\/p>\n<h3><strong>Tidying up<\/strong><\/h3>\n<p>As usual, you can delete your entire resource group, including your App Service plan, registry (if created) and webapps by running:<\/p>\n<pre>az group delete --name myResourceGroup<\/pre>\n<h3><strong>Summary<\/strong><\/h3>\n<p>In this post we&#8217;ve demonstrated how a Docker image can be run on Azure using one command, and how to build an deploy a simple app that presents a simple interface to explore data provided in CSV format. We&#8217;ve also shown how to use images from private registries.<\/p>\n<p>This approach is ideal for deploying self-contained apps, but doesn&#8217;t present an immediate solution for orchestrating more complex, multi-container applications. We&#8217;ll revisit this in a subsequent post.<\/p>\n<p><em>Many thanks to the <a href=\"https:\/\/www.software.ac.uk\/\">Software Sustainability Institute<\/a> for curating and sharing the the RSE survey data (reused under\u00a0<a href=\"https:\/\/creativecommons.org\/licenses\/by\/2.5\/scotland\/deed.en_GB\">CC BY 2.5 SCOTLAND<\/a>) and <a href=\"https:\/\/simonwillison.net\/\">Simon Willison<\/a> for Datasette.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is the second in a series of posts describing activities funded by our RSE Cloud Computing Award. We are exploring the use of selected Microsoft Azure services to accelerate the delivery of RSE projects via a cloud-first approach. In our previous post we described the deployment of a fairly typical web application to the [&hellip;]<\/p>\n","protected":false},"author":1133,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[390],"tags":[289397,289169],"class_list":["post-72","post","type-post","status-publish","format-standard","hentry","category-technology","tag-azure","tag-rse-cloud-computing-award"],"_links":{"self":[{"href":"https:\/\/blogs-staging.imperial.ac.uk\/research-software-engineering\/wp-json\/wp\/v2\/posts\/72","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs-staging.imperial.ac.uk\/research-software-engineering\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs-staging.imperial.ac.uk\/research-software-engineering\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs-staging.imperial.ac.uk\/research-software-engineering\/wp-json\/wp\/v2\/users\/1133"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs-staging.imperial.ac.uk\/research-software-engineering\/wp-json\/wp\/v2\/comments?post=72"}],"version-history":[{"count":25,"href":"https:\/\/blogs-staging.imperial.ac.uk\/research-software-engineering\/wp-json\/wp\/v2\/posts\/72\/revisions"}],"predecessor-version":[{"id":100,"href":"https:\/\/blogs-staging.imperial.ac.uk\/research-software-engineering\/wp-json\/wp\/v2\/posts\/72\/revisions\/100"}],"wp:attachment":[{"href":"https:\/\/blogs-staging.imperial.ac.uk\/research-software-engineering\/wp-json\/wp\/v2\/media?parent=72"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs-staging.imperial.ac.uk\/research-software-engineering\/wp-json\/wp\/v2\/categories?post=72"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs-staging.imperial.ac.uk\/research-software-engineering\/wp-json\/wp\/v2\/tags?post=72"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}