Ship Your Apps to Azure RemoteApp with Containers

Azure RemoteApp is a new cloud service from Microsoft that allows RDP-based access to individual Windows desktop applications running in the Azure cloud. In this walkthrough, we’ll explain how to use Spoon containers with RemoteApp to allow individual desktop applications to be deployed and managed on Azure.

image005

Why containers?

Azure RemoteApp supports deployment of custom applications and environments via uploading of VHD (virtual hard drive) images. These images contain both the base operating system and all installed user applications. While this allows complete customization of the OS environment, it requires creation and management of a complete server OS image (called a “RemoteApp Template Image”) for each set of applications, application versions, and configuration variants. When an individual application is updated, the entire OS image must be updated.

With containers, individual applications can be deployed to a single base Azure image. New applications can be deployed to the Azure cloud instantly without changing the base Azure image. When an application is updated, only the container for that specific application needs to be updated. And a single base Azure image can support many different sets of applications, user entitlements, and even multiple configurations of the same application.

Combining Spoon containerization with Azure RemoteApp dramatically increases the power and flexibility of RemoteApp for end users by allowing instant access to applications. Spoon containers also simplify administration by requiring management of just a single RemoteApp Template that can then host any set of individual application containers.

Here is how to set it up!

What you’ll need

Azure Settings
  • If you are new to Azure and you do not have a thumbprint, follow these instructions under the “Use Certificate Method” to generate your Thumbprint.
  • Create or identify the Azure Storage account that you will be using to store your VM templates. When creating a Storage account be sure to select the right location so that it will match your RemoteApp deployment.
Azure Storage

Getting Started

Add the Azure RemoteApp Services module

First you need to add the RemoteApp PowerShell modules to your environment. Download the Azure RemoteApp Services zip. Next go to the properties of the file and select Unblock. This is important otherwise when you extract the DLLs, they will be blocked and any scripts that attempt to load the DLLs will fail.

Unblock Files

Unzip the files into a local directory like C:\RemoteApp. Close any PowerShell windows that are open. Run Azure PowerShell as Administrator, go to the directory where the files were unzipped and install the new module.

Set-ExecutionPolicy Unrestricted
cd C:\RemoteApp\AzureRemoteAppServices
.\install_azureremoteappservices.cmd

Keep PowerShell open and move on to the next step.

Connect to your Azure RemoteApp account

There is a Publisher Settings file that you need to import in order for the PowerShell environment to be connected to your Azure account.  Use the Get-AzurePublishSettingsFile to download the file and the Import-AzurePublishSettingsFile to import it into your environment.

Import Publisher Settings

Create a PowerShell script file, C:\RemoteApp\RemoteAppSetup.ps1, with the following content.

Import-module AzureRemoteAppServices
Set-AzureRemoteAppSubscriptionId <Azure Subscription ID>
Set-AzureRemoteAppCertificateThumbprint <Thumbprint of the Management Certificate>
Set-AzureRemoteAppServiceUrl -Url https://management.core.windows.net
Set-AzureRemoteAppRdfeNamespace RemoteApp
Set-AzureRemoteAppRdfeMode $true

Run the following command in PowerShell:

C:\RemoteApp\RemoteAppSetup.ps1
Load RemoteApp Modules

Keep PowerShell open and move on to the next step.

Setting up the RemoteApp Template

The RemoteApp template that will be used for the RemoteApp service is based on a virtual machine image. To create the virtual machine image, we will first instantiate a new virtual machine instance.

Create the Virtual Machine Image

The RemoteApp team has provided a starting point for this VM instance that has the RDSH role and other Azure RemoteApp services already configured.  Here is the command to use to create this VM.

New-AzureQuickVM -Windows -ImageName "ad072bd3082149369c449ba5832401ae__Windows-Server-Remote-Desktop-Session-Host-on-Windows-Server-2012-R2-20140920-1926" -ServiceName <NewServiceName> -Name <NewVmName>  -AdminUsername <adminusername> -Password <pswd> -Location <location of the Service> -MediaLocation <URL of the OS VHD Blob which will be created in your storage account>

