Slide 1

Slide 1 text

Infrastructure as TypeScript | November 13 | 2019

Slide 2

Slide 2 text

Why Infrastructure as Code General- purpose Languages

Slide 3

Slide 3 text

On-Premises 2

Slide 4

Slide 4 text

On-premises Load Balancer Web Server Web Server Load Balancer Database Server Database Server

Slide 5

Slide 5 text

LB Web Web DB LB DB LB Web Web DB LB DB Web DB Web + DB

Slide 6

Slide 6 text

Issues with Manual Server Management

Slide 7

Slide 7 text

Configuration management tools: Puppet/Chef

Slide 8

Slide 8 text

Benefits of Infrastructure as Code

Slide 9

Slide 9 text

Cloud Automation 6

Slide 10

Slide 10 text

Unified Management API

Slide 11

Slide 11 text

REST calls Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Amz-Date: 20130813T150211Z Host: ec2.amazonaws.com Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20130813/us-east- 1/ec2/aws4_request, SignedHeaders=content-type;host;x-amz- date, Signature=ced6826de92d2bdeed8f846f0bf508e8559e98e4b0194b84example54174deb456c http://ec2.amazonaws.com/?Action=RunInstances ImageId=ami-2bb65342 &MaxCount=3 &MinCount=1 &Monitoring.Enabled=true &Placement.AvailabilityZone=us-east-1a &Version=2016-11-15

Slide 12

Slide 12 text

var launchRequest = new RunInstancesRequest() { ImageId = amiID, InstanceType = "t1.micro", MinCount = 1, MaxCount = 1, KeyName = keyPairName, SecurityGroupIds = groups }; var launchResponse = ec2Client.RunInstances(launchRequest); var instances = launchResponse.Reservation.Instances; SDKs to call those REST endpoints

Slide 13

Slide 13 text

az storage account create \ --location westus \ --name samplesa \ --resource-group myrg \ --sku LRS Command-line Tools

Slide 14

Slide 14 text

Scripting: Challenges

Slide 15

Slide 15 text

Desired State Configuration 8

Slide 16

Slide 16 text

Desired State Configuration

Slide 17

Slide 17 text

Managing Resource Graphs

Slide 18

Slide 18 text

Challenges

Slide 19

Slide 19 text

Desired State Provisioning

Slide 20

Slide 20 text

Markup Languages 12 Yet Another Markup Language

Slide 21

Slide 21 text

Azure ARM Templates: JSON "resources": [ { "apiVersion": "2016-01-01", "type": "Microsoft.Storage/storageAccounts", "name": "mystorageaccount", "location": "westus", "sku": { "name": "Standard_LRS" }, "kind": "Storage", "properties": { } } ]

Slide 22

Slide 22 text

Converted to REST calls PUT https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/ {resourceGroupName}/providers/Microsoft.Storage/storageAccounts/mystorageaccount?api- version=2016-01-01 { "location": "westus", "properties": { } "sku": { "name": "Standard_LRS" }, "kind": "Storage" }

Slide 23

Slide 23 text

AWS CloudFormation: YAML Resources: S3BucketForURLs: Type: "AWS::S3::Bucket" DeletionPolicy: Delete Properties: BucketName: !If [ "CreateNewBucket", !Ref "AWS::NoValue", !Ref S3BucketName ] WebsiteConfiguration: IndexDocument: "index.html" LifecycleConfiguration: Rules: - Id: DisposeShortUrls ExpirationInDays: !Ref URLExpiration Prefix: "u" Status: Enabled

Slide 24

Slide 24 text

Challenges

Slide 25

Slide 25 text

resource "azurerm_storage_account" "sa" { name = "mysa" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name account_tier = "Standard" account_replication_type = "LRS" } Terraform: DSL (HashiCorp Configuration Language)

Slide 26

Slide 26 text

• • • • • Terraform Providers • • • • •

Slide 27

Slide 27 text

Markup Authoring Experience

Slide 28

Slide 28 text

Example: Code to infrastructure ratio KV Store Table “URLs” Function “Add URL” Function “Open URL”

Slide 29

Slide 29 text

