(一)在Azure上创建完整的无服务器云原生应用程序

目录

背景

设计

 设置项目

保存数据

Get函数

部署Functions

下一步


在单个Cloud Native应用程序中同时使用无服务器函数和容器是一个常见用例,因此在这里我们旨在向读者展示这在实际应用程序中的外观,以确保我们将教授他们可以立即使用的实际技能。我们还讨论了迄今为止我们一直在使用的无服务器函数的局限性。

本系列的前一篇文章中,我们在Azure函数中创建了一个简单的微服务。让我们进一步扩展这个概念,并使用多个Azure Functions构建一个基于微服务的后端应用程序。

我们稍微介绍了如何进行应用程序设计、我们可以使用的一些组件、如何在TypeScript中构建我们的函数以及如何使用Azure DevOps部署函数。到本文结束时,您将拥有许多可在应用程序中使用的API,所有API均由Azure Functions提供支持。

背景

对于此示例,我们在TypeScript中构建了一个简单的任务管理应用程序。这包括创建、更新、完成和删除任务,以及跟踪任务处于哪个阶段(未开始、正在执行或已完成)。

我们不会担心实际的前端应用程序组件,只需设计和交付后端API,以便在任何前端应用程序中使用。我们也不会太关心实现基于用户的安全性或角色。

我们将代码存储在Azure DevOps中,并使用自动化管道构建Azure Functions并将其直接部署到Azure租户。

设计

我们应用程序设计的基本经验法则是每个函数一条指令。对于我们的示例应用程序,我们开发的指令是:

  • 获取任务——检索单个任务
  • 列出任务——列出与用户关联的所有任务
  • 创建任务——为用户创建一个新任务
  • 更新任务——为用户更新现有任务
  • 删除任务——删除任务

这涵盖了基本任务管理应用程序的所有组件。一旦我们确定了基本功能,我们就可以查看一些额外的组件,例如API管理。我们不会实现它们,只是为了保持简单。

考虑到这一点,以下是我们将提供的组件的高级视图。

 设置项目

让我们首先使用Visual Studio CodeAzure DevOps中设置我们的项目。您应该已经拥有Azure DevOps帐户Visual Studio Code。首先,打开Azure DevOps并登录,新建一个唯一名称的新项目,例如TaskManager,默认即可,点击创建

创建项目后,在VS Code中克隆的选项位于Repos > Files下。这将使用Git下载您的项目并在VS Code中打开结果。

 完成并打开空白项目后,如果您尚未安装它,请搜索来自Microsoft的名为Azure FunctionsVS Code扩展。安装后,左侧工具栏上有一个Azure图标,使您能够在当前工作区中创建新的Functions项目。

最后,要在本地运行Functions,请安装Azure Functions Core ToolsStorage Emulator,它们应该是Azure SDK的一部分。

保存数据

首先,我们在VS CodeCreateTask函数中创建一个新的TypeScript函数项目。此函数应仅使用HTTP触发器,并在授权级别将范围限定为匿名。这个基础项目拥有部署单个Azure函数所需的一切,类似于我们之前的文章。当我们运行这个函数时(使用 F5),我们得到一个默认的return语句,它在GETPOST上触发。

我们将修改此函数,使我们能够创建新任务并将它们存储在Azure表存储中。在我们这样做之前,我们需要配置函数和一些依赖项。运行以下npm install命令来安装两个额外的库:

npm install azure-storage
npm install guid-typescript

我们还将更新function.json文件中的函数签名以仅接受POST请求。我们的函数需要获取任务负载,然后在我们的表存储帐户中创建、更新或删除任务。代码是:

import { AzureFunction, Context, HttpRequest } from "@azure/functions"
import * as AzureStorage from "azure-storage"
import { Guid } from "guid-typescript";

const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
    context.log('Create Task Triggered');

    if(!req.body.username || req.body.username === ""){
        context.res.status(400).json({ error: "No Username Defined" });
        return;
    }

    var tableSvc = AzureStorage.createTableService();
    var tableName = "Tasks";

    var taskID = Guid.create().toString();
    
    var entGen = AzureStorage.TableUtilities.entityGenerator;
    var task = {
        PartitionKey: entGen.String(req.body.username),
        RowKey: entGen.String(taskID),
        name: entGen.String(req.body.name),
        dueDate: entGen.DateTime(new Date(Date.UTC(
          req.body.dueYear, req.body.dueMonth, req.body.dueDay))),
        completed: entGen.String(req.body.completed)
    };
    
    await apiFunctionWrapper(tableSvc, tableName, task).then(value => {
        return context.res.status(201).json({ "taskId": req.body.taskID, 
          "result": value });
    }, error => {
        context.log(error);
        return context.res.status(500).json({ taskId: req.body.taskID, 
          error: error });
    });
};

export default httpTrigger;

function apiFunctionWrapper(tableSvc, tableName, task) {
    return new Promise((res,err) => {
        tableSvc.insertEntity(tableName, task, function (error, result) {
            if (!error) {
                return res(result);
            } else {
                return err(error);
            }
        });
    });
}

此函数现在将接受带有任务信息的post正文中的有效负载,然后在表存储中创建任务。

最后一步是为我们的表存储帐户提供连接字符串。为确保此功能有效,我们使用Azurite模拟器并在local.settings.json文件中指定环境变量AZURE_STORAGE_CONNECTION_STRING

