Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Infrastructure as TypeScript

Infrastructure as TypeScript

Modern cloud applications consist of many moving parts, so they are hard to manage without employing Infrastructure as Code approach.

Traditionally, tools like CloudFormation, ARM templates and Terraform employ text-based formats, which tend to be tedious, repetitive and difficult to reuse.

What if instead of configuration files you could use a real programming language like TypeScript? See how you can bring your favorite developer tools like code completion, types, components, and abstractions to cloud infrastructure definition.

Mikhail Shilkov

November 13, 2019
Tweet

More Decks by Mikhail Shilkov

Other Decks in Technology

Transcript

  1. LB Web Web DB LB DB LB Web Web DB

    LB DB Web DB Web + DB
  2. 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
  3. 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
  4. az storage account create \ --location westus \ --name samplesa

    \ --resource-group myrg \ --sku LRS Command-line Tools
  5. Azure ARM Templates: JSON "resources": [ { "apiVersion": "2016-01-01", "type":

    "Microsoft.Storage/storageAccounts", "name": "mystorageaccount", "location": "westus", "sku": { "name": "Standard_LRS" }, "kind": "Storage", "properties": { } } ]
  6. 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
  7. 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)
  8. { "Resources": { "InstanceSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "SecurityGroupIngress":

    [ ... ] } }, "EC2Instance": { "Type": "AWS::EC2::Instance", "Properties": { "InstanceType": "t2.micro", "SecurityGroups": [ { "Ref": "InstanceSecurityGroup" } ], "ImageId": "ami-0080e4c5bc078760e" } } } } References
  9. { "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
  10. 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
  11. IDEs Code completion Unit tests Types Functions Package managers Versioning

    Classes Code reviews Contracts SDKs Workflows Refactoring
  12. const resourceGroup = new azure.core.ResourceGroup("rg"); const storageAccount = new azure.storage.Account("storage",

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

    { resourceGroupName: resourceGroup.name, accountReplicationType: "LRS", accountTier: "Standard", }); Still, Desired State!
  14. How Pulumi works CLI and Engine Last deployed state index.ts

    Language host AWS Azure GCP Kubernetes new Resource() Create, update, delete
  15. 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
  16. // 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
  17. // 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
  18. 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
  19. 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
  20. const f = new azure.appservice.HttpEventSubscription("greeting", { resourceGroup, callback: async (context,

    req) => { return { status: 200, body: `Hello ${req.params.name}!`, }; }, }); Serverless Functions as Callbacks
  21. 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
  22. 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
  23. 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