A more concrete example with actual values:

New-AzureQuickVM -Windows -ImageName "ad072bd3082149369c449ba5832401ae__Windows-Server-Remote-Desktop-Session-Host-on-Windows-Server-2012-R2-20140920-1926" -ServiceName spoondemo-ara-vm -Name spoondemo  -AdminUsername spoondemo -Password password -Location "West US" -MediaLocation https://spoondemo.blob.core.windows.net/vhds/spoondemo-ara-vm.vhd

When the command finishes, a virtual machine instance will appear in the Azure Management Portal.

New Virtual Machine

Configure the Virtual Machine

Now that we have the VM created, we just need to configure it and convert it into a static VM image.

  • Connect to the VM
  • Open Internet Explorer and go to http://spoon.net
  • Login to your account and click the Download link on the home page
  • Download and install the spoon-plugin.exe
  • Open a command window and verify that everything is working as expected by running Sublime Text from the Spoon.net Hub
> spoon login <username>
> spoon run sublime-text

 Run Sysprep

Now that the VM is configured, there it needs to be prepped before converting it to an image.

  • Run and elevated command prompt (Run as Administrator)
  • Run the following sysprep command
%windir%\system32\sysprep\sysprep.exe /generalize /oobe /shutdown

Once the sysprep command completes, the VM will shutdown.

Create the Virtual Machine Image

Back in the Azure Management Portal, select the virtual machine instance and click on the Capture link at the bottom of the page.

This will create a new virtual machine Image. Be sure to note down the name of the new image that you created.

Virtual Machine Image

Create a default RemoteApp Service

Before converting the VM image into a RemoteApp template, I had to create a RemoteApp service using an available Microsoft Template. I’m not sure if this is a bug, but the following step would not succeed until I created a RemoteApp service. Again, be sure to select the right Region. In this example, I chose the Basic plan with just Windows Server 2012 R2 as the template image. Provisioning may take up to 30 minutes, but you do not have to wait for it to complete before moving on to the next step.

 Default RemoteApp Service

Convert the Virtual Machine Image into a new RemoteApp Template Image

The Azure RemoteApp team has provided a PowerShell script, Import-AzureRemoteAppTemplateImage, that will import the VM image we create earlier into our RemoteApp template images. Download that text file and save it to C:\RemoteApp\Import-AzureRemoteTemplateImage.ps1. Note the file extension.

Run the following command in PowerShell

C:\RemoteApp>.\Import-AzureRemoteAppTemplateImage.ps1 -AzureVMImageName <your VM image name> -RemoteAppTemplateImageName <new RemoteApp template name>

Here is a concrete example:

C:\RemoteApp>.\Import-AzureRemoteAppTemplateImage.ps1 -AzureVMImageName spoondemo-image -RemoteAppTemplateImageName spoondemo-remoteapp-template

When this process completes, the template image will be available in the list of RemoteApp templates in the Azure Management Portal.

RemoteApp Template Image

Configure the RemoteApp Service

Create a new RemoteApp Service

Now that the customer RemoteApp template is complete, it is listed in the available templates when creating a new RemoteApp service. Use that template to create a new service.

List of Templates

Publish the Spoon Console Application to the RemoteApp Collection

Once the service is created, it’s time to publish the applications for the user.  In this case, we will use the Publish programs using path option.

Publish using path

Enter the name, Spoon Console, and the path to the command prompt. The Spoon Console is available on the system path.

Add Spoon Console

 

After the process completes, you will see the console as a published app.

Spoon Console Published

Test the Spoon Console using the RemoteApp client

Provide users access to the RemoteApp Collection

Under the User Access section you can add users that can access the applications.

User Access

Testing the RemoteApps

If you don’t have the RemoteApp client, download the appropriate client for your device and install it. When you run the RemoteApp client and login, you should see the application that are available to you. In the Windows client you should see something like this.

RemoteApps

Double click on the Spoon Console icon to run the application. This will launch a command window that is running on the Azure Cloud environment.

Run applications from the Spoon Console

