自动化yaml文件_从YAML到TypeScript:开发人员对云自动化的看法

本文探讨了随着云服务的兴起,如何将软件开发实践应用于云基础设施自动化。作者提倡使用TypeScript等编程语言代替YAML来定义基础设施,以实现更高的灵活性和可维护性。通过一个无服务器URL缩短器应用的例子,展示了如何使用Pulumi进行云资源的自动化配置,强调了类型安全、可重用组件和避免供应商锁定的优势。
摘要由CSDN通过智能技术生成

自动化yaml文件

The rise of managed cloud services, cloud-native, and serverless applications brings both new possibilities and challenges. More and more practices from software development processes like version control, code review, continuous integration, and automated testing are applied to cloud infrastructure automation.

受管云服务,云原生和无服务器应用程序的兴起带来了新的可能性和挑战。 来自软件开发过程的越来越多的实践(例如版本控制,代码审查,持续集成和自动化测试)被应用到云基础架构自动化中。

Most existing tools suggest defining infrastructure in text-based markup formats, YAML being the favorite. In this article, I’m making a case for using real programming languages like TypeScript instead. Such a change makes even more software development practices applicable to the infrastructure realm.

大多数现有工具建议以基于文本的标记格式定义基础结构,YAML是最受欢迎的工具。 在本文中,我将提出使用诸如TypeScript之类的真实编程语言的理由。 这样的改变使得更多的软件开发实践适用于基础架构领域。

样品申请 (Sample Application)

It’s easier to make a case given a specific example. For this article, we’ll build a URL Shortener application, a basic clone of tinyurl.com or bit.ly. There is an administrative page where we can define short aliases for long URLs:

在给出具体示例的情况下进行案例比较容易。 对于本文,我们将构建一个URL Shortener应用程序,它是tinyurl.com或bit.ly的基本克隆。 在一个管理页面中,我们可以为长URL定义短别名:

Now, whenever a visitor goes to the base URL of the application + an existing alias, they get redirected to the full URL.

现在,只要访问者转到应用程序的基本URL +现有别名,他们就会被重定向到完整URL。

This app is simple to describe but involves enough moving parts to be representative of some real-world issues. As a bonus, there are many existing implementations on the web to compare with.

该应用程序易于描述,但涉及足够多的运动部件,可以代表一些实际问题。 值得一提的是,网络上有许多现有的实现方式可以与之进行比较。

无服务器URL缩短器 (Serverless URL Shortener)

I’m a big proponent of serverless architecture: the style of cloud applications being a combination of serverless functions and managed cloud services. They are fast to develop, effortless to run, and cost pennies unless the application gets lots of users. However, even serverless applications have to deal with infrastructure, like databases, queues, and other sources of events and destinations of data.

我大力支持无服务器架构:云应用程序的风格是无服务器功能和托管云服务的结合。 除非应用程序吸引大量用户,否则它们开发速度快,运行省力且花费不菲。 但是,即使是无服务器的应用程序也必须处理基础结构,例如数据库,队列以及其他事件源和数据目标。

My examples are going to use Amazon’s AWS, but this could be Microsoft Azure or Google Cloud Platform too.

我的示例将使用亚马逊的AWS,但这也可能是Microsoft Azure或Google Cloud Platform。

So, the gist is to store URLs with short names as key-value pairs in Amazon DynamoDB and use AWS Lambdas to run the application code. Here is the initial sketch:

因此,要点是将带有短名称的URL作为键值对存储在Amazon DynamoDB中,并使用AWS Lambdas运行应用程序代码。 这是初始草图:

The Lambda at the top receives an event when somebody decides to add a new URL. It extracts the name and the URL from the request and saves them as an item in the DynamoDB table.

当有人决定添加新的URL时,顶部的Lambda会收到一个事件。 它从请求中提取名称和URL,并将它们另存为DynamoDB表中的一项。

The Lambda at the bottom is called whenever a user navigates to a short URL. The code reads the full URL based on the requested path and returns a 301 response with the corresponding location.

每当用户导航到短URL时,都会调用底部的Lambda。 该代码根据请求的路径读取完整的URL,并返回带有相应位置的301响应。

Here is the implementation of the Open URL Lambda in JavaScript:

这是JavaScript中Open URL Lambda的实现:

const aws = require('aws-sdk');
const table = new aws.DynamoDB.DocumentClient(); 
exports.handler = async (event) => { 
  const name = event.path.substring(1); 
  const params = { TableName: "urls", Key: { "name": name } }; 
  const value = await table.get(params).promise(); 
  const url = value && value.Item && value.Item.url; 
  return url 
    ? { statusCode: 301, body: "", headers: { "Location": url } } 
    : { statusCode: 404, body: name + " not found" }; 
};

That’s 11 lines of code. I’ll skip the implementation of Add URL function because it's very similar. Considering a third function to list the existing URLs for UI, we might end up with 30-40 lines of JavaScript in total.

那是11行代码。 因为它非常相似,所以我将跳过“ Add URL功能的实现。 考虑到列出UI的现有URL的第三个功能,我们最终可能总共需要30-40行JavaScript。

So, how do we deploy the application?

那么,我们如何部署应用程序?

Well, before we do that, we should realize that the above picture was an over-simplification:

好吧,在我们这样做之前,我们应该意识到上面的图片过于简单了:

  • AWS Lambda can’t handle HTTP requests directly, so we need to add AWS API Gateway in front of it.

    AWS Lambda无法直接处理HTTP请求,因此我们需要在其前面添加AWS API Gateway。
  • We also need to serve some static files for the UI, which we’ll put into AWS S3 and proxy it with the same API Gateway.

    我们还需要为UI提供一些静态文件,这些文件将放入AWS S3中并使用相同的API网关进行代理。

Here is the updated diagram:

这是更新的图:

This is a viable design, but the details are even more complicated:

这是一个可行的设计,但细节更加复杂:

  • API Gateway is a complex beast which needs Stages, Deployments, and REST Endpoints to be appropriately configured.

    API网关是一个复杂的野兽,需要适当配置阶段,部署和REST端点。
  • Permissions and Policies need to be defined so that API Gateway could call Lambda and Lambda could access DynamoDB.

    需要定义权限和策略,以便API网关可以调用Lambda,而Lambda可以访问DynamoDB。
  • Static Files should go to S3 Bucket Objects.

    静态文件应转到S3存储桶对象。

So, the actual setup involves a couple of dozen objects to be configured in AWS:

因此,实际设置涉及在AWS中配置的数十个对象:

How do we approach this task?

我们如何完成这项任务?

提供基础架构的选项 (Options to Provision the Infrastructure)

There are many options to provision a cloud application, and each one has its trade-offs. Let’s quickly go through the list of possibilities to understand the landscape.

部署云应用程序有很多选择,每个选择都有其取舍。 让我们快速浏览一下各种可能性以了解景观。

AWS Web控制台 (AWS Web Console)

AWS, like any other cloud, has a web user interface to configure its resources:

与其他任何云一样,AWS具有一个Web用户界面来配置其资源:

That’s a decent place to start — good for experimenting, figuring out the available options, following the tutorials, i.e., for exploration.

这是一个不错的起点–适用于进行实验,根据教程(例如进行探索)找出可用选项。

However, it doesn’t suit particularly well for long-lived ever-changing applications developed in teams. A manually clicked deployment is pretty hard to reproduce in the exact manner, which becomes a maintainability issue pretty fast.

但是,它不适用于团队中长期存在且不断变化的应用程序。 手动单击的部署很难以精确的方式进行复制,这很快成为可维护性问题。

AWS命令行界面 (AWS Command Line Interface)

The AWS Command Line Interface (CLI) is a unified tool to manage all AWS services from a command prompt. You write the calls like this:

AWS Command Line Interface (CLI)是一个统一的工具,可从命令提示符管理所有AWS服务。 您可以这样编写呼叫:

aws apigateway create-rest-api --name 'My First API' --description 'This is my first API' 

aws apigateway create-stage --rest-api-id 1234123412 --stage-name 'dev' --description 'Development stage' --deployment-id a1b2c3

The initial experience might not be as smooth as clicking buttons in the browser, but the huge benefit is that you can reuse commands that you once wrote. You can build scripts by combining many commands into cohesive scenarios. So, your colleague can benefit from the same script that you created. You can provision multiple environments by parameterizing the scripts.

最初的体验可能不如单击浏览器中的按钮那么顺畅,但是巨大的好处是您可以重用曾经编写的命令。 您可以通过将许多命令组合到有凝聚力的方案中来构建脚本。 因此,您的同事可以从您创建的相同脚本中受益。 您可以通过参数化脚本来设置多个环境。

