0 Comments

In my Azure Functions Fundamentals Pluralsight course, I focused on deploying functions using Git. In many ways this should be thought of as the main way to deploy your Azure Functions apps because it really is so straightforward to use.

Having said that, there are sometimes reasons why you might not want to take this approach. For example, your Git repository may contain source code for several different applications, and while there are ways to help Kudu understand which folder contains your functions, it may feel like overkill to clone loads of code unrelated to the deployment.

Another reason is that you might want to have a stricter separation of pushing code to Git and deploying it. Of course you can already do this when deploying with Git – you can have a separate remote that you push to for deployment, or even configure a certain branch to be the one that is monitored. But nevertheless you might want to protect yourself from a developer issuing the wrong Git command and accidentally sending some experimental code live.

So in this post, I want to show how we can use PowerShell to call the Kudu REST API to deploy your function app on demand by pushing a zip file.

First of all, we want to create a zip file containing our function app. To help me do that, I’ve created a simple helper function that zips up the contents of our functions folder with a few exclusions specified:

Function ZipAzureFunction(
    [Parameter(Mandatory = $true)]
    [String]$functionPath,
    [Parameter(Mandatory = $true)]
    [String]$outputPath
)
{
  $excluded = @(".vscode", ".gitignore", "appsettings.json", "secrets")
  $include = Get-ChildItem $functionPath -Exclude $excluded
  Compress-Archive -Path $include -Update -DestinationPath $outputPath
}

And now we can use this to zip up our function:

$functionAppName = "MyFunction"
$outFolder = ".\deployassets"
New-Item -ItemType Directory -Path $outFolder -Force
$deployzip = "$outFolder\$functionAppName.zip"

If (Test-Path $deployzip) {
    Remove-Item $deployzip # delete if already exists
}

ZipAzureFunction "..\funcs" $deployzip

Next, we need to get hold of the credentials to deploy our app. Now you could simply download the publish profile from the Azure portal and extract the username and password from that. But you can also use Azure Resource Manager PowerShell commands to get them. In order to do this, we do need to sign into Azure, which you can do like this:

# sign in to Azure
Login-AzureRmAccount

# find out the current selected subscription
Get-AzureRmSubscription | Select SubscriptionName, SubscriptionId

# select a particular subscription
Select-AzureRmSubscription -SubscriptionName "My Subscription"

Note that this does prompt you to enter your credentials, so if you want to use this unattended, you would need to set up a service principal instead or just use the credentials from the downloaded publish profile file.

But having done this, we can now get hold of the username and password needed to call Kudu:

$resourceGroup = "MyResourceGroup"
$functionAppName = "MyFunctionApp"
$creds = Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroup -ResourceType Microsoft.Web/sites/config `
            -ResourceName $functionAppName/publishingcredentials -Action list -ApiVersion 2015-08-01 -Force

$username = $creds.Properties.PublishingUserName
$password = $creds.Properties.PublishingPassword

Now we have the deployment credentials, and the zip file to deploy. The next step is to actually call the Kudu REST API to upload our zip. We can do that using this helper function:

Function DeployAzureFunction(
    [Parameter(Mandatory = $true)]
    [String]$username,
    [Parameter(Mandatory = $true)]
    [String]$password,
    [Parameter(Mandatory = $true)]
    [String]$functionAppName,
    [Parameter(Mandatory = $true)]
    [String]$zipFilePath    
)
{
  $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))
  $apiUrl = "https://$functionAppName.scm.azurewebsites.net/api/zip/site/wwwroot"
  Invoke-RestMethod -Uri $apiUrl -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method PUT -InFile $zipFilePath -ContentType "multipart/form-data"
}

Which we can then easily call:

DeployAzureFunction $username $password $functionAppName $deployzip

This works great, but there is one caveat to bear in mind. It won’t delete any existing files in the site/wwwroot folder. It simply unzips the file and overwrites what’s already there. Normally this is fine, but if you had deleted a function so it wasn’t in your zip file, the version already uploaded would remain in place and stay active.

There are a couple of options here. One is to use the VFS part of the Kudu API to specifically delete a single function. Unfortunately, it won’t let you delete a folder with its contents, so you have to recurse through and delete each file individually before deleting the folder. Here’s a function I made to do that:

Function DeleteAzureFunction(
    [Parameter(Mandatory = $true)]
    [String]$username,
    [Parameter(Mandatory = $true)]
    [String]$password,
    [Parameter(Mandatory = $true)]
    [String]$functionAppName,
    [Parameter(Mandatory = $true)]
    [String]$functionName
)
{
  $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))
  $apiUrl = "https://$functionAppName.scm.azurewebsites.net/api/vfs/site/wwwroot/$functionName/"
  
  $files = Invoke-RestMethod -Uri $apiUrl -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method GET
  $files | foreach { 
    
    $fname = $_.name
    Write-Host "Deleting $fname"
    # don't know how to get the etag, so tell it to ignore by using If-Match header
    Invoke-RestMethod -Uri $apiUrl/$fname -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo); "If-Match"="*"} -Method DELETE
  }

  # might need a delay before here as it can think the directory still contains some data
  Invoke-RestMethod -Uri $apiUrl -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method DELETE
}

It sort of works, but is a bit painful due to the need to recurse through all the contents of the function folder.

Another approach I found here is to make use of the command Kudu API and instruct it to delete either our whole function app folder at site/wwwroot, or a specific function as I show in this example:

Function DeleteAzureFunction2(
    [Parameter(Mandatory = $true)]
    [String]$username,
    [Parameter(Mandatory = $true)]
    [String]$password,
    [Parameter(Mandatory = $true)]
    [String]$functionAppName,
    [Parameter(Mandatory = $true)]
    [String]$functionName
)
{
  $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))
  $apiUrl = "https://$functionAppName.scm.azurewebsites.net/api/command"
  
  $commandBody = @{
    command = "rm -d -r $functionName"
    dir = "site\\wwwroot"
  }

  Invoke-RestMethod -Uri $apiUrl -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method POST `
        -ContentType "application/json" -Body (ConvertTo-Json $commandBody) | Out-Null
}

This is nicer as it’s just one REST method, and you could use it to clear out the whole wwwroot folder if you wanted a completely clean start before deploying your new zip.

The bottom line is that Azure Functions gives you loads of deployment options, so there’s bound to be something that meets your requirements. Have a read of this article by Justin Yoo for a summary of the main options at your disposal.

Want to learn more about how easy it is to get up and running with Azure Functions? Be sure to check out my Pluralsight course Azure Functions Fundamentals.

0 Comments

If you’re ever working locally on a static website with a mix of HTML, CSS and JavaScript, you’ve probably run into the situation where simply testing the files in your web browser with a file:// link doesn’t work. Things like retrieving JSON or accessing the webcam require you to load the page via http://localhost instead.

So is there an easy way to start a webserver from any local folder? Well, if you have nodejs installed, then there is a super simple npm package called http-server which is ideal for this.

Just install it with npm install –g http-server, and then run it from whatever folder your website is in with http-server or even simpler hs.

Now browse to http://localhost:8080, and view your site.

Of course if you’re a seasoned web developer I’m sure you know about this already, as well as a thousand other ways to do the same thing. For a more advanced local server, there is browser-sync, which has the ability to live re-load the browser as you edit your local assets. But most of the time, http-server works just fine for me.

0 Comments

I recently blogged about how easy it is to use Docker Compose to set up an instance of WordPress. But I was just running that locally on my development box. What if I wanted to get it up and running in the cloud?

Well, one way would be to create a Linux Virtual Machine, install Docker, copy up our docker-compose.yml file, and run docker-compose up. But that sounds like quite a bit of work. Can we automate all that?

Well, if we’re using Azure we can make use of ARM templates to deploy a whole Resource Group in one go. An ARM template is a JSON description of all the resources we need including the Virtual Machine itself, the Virtual Network it is on, the Storage Account that will hold its disk images, and so on.

ARM templates make it super easy to deploy cloud infrastructure, and super easy to tear it all down again when we’re done because we can simply delete the resource group.

There is a superb library of example ARM templates in the Azure QuickStart Templates GitHub respitory. One that caught my eye was the WordPress Docker Compose template.

Not only does this template set up a Ubuntu Virtual Machine and install the Azure Docker Extension onto it, but it includes a basic WordPress Docker compose template that specifies the WordPress and MySql containers very similar to what I showed in my own demo. So this means that as part of the deployment of this template, both containers will be downloaded and started.