Normally the applications that the user can run is limited what was originally installed on the virtual machine we configured earlier, but with the Spoon Console, we can run any application that is available on the Spoon.net Hub.

> spoon login <username>
> spoon run sublime-text
Run Sublime Text

Some other applications you might want to try:

> # Surf the web with Opera
> spoon run opera

> # Do some coding in Python
> spoon run python

> # Edit some text files with Atom
> spoon run atom

Thanks for reading, and I hope this makes helps your Azure RemoteApps deployment!

Trying out Go 1.4 with `spoon try`

The Go team just released version 1.4, the fifth major release of Google’s open source programming language. Spoon has updated the official hub image with version 1.4 and I decided to give it a test drive. (Click here for more details about golang 1.4.)

Since I just wanted to test out the new Go and wasn’t intending to work on a real project, this was a great opportunity to use the spoon try command. try behaves exactly like run except a temporary container is created. The container is destroyed as soon as the last process exits.

To create a temporary container and launch Go, type spoon try go in the command prompt:

go1

This command will start a new command prompt running in the container with the latest go and clean image available. The clean root image has Go run in a virtual clean operating system. Just like the installed version of Go, the Spoon image adds the Go install directory to the PATH environment variable in the container, so you can run the go command from any directory.

Below you can see we included an ultra-simple ‘Hello, World’ application written in Go in the image, and that the complete arsenal of Go commands is available:

go3

We can exit the container at any time by typing exit. Doing so will automatically remove the temporary container and all content from our test drive will go away, which is very convenient if you’re just experimenting with new languages or environments.

If you’re new to Go (or Go on Spoon) and looking to get started developing in Go, you might want to include a text editor image in your container. We’ll use one of my favorite editors, Sublime Text:

go4

Once you’re in the container, launch Sublime:

go5

Sublime Text will launch. I’ve copied in an interesting example from the Go homepage that does arithmetic via Peano’s axioms (“Peano Playing”!). There are many other cool examples available on the Go homepage and the Go Tour.

go9

Save the file as C:\peano.go. Then exit Sublime and run your program from the command prompt (which is still running in the container):

go10

For more information on Spoon’s support for Go, different versions of the Go image, and some more examples, visit the Go repository on the Spoon Hub. If you’re not a Gopher, we also have many of other programming language images on the Hub that you should love.

Side-by-side testing of Windows web applications made easy

In this post, I will present a walkthrough explaining how to test multiple versions of Windows web server applications side-by-side using Spoon containers. This example will use WordPress, but the approach can be generalized to any web application.

First, I will show how to prepare an image with all dependencies (PHP, Apache, and MySQL in this case) configured and that performs an SVN checkout of the current stable WordPress version (4.0.1 at the time of writing). Then I will show how to configure network virtualization, install WordPress in the container, clone the container, and checkout the development version of WordPress in the cloned container for side-by-side testing.

The end result will look like this:
Testing WordPress Side-by-Side
Note that the WordPress versions indicated in each browser window are different! The blue border window is running 4.1 beta 2 while the green window is running 4.0.1. Traditionally, this would require the use of separate physical machines or heavyweight virtual machines. With Spoon, we can achieve this on a single Windows box without the need for full virtual machines.

Building the Base Image

The first thing we need is a ready-to-use WordPress image with all dependencies packaged. We can use the spoon search command or use the Hub web interface and find the official wordpress/wordpress image. This is almost what we want, as it includes preconfigured PHP, Apache, and MySQL. Unfortunately the WordPress files in this image were installed by unpacking a zip archive and, so that we can easily switch between WordPress versions, we would ideally like to have the sources checked out from the source SVN repository. We could download the wordpress/wordpress image and modify it, but the best approach in these situations is to roll your own image.

The SpoonScript file used to build the wordpress/wordpress image is public and available on GitHub. The PHP, Apache, and MySQL setup has already been done for us. The only change we want is to checkout the WordPress sources through SVN instead of downloading and unpacking a zip archive.

