Pages

Monday, October 11, 2010

Building, Running, and Packaging Windows Azure Applications From the Command Line


Most developers who build Windows Azure applications do so using Visual StudioEclipse, or the PHP command line tools. All of these IDEs and tools are based on the same underlying Windows Azure SDK (which you usually get with the Visual Studio tools but can also get as a standalone download).
In this week’s episode of Cloud CoverRyan and I explore packaging up a Windows Azure application using only the command line tools in the SDK. In this post, I’ll share some more details by walking you through building, running, and packaging a Windows Azure application, all from the command line.

Step 1: Authoring a web site

The first thing we’ll do is create a simple web site. To go with the theme, I did that part via the command-line too. If you had, for example, an existing ASP.NET web site, you could use that instead.
c:\CmdlineWindowsAzure>md MyWebRole

c:\CmdlineWindowsAzure>copy con MyWebRole\index.html
<html><body><h1>Hello, World!</h1></body></html>^Z
        1 file(s) copied.

c:\CmdlineWindowsAzure>copy con MyWebRole\web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.webServer>
        <defaultDocument enabled="true">
            <files>
                <clear />
                <add value="index.html" />
            </files>
        </defaultDocument>
    </system.webServer>
</configuration>^Z
        1 file(s) copied.
Notice that I created a minimal web.config, just to make sure index.html is configured as a default document.

Step 2: Creating a service definition

For Windows Azure to run our application, we need to describe it in a service definition file. Here, we tell Windows Azure that we have a single role, and that it’s a web role. We also specify that we want IIS to listen for incoming HTTP requests on port 80.
c:\CmdlineWindowsAzure>copy con ServiceDefinition.csdef
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="CmdlineWindowsAzure" xmlns="http://schemas.microsoft.com/ServiceH
osting/2008/10/ServiceDefinition">
  <WebRole name="MyWebRole" enableNativeCodeExecution="true">
    <InputEndpoints>
      <InputEndpoint name="HttpIn" protocol="http" port="80" />
    </InputEndpoints>
  </WebRole>
</ServiceDefinition>^Z
        1 file(s) copied.

Step 3: Configuring the application

Now we have a Windows Azure application, but we still need to create a configuration file for it. In a more advanced Windows Azure application, we might declare some configuration settings (such as storage connection strings), but in the case of our simple web site, the only thing we need to specify in our configuration file is how many instances of our web role we want to run.
This next command line actually combines two steps. We’re packaging the application so we can run it locally, and at the same time, we’re asking cspack to generate a basic configuration file for us via thegenerateConfigurationFile parameter. Once we have the basic configuration file, we edit it in Notepad and change the instance count to two.
c:\CmdlineWindowsAzure>cspack ServiceDefinition.csdef /role:MyWebRole;MyWebRole /copyOnly
/out:CmdlineWindowsAzure.csx /generateConfigurationFile:ServiceConfiguration.cscfg
Windows(R) Azure(TM) Packaging Tool version 1.2.0.0
for Microsoft(R) .NET Framework 3.5
Copyright (c) Microsoft Corporation. All rights reserved.


c:\CmdlineWindowsAzure>type ServiceConfiguration.cscfg
<?xml version="1.0"?>
<ServiceConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="htt
p://www.w3.org/2001/XMLSchema" serviceName="CmdlineWindowsAzure" xmlns="http://schemas.mic
rosoft.com/ServiceHosting/2008/10/ServiceConfiguration">
  <Role name="MyWebRole">
    <ConfigurationSettings />
    <Instances count="1" />
  </Role>
</ServiceConfiguration>
c:\CmdlineWindowsAzure>notepad ServiceConfiguration.cscfg

c:\CmdlineWindowsAzure>type ServiceConfiguration.cscfg
<?xml version="1.0"?>
<ServiceConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="htt
p://www.w3.org/2001/XMLSchema" serviceName="CmdlineWindowsAzure" xmlns="http://schemas.mic
rosoft.com/ServiceHosting/2008/10/ServiceConfiguration">
  <Role name="MyWebRole">
    <ConfigurationSettings />
    <Instances count="2" />
  </Role>
</ServiceConfiguration>

Step 4: Running the application in the development fabric

To run a Windows Azure application in the development fabric, it needs to packaged via cspack with thecopyOnly parameter. This creates a directory with our roles in it instead of an encrypted and compressed package that we upload to the cloud. In the previous step, we actually created the local package we need already, and it’s now in CmdlineWindowsAzure.csx. (The convention is to use the .csx extension for this package/directory, but you can call it anything you want.)
To run it, we use the csrun command. It takes the local package (really a directory) and the configuration file. If you add the launchBrowser option, it will automatically open the browser to the HTTP endpoint we declared.
c:\CmdlineWindowsAzure>csrun CmdlineWindowsAzure.csx ServiceConfiguration.cscfg /launchBro
wser
Windows(R) Azure(TM) Desktop Execution Tool version 1.2.0.0
for Microsoft(R) .NET Framework 3.5
Copyright (c) Microsoft Corporation. All rights reserved.