Frankly speaking, I’ve never done that for several reasons:

坦白地说,出于以下几个原因,我从未这样做过:

  • CLI scripts feel too imperative to me. I have to describe “how” to do things, not “what” I want to get in the end.

    CLI脚本对我来说太重要了。 我必须描述“如何”做事情,而不是最后要表达的“什么”。
  • There seems to be no good story for updating existing resources. Do I write small delta scripts for each change? Do I have to keep them forever and run the full suite every time I need a new environment?

    更新现有资源似乎没有好故事。 是否为每次更改编写小的增量脚本? 我是否需要永久保留它们并在每次需要新环境时都运行完整套件?
  • If a failure occurs mid-way through the script, I need to manually repair everything to a consistent state. This gets messy real quick, and I have no desire to exercise this process, especially in production.

    如果脚本中途发生故障,我需要手动将所有内容修复到一致状态。 这很快就会变得凌乱,我不希望执行此过程,尤其是在生产中。

To overcome such limitations, the notion of the Desired State Configuration (DSC) was invented. Under this paradigm, we describe the desired layout of the infrastructure, and then the tooling takes care of either provisioning it from scratch or applying the required changes to an existing environment.

为了克服这些限制,发明了期望状态配置 (DSC)的概念。 在此范例下,我们描述了所需的基础结构布局,然后该工具负责从头开始进行配置或将所需的更改应用于现有环境。

Which tool provides DSC model for AWS? There are legions.

哪个工具为AWS提供DSC模型? 有军团。

AWS CloudFormation (AWS CloudFormation)

AWS CloudFormation is the first-party tool for Desired State Configuration management from Amazon. CloudFormation templates use YAML to describe all the infrastructure resources of AWS.

AWS CloudFormation是Amazon进行所需状态配置管理的第一方工具。 CloudFormation模板使用YAML来描述AWS的所有基础架构资源。

Here is a snippet from a private URL shortener example kindly provided on the AWS blog:

以下是AWS博客上提供的私有URL缩短程序示例的摘录:

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

This is just a very short fragment: the complete example consists of 317 lines of YAML. That’s an order of magnitude more than the actual JavaScript code that we have in the application!

这只是一个很短的片段:完整的示例包含317行YAML。 这比我们在应用程序中拥有的实际JavaScript代码高出一个数量级!

CloudFormation is a powerful tool, but it demands quite some learning to be done to master it. Moreover, it’s specific to AWS: you won’t be able to transfer the skill to other cloud providers.

CloudFormation是一个功能强大的工具,但要掌握它需要大量的学习。 而且,它特定于AWS:您将无法将该技能转让给其他云提供商。

Wouldn’t it be great if there was a universal DSC format? Meet Terraform.

如果有通用的DSC格式不是很好吗? 认识Terraform。

地貌 (Terraform)

HashiCorp Terraform is an open source tool to define infrastructure in declarative configuration files. It has a pluggable architecture, so the tool supports all major clouds and even hybrid scenarios.

HashiCorp Terraform是一个开放源代码工具,用于在声明性配置文件中定义基础结构。 它具有可插拔架构,因此该工具支持所有主要云甚至混合方案。

The custom text-based Terraform .tf format is used to define the configurations. The templating language is quite powerful, and once you learn it, you can use it for different cloud providers.

基于文本的自定义Terraform .tf格式用于定义配置。 模板语言功能强大,一旦学习,便可以将其用于其他云提供商。

Here is a snippet from AWS Lambda Short URL Generator example:

这是AWS Lambda短URL生成器示例的片段:

resource "aws_api_gateway_rest_api" "short_urls_api_gateway" {
  name        = "Short URLs API"
  description = "API for managing short URLs."
}
resource "aws_api_gateway_usage_plan" "short_urls_api_usage_plan" {
  name         = "Short URLs admin API key usage plan"
  description  = "Usage plan for the admin API key for Short URLS."
  api_stages {
    api_id = "${aws_api_rest_api.short_urls_gateway.id}"
    stage  = "${aws_api_deployment.short_url_deployment.stage_name}"
  }
}

This time, the complete example is around 450 lines of textual templates. Are there ways to reduce the size of the infrastructure definition?

这次,完整的示例是大约450行文本模板。 有没有办法减小基础架构定义的大小?

Yes, by raising the level of abstraction. It’s possible with Terraform’s modules, or by using other, more specialized tools.

