forked from pulumi/examples
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a couple Azure web server examples (pulumi#309)
* Add a couple Azure web server examples This adds two new examples: 1) A simple Azure web server in a VM, in TypeScript, with a public IP. 2) An Azure web server component that hides many details about how to create a VM with a public IP address, etc, and then uses it from the primary program to create a variable number of instances. I used these in recent customer demos and found them to be helpful for telling a story around components for those working with Azure. * Fixup after review comments * Adding the azure-ts-webserver* tests to CI * Async-await and some formatting
- Loading branch information
Showing
10 changed files
with
419 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
name: ws-ts-azure-comp | ||
runtime: nodejs | ||
description: Basic example of an Azure web server accessible over HTTP | ||
template: | ||
config: | ||
azure:location: | ||
description: The Azure location to use | ||
default: westus | ||
username: | ||
description: The username used to configure the Virtual Machine | ||
password: | ||
description: The password used to configure the Virtual Machine | ||
secret: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
[![Deploy](https://get.pulumi.com/new/button.svg)](https://app.pulumi.com/new) | ||
|
||
# Azure Web Server Virtual Machine Component | ||
|
||
This example provisions a configurable number of Linux web servers in an Azure Virtual Machine, and returns the | ||
resulting public IP addresses. This example uses a reusable [Pulumi component]( | ||
https://pulumi.io/reference/programming-model/#components) to simplify the creation of new virtual machines. By | ||
defining a `WebServer` class, we can hide many details (see [here](./webserver.ts) for its definition). | ||
|
||
## Prerequisites | ||
|
||
- [Node.js](https://nodejs.org/en/download/) | ||
- [Download and install the Pulumi CLI](https://pulumi.io/install) | ||
- [Connect Pulumi with your Azure account](https://pulumi.io/quickstart/azure/setup.html) (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 deployment. The username and password here will be used to configure the Virtual Machine. The | ||
password must adhere to the [Azure restrictions on VM passwords]( | ||
https://docs.microsoft.com/en-us/azure/virtual-machines/windows/faq#what-are-the-password-requirements-when-creating-a-vm). | ||
|
||
``` | ||
$ pulumi config set azure:location westus # any valid Azure region will do | ||
$ pulumi config set username webmaster | ||
$ pulumi config set password <your-password> --secret | ||
$ pulumi config set count 5 # optional -- will default to 2 if left out | ||
``` | ||
|
||
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 changes: | ||
... | ||
Performing changes: | ||
... | ||
info: 15 changes performed: | ||
+ 15 resources created | ||
Update duration: 4m27s | ||
``` | ||
|
||
1. Check the resulting IP addresses: | ||
|
||
``` | ||
$ pulumi stack output ipAddresses | ||
[ 40.112.181.239, ..., 40.112.181.240 ] | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import * as pulumi from "@pulumi/pulumi"; | ||
import * as azure from "@pulumi/azure"; | ||
import { WebServer } from "./webserver"; | ||
|
||
// Get the desired username and password for our webserver VMs. | ||
const config = new pulumi.Config(); | ||
const count = config.getNumber("count") || 2; | ||
const username = config.require("username"); | ||
const password = config.requireSecret("password"); | ||
|
||
// All resources will share a resource group. | ||
const resourceGroupName = new azure.core.ResourceGroup("server-rg").name; | ||
|
||
// Create a network and subnet for all VMs. | ||
const network = new azure.network.VirtualNetwork("server-network", { | ||
resourceGroupName, | ||
addressSpaces: ["10.0.0.0/16"], | ||
subnets: [{ | ||
name: "default", | ||
addressPrefix: "10.0.1.0/24", | ||
}], | ||
}); | ||
const subnet = new azure.network.Subnet("server-subnet", { | ||
resourceGroupName, | ||
virtualNetworkName: network.name, | ||
addressPrefix: "10.0.2.0/24", | ||
}); | ||
|
||
// Now, allocate a few websever VMs -- by default, just 2, but this is configurable. | ||
export const ipAddresses = []; | ||
for (let i = 0; i < count; i++) { | ||
const server = new WebServer(`ws-${i}`, { | ||
username, | ||
password, | ||
bootScript: `#!/bin/bash\n | ||
echo "Hello, from Server #{i+1}!" > index.html | ||
nohup python -m SimpleHTTPServer 80 &`, | ||
resourceGroupName: resourceGroupName, | ||
subnetId: subnet.id, | ||
}); | ||
ipAddresses.push(server.getIpAddress()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"name": "ws-ts-azure-comp", | ||
"version": "0.1.0", | ||
"dependencies": { | ||
"@pulumi/pulumi": "latest", | ||
"@pulumi/azure": "latest" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import * as pulumi from "@pulumi/pulumi"; | ||
import * as azure from "@pulumi/azure"; | ||
|
||
/** | ||
* WebServer is a reusable web server component that creates and exports a NIC, public IP, and VM. | ||
*/ | ||
export class WebServer extends pulumi.ComponentResource { | ||
public readonly publicIp: azure.network.PublicIp; | ||
public readonly networkInterface: azure.network.NetworkInterface; | ||
public readonly vm: azure.compute.VirtualMachine; | ||
|
||
/** | ||
* Allocate a new web server VM, NIC, and public IP address. | ||
* @param name The name of the web server resource. | ||
* @param args A bag of arguments to control the web server VM creation. | ||
*/ | ||
constructor(name: string, args: WebServerArgs) { | ||
super("ws-ts-azure-comp:webserver:WebServer", name); | ||
|
||
// Allocate a public IP and assign it to our NIC. | ||
this.publicIp = new azure.network.PublicIp(`${name}-ip`, { | ||
resourceGroupName: args.resourceGroupName, | ||
allocationMethod: "Dynamic", | ||
}, { parent: this }); | ||
this.networkInterface = new azure.network.NetworkInterface(`${name}-nic`, { | ||
resourceGroupName: args.resourceGroupName, | ||
ipConfigurations: [{ | ||
name: "webserveripcfg", | ||
subnetId: args.subnetId, | ||
privateIpAddressAllocation: "Dynamic", | ||
publicIpAddressId: this.publicIp.id, | ||
}], | ||
}, { parent: this }); | ||
|
||
// Now create the VM, using the resource group and NIC allocated above. | ||
this.vm = new azure.compute.VirtualMachine(`${name}-vm`, { | ||
resourceGroupName: args.resourceGroupName, | ||
networkInterfaceIds: [this.networkInterface.id], | ||
vmSize: args.vmSize || "Standard_A0", | ||
deleteDataDisksOnTermination: true, | ||
deleteOsDiskOnTermination: true, | ||
osProfile: { | ||
computerName: "hostname", | ||
adminUsername: args.username, | ||
adminPassword: args.password, | ||
customData: args.bootScript, | ||
}, | ||
osProfileLinuxConfig: { | ||
disablePasswordAuthentication: false, | ||
}, | ||
storageOsDisk: { | ||
createOption: "FromImage", | ||
name: `${name}-osdisk1`, | ||
}, | ||
storageImageReference: { | ||
publisher: "canonical", | ||
offer: "UbuntuServer", | ||
sku: "16.04-LTS", | ||
version: "latest", | ||
}, | ||
}, { parent: this }); | ||
} | ||
|
||
public getIpAddress(): pulumi.Output<string> { | ||
// The public IP address is not allocated until the VM is running, so wait for that | ||
// resource to create, and then lookup the IP address again to report its public IP. | ||
const ready = pulumi.all({ _: this.vm.id, name: this.publicIp.name, resourceGroupName: this.publicIp.resourceGroupName }); | ||
return ready.apply(async d => { | ||
const ip = await azure.network.getPublicIP({ name: d.name, resourceGroupName: d.resourceGroupName }); | ||
return ip.ipAddress; | ||
}); | ||
} | ||
} | ||
|
||
export interface WebServerArgs { | ||
/** | ||
* A required username for the VM login. | ||
*/ | ||
username: pulumi.Input<string>; | ||
/** | ||
* A required encrypted password for the VM password. | ||
*/ | ||
password: pulumi.Input<string>; | ||
/** | ||
* An optional boot script that the VM will use. | ||
*/ | ||
bootScript?: pulumi.Input<string>; | ||
/** | ||
* An optional VM size; if unspecified, Standard_A0 (micro) will be used. | ||
*/ | ||
vmSize?: pulumi.Input<string>; | ||
/** | ||
* A required Resource Group in which to create the VM | ||
*/ | ||
resourceGroupName: pulumi.Input<string>; | ||
/** | ||
* A required Subnet in which to deploy the VM | ||
*/ | ||
subnetId: pulumi.Input<string>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
name: webserver-ts-azure | ||
runtime: nodejs | ||
description: Basic example of an Azure web server accessible over HTTP | ||
template: | ||
config: | ||
azure:location: | ||
description: The Azure location to deploy to | ||
default: westus | ||
username: | ||
description: The username used to configure the Virtual Machine | ||
password: | ||
description: The password used to configure the Virtual Machine | ||
secret: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
[![Deploy](https://get.pulumi.com/new/button.svg)](https://app.pulumi.com/new) | ||
|
||
# Azure Web Server Virtual Machine | ||
|
||
This example provisions a Linux web server in an Azure Virtual Machine and gives it a public IP address. | ||
|
||
## Prerequisites | ||
|
||
- [Node.js](https://nodejs.org/en/download/) | ||
- [Download and install the Pulumi CLI](https://pulumi.io/install) | ||
- [Connect Pulumi with your Azure account](https://pulumi.io/quickstart/azure/setup.html) (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. The username and password here will be used to configure the Virtual Machine. The | ||
password must adhere to the [Azure restrictions on VM passwords]( | ||
https://docs.microsoft.com/en-us/azure/virtual-machines/windows/faq#what-are-the-password-requirements-when-creating-a-vm). | ||
|
||
``` | ||
$ pulumi config set azure:location westus # any valid Azure region will do | ||
$ pulumi config set username webmaster | ||
$ pulumi config set password <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 changes: | ||
... | ||
Performing changes: | ||
... | ||
info: 7 changes performed: | ||
+ 7 resources created | ||
Update duration: 2m38s | ||
``` | ||
|
||
1. Check the IP address: | ||
|
||
``` | ||
$ pulumi stack output ipAddress | ||
40.112.181.239 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import * as pulumi from "@pulumi/pulumi"; | ||
import * as azure from "@pulumi/azure"; | ||
|
||
// Get the desired username and password for our VM. | ||
const config = new pulumi.Config(); | ||
const username = config.require("username"); | ||
const password = config.requireSecret("password"); | ||
|
||
// All resources will share a resource group. | ||
const resourceGroupName = new azure.core.ResourceGroup("server-rg").name; | ||
|
||
// Create a network and subnet for all VMs. | ||
const network = new azure.network.VirtualNetwork("server-network", { | ||
resourceGroupName, | ||
addressSpaces: ["10.0.0.0/16"], | ||
subnets: [{ | ||
name: "default", | ||
addressPrefix: "10.0.1.0/24", | ||
}], | ||
}); | ||
const subnet = new azure.network.Subnet("server-subnet", { | ||
resourceGroupName, | ||
virtualNetworkName: network.name, | ||
addressPrefix: "10.0.2.0/24", | ||
}); | ||
|
||
// Now allocate a public IP and assign it to our NIC. | ||
const publicIp = new azure.network.PublicIp("server-ip", { | ||
resourceGroupName, | ||
allocationMethod: "Dynamic", | ||
}); | ||
|
||
const networkInterface = new azure.network.NetworkInterface("server-nic", { | ||
resourceGroupName, | ||
ipConfigurations: [{ | ||
name: "webserveripcfg", | ||
subnetId: subnet.id, | ||
privateIpAddressAllocation: "Dynamic", | ||
publicIpAddressId: publicIp.id, | ||
}], | ||
}); | ||
|
||
// Now create the VM, using the resource group and NIC allocated above. | ||
const vm = new azure.compute.VirtualMachine("server-vm", { | ||
resourceGroupName, | ||
networkInterfaceIds: [networkInterface.id], | ||
vmSize: "Standard_A0", | ||
deleteDataDisksOnTermination: true, | ||
deleteOsDiskOnTermination: true, | ||
osProfile: { | ||
computerName: "hostname", | ||
adminUsername: username, | ||
adminPassword: password, | ||
customData: `#!/bin/bash\n | ||
echo "Hello, World!" > index.html | ||
nohup python -m SimpleHTTPServer 80 &`, | ||
}, | ||
osProfileLinuxConfig: { | ||
disablePasswordAuthentication: false, | ||
}, | ||
storageOsDisk: { | ||
createOption: "FromImage", | ||
name: "myosdisk1", | ||
}, | ||
storageImageReference: { | ||
publisher: "canonical", | ||
offer: "UbuntuServer", | ||
sku: "16.04-LTS", | ||
version: "latest", | ||
}, | ||
}); | ||
|
||
// The public IP address is not allocated until the VM is running, so wait for that | ||
// resource to create, and then lookup the IP address again to report its public IP. | ||
const done = pulumi.all({ _: vm.id, name: publicIp.name, resourceGroupName: publicIp.resourceGroupName }); | ||
|
||
export const ipAddress = done.apply(async d => { | ||
const ip = await azure.network.getPublicIP({ name: d.name, resourceGroupName: d.resourceGroupName }); | ||
return ip.ipAddress; | ||
}); |
Oops, something went wrong.