Using session id 1
Created deployment(631)
Started deployment(631)
Deployment input endpoint HttpIn of role MyWebRole at http://127.0.0.1:82/
If you try this, you should see the browser pop up and tell you “Hello, World” at this point.
We can check what’s running in the development fabric either by opening the development fabric UI, or by using csrun. We can also use csrun to delete the local deployment when we’re finished testing.
c:\CmdlineWindowsAzure>csrun /status
Windows(R) Azure(TM) Desktop Execution Tool version 1.2.0.0
for Microsoft(R) .NET Framework 3.5
Copyright (c) Microsoft Corporation. All rights reserved.

Using session id 1
==================================================================
Deployment-Id: 631
EndPoint: http://127.0.0.1:82/
Roles:
  MyWebRole
    0 Started (ProcessId 5844)
    1 Started (ProcessId 9060)
Image-Location: c:\CmdlineWindowsAzure\CmdlineWindowsAzure.csx

c:\CmdlineWindowsAzure>csrun /remove:631
Windows(R) Azure(TM) Desktop Execution Tool version 1.2.0.0
for Microsoft(R) .NET Framework 3.5
Copyright (c) Microsoft Corporation. All rights reserved.

Using session id 1
Stopping deployment 631.
Removing deployment 631.

Step 5: Deploying to the cloud

We invoke cspack again to create a package ready for the cloud. This time, we don’t specifygenerateConfigurationFile, since we already have one, and we don’t specify copyOnly because we want a package for the cloud, not for the development fabric. The usual convention is to use the extension .cspkg for the output package file.
c:\CmdlineWindowsAzure>cspack ServiceDefinition.csdef /role:MyWebRole;MyWebRole /out:Cmdli
neWindowsAzure.cspkg
Windows(R) Azure(TM) Packaging Tool version 1.2.0.0
for Microsoft(R) .NET Framework 3.5
Copyright (c) Microsoft Corporation. All rights reserved.


c:\CmdlineWindowsAzure>
At this point, we have a .cspkg file and a .cscfg file, which are the two files we need to provide when we deploy via the Windows Azure Portal (or MMC snap-in, or PowerShell scripts, or csmanage tool, etc.).

More Information

For more information, visit the Windows Azure SDK Tools Reference topic on MSDN, and specifically the documentation for cspack and csrun.
You might also want to watch this week’s Cloud Cover episode, where we use the command line tools to deploy a more interesting application.

Web Page Image Capture in Windows Azure

46aecb90-73e5-44ae-ab47-6e50ff13f6d6[1]In this week’s upcoming episode of Cloud CoverRyan and I will showhttp://webcapture.cloudapp.net, a little app that captures images of web pages, like the capture of http://silverlight.net you see on the right.
When I’ve seen people on the forum or in email asking about how to do this, they’re usually running into trouble using IECapt or the .NET WebBrowser object. This is most likely due to the way applications are run in Windows Azure (inside a job object, where a number of UI-related things don’t work). I’ve found that CutyCapt works great, so that’s what I used.

Using Local Storage

The application uses CutyCapt, a Qt- and WebKit-based web page rendering tool. Because that tool writes its output to a file, I’m using local storage on the VM to save the image and then copying the image to its permanent home in blob storage.
This is the meat of the backend processing:
var proc = new Process()
{
    StartInfo = new ProcessStartInfo(Environment.GetEnvironmentVariable("RoleRoot")
                    + @"\\approot\CutyCapt.exe",
            string.Format(@"--url=""{0}"" --out=""{1}""",
                url,
                outputPath))
        {
            UseShellExecute = false
        }
};
proc.Start();
proc.WaitForExit();
if (File.Exists(outputPath))
{
    var blob = container.GetBlobReference(guid);
    blob.Properties.ContentType = "image/png";
    blob.UploadFile(outputPath);
    File.Delete(outputPath);
}

Combining Roles

Typically, this sort of architecture (a web UI which creates work that can be done asynchronously) is accomplished in Windows Azure with two roles. A web role will present the web UI and enqueue work on a queue, and a worker role will pick up messages from that queue and do the work.
For this application, I decided to combine those two things into a single role. It’s a web role, and the UI part of it looks like anything else (ASP.NET MVC for the UI, and a queue to track the work). The interesting part is inWebRole.cs. Most people don’t realize that the entire role instance lifecycle is available in web roles just as it is in worker roles. Even though the template you use in Visual Studio doesn’t do it, you can simply override Run()as you do in a worker role and put all your work there. The code that I pasted above is in the Run() method inWebRole.cs.
If I later want to separate the front-end from the back-end, I can just copy the code from Run() into a new worker role.

Get the Code

You can download the full source code here: http://cdn.blog.smarx.com/files/WebCapture_source.zip, but note that it’s missing CutyCapt.exe. You can download the most recent version of CutyCapt.exe here:http://cutycapt.sourceforge.net. Just drop it in the root of the web role, and everything should build and run properly.

Watch Cloud Cover!

Be sure to watch the Cloud Cover episode about http://webcapture.cloudapp.net, as well as all of our other fantastic episodes.
If you have ideas about other things you’d like to see covered on the show, be sure to ping us on Twitter (@cloudcovershow) to let us know.

No comments:

Post a Comment