是的,通过提高抽象水平。 使用Terraform的模块,或使用其他更专业的工具,这是可能的。

无服务器框架和SAM (Serverless Framework and SAM)

The Serverless Framework is an infrastructure management tool focused on serverless applications. It works across cloud providers (AWS support is the strongest though) and only exposes features related to building applications with cloud functions.

无服务器框架是针对无服务器应用程序的基础结构管理工具。 它可跨云提供商使用(尽管AWS支持最强),并且仅公开与使用云功能构建应用程序有关的功能。

The benefit is that it’s much more concise. Once again, the tool is using YAML to define the templates, here is the snippet from Serverless URL Shortener example:

好处是它更加简洁。 该工具再次使用YAML定义模板,这是Serverless URL Shortener示例的摘录:

functions:
  store:
    handler: api/store.handle
    events:
      - http:
          path: /
          method: post
          cors: true

The domain-specific language yields a shorter definition: this example has 45 lines of YAML + 123 lines of JavaScript functions.

特定领域的语言产生了一个较短的定义:此示例包含45行的YAML + 123行JavaScript函数。

However, the conciseness has a flip side: as soon as you veer outside of the fairly “thin” golden path — the cloud functions and an incomplete list of event sources — you have to fall back to more generic tools like CloudFormation. As soon as your landscape includes lower-level infrastructure work or some container-based components, you’re stuck using multiple config languages and tools again.

但是,简洁有一个缺点:一旦您走出了相当“细”的黄金路径(云功能和事件源列表不完整)之外,您就不得不依靠CloudFormation等更通用的工具。 一旦您的环境包括较低级别的基础结构工作或某些基于容器的组件,您将再次陷入使用多种配置语言和工具的困境。

Amazon’s AWS Serverless Application Model (SAM) looks very similar to the Serverless Framework but is tailored to be AWS-specific.

亚马逊的AWS无服务器应用程序模型 (SAM)看起来与无服务器框架非常相似,但专门针对AWS而量身定制。

Is that the end game? I don’t think so.

那是最后的比赛吗? 我不这么认为。

基础架构定义工具的所需属性 (Desired Properties of Infrastructure Definition Tool)

So what have we learned while going through the existing landscape? The perfect infrastructure tools should:

那么,在浏览现有环境时我们学到了什么? 完善的基础架构工具应:

  • Provide reproducible results of deployments

    提供可重复的部署结果

  • Be scriptable, i.e., require no human intervention after the definition is complete

    可编写脚本 ,即在定义完成后无需人工干预

  • Define the desired state rather than exact steps to achieve it

    定义所需的状态,而不是实现它的确切步骤

  • Support multiple cloud providers and hybrid scenarios

    支持多个云提供商和混合方案

  • Be universal in the sense of using the same tool to define any type of resource

    在使用相同工具定义任何类型的资源的意义上具有通用性

  • Be succinct and concise to stay readable and manageable

    简洁 明了,以保持可读性和可管理性

  • ̶U̶̶̶s̶̶̶e̶̶̶ ̶̶̶Y̶̶̶A̶̶̶M̶̶̶L̶̶̶-̶̶̶b̶̶̶a̶̶̶s̶̶̶e̶̶̶d̶̶̶ ̶̶̶f̶̶̶o̶̶̶r̶̶̶m̶̶̶a̶̶̶t̶̶̶

    ̶U̶̶̶s̶̶̶e̶̶̶̶̶̶Y̶̶̶A̶̶̶M̶̶̶L̶̶̶-̶̶̶b̶̶̶a̶̶̶s̶̶̶e̶̶̶d̶̶̶̶̶̶f̶̶̶o̶̶̶r̶̶̶m̶̶̶a̶̶̶t̶̶̶

Nah, I crossed out the last item. YAML seems to be the most popular language among this class of tools (and I haven’t even touched Kubernetes yet!), but I’m not convinced it works well for me. YAML has many flaws, and I just don’t want to use it.

不,我删除了最后一个项目。 在这类工具中,YAML似乎是最受欢迎的语言(而且我还没有接触过Kubernetes!),但我不认为它对我来说效果很好。 YAML有很多缺陷,我只是不想使用它

Have you noticed that I haven’t mentioned Infrastructure as code a single time yet? Well, here we go (from Wikipedia):