现在,当我们在VSCode中运行我们的函数(使用F5)时,它会启动并侦听http://localhost:7071/api/UpdateData上的任务。

我们可以使用Postman之类的工具,通过发送如下所示的JSON有效负载来测试我们的函数:

{
    "username" : "testuser",
    "name" : "Finish Function Example",
    "dueYear" : "2021",
    "dueMonth" : "04",
    "dueDay" : "01",
    "completed" : "0"
}

现在,当我们查看本地存储实例时,我们会看到为我们的用户添加了一个任务实体到表中。

在我们继续下一个函数之前,让我们将更改提交到 Azure DevOps,以便保存它们。切换到源代码控制部分,暂存并提交更改,然后将它们推送到 Azure DevOps

Get函数

现在我们可以将数据保存在数据存储中,让我们创建一个函数来检索任务数据。我们创建了一个GetTask函数来根据传递给它的用户名和任务ID来检索任务。首先,使用HTTP触发器创建一个新函数,代码如下:

import { AzureFunction, Context, HttpRequest } from "@azure/functions"
import * as AzureStorage from "azure-storage"

const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
    context.log('Task Store Triggered');

    if(!req.body.username || req.body.username === ""){
        context.res.status(400).json({ error: "No Username Defined" });
        return;
    }
    
    if(!req.body.taskID || req.body.taskID === ""){
        context.res.status(400).json({ error: "No Task ID Defined" });
        return;
    }

    var tableSvc = AzureStorage.createTableService();
    var tableName = "Tasks";

    await apiFunctionWrapper(tableSvc, tableName, req.body.username,  
        req.body.taskID).then(value => {
        context.res.status(200).json({
        username: value["PartitionKey"]._, 
        taskID: value["RowKey"]._, 
        name: value["name"]._, 
        dueDate: value["dueDate"]._, 
        completed: value["completed"]._
        });
    }, error => {
        context.log(error);
        context.res.status(500).json({ taskId: req.body.taskID, 
          error: "TaskID does not exist for user" });
    });
};

export default httpTrigger;

function apiFunctionWrapper(tableSvc, tableName, username, taskID) {
    return new Promise((res, err) => {
        tableSvc.retrieveEntity(tableName, username,  taskID, 
            function(error, result) {
            if (!error) {
                return res(result);
            } else {
                return err(error);
            }
        });
    });
}

此函数遵循与前一个函数类似的模式,不同之处在于它这次使用该retrieveEntity方法返回单个任务并将JSON输出格式化为更具可读性。这是以这种方式生成微服务的一大好处:各个组件易于阅读和实现,因为它们只执行一项任务。

构成我们应用程序的其他函数非常相似(您可以在GitHub存储库中找到代码),所以让我们继续将我们的函数部署到Azure

部署Functions

一旦我们在本地启动并运行所有函数,我们就可以将它们部署到Azure。我们有几个选项(例如Azure Pipelines),但首先,让我们直接从VSCode部署。在我们这样做之前,我们需要确保我们已经创建和配置了我们的函数应用程序和存储。

打开Azure门户,打开或创建资源组,然后添加新资源。找到Function App并启动安装向导。选择一个合适的名称并确保运行时堆栈选择了Node.js

单击下一步,指定一个新的存储帐户并为其命名。我们正在重用Azure Functions所需的存储帐户,但在大多数情况下,您可能希望创建一个不同的存储帐户来仅保存数据。

单击查看创建以创建函数应用程序。

创建Function应用程序及其资源后,我们需要像在本地一样指定AZURE_STORAGE_CONNECTION_STRING属性。

导航到存储帐户,然后在访问密钥下复制连接字符串。回到我们的功能应用程序,在配置下创建一个新的应用程序设置,名称为AZURE_STORAGE_CONNECTION_STRING和我们刚刚复制的连接字符串。

当我们返回VS Code并单击Azure扩展时,我们可以选择登录到我们的Azure帐户。完成登录步骤,当您返回VSCode时,它应该会列出您的帐户可用的Azure实例。

在此之上,有一个小的蓝色向上箭头图标,可让您部署到函数应用程序

单击此图标,选择您的Azure实例,然后选择我们刚刚创建的Function App。这将启动部署过程。

完成后,如果您切换回您的函数应用程序并单击部署中心选项,您应该会看到您的代码已部署。我们现在可以使用公开可用的URL测试我们的API

下一步

在本文中,我们采用了创建单个函数应用程序的概念,并将其构建为用于简单任务管理应用程序的完整函数集。在Azure Functions中编写事件驱动的应用程序组件并快速部署它们很容易。

但是,您可能会遇到一些需要额外组件或替代解决方案的挑战。特别是,长时间运行或密集的流程需要更多的一直运行的传统应用程序。此外,某些库需要特定版本或使函数过大而无法有效运行。为了解决这些挑战,将容器化应用程序与Functions相结合,以创建功能齐全的基于云的应用程序。

在接下来的几篇文章中,我们将讨论容器化以及如何在我们的应用程序代码旁边部署集群和容器。

Creating a Complete Serverless Cloud Native Application on Azure - CodeProject

Guess you like

Origin blog.csdn.net/mzl87/article/details/121162416