Trying this out couldn’t be easier if you have an Azure subscription. And, as I said earlier, it’s very safe since you can clean up after yourself very easily when your done by deleting the Resource Group.

Start off by clicking the helpful “Deploy to Azure” button on the GitHub Repo.

image

This will take you into the Azure Portal with that template ready to run. At this point you have the option to edit the template, and also to specify any parameters. We need to supply a resource group name and location, and then credentials for MySql and the Linux machine credentials.

docker-wordpress-azure

This particular script doesn’t give me a choice of what VM size I get – it will make a D1 (3.5GB, 1 Core, SSD disks), which would cost about £40 a month if I left it running.

Once we’ve kicked it off, we’ll see that our Resource Group is deploying:

docker-wordpress-deploying

This can take some time, as there is the time to create and start a new Virtual Machine as well as the time required to get the Docker container images downloaded and running. This template actually creates seven resources:

docker-wordpress-resource-group

My deployment however seemed to get stuck. All the resources were present but the site (at dockerwptest.northeurope.cloudapp.azure.com) wasn’t up.

To troubleshoot I needed to ssh into the machine. If you have Git for Windows installed, you can open up the Git Bash prompt and use ssh from there, logging in with the credentials you supplied when deploying the ARM template.

Once into the Virtual Machine a call to docker ps –a revealed that the containers were both present and the MySql one had been running for some time, but the WordPress one had stopped. I used docker logs f8f to view the logs of the WordPress container and saw it had failed because it couldn’t contact MySql. So there is a timing issue there on startup, but I could easily restart the WordPress container with a call to docker start f8f.

This time the WordPress container started, and browsing to my site’s public address showed me the WordPress installation screen:

docker-wordpress-running

So, apart from the timing issue with starting the Docker container, this was a remarkably quick and easy way to get some Docker containers deployed to the cloud. And Docker Compose does have some options to auto-restart failed containers which would have been useful in this scenario.

One thing I don’t like about this approach is that we don’t actually provide a docker-compose.yml file. Instead, the Azure Docker Extension wants the contents of the docker-compose.yml file to be turned into JSON and placed within the ARM template. And the Azure Docker Extension documentation actually makes it clear that this is not the normal intended way to manage your containers. There are better ways to get your containers running on your VM once you have deployed it.

In conclusion, ARM templates are a great way to get a Docker VM set up, and can also be used to specify an initial set of containers to compose. This is also a really great way to experiment. After getting it all working I was able to tear down the whole thing in minutes, having spent only a few pennies trying this out.

0 Comments

Almost 10 years ago, I blogged about how to use CSS to create a simple blog layout with a header, footer, main section and sidebar(s). I wrote it mainly for my own reference, because it seemed far harder to achieve than it ought to be, and the solution I came up with relied on some ugly hacks including hard-coded widths and margins, and a special “clear” div to force the footer to stay underneath both the sidebar and the main content area.

Of course these days there’s always Bootstrap to help us out, but it does feel rather heavyweight to depend on such a large framework just to achieve what ought to be a very simple layout.

But recently I’ve taken another look at Flexbox. Flexbox is extremely powerful although perhaps a little intimidating at first. And now that the majority of active browsers support it, it’s worth considering as it offers a much simpler way to get the layout we want.

At first glance, Flexbox appears to be about arranging elements in a single line, either horizontally or vertically, so it might feel like it wouldn’t be appropriate for a typical blog layout, which is more grid or table-like with its three rows and two or three columns.

But in this post I’ll show you how we can use Flexbox to create a typical blog layout with sidebar to the right of a main article area, and a header and footer to get something looking like this:

image

And our layout will have the capability to adjust its layout for smaller screens such as phones, putting the sidebar underneath the main blog area where necessary:

image

So first of all, the HTML is about as straightforward as it gets. We’ll create one div for each of the four sections (header, main area, sidebar and footer), and put them all in a container div. No need for any clearfix hacks here.

<div class="container">     <div class="header"><h1>Header</h1></div>     <div class="blog">        <h3>Blog 1</h3>       ...     </div>     <div class="sidebar">       <h3>Some things</h3>      ...     </div>     <div class="footer">Footer</div>
</div>