I made this change and published it in a branch of my personal fork of the spoonapps/spoonme GitHub repository, available here. Since I was already modifying the build script, I took the chance to change the default Apache port from 8080 to 80. You can download the updated spoon.me file with your browser, with a PowerShell one-liner, or using the below Spoon wget one-line command. The --mount option allows us to download to the host OS, not the container file system. (As a side note, PowerShell is also available as a Spoon image if you need it.)

md tmp && spoon try --mount %CD%\tmp=%CD%\tmp wget wget https://raw.githubusercontent.com/beevvy/spoonme/wordpress-svn/wordpress-svn/spoon.me --no-check-certificate -O tmp\spoon.me

Now we just need to run the image build using the spoon build command using our SpoonScript:

spoon build --name=wp-svn tmp\spoon.me

…and wait. After a minute, our brand new wp-svn image is ready. Once it has been built, we do not need to repeat this step for any future testing unless we want to change the image setup.

WordPress Installation and Network Virtualization

Now that our image is ready, we can run it to setup the WordPress installation. By specifying the --route-block=tcp,udp option, we instruct Spoon’s network virtualization system to isolate the container so that it doesn’t expose any web services to the outside world and doesn’t bind to the real port 80 of the host OS. We will name the container wp-401 and run it detached to leave our main command prompt available to use. We will also include the official svn image in the run command since we will need it later to switch between WordPress versions.

spoon run --route-block=tcp,udp --name=wp-401 --detach svn,wp-svn

Next we start a Firefox container and link it to the wp-401 container so that the browser can access services exposed by the server. We will name the link wp:

spoon run --link=wp-401:wp --detach firefox+skin(green) http://wp

Voila! Our first WordPress container is ready to use!

Note that in fact we are using two containers — a containerized WordPress server (including its dependencies) and a containerized browser — which have been linked together on an internal virtual network.

Also notice the green box around Firefox window. As you will see, we will have another instance of Firefox running soon and in these situations I like to have a visual hint to help distinguish between containers.

Using Firefox, let’s complete the WordPress installation in our container and maybe add some content.

Cloning the Container and Testing Side-by-Side

Once done with installing WordPress using Firefox, let’s use our container as a base and clone it into a new container wp-trunk. Before cloning, we will stop the container and wait until it shuts down to make sure MySQL terminates gracefully. (An alternative approach would be to commit the container state to a new image.)

spoon stop wp-401
spoon clone wp-401 wp-trunk

Now we can start both containers and switch WordPress versions in the console window of the wp-trunk container:

spoon start --detach wp-401
spoon start --detach wp-trunk

(wp-trunk) C:\Users\Bartek>cd \apache2\htdocs
(wp-trunk) C:\apache2\htdocs>svn sw http://core.svn.wordpress.org/trunk/ .

Notice that we were able to start both containers side-by-side even though Apache and MySQL are configured to bind on the same ports! This is possible thanks to Spoon’s network virtualization.

Finally, we start a second Firefox instance to upgrade and test the second server container side-by-side. WordPress remembers the wp domain name during installation, so in order to avoid reconfiguration, we will use the same container link name here.

spoon run --link=wp-trunk:wp --detach firefox+skin(blue) http://wp/wp-admin/upgrade.php

All done! We are now set with two independent WordPress installations (both client and server) on isolated networks on a single Windows box.

Tag, You’re It! Improvements to hub version resolution

tags

Tags allow easy identification of different versions of Spoon images. Tags can be alphanumeric identifiers such as releasealpha, beta, etc or version identifiers, such as 33.5, 4.0.1, and so forth. (Version numbers expressed in this way are said to be in dotted decimal form.) The special head tag always indicates the latest version of an image.

Specific tagged versions of an image can be referenced using the : (colon) operator. For example, the Java Development Kit image jdk has three tagged versions: 8.0 (which is also the head version), 7.65, and 6.45. If the image identifier jdk is specified, by default the head version is used. To reference  other releases, one would use the identifiers jdk:7.65 or jdk:6.45.

Previously the entire tag name was required. This was troublesome in the jdk example because only specific — and difficult to remember — subversions were available in the hub.