您是否注意到我还没有一次提到基础架构作为代码 ? 好吧,我们开始(来自Wikipedia ):

Infrastructure as code (IaC) is the process of managing and provisioning computer data centers through machine-readable definition files, rather than physical hardware configuration or interactive configuration tools.

基础架构即代码(IaC)是通过机器可读的定义文件而不是物理硬件配置或交互式配置工具来管理和配置计算机数据中心的过程。

Shouldn’t it be called “Infrastructure as definition files”, or “Infrastructure as YAML”?

不应将其称为“基础结构定义文件”或“基础结构YAML”吗?

As a software developer, what I really want is “Infrastructure as actual code, you know, the program thing”. I want to use the same language that I already know. I want to stay in the same editor. I want to get IntelliSense auto-completion when I type. I want to see the compilation errors when what I typed is not syntactically correct. I want to reuse the developer skills that I already have. I want to come up with abstractions to generalize my code and create reusable components. I want to leverage the open-source community who would create much better components than I ever could. I want to combine the code and infrastructure in one code project.

作为软件开发人员,我真正想要的是“将基础结构作为实际的程序代码”。 我想使用我已经知道的相同语言 。 我想留在同一个编辑器中。 我想在键入时获得IntelliSense 自动完成功能 。 当我键入的内容在语法上不正确时,我想查看编译错误 。 我想重用已经拥有的开发人员技能 。 我想提出抽象来概括我的代码并创建可重用的组件 。 我想利用开源社区该社区将创建比以往任何时候都更好的组件。 我想将代码和基础结构合并到一个代码项目中。

If you are with me on that, keep reading. You get all of that with Pulumi.

如果您和我在一起,请继续阅读。 您可以通过Pulumi获得所有这些。

普鲁米 (Pulumi)

Pulumi is a tool to build cloud-based software using real programming languages. They support all major cloud providers, plus Kubernetes.

Pulumi是使用真正的编程语言构建基于云的软件的工具。 他们支持所有主要的云提供商以及Kubernetes。

Pulumi programming model supports Go and Python too, but I’m going to use TypeScript for the rest of the article.

Pulumi编程模型也支持Go和Python,但在本文的其余部分中,我将使用TypeScript。

While prototyping a URL shortener, I explain the fundamental way of working and illustrate the benefits and some trade-offs. If you want to follow along, install Pulumi.

在为URL缩短器制作原型时,我解释了基本的工作方式,并说明了其好处和一些折衷。 如果要继续, 请安装Pulumi

Pulumi如何运作 (How Pulumi Works)

Let’s start defining our URL shortener application in TypeScript. I installed @pulumi/pulumi and @pulumi/aws NPM modules so that I can start the program. The first resource to create is a DynamoDB table:

让我们开始在TypeScript中定义我们的URL缩短程序。 我安装了@pulumi/pulumi@pulumi/aws NPM模块,以便可以启动该程序。 创建的第一个资源是DynamoDB表:

import * as aws from "@pulumi/aws";

// A DynamoDB table with a single primary key
let counterTable = new aws.dynamodb.Table("urls", {
    name: "urls",
    attributes: [
        { name: "name", type: "S" },
    ],
    hashKey: "name",
    readCapacity: 1,
    writeCapacity: 1
});

I use pulumi CLI to run this program to provision the actual resource in AWS:

我使用pulumi CLI运行该程序来配置AWS中的实际资源:

> pulumi up 
Previewing update (urlshortener): 
   Type                  Name           Plan 
+  pulumi:pulumi:Stack   urlshortener   create 
+    aws:dynamodb:Table  urls           create 
Resources: 
    + 2 to create 
Do you want to perform this update? yes 
Updating (urlshortener): 
   Type                  Name           Status 
+  pulumi:pulumi:Stack   urlshortener   created 
+    aws:dynamodb:Table  urls           created 
Resources: 
    + 2 created

The CLI first shows the preview of the changes to be made, and when I confirm, it creates the resource. It also creates a stack — a container for all the resources of the application.

CLI首先显示要进行的更改的预览,当我确认时,它将创建资源。 它还创建了一个堆栈 -应用程序所有资源的容器。

This code might look like an imperative command to create a DynamoDB table, but it actually isn’t. If I go ahead and change readCapacity to 2 and then re-run pulumi up, it produces a different outcome:

这段代码看起来像是创建DynamoDB表的命令命令,但实际上并非如此。 如果我继续将readCapacity更改为2 ,然后重新运行pulumi up ,它将产生不同的结果:

> pulumi up
Previewing update (urlshortener):
   Type                  Name           Plan
   pulumi:pulumi:Stack   urlshortener 
~    aws:dynamodb:Table  urls           update [diff: ~readCapacity]
Resources: 
    ~ 1 to update 1 unchanged

It detects the exact change that I made and suggests an update. The following picture illustrates how Pulumi works:

它检测到我所做的确切更改并建议进行更新。 下图说明了Pulumi的工作方式:

index.ts in the red square is my program. Pulumi's language host understands TypeScript and translates the code to commands to the internal engine. As a result, the engine builds a tree of resources-to-be-provisioned, the desired state of the infrastructure.

index.ts中的index.ts是我的程序。 Pulumi的语言宿主理解TypeScript并将代码转换为命令到内部引擎。 结果,引擎构建了待配置资源的树,即基础结构的期望状态。

The end state of the last deployment is persisted in the storage (can be in pulumi.com backend or a file on disk). The engine then compares the current state of the system with the desired state of the program and calculates the delta in terms of create-update-delete commands to the cloud provider.

上次部署的结束状态保留在存储中(可以位于pulumi.com后端或磁盘上的文件中)。 然后,引擎将系统的当前状态与程序的期望状态进行比较,并根据向云提供商提供的create-update-delete命令来计算增量。

类型帮助 (Help Of Types)

Now I can proceed to the code that defines a Lambda function:

现在,我可以继续定义Lambda函数的代码:

// Create a Role giving our Lambda access.
let policy: aws.iam.PolicyDocument = { /* Redacted for brevity */ };
let role = new aws.iam.Role("lambda-role", {
    assumeRolePolicy: JSON.stringify(policy),
});
let fullAccess = new aws.iam.RolePolicyAttachment("lambda-access", {
    role: role,
    policyArn: aws.iam.AWSLambdaFullAccess,
});

// Create a Lambda function, using code from the `./app` folder.
let lambda = new aws.lambda.Function("lambda-get", {
    runtime: aws.lambda.NodeJS8d10Runtime,
    code: new pulumi.asset.AssetArchive({
        ".": new pulumi.asset.FileArchive("./app"),
    }),
    timeout: 300,
    handler: "read.handler",
    role: role.arn,
    environment: { 
        variables: {
            "COUNTER_TABLE": counterTable.name
        }
    },
}, { dependsOn: [fullAccess] });

You can see that the complexity kicked in and the code size is growing. However, now I start to gain real benefits from using a typed programming language:

您会看到复杂性增加了,代码大小也在增加。 但是,现在我开始从使用类型化的编程语言中获得真正的好处:

  • I’m using objects in the definitions of other object’s parameters. If I misspell their name, I don’t get a runtime failure but an immediate error message from the editor.

    我在其他对象的参数定义中使用对象。 如果我拼错了他们的名字,我不会遇到运行时失败,而是会收到来自编辑器的立即错误消息。
  • If I don’t know which options I need to provide, I can go to the type definition and look it up (or use IntelliSense).

    如果我不知道需要提供哪些选项,则可以转到类型定义并进行查找(或使用IntelliSense)。
  • If I forget to specify a mandatory option, I get a clear error.

    如果忘记指定强制性选项,则会收到明确的错误消息。
  • If the type of the input parameter doesn’t match the type of the object I’m passing, I get an error again.

    如果输入参数的类型与我传递的对象的类型不匹配,则会再次出现错误。
  • I can use language features like JSON.stringify right inside my program. In fact, I can reference and use any NPM module.

    我可以在程序内部使用JSON.stringify类的语言功能。 实际上,我可以引用和使用任何NPM模块。

You can see the code for API Gateway here. It looks too verbose, doesn’t it? Moreover, I’m only half-way through with only one Lambda function defined.

您可以在此处查看API Gateway的代码。 它看起来太冗长了,不是吗? 而且,我只定义了一个Lambda函数而已完成一半。

可重复使用的组件 (Reusable Components)

We can do better than that. Here is the improved definition of the same Lambda function:

我们可以做得更好。 这是相同Lambda函数的改进定义:

import { Lambda } from "./lambda";

const func = new Lambda("lambda-get", {
    path: "./app",
    file: "read",
    environment: { 
       "COUNTER_TABLE": counterTable.name
    },
});