So how do we set up the actual Flexbox part of this? Well, the container div needs to be set up as display: flex, and the flex-flow needs to be set as row wrap. So we’re saying, lay out the header, blog, sidebar, and footer in a horizontal row, but wrap if we need to.

.container {
    display: flex;
    flex-flow: row wrap;
}

And we will need to wrap, because we’re going to say that each of the sections has a flex-grow value of 1 and a flex-basis of 100%. The 1 means all sections should have equal width (initially at least), but the flex-basis means they all want to take up 100% of available width. So what ends up happening is that each of the four sections wrap and end up sitting on top of each other vertically. This is our mobile friendly layout.

.header, .blog, .sidebar, .footer {
    flex-grow: 1;
    flex-basis: 100%;
}

Now so far we seem to have gone to an awful lot of trouble just to stack each section on top of each other, which we could have achieved without Flexbox.

image

But the power of Flexbox comes into its own when we want to adjust the layout for wider screens. If the screen is greater than 600 pixels wide, we’ll give the blog section a flex-grow of 2 and a flex-basis of 0px, and the sidebar will have a flex-grow of 1 and a flex-basis of 0px; This means these sections no longer are asking for 100% of the available width, so they will be laid out side by side, and the flex-grow values mean that the blog section will be twice as wide as the sidebar. So the sidebar gets 1/3 of the available space.

Here’s the CSS for that:

@media all and (min-width: 600px) {
  /* if screen > 600px sidebar appears alongside blog getting 1/3rd of space */
  .blog { flex: 2 0px; }
  .sidebar { flex: 1 0px; }
}

And so as we go beyond 600 pixels wide, the sidebar suddenly snaps to the right:

image

We can change things further on wider screens and give the sidebar just 1/4 of the available space if we want:

@media all and (min-width: 800px) {
  /* On bigger screens, sidebar now only gets 1/4 of space */
  .blog { flex: 3 0px; }
  .sidebar { flex: 1 0px; }
}

In summary, you can see that the CSS required for this layout is much simpler with Flexbox than the previous floats, margins and clears technique I discussed. It also lends itself much better to being responsive to screen size. For the first time in a long time I feel like I can easily layout a webpage how I want it, without having to use Bootstrap or read complicated explanations of floats and clearfixes.

I’ve put the full example HTML and CSS for this example in a GitHub Gist. Hope this proves useful to someone, and do let me know in the comments if there’s an even easier way to achieve this layout.

0 Comments

I recently needed to quickly set up a static website, and so the obvious thing to do was to add a new site to a hosting plan I’ve already got in Azure. But how to deploy my HTML and CSS?

Azure App Service offers a wide variety of deployment techniques including FTPing your code directly on, or using a Git repository, or using the Web Deploy tool. But for this site, I quite liked the idea of having the source just sat in a OneDrive folder, allowing me a very easy way to tweak the site live if I needed to.

The steps are quite simple. In our the Azure Portal, we need to navigate to the App Service and select “Deployment Options”:

image

Then we need to choose a deployment source

image

From here we can select from a wide variety of options, including OneDrive;

image

Having selected OneDrive, we’ll first of all be prompted to grant Azure App Service permission to read our OneDrive folder. This sounds scary, but fortunately you’re only allowing it access to a specific sub-folder – in my case “C:\Users\markh\OneDrive\Apps\Azure Web Apps”.

Inside that folder, there will be one folder for each web app you deploy using this technique, and by default it will be named after the site you are deploying. So for example “Apps\Azure Web Apps\my-demo-site

With this in place, we can simply copy our static HTML and CSS into that folder in our OneDrive. As we edit them, the changes will be automatically picked up and deployed:

image

However, I found that despite putting an index.html file into this folder on OneDrive, my homepage wasn’t available. After a bit of digging I found that this deployment technique uses the Kudu deployment engine and we need to give it a hint about how to build and where to find the files by creating a .deployment file.

In our case, this is a static HTML site, so our .deployment file is very simple and just tells Kudu that the root folder contains the contents of the site:

[config]
project = .

And so with this .deployment file sitting alongside the index.html file, I can now very quickly and easily update the contents of the site from anywhere I can access my OneDrive.

Obviously this technique isn’t appropriate for larger sites, but for quick experiments, its a great option to have available.