Spoon.net will now automatically match the latest version consistent with a given tag whenever a numerical (dotted decimal) tag is used. For example, the expression jdk:7 will now match the tag 7.65. If two tags 7.65 and 7.64 were available, jdk:7 would still match 7.65 since 7.65 is greater than 7.64 when interpreted as a decimal version. This behavior change does not impact tags not in dotted decimal form.

This change makes it much easier to reference major image versions in cases where the minor or revision numbers are not relevant.

As a reminder, you can view all of the tags associated with an image with the command spoon tags <imageName>.

New in Spoon Containers 3.33.8.485

This update includes the following new features, improvements, and patches:

New:

  • Numerical version tags are now resolved by decimal prefix to latest matching version (e.g. jre:7 will resolve to jre:7.51)
  • spoon clone command creates a copy of a container
  • spoon tags command shows all tags associated with an image
  • spoon states command shows states associated with a container
  • Progress shown during spoon continuespoon commit, and synchronization scan operations

Improved:

  • Improved progress reporting during spoon pull operations
  • Do not show version for the clean image if it is the latest version
  • spoon run clean –disable-sync persists setting on container restart
  • spoon diff pulls an image from the hub when not present in the local cache
  • spoon push now accepts an optional destination parameter

Fixed:

  • spoon run can no longer be executed with an expired login ticket
  • Environment variables not remapped correctly in some cross-device scenarios
  • Quotes around path variables now supported in images
  • Continuation will not occur if an error occurred during synchronization
  • Continuation could overwrite data in executing container
  • Skin driver causing crash with Chrome

Containerized Scala builds with SBT

Tired of checking out a Scala project, downloading the right JDK, finding out the right SBT version needed to build a project? And then do it all over again on your build server of choice? Containers allow you to create a Scala build environment in minutes and use it on all your machines. You can even share your build environment with others, making it incredibly easy to get going on a project.

same-script-on-server-and-local

Picking your JDK and SBT versions

With Spoon containers you can combine different JDK and SBT versions easily. Need Java 8 with SBT 0.13? Or Java 6 with SBT 0.12 for a other project? Simply list the images you need. Here are some examples:

# JDK 8 with the latest SBT
spoon jdk:8.20,sbt
 
# JDK 7 with SBT 0.13.5
spoon run jdk:8.20,sbt:0.13.5
 
# JDK 6 with SBT 0.12.4
spoon run jdk:8.20,sbt:0.12.4
 
# Need more memory? Use the 64-bit version of the JDK
spoon run jdk64:8.20,sbt

This will open a new console prompt with the specified JDK and SBT combination. From there you can build the project with the usual SBT commands.

Avoid redownloading dependencies

On a fresh machine, SBT downloads many dependencies to compile a project. When you run your build in a fresh container, you may notice that it will download the depedencies over and over. A simple solution to this is to map SBT’s dependencies folder to a folder on your host system. This way the files are shared between containers and your host.

You can do this with the  –mount option. The basic format is:

# Basic mount command
spoon --mount C:\FolderOnHost=C:\FolderInContainer
# Mount multiple locations
spoon --mount C:\Location1=C:\Location1 --mount C:\Location1=C:\Location1

Now let’s apply this to the SBT example. We mount our SBT cache of the host system into the container:

spoon --mount %USERPROFILE%\.ivy2=%USERPROFILE%\.ivy2 jdk:8.20,sbt

You can also mount dependencies into a dedicated container rather than the host device.

Getting your build artifacts out of the container

Now we want to get our shiny new build outputs out of the container. To accomplish this, use the –mount option as before to share the build target output folder. For example:

spoon --mount %USERPROFILE%\.ivy2=%USERPROFILE%\.ivy2 --mount %CD%/target=%CD%/target jdk:8.20,sbt

Explicit build container

What if just running SBT is not enough? Perhaps we need to setup some environment variables, use more memory with SBT, or do some more steps after the SBT build. For that, we simply write a small batch script which we call from within the container. In our example, we call this test-and-publish.bat:

set JAVA_OPTS=-Xmx4g -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true -Dorg.slf4j.simpleLogger.defaultLogLevel=warn 
rem If we run on the build server, we give publish, otherwise we publish just locally
if DEFINED bamboo_buildNumber (
    echo "Will publish the artifacts to the shared repository"
	set BUILD_ARG=clean test publish
) ELSE (
    echo "Will publish the artifacts to the local repository"
	set BUILD_ARG=clean test publish-local
)
sbt %BUILD_ARG%

If you have a default setup for your SBT, you might consider creating a new container built with a SpoonScript script. Similar to our command-line example above, we pick a set of base images. We then set our test-and-publish.bat script to execute on container startup:

# use the build enviroment and tools
from oracle/jdk64:7.67,sbt:0.13.5

cmd mkdir C:\BuildEnviroment
cmd copy test-and-publish.bat C:\BuildEnviroment\test-and-publish.bat

startup file ("C:\BuildEnviroment\test-and-publish.bat")

After that, you can build this container and use it on different projects:

spoon build --name test-and-build spoon.me
spoon run test-and-build

Surrounding script

To wrap it all up, let’s create a script which uses the building blocks created before. We select an image, mount the SBT dependency cache and target folder, and run the build. Finally, we give the container a name so we can easily find it later on:

spoon rm sbt-build
spoon run --attach --name=sbt-build --mount %USERPROFILE%\.ivy2=%USERPROFILE%\.ivy2 --mount %CD%/target=%CD%/target oracle/jdk64:6.45,sbt:0.13.5 test-and-publish.bat

#Or if you created your own container, run
spoon run --attach --name=sbt-build --mount %USERPROFILE%\.ivy2=%USERPROFILE%\.ivy2 --mount %CD%/target=%CD%/target test-and-build

Spoon containers make it much easier to build and share your favorite SBT-based Scala projects!

Walkthrough: Containerizing Python and Pip in automated build processes

 

In this walkthrough, I’ll explain how we use Spoon containers internally to run Python scripts without having to install Python and its dependencies.

Why containerize build processes? Once containerized, build processes can be executed immediately on any device, including those that may not have Python and Pip installed. And containerizing avoids “polluting” the build machine. Containerized build processes also make it very easy for developers and testers to execute build tasks on their local desktops.

This example is taken from our document build system, which uses Python to transform Markdown files into HTML.

success

First, here is the batch file that runs the document build on a system with Python installed which I named build-docs-python.bat. The script uses pip to install some dependencies and then runs the python command to create the documentation:

pip install -r py-reqs.txt
python build.py

The script is run inside of a Spoon container using pip and python:2.7.8 layered together as the base image. We’re going to need the container ID later so we save it into the file build-container-id.txt to remember it as a variable for the next command:

spoon run pip,python:2.7.8 /c .\build-docs-python.bat > build-container-id.txt
set /p CONTAINER_ID=<build-container-id.txt

Finally, we use the cp command to copy the files from the build container into the ultimate output folder:

spoon cp %CONTAINER_ID%:c:\build_output c:\web_root\docs

This solution works, but let’s improve it some more. The Python script requires external packages, so each new build requires downloading and installing the packages inside of the container. Repeating the download really slows down the build process and wastes network bandwidth, so we’d like to store the cached package manager contents between runs.

Also, the extra cp command could also be avoided if we could specify a path external to the container that files would be written to. The mount flag does exactly this.

First, remove the cp command by using the –mount flag to mount the (containerized) output folder c:\build_output to the desired external destination folder c:\web_root\docs:

--mount c:\web_root\docs=c:\build_output

Next the redundant Python dependency downloads are eliminated by mapping the cache into the local filesystem:

--mount c:\temp\python27=c:\python27

The build now works as a single Spoon command:

spoon run --mount c:\web_root\docs=c:\build_output --mount c:\temp\python27=c:\python27 pip,python:2.7.8 /c .\build-docs-python.bat

In this sample, we used Spoon to automate our document builds. But the same steps can be used to efficiently automate virtually any process scripted with Python!

Minecraft Servers + Chef containerized with Spoon

Giving Thanks

Thankful today for our amazing team, partners, and customers, and 8 years building a different type of tech company. Thanks!

- Kenji and the Spoon Team

Thanksgiving Collage