Now, isn’t that beautiful? Only the essential options remained, while all the machinery is gone. Well, it’s not completely gone, it’s been hidden behind an abstraction.

现在,那不漂亮吗? 只剩下基本的选择,而所有的机器都消失了。 嗯,它还没有完全消失,它已经被隐藏在一个抽象背后。

I defined a custom component called Lambda:

我定义了一个名为Lambda自定义组件

export interface LambdaOptions {
    readonly path: string;
    readonly file: string;
    
    readonly environment?:  pulumi.Input<{
        [key: string]: pulumi.Input<string>;
    }>;    
}

export class Lambda extends pulumi.ComponentResource {
    public readonly lambda: aws.lambda.Function;

    constructor(name: string,
        options: LambdaOptions,
        opts?: pulumi.ResourceOptions) {
        
        super("my:Lambda", name, opts);

        const role = //... Role as defined in the last snippet
        const fullAccess = //... RolePolicyAttachment as defined in the last snippet
        
        this.lambda = new aws.lambda.Function(`${name}-func`, {
            runtime: aws.lambda.NodeJS8d10Runtime,
            code: new pulumi.asset.AssetArchive({
                ".": new pulumi.asset.FileArchive(options.path),
            }),
            timeout: 300,
            handler: `${options.file}.handler`,
            role: role.arn,
            environment: {
                variables: options.environment
            }
        }, { dependsOn: [fullAccess], parent: this });
    }
}

The interface LambdaOptions defines options that are important for my abstraction. The class Lambda derives from pulumi.ComponentResource and creates all the child resources in its constructor.

接口LambdaOptions定义了对我的抽象很重要的选项。 Lambda类从pulumi.ComponentResource派生,并在其构造函数中创建所有子资源。

A nice effect is that one can see the structure in pulumi preview:

一个不错的效果是,可以在pulumi预览中看到结构:

> pulumi up
Previewing update (urlshortener):
   Type                              Name               Plan 
+  pulumi:pulumi:Stack               urlshortener       create 
+    my:Lambda                       lambda-get         create 
+      aws:iam:Role                  lambda-get-role    create
+      aws:iam:RolePolicyAttachment  lambda-get-access  create 
+      aws:lambda:Function           lambda-get-func    create 
+    aws:dynamodb:Table              urls               create

The Endpoint component simplifies the definition of API Gateway (see the source):

Endpoint组件简化了API网关的定义(请参阅参考资料 ):

const api = new Endpoint("urlapi", {
    path: "/{proxy+}",
    lambda: func.lambda
});

The component hides the complexity from the clients — if the abstraction was selected correctly, that is. The component class can be reused in multiple places, in several projects, across teams, etc.

该组件向客户端隐藏了复杂性-也就是说,如果正确选择了抽象。 组件类可以在多个地方,多个项目中,跨团队等中重用。

标准组件库 (Standard Component Library)

In fact, the Pulumi team came up with lots of high-level components that build abstractions on top of raw resources. The components from the @pulumi/cloud-aws package are particularly useful for serverless applications.

实际上,Pulumi团队提出了许多高级组件,它们在原始资源的基础上构建了抽象。 @pulumi/cloud-aws软件包中的组件对于无服务器应用程序特别有用。

Here is the full URL shortener application with DynamoDB table, Lambdas, API Gateway, and S3-based static files:

这是带有DynamoDB表,Lambdas,API Gateway和基于S3的静态文件的完整URL缩短器应用程序:

import * as aws from "@pulumi/cloud-aws";

// Create a table `urls`, with `name` as primary key.
let urlTable = new aws.Table("urls", "name");

// Create a web server.
let endpoint = new aws.API("urlshortener");

// Serve all files in the www directory to the root.
endpoint.static("/", "www");

// GET /url/{name} redirects to the target URL based on a short-name.
endpoint.get("/url/{name}", async (req, res) => {
    let name = req.params["name"];
    let value = await urlTable.get({name});
    let url = value && value.url;

    // If we found an entry, 301 redirect to it; else, 404.
    if (url) {
        res.setHeader("Location", url);
        res.status(301);
        res.end("");
    }
    else {
        res.status(404);
        res.end("");
    }
});

// POST /url registers a new URL with a given short-name.
endpoint.post("/url", async (req, res) => {
    let url = req.query["url"];
    let name = req.query["name"];
    await urlTable.insert({ name, url });
    res.json({ shortenedURLName: name });
});

