Friday 23 September 2016

Tutorial: Building an Azure Template


An Azure Template is a JSON file that captures the infrastructure requirements of your application. An Azure Template defines a number of related resources that are required by your application. Each resource represents a manageable entity, such as an Azure Website, a virtual machine, a SQL database, an identity, a load balancer, or an autos-scaling rule, etc. When an Azure Template is deployed on Azure, Azure Resource Manager ensures that all resources are brought to the specified states so that your application runs under the exact desired environments.
In this tutorial, we’ll walk you through of steps of authoring and deploying a simple Azure Template. The template defines a web application with a frontend running on Azure Websites and a database running on Azure SQL Database. The goal of this tutorial is to walk you through the structure of an Azure Template. In your actual projects, you should use graphical UIs to edit your templates to avoid manual editing errors.

Preparing the environment

At the time when this blog is written, the easiest way to get started with Azure Template editing is to use Visual Studio with Azure Resource Manager Tools (Preview) for Visual Studio. In addition, you’ll also need an active Azure subscription. You can get a free trial subscription at www.azure.com.

Getting started

Azure provides a rich set of Azure Templates in its Azure Gallery. In this tutorial we’ll use an existing template from the gallery to get the editing experience started. But we’ll clear the template so that we can start from scratch.
  1. In Visual Studio, select the FILE –> New –> Project… menu.
  2. On the New Project dialog, select the Cloud –> Cloud App from the Azure Gallery template, enter a Name for your project, and then click the OK button.
  3. On the Select Azure Template dialog, select the Website + SQL template, and click the OK button.
  4. On the New ASP.NET Project dialog, select MVC template, and click the OK button.
    Once the wizard completes, you’ll have an ASP.NET website and an Azure Template that is ready to be deployed to Azure. Under the solution’s DeploymentItems\Templates folder, you’ll find an Azure Template namedWebSiteSQLDatabase1.json. This template already contains all necessary resources for you to deploy your website to Azure. However, for the sake of learning, we’ll clear the template to a bare minimum.
  5. Modify the template so the code looks like the following code list:
    {
        "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
        "contentVersion": "1.0.0.0",
        "location": "West US",
        "resources": [
        ]
    }
    In this minimum template file, the $schema property indicates the schema version of the template file. ThecontentVersion property indicates the version of the template file itself. The main element of the file is theresources array, which contains all the resources to be defined in the group. 

    NOTE: There are several other top-level properties such as parametersvariablestags and outputs. We’ll cover some of these properties later in this tutorial.
  6. Save the template. And then, in Solution Explorer, right-click on the template and select the Deploy Template…menu. On the Deploy Template dialog, select the Azure subscription, storage account, and deployment location you want to use, then click the Deploy button to deploy the template to Azure.

    NOTE: Leave the Template parameters file field at its default value. We’ll come back to this later. 

    The deployment should succeed after a short delay. You can observe the deployment traces in the Outputwindow. Deployment of an Azure Template is an idempotent operation so that you can deploy the same template as many times as you like. You can think an Azure Template as a definition of the desired states of your application resources. And Azure will make sure the resources are brought to specified states when you deploy the template.

Defining a Resource

In previous section you’ve deployed an empty Azure Template to Azure. In this part you’ll add a SQL Database resource to the template. You define a new resource by adding a new child element to the resources array.
A resource definition is a JSON object with three mandatory properties: nametype and apiVersion. The nameproperty identifies the resource. And the type property and the apiVersion property combined specifies which version of what Resource Provider to use. Azure Resource Manager has an extensible architecture, in which different Resource Providers can be plugged into the system to provide capabilities of managing a variety type of resources. For example, for SQL Database servers, the corresponding Resource Provider type is Microsoft.Sql/servers, and the current apiVersion is “2.0”.
  1. Modify your Azure Template to include the definition of a SQL Database server resource. In the following code list, a new SQL Database server named mysqlserver has been added to the resources array.
     1:{
     2:     "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
     3:     "contentVersion": "1.0.0.0",
     4:     "resources": [
     5:         {
     6:             "apiVersion": "2.0",
     7:             "name": "mysqlserver",
     8:             "type": "Microsoft.Sql/servers",
     9:             "location": "West US",
    10:             "properties": {
    11:                 "administratorLogin": "admin",
    12:                 "administratorLoginPassword": "password$123"
    13:             }
    14:         }
    15:     ]
    16:}
    
    In above template, line 5 to line 14 defines a SQL Database server resource. In addition to the apiVersionname, and type properties, you also see a location property and a properties property. These two properties, along with a tags property, are defined by a Resource Provider Contract, which defines the communication protocol between Azure Resource Manager and Resource Providers. The properties list is defined and consumed by the specific Resource Provider. In this case, SQL Server Resource Provider has defined two properties (among others) that represent administrator login (administratorLogin) and administrator password (administratorPassword).
  2. Deploy the modified template. Once the template has been successfully deployed, you should be able to observe on Azure Management Portal that the new SQL Database server has been provisioned.