{ "Resources": { "InstanceSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "SecurityGroupIngress": [ ... ] } }, "EC2Instance": { "Type": "AWS::EC2::Instance", "Properties": { "InstanceType": "t2.micro", "SecurityGroups": [ { "Ref": "InstanceSecurityGroup" } ], "ImageId": "ami-0080e4c5bc078760e" } } } } References

Slide 30

Slide 30 text

{ "condition": "[equals(parameters('production'), 'Yes')]", "type": "Microsoft.Compute/availabilitySets", "apiVersion": "2017-03-30", "name": "[variables('availabilitySetName')]", "location": "[resourceGroup().location]", "properties": { "platformFaultDomainCount": 2, "platformUpdateDomainCount": 3 } } Conditionals

Slide 31

Slide 31 text

locals { files = ["index.php","main.php"] } resource "aws_s3_bucket_object" "files" { count = "${length(local.files)}" key = "${local.files[count.index]}" bucket = "${aws_s3_bucket.examplebucket.id}" source = "./src/${local.files[count.index]}" } Loops

Slide 32

Slide 32 text

Reusability

Slide 33

Slide 33 text

Testability

Slide 34

Slide 34 text

I think we solved these problems before?

Slide 35

Slide 35 text

IDEs Code completion Unit tests Types Functions Package managers Versioning Classes Code reviews Contracts SDKs Workflows Refactoring

Slide 36

Slide 36 text

What if developers did infrastructure?

Slide 37

Slide 37 text

Pulumi 20

Slide 38

Slide 38 text

General-Purpose Programming Languages

Slide 39

Slide 39 text

const resourceGroup = new azure.core.ResourceGroup("rg"); const storageAccount = new azure.storage.Account("storage", { resourceGroupName: resourceGroup.name, accountReplicationType: "LRS", accountTier: "Standard", }); TypeScript example

Slide 40

Slide 40 text

const resourceGroup = new azure.core.ResourceGroup("rg"); const storageAccount = new azure.storage.Account("storage", { resourceGroupName: resourceGroup.name, accountReplicationType: "LRS", accountTier: "Standard", }); Still, Desired State!

Slide 41

Slide 41 text

How Pulumi works CLI and Engine Last deployed state index.ts Language host AWS Azure GCP Kubernetes new Resource() Create, update, delete

Slide 42

Slide 42 text

• • • • • Providers • • • • •

Slide 43

Slide 43 text

AWS Cloud Development Kit (CDK) 24

Slide 44

Slide 44 text

м TypeScript Python Java .NET Compiles to CloudFormation

Slide 45

Slide 45 text

const hello = new lambda.Function(this, 'HelloHandler', { runtime: lambda.Runtime.NODEJS_8_10, code: lambda.Code.asset('lambda'), handler: 'hello.handler' }); new apigw.LambdaRestApi(this, 'Endpoint', { handler: hello }); AWS CDK example

Slide 46

Slide 46 text

Benefits of Real Code

Slide 47

Slide 47 text

Programming Languages for Infrastructure? You sure?

Slide 48

Slide 48 text

Static Website on AWS 27

Slide 49

Slide 49 text

Demo!

Slide 50

Slide 50 text

Serverless Functions on Azure 32

Slide 51

Slide 51 text

Resources to Provision an Azure Function

Slide 52

Slide 52 text

// A resource group to contain our Azure Functions const resourceGroup = new azure.core.ResourceGroup("rg"); // A Node.js Azure Function const nodeApp = new azure.appservice.ArchiveFunctionApp("http", { resourceGroup, archive: new pulumi.asset.FileArchive("./javascript"), }); export const nodeEndpoint = nodeApp.endpoint; Node.js Azure Function

Slide 53

Slide 53 text

// A .NET (C#) Azure Function const dotnetApp = new azure.appservice.ArchiveFunctionApp("dotnet", { resourceGroup, archive: new pulumi.asset.FileArchive("./dotnet/bin/Debug/"), appSettings: { runtime: "dotnet", }, }); .NET Azure Function

Slide 54

Slide 54 text

const linuxResourceGroup = new azure.core.ResourceGroup("linuxrg"); const linuxPlan = new azure.appservice.Plan("linux-asp", { resourceGroupName: linuxResourceGroup.name, kind: "Linux", sku: { tier: "Dynamic", size: "Y1" }, reserved: true, }); const pythonApp = new azure.appservice.ArchiveFunctionApp(...); Azure Function in Python on Linux

Slide 55

Slide 55 text

const linuxResourceGroup = new azure.core.ResourceGroup("linuxrg"); const linuxPlan = new azure.appservice.Plan("linux-asp", {...}); const pythonApp = new azure.appservice.ArchiveFunctionApp("http", { resourceGroup: linuxResourceGroup, plan: linuxPlan, archive: new pulumi.asset.FileArchive("./python"), appSettings: { runtime: "python", }, }); Azure Function in Python on Linux

Slide 56

Slide 56 text

const f = new azure.appservice.HttpEventSubscription("greeting", { resourceGroup, callback: async (context, req) => { return { status: 200, body: `Hello ${req.params.name}!`, }; }, }); Serverless Functions as Callbacks

Slide 57

Slide 57 text

Containers 35

Slide 58

Slide 58 text

Load- balanced container instances Load Balancer nginx nginx

Slide 59

Slide 59 text

const listener = new awsx.elasticloadbalancingv2.NetworkListener("lb",{ port: 80 }); const service = new awsx.ecs.FargateService("nginx", { desiredCount: 2, taskDefinitionArgs: { containers: { nginx: { image: awsx.ecs.Image.fromPath("nginx", "./app"), memory: 512, portMappings: [listener], }}}}); Nginx on Fargate with a Load Balancer

Slide 60

Slide 60 text

Cosmos App 36

Slide 61

Slide 61 text

Cosmos App (1)

Slide 62

Slide 62 text

Cosmos App (2)

Slide 63

Slide 63 text

Cosmos App (3)

Slide 64

Slide 64 text

export const functions = new CosmosApp("urls", { resourceGroup, locations: ["WestEurope", "WestUS", "SouthEastAsia"], factory: ({location, cosmosdb}) => { const app = new azure.appservice.ArchiveFunctionApp("app", { location, archive: new pulumi.asset.FileArchive("./app"), appSettings: { COSMOSDB_ENDPOINT: cosmosdb.endpoint, }, }); return { id: app.functionApp.id }; }}); Global Apps

Slide 65

Slide 65 text

export const functions = new CosmosApp("urls", { resourceGroup, locations: ["WestEurope", "WestUS", "SouthEastAsia"], factory: ({location, cosmosdb}) => { const app = new azure.appservice.ArchiveFunctionApp("app", { location, archive: new pulumi.asset.FileArchive("./app"), appSettings: { COSMOSDB_ENDPOINT: cosmosdb.endpoint, }, }); return { id: app.functionApp.id }; }}); Global Apps

Slide 66

Slide 66 text

Kubernetes 39

Slide 67

Slide 67 text

Demo!

Slide 68

Slide 68 text

Conclusions 42

Slide 69

Slide 69 text

Define Infrastructure as Code Making Cloud Apps?

Slide 70

Slide 70 text

Fine-grained components Better Automation

Slide 71

Slide 71 text

м Infrastructure as Code Architecture as Code

Slide 72

Slide 72 text

No content