export let endpointUrl = endpoint.publish().url;

The coolest thing here is that the actual implementation code of AWS Lambdas is intertwined with the definition of resources. The code looks very similar to an Express application. AWS Lambdas are defined as TypeScript lambdas. All strongly typed and compile-time checked.

这里最酷的是,AWS Lambdas的实际实现代码资源定义 交织在一起 。 该代码看起来与Express应用程序非常相似。 AWS Lambda被定义为TypeScript lambda。 所有强类型和编译时检查。

It’s worth noting that at the moment such high-level components only exist in TypeScript. One could create their custom components in Python or Go, but there is no standard library available. Pulumi folks are actively trying to figure out a way to bridge this gap.

值得注意的是,目前此类高级组件仅存在于TypeScript中。 可以使用Python或Go创建其自定义组件,但没有标准库可用。 普鲁米(Pulumi)乡亲正在积极尝试寻找一种弥合这种差距的方法

避免供应商锁定? (Avoiding Vendor Lock-in?)

If you look closely at the previous code block, you notice that only one line is AWS-specific: the import statement. The rest is just naming.

如果仔细查看前一个代码块,您会发现只有一行是特定于AWS的: import语句。 其余只是命名。

We can get rid of that one too: just change the import to import * as cloud from "@pulumi/cloud"; and replace aws. with cloud. everywhere. Now, we'd have to go to the stack configuration file and specify the cloud provider there:

我们也可以摆脱这种情况:只需将导入更改为import * as cloud from "@pulumi/cloud"; 并更换aws.cloud. 到处。 现在,我们必须转到堆栈配置文件并在此处指定云提供商:

config: 
  cloud:provider: aws

Which is enough to make the application work again!

这足以使应用程序再次运行!

Vendor lock-in seems to be a big concern among many people when it comes to cloud architectures heavily relying on managed cloud services, including serverless applications. While I don’t necessarily share those concerns and am not sure if generic abstractions are the right way to go, Pulumi Cloud library can be one direction for the exploration.

当涉及严重依赖托管云服务(包括无服务器应用程序)的云体系结构时,供应商锁定似乎是许多人关注的大问题。 虽然我不一定会分享这些担忧,并且不确定通用抽象是否是正确的方法,但Pulumi Cloud库可以是探索的一个方向。

The following picture illustrates the choice of the level of abstraction that Pulumi provides:

下图说明了Pulumi提供的抽象级别的选择:

Working on top of the cloud provider’s API and internal resource provider, you can choose to work with raw components with maximum flexibility, or opt-in for higher-level abstractions. Mix-and-match in the same program is possible too.

您可以选择在云提供商的API和内部资源提供商的基础上使用具有最大灵活性的原始组件,也可以选择加入更高级别的抽象。 同一程序中也可以进行混搭。

基础架构即实代码 (Infrastructure as Real Code)

Designing applications for the modern cloud means utilizing multiple cloud services which have to be configured to play nicely together. The Infrastructure as Code approach is almost a requirement to keep the management of such applications reliable in a team setting and over the extended period.

为现代云设计应用程序意味着必须利用多个云服务,这些服务必须配置为可以很好地协同工作。 几乎需要一种“基础结构即代码”方法,以在团队环境中和较长时间内保持此类应用程序的管理可靠。

Application code and supporting infrastructure become more and more blended, so it’s natural that software developers take the responsibility to define both. The next logical step is to use the same set of languages, tooling, and practices for both software and infrastructure.

应用程序代码和支持基础结构变得越来越融合,因此软件开发人员自然有责任同时定义两者。 下一步的逻辑步骤是对软件和基础架构使用相同的语言,工具和实践集。

Pulumi exposes cloud resources as APIs in several popular general-purpose programming languages. Developers can directly transfer their skills and experience to define, build, compose, and deploy modern cloud-native and serverless applications more efficiently than ever.

Pulumi以几种流行的通用编程语言将云资源作为API公开。 开发人员可以直接转移他们的技能和经验,从而比以往更有效地定义,构建,组成和部署现代的云原生和无服务器应用程序。

Originally published at mikhail.io.

最初发表于mikhail.io

翻译自: https://www.freecodecamp.org/news/from-yaml-to-typescript-a-developers-view-on-cloud-automation/

自动化yaml文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值