How to deploy Service Fabric application using ARM template and PowerShell, part 2: ARM

This is a series of blog posts:

To publish an ARM template using whichever mechanism you’d like, first you need the actual ARM template. Here’s an example of an application consisting of one stateless service (the front-end) and one stateful service (the back-end):

{
  "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "clusterName": {
      "type": "string",
      "metadata": {
        "description": "Name of your cluster - Between 3 and 23 characters. Letters and numbers only."
      }
    },
    "appPackageUrl": {
      "type": "string",
      "metadata": {
        "description": "The URL to the application package sfpkg file."
      }
    },
    "applicationTypeVersion": {
      "type": "string",
      "metadata": {
        "description": "The application type version."
      }
    },
    "applicationParameters": {
      "type": "object",
      "metadata": {
        "description": "Application parameters override to be applied when creating or upgrading an application."
      }
    },
    "MyStatelessService_InstanceCount": {
      "type": "string",
      "defaultValue": "",
      "metadata": {
        "description": "Dynamically generated parameter for service type MyStatelessService"
      }
    },
    "MyStatefulService_TargetReplicaSetSize": {
      "type": "string",
      "defaultValue": "",
      "metadata": {
        "description": "Dynamically generated parameter for service type MyStatefulService"
      }
    },
    "MyStatefulService_MinReplicaSetSize": {
      "type": "string",
      "defaultValue": "",
      "metadata": {
        "description": "Dynamically generated parameter for service type MyStatefulService"
      }
    },
    "MyStatefulService_PartitionCount": {
      "type": "string",
      "defaultValue": "",
      "metadata": {
        "description": "Dynamically generated parameter for service type MyStatefulService"
      }
    }
  },
  "variables": {
    "clusterLocation": "[resourcegroup().location]",
    "applicationName": "MyProject",
    "applicationTypeName": "MyProjectType"
  },
  "resources": [
    {
      "apiVersion": "2017-07-01-preview",
      "type": "Microsoft.ServiceFabric/clusters/applicationTypes",
      "name": "[concat(parameters('clusterName'), '/', variables('applicationTypeName'))]",
      "location": "[variables('clusterLocation')]",
      "dependsOn": [],
      "properties": {
        "provisioningState": "Default"
      }
    },
    {
      "apiVersion": "2017-07-01-preview",
      "type": "Microsoft.ServiceFabric/clusters/applicationTypes/versions",
      "name": "[concat(parameters('clusterName'), '/', variables('applicationTypeName'), '/', parameters('applicationTypeVersion'))]",
      "location": "[variables('clusterLocation')]",
      "dependsOn": [
        "[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applicationTypes/', variables('applicationTypeName'))]"
      ],
      "properties": {
        "provisioningState": "Default",
        "appPackageUrl": "[parameters('appPackageUrl')]"
      }
    },
    {
      "apiVersion": "2017-07-01-preview",
      "type": "Microsoft.ServiceFabric/clusters/applications",
      "name": "[concat(parameters('clusterName'), '/', variables('applicationName'))]",
      "location": "[variables('clusterLocation')]",
      "dependsOn": [
        "[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applicationTypes/', variables('applicationTypeName'), '/versions/', parameters('applicationTypeVersion'))]"
      ],
      "properties": {
        "provisioningState": "Default",
        "typeName": "[variables('applicationTypeName')]",
        "typeVersion": "[parameters('applicationTypeVersion')]",
        "parameters": "[parameters('applicationParameters')]",
        "upgradePolicy": {
          "upgradeReplicaSetCheckTimeout": "01:00:00.0",
          "forceRestart": "true",
          "rollingUpgradeMonitoringPolicy": {
            "healthCheckWaitDuration": "00:02:00.0",
            "healthCheckStableDuration": "00:05:00.0",
            "healthCheckRetryTimeout": "00:10:00.0",
            "upgradeTimeout": "01:00:00.0",
            "upgradeDomainTimeout": "00:20:00.0"
          },
          "applicationHealthPolicy": {
            "considerWarningAsError": "true",
            "maxPercentUnhealthyDeployedApplications": "0",
            "defaultServiceTypeHealthPolicy": {
              "maxPercentUnhealthyServices": "0",
              "maxPercentUnhealthyPartitionsPerService": "0",
              "maxPercentUnhealthyReplicasPerPartition": "0"
            }
          }
        }
      }
    },
    {
      "apiVersion": "2017-07-01-preview",
      "type": "Microsoft.ServiceFabric/clusters/applications/services",
      "name": "[concat(parameters('clusterName'), '/', variables('applicationName'), '/', 'MyProject~MyStatelessService')]",
      "location": "[variables('clusterLocation')]",
      "dependsOn": [
        "[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applications/', variables('applicationName'))]"
      ],
      "properties": {
        "provisioningState": "Default",
        "serviceKind": "Stateless",
        "correlationScheme": [],
        "serviceLoadMetrics": [],
        "servicePlacementPolicies": [],
        "serviceTypeName": "MyStatelessServiceType",
        "placementConstraints": "(NodeType != sysnode)",
        "instanceCount": "[parameters('MyStatelessService_InstanceCount')]",
        "partitionDescription": {
          "partitionScheme": "Singleton"
        }
      }
    },
    {
      "apiVersion": "2017-07-01-preview",
      "type": "Microsoft.ServiceFabric/clusters/applications/services",
      "name": "[concat(parameters('clusterName'), '/', variables('applicationName'), '/', 'MyProject~MyStatefulService')]",
      "location": "[variables('clusterLocation')]",
      "dependsOn": [
        "[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applications/', variables('applicationName'))]"
      ],
      "properties": {
        "provisioningState": "Default",
        "serviceKind": "Stateful",
        "correlationScheme": [],
        "serviceLoadMetrics": [],
        "servicePlacementPolicies": [],
        "serviceTypeName": "MyStatefulServiceType",
        "placementConstraints": "(NodeType != sysnode)",
        "hasPersistedState": "true",
        "defaultMoveCost": "Zero",
        "replicaRestartWaitDuration": "00:01:00.0",
        "quorumLossWaitDuration": "00:02:00.0",
        "standByReplicaKeepDuration": "00:00:30.0",
        "targetReplicaSetSize": "[parameters('MyStatefulService_TargetReplicaSetSize')]",
        "minReplicaSetSize": "[parameters('MyStatefulService_MinReplicaSetSize')]",
        "partitionDescription": {
          "partitionScheme": "UniformInt64Range",
          "count": "[parameters('MyStatefulService_PartitionCount')]",
          "lowKey": "-9223372036854775808",
          "highKey": "9223372036854775807"
        }
      }
    }
  ]
}

