Infrastructure as Javascript

with

Luke Nimtz

/protometa

@lukenimtz

Social media icons made by Dave Gandy from www.flaticon.com are licensed by CC 3.0 BY

Full Stack Javascript (and Devops)

The Problem

  • Manually provisioned infrastructure with manually deployed code
  • No reliable record of what was deployed where or how things were configured

The Consequences

  • Slow, error-prone deployments, rollbacks, and scaling
  • Inability to improve expensive, inefficient infrastructure for fear of breaking things
  • Complete reliance on a few system admins with arcane knowledge
  • Difficulty replicating the system for test and staging environments leading to unreliable testing
  • No way to snapshot and restore the system as a whole if something goes really wrong

The Solution

  • Orchestration: automated deployments, rollbacks, and scaling
  • Immutable Infrastructure: The current state of the infrastructure should not depend on the previous state
  • Infrastructure as Code (IaC): The current state of the infrastructure is defined in source control and can be provisioned automatically from the definition

The Implimentation

What I tried...

Kubernetes

  • Great orchestration: automatic scheduling, horizontal scaling, rolling updates / rollbacks, service discovery
  • Immutable infrastructure via container images
  • Declarative IaC in the form of yaml files

Pros

Cons

  • The Kubernetes IaC doesn't define other cloud resources or the cluster itself
  • More parametric stuff has to be done by templating the yaml (see Helm charts)
  • Doesn't cover the full lifecycle of resources (removal is manual for example)

Terraform

  • Also a declarative IaC language
  • Well-established, large ecosystem of providers for AWS, GCP, Azure, OpenStack, and more...
  • So can cover AWS and Kubernetes resources in one tool

Pros

Cons

  • Unique domain specific language that requires learning new patterns and can struggle with complex logic
  • Sometimes the only way around the limitations of the language is to generate the Terraform files before applying them
  • It builds on Terraform's excellent library of providers (In theory any Terraform provider could be used in Pulumi)
  • Like Terraform, can be used to define cloud and Kubernetes resources all in one tool 
  • The language is a real programming language (not a DSL)
  • There is no templating of config files, the code simply creates objects that define your infrastructure
  • That code can be Javascript! or Typescript, or Python, or Go...

Demo

Simple Static Site on S3

$ curl -sSL https://get.pulumi.com | sh

Install Pulumi

$ pulumi new --dir pulumi-demo-s3-site

Create Project

<!DOCTYPE html>
<html>
<head>
  <title>Hello</title>
</head>
<body>
  <h1>Hello Javascript Admirers</h1>
</body>
</html>

Create an HTML file to serve

index.html
-const bucket = new aws.s3.Bucket("my-bucket");
+const bucket = new aws.s3.Bucket("my-bucket", {
+  website: {
+    indexDocument: "index.html"
+  }
+});

Add website configs to bucket

index.ts
+new aws.s3.BucketObject("index.html", {
+  bucket: bucket,
+  source: "index.html",
+  contentType: "text/html"
+});

Add S3 object

index.ts
+export const endpoint = websiteBucket.websiteEndpoint;

Add endpoint to outputs

index.ts
$ pulumi up

Deploy

$ aws s3 ls $(pulumi stack output bucketName)

Check contents of bucket

$ open http://$(pulumi stack output endpoint)

Check web endpoint of bucket

// Create an S3 Bucket Policy to allow public read of all objects in bucket
export default function (bucketName: String) {
  return JSON.stringify({
    Version: "2012-10-17",
    Statement: [{
      Effect: "Allow",
      Principal: "*",
      Action: [
        "s3:GetObject"
      ],
      Resource: [
        `arn:aws:s3:::${bucketName}/*` // policy refers to bucket name explicitly
      ]
    }]
  })
}

Create S3 public policy generator

lib/s3-policy.ts
+import s3Policy from "./lib/s3-policy"

...

+new aws.s3.BucketPolicy("bucketPolicy", {
+  bucket: bucket.bucket,
+  policy: bucket.bucket.apply(s3Policy)
+});

Apply policy to bucket

index.ts
$ pulumi up

Deploy

$ open http://$(pulumi stack output endpoint)

Check web endpoint of bucket

$ pulumi destroy

Cleanup

Thank you!

Made with Slides.com