In above template we put password as plain text, which is not a recommended practice. We’ll fix this when we discussparameters.

Defining a Child Resource

Next we’ll define a SQL Database on the newly defined SQL Database server. Naturally, a SQL Database belongs to a SQL Database server. In other words, a SQL Database is a child resource of a SQL Database server resource. And this is exactly how you would define it – to add a child element to the server JSON object we just defined.
  1. Modify the template as shown in the following code list (line 14 – 28):
     1:{
     2:     "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
     3:     "contentVersion": "1.0.0.0",
     4:     "resources": [
     5:         {
     6:             "apiVersion": "2.0",
     7:             "name": "mysqlserver",
     8:             "type": "Microsoft.Sql/servers",
     9:             "location": "West US",
    10:             "properties": {
    11:                 "administratorLogin": "admin",
    12:                 "administratorLoginPassword": "password$123"
    13:             },
    14:             "resources": [
    15:                 {
    16:                      "apiVersion": "2.0",
    17:                      "name": "mysqldatabase",
    18:                      "type": "databases",
    19:                       "location": "West US",
    20:                      "dependsOn": [
    21:                           "[concat('Microsoft.Sql/servers/', 'mysqlserver')]"
    22:                      ],
    23:                      "properties": {
    24:                          "edition": "Web",
    25:                          "maxSizeBytes": "1073741824"
    26:                      }
    27:                 }
    28:             ]
    29:         }
    30:     ]
    31:}
    In above template, line 15 to line 27 defines the SQL Database resource to be added to the SQL Database server resource. You can see all resource definitions in Azure Templates follow a consistent format. In this new resource definition, we define a SQL Database named “mysqldatabase”, and specify it should be a Web edition with maximum size of 1G. 

    NOTE: You’ll need to pick a different name other than mysqldatabase as the name is already taken.

    Please note the dependsOn property in line 20. The dependsOn property is used to define dependencies among resources. In this particular case, the property specifies that the SQL Database resource depends on the SQL Database server resource – this makes sense because a SQL Database server has to be provisioned first before a SQL Database can be added to it. When an Azure Template is deployed, Azure Resource Manger builds up a dependency graph based on these dependencies and ensures the resources are configured in the correct order. 

    NOTE: We’ll see another type of dependency by references later in this tutorial.
  2. As an added exercise, define another child resource under the SQL Database Server resource to enable accesses to the sever from all IP addresses:
    {
        "apiVersion": "2.0",
        "type": "firewallrules",
        "name": "AllowAllWindowsAzureIps",
        "location": "West US",
        "dependsOn": [
            "[concat('Microsoft.Sql/servers/', 'mysqlserver')]"
        ],
        "properties": {
            "endIpAddress": "255.255.255.255",
            "startIpAddress": "0.0.0.0"
        }
    }
    

Using Variables

In our current version of template, the SQL Database Server name “mysqlserver” has appeared in several different places. Since it’s not a good practice to repeat string literals in your template, you can use variables to correct this.
In an Azure Template, you can define an arbitrary JSON key/value dictionary named variables. And then, you can refer to any defined values in your template by the syntax [variables(‘[key]’)]. A property value can be a simple type or a complex type. As long as you follow standard JSON syntax, you can define very complex properties if you’d like. However in this tutorial we’ll use only string properties.
  1. Add a variables element to the template root:
    "variables": {
        "serverName":"mysqlserver"
    },
    …
    
  2. Once a variable is defined, you can refer it in your template code. For instance, instead
    "name": "mysqlserver"
    use:
    "name": "[variables('serverName')]"
    And instead of
    "[concat('Microsoft.Sql/servers/', 'mysqlserver')]"
    use:
    "[concat('Microsoft.Sql/servers/', variables('serverName'))]

Using Parameters

It’s often useful to get an Azure Template parameterized. For instance, instead of fixing the SQL Database server name in the script, you can define the server name as a parameter so that the template can be used to deploy multiple instances of identically configured servers. Another use case of parameters is to separate secure information such as passwords from the template. In the following steps, we’ll define both a serverLocation parameter and anadminPassword parameter.
  1. To define parameters, add a new parameters element to the template root. Each parameter is defined as a complex type with a type property and optional allowedValues and defaultValue properties. In current schema the supported types are: intstringsecurestring and bool. The following code segment defines a string-typedserverLocation parameter and an adminPasswword parameter as a secure string.
    "parameters": {
        "serverLocation": {
            "type": "string"
        } ,
        "adminPassword": {
            "type": "securestring"
        }
    },
    …
    
    When a parameterized template is deployed, Azure reads parameter values from a separate parameter file, which is another JSON file with a list of parameter values. You can create multiple parameter files for different environments. This helps you to make sure all your environments are configured in a consistent manor.
  2. In Visual Studio, replace the content of WebSiteSQLDatabase1.dev.json with the following code list:
    {
        "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentParameters.json#",
        "contentVersion": "1.0.0.0",
        "parameters": {
            "serverLocation": {
                "value": "West Us"
            }
        }
    }
    Note we are not hard-coding the adminPassword value in this file. We’ll manually enter the value during deployment.
  3. Then, replaces all “West US” constants in your template to parameter references:
    [parameters('serverLocation')]
    And replace all "password$123" with
    [parameters('adminPassword')]
  4. In Solution Explorer, right-click the template and select the Deploy Template menu. On the Deploy Template dialog, you can choose which template parameter file to use. Click the Edit Parameters button and enter a value for the adminPassword parameter.
  5. Click the Deploy button to deploy the template again. The template should be deployed correctly.

Resource Dependencies

In the “Defining a Child Resource” section you’ve seen how you can add a dependency to a resource. In this part you’ll extend the template to include a definition of a web site, which is to be deployed on Azure Websites. In this case, the web site resource depends on an Azure Websites host plan resource.
  1. Add the following resource definitions to your template:
    {
        "apiVersion": "2014-04-01",
        "type": "Microsoft.Web/serverFarms",
        "name": "myhostplan",
        "location": "[parameters('serverLocation')]",
        "properties": {
            "name": "myhostplan",
            "sku": "Free"
        }
    },
    {
        "apiVersion": "2014-04-01",
        "type": "Microsoft.Web/Sites",
        "name": "mywebsite",
        "location": "[parameters('serverLocation')]",
        "dependsOn": [
            "[concat('Microsoft.Web/serverFarms/', 'myhostplan')]"
        ],
        "properties": {
            "name": "mywebsite",
            "serverFarm": "myhostplan"
        }
    }
    

    NOTE: You’ll need to pick a different name other than mywebsite for your website as the name is already taken.

    In the above code segment, the first resource definition defines a free-tier Azure Website host plan. This shows that in addition to the resources you own, you can also use resource definitions to create references to other PaaS and SaaS services. The second resource definition defines the web site to be provisioned on the selected host plan. And the dependency is described by the dependsOn property just like you’ve seen earlier in this tutorial. 
    A second type of dependencies is created by references. In a resource definition, you can refer to a property from another resource definition, creating a dependency between the two. For example, in our case we’d like to enter a connection string to the SQL Database into the web.config file of our website. And in this connection string we’ll need to refer to the fully qualified domain name (FQDN) of the database server. Obviously the website resource provider has no place to understand how to find that name, but the SQL Database resource provider should be able to provide it. And this is done by the reference keyword.
  2. Add a new child resource that represents a web.config file to the website resource, as shown in the bolded part of the following code list:
    …
    {
        "apiVersion": "2014-04-01",
        "type": "Microsoft.Web/Sites",
        "name": "mywebsite",
        "location": "[parameters('serverLocation')]",
        "dependsOn": [
            "[concat('Microsoft.Web/serverFarms/', 'myhostplan')]"
        ],
        properties": {
            "name": "mywebsiteddf",
            "serverFarm": "myhostplan"
        },
        "resources": [{
            "apiVersion": "2014-04-01",
            "type": "config",
            "name": "web",
            "dependsOn": [
                "[concat('Microsoft.Web/Sites/', 'mywebsiteddf')]"
            ],
            "properties": {
                "connectionStrings": [{
                    "ConnectionString": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', variables('serverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=mytestdatabase;User Id=admin@', variables('serverName'), ';Password=', parameters('adminPassword'), ';')]",
                    "Name": "DefaultConnection",
                    "Type": 2
                }]
            }
        }]
    }
    …
    Please note how the connection string uses reference([SQL Database Server resource name]) to get a reference to the SQL Database server resource, and then its fullQualifiedDomainName to get the server’s fully qualified domain name.
  3. Deploy the template again. You should see the website provisioned with the connection string correctly set.

Conclusion

In this tutorial we walked through the steps of creating a Azure Template that defines both a website and SQL Database. And we studied how to link them together using resource dependencies. We also covered how to use variables and parameters in Azure Template and how to use different parameter files for different deployment environments.

No comments:

Post a Comment