Happy deployment!

This entry was posted in Programming and tagged , , . Bookmark the permalink.

19 Responses to How to deploy Service Fabric application using ARM template and PowerShell, part 2: ARM

  1. Demetri says:

    Can you provide any examples for the “applicationParameters” parameter. I’m trying to get this working with the Service Fabric Patch Orchestration Application, but having no luck.

  2. Pooja says:

    “appPackageUrl”: {
    “type”: “string”,
    “metadata”: {
    “description”: “The URL to the application package sfpkg file.”
    }

    which URl I need to provide as there is no such file .sfpkg in my application package.

  3. Pooja says:

    why do we need to zip pkg folder to get Application Package URL,
    Can we directly provide path of the pkg folder? or how can we get the .sfpkg zip folder(I am not able to get the required URL, I did the same that you mentioned,but didn’t work for me).

    • abatishchev says:

      That’s how ARM works: all additional to the template itself resources must be available from an online location. Such as linked templates, or a package to be deployed.

      Service Fabric basically supports two ways to deploy an application:
      – Connect to cluster management endpoint using PowerShell (the old way and the new way) or C# (using the new HTTP client). This accepts a file on the disk or a URL/SAS
      – ARM. This accepts only a URL/SAS

      Ideally ARM would have uploaded your package to a hidden blob storage transparently for you. But would this would complicate the deployment process and also cost money to Microsoft so instead this burden is unfortunately on the user.

      How to create sfpkg you can find in the docs.

  4. Allen Chen says:

    Can you provide an example of supplying EnvironmentOverrides to services?

    • Allen Chen says:

      And more generally, how does ServiceManifestImport in ApplicationManifest translate to the ARM json template?

      For example:

      <ServiceManifestImport>
        <ServiceManifestRef ServiceManifestName="FrontEndServicePkg" ServiceManifestVersion="1.0.0" />
        <EnvironmentOverrides CodePackageRef="MyCode">
          <EnvironmentVariable Name="MyEnvVariable" Value="OverrideValue"/>
        </EnvironmentOverrides>
      </ServiceManifestImport>
      
      • abatishchev says:

        We’re parsing XML and generating JSON manually, haven’t found any tool to do that. Only model classes from a DLL shipped within the SF NuGet package.

  5. Marcela says:

    I have generated several application parameters XML files which I use to set environment variable values in service manifest. When deploying through visual studio I can choose which application parameter file to use, how can I set that here on an ARM template deployment?

    I see that on applicationParameters you can provide specific values, what would be the process to specify a specific XML application parameter file?

    • abatishchev says:

      Basically, you can’t do that. XML files with application parameters play no role in deployment using ARM. You specify them inside template or template parameters (preferably) and that’s it. Only Visual Studio uses those files during local deployment, the PowerShell script which is shipped alongside the template parses them.

      XML files for application and services manifest are still used, though. But they come within SFPKG which you have to produce either way.

      So, you end up having two options:

      Generate JSON files based on XML files

      Keep application parameters for local cluster in XML and use them from VS, and in JSON for cloud-based environments.

  6. Marcela says:

    Oh I get it now, I shall generate the JSON template param files based on those XML files, and on deployment of the ARM template I specify the correct JSON param file to use.
    Thanks!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.