Skip to content

Commit

Permalink
Azure VM Scale Sets example (pulumi#358)
Browse files Browse the repository at this point in the history
* Azure VM Scale Sets example

* Add a test
  • Loading branch information
mikhailshilkov authored and stack72 committed Aug 6, 2019
1 parent 9005d24 commit f1e2826
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 0 deletions.
8 changes: 8 additions & 0 deletions azure-ts-vm-scaleset/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: azure-ts-vm-scaleset
runtime: nodejs
description: Basic example of nginx deployed in Azure VM Scale Sets
template:
config:
azure:environment:
description: The Azure environment to use (`public`, `usgovernment`, `german`, `china`)
default: public
70 changes: 70 additions & 0 deletions azure-ts-vm-scaleset/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
[![Deploy](https://get.pulumi.com/new/button.svg)](https://app.pulumi.com/new)

# Azure VM Scale Sets

This example provisions a Scale Set of Linux web servers with nginx deployed, configured the auto-scaling based on CPU load, puts a Load Balancer in front of them, and gives it a public IP address.

## Prerequisites

- [Node.js](https://nodejs.org/en/download/)
- [Download and install the Pulumi CLI](https://www.pulumi.com/docs/reference/install/)
- [Connect Pulumi with your Azure account](https://www.pulumi.com/docs/reference/clouds/azure/setup/) (if your `az` CLI is
configured, this will just work)

## Running the App

1. Create a new stack:

```
$ pulumi stack init dev
```
1. Configure the app deployment.
```
$ pulumi config set azure:location westus # any valid Azure region will do
```
Optionally, configure the username and password for the admin user. Otherwise, they will be auto-generated.
```
$ pulumi config set adminUser webmaster
$ pulumi config set adminPassword <your-password> --secret
```
Note that `--secret` ensures your password is encrypted safely.
1. Login to Azure CLI (you will be prompted to do this during deployment if you forget this step):
```
$ az login
```
1. Restore NPM dependencies:
```
$ npm install
```
1. Run `pulumi up` to preview and deploy changes:
```
$ pulumi up
Previewing update:
...
Updating:
...
Resources:
13 created
Update duration: 2m19s
```
1. Check the domain name of the PIP:
```
$ pulumi stack output publicAddress
dsuv3vqbgi.westeurope.cloudapp.azure.com
$ curl http://$(pulumi stack output publicAddress)
#nginx welcome screen HTML is returned
```
177 changes: 177 additions & 0 deletions azure-ts-vm-scaleset/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// Copyright 2016-2019, Pulumi Corporation. All rights reserved.

import * as azure from "@pulumi/azure";
import * as pulumi from "@pulumi/pulumi";
import * as random from "@pulumi/random";

const config = new pulumi.Config();
const adminUser = config.get("adminUser") || "azureuser";
const adminPassword = config.getSecret("adminPassword") || new random.RandomString("pwd", {
length: 20,
}).result;
const domain = config.get("domain") || new random.RandomString("domain", {
length: 10,
number: false,
special: false,
upper: false,
}).result;
const applicationPort = config.getNumber("applicationPort") || 80;

const resourceGroup = new azure.core.ResourceGroup("vmss-rg");

const publicIp = new azure.network.PublicIp("public-ip", {
resourceGroupName: resourceGroup.name,
allocationMethod: "Static",
domainNameLabel: domain,
});

const loadBalancer = new azure.lb.LoadBalancer("lb", {
resourceGroupName: resourceGroup.name,
frontendIpConfigurations: [{
name: "PublicIPAddress",
publicIpAddressId: publicIp.id,
}],
});

const bpepool = new azure.lb.BackendAddressPool("bpepool", {
resourceGroupName: resourceGroup.name,
loadbalancerId: loadBalancer.id,
});

const sshProbe = new azure.lb.Probe("ssh-probe", {
resourceGroupName: resourceGroup.name,
loadbalancerId: loadBalancer.id,
port: applicationPort,
});

const natRule = new azure.lb.Rule("lbnatrule-http", {
resourceGroupName: resourceGroup.name,
backendAddressPoolId: bpepool.id,
backendPort: applicationPort,
frontendIpConfigurationName: "PublicIPAddress",
frontendPort: applicationPort,
loadbalancerId: loadBalancer.id,
probeId: sshProbe.id,
protocol: "Tcp",
});

const vnet = new azure.network.VirtualNetwork("vnet", {
resourceGroupName: resourceGroup.name,
addressSpaces: ["10.0.0.0/16"],
});

const subnet = new azure.network.Subnet("subnet", {
resourceGroupName: resourceGroup.name,
addressPrefix: "10.0.2.0/24",
virtualNetworkName: vnet.name,
});

const scaleSet = new azure.compute.ScaleSet("vmscaleset", {
resourceGroupName: resourceGroup.name,
networkProfiles: [{
ipConfigurations: [{
loadBalancerBackendAddressPoolIds: [bpepool.id],
name: "IPConfiguration",
primary: true,
subnetId: subnet.id,
}],
name: "networkprofile",
primary: true,
}],
osProfile: {
adminUsername: adminUser,
adminPassword,
computerNamePrefix: "vmlab",
customData:
`#cloud-config
packages:
- nginx`,
},
osProfileLinuxConfig: {
disablePasswordAuthentication: false,
},
sku: {
capacity: 1,
name: "Standard_DS1_v2",
tier: "Standard",
},
storageProfileDataDisks: [{
caching: "ReadWrite",
createOption: "Empty",
diskSizeGb: 10,
lun: 0,
}],
storageProfileImageReference: {
offer: "UbuntuServer",
publisher: "Canonical",
sku: "16.04-LTS",
version: "latest",
},
storageProfileOsDisk: {
caching: "ReadWrite",
createOption: "FromImage",
managedDiskType: "Standard_LRS",
name: "",
},
upgradePolicyMode: "Manual",
}, { dependsOn: [bpepool] });

const autoscale = new azure.monitoring.AutoscaleSetting("vmss-autoscale", {
resourceGroupName: resourceGroup.name,
notification: {
email: {
customEmails: ["[email protected]"],
sendToSubscriptionAdministrator: true,
sendToSubscriptionCoAdministrator: true,
},
},
profiles: [{
capacity: {
default: 1,
maximum: 10,
minimum: 1,
},
name: "defaultProfile",
rules: [
{
metricTrigger: {
metricName: "Percentage CPU",
metricResourceId: scaleSet.id,
operator: "GreaterThan",
statistic: "Average",
threshold: 75,
timeAggregation: "Average",
timeGrain: "PT1M",
timeWindow: "PT5M",
},
scaleAction: {
cooldown: "PT1M",
direction: "Increase",
type: "ChangeCount",
value: 1,
},
},
{
metricTrigger: {
metricName: "Percentage CPU",
metricResourceId: scaleSet.id,
operator: "LessThan",
statistic: "Average",
threshold: 25,
timeAggregation: "Average",
timeGrain: "PT1M",
timeWindow: "PT5M",
},
scaleAction: {
cooldown: "PT1M",
direction: "Decrease",
type: "ChangeCount",
value: 1,
},
},
],
}],
targetResourceId: scaleSet.id,
});

export const publicAddress = publicIp.fqdn;
9 changes: 9 additions & 0 deletions azure-ts-vm-scaleset/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "azure-ts-vm-scaleset",
"version": "0.1.0",
"dependencies": {
"@pulumi/azure": "latest",
"@pulumi/pulumi": "latest",
"@pulumi/random": "latest"
}
}
11 changes: 11 additions & 0 deletions misc/test/examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,17 @@ func TestExamples(t *testing.T) {
"azure:location": azureLocation,
},
}),
base.With(integration.ProgramTestOptions{
Dir: path.Join(cwd, "..", "..", "azure-ts-vm-scaleset"),
Config: map[string]string{
"azure:location": azureLocation,
},
ExtraRuntimeValidation: func(t *testing.T, stack integration.RuntimeValidationStackInfo) {
assertHTTPResult(t, stack.Outputs["publicAddress"].(string), nil, func(body string) bool {
return assert.Contains(t, body, "nginx")
})
},
}),
base.With(integration.ProgramTestOptions{
Dir: path.Join(cwd, "..", "..", "azure-ts-webserver"),
Config: map[string]string{
Expand Down

0 comments on commit f1e2826

Please sign in to comment.