当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 为 PowerShell 设计 Azure Functions

作者:精品下载站 日期:2024-12-14 07:14:05 浏览:11 分类:玩电脑

为 PowerShell 设计 Azure Functions


这篇文章是有关 Azure Functions 和 PowerShell 的系列文章的一部分。查看该系列中其他帖子的列表!

介绍

Azure Functions 对 PowerShell 的支持自 2019 年 11 月 4 日起普遍可用,并且运行良好!

在我上一篇关于设计用于生产的 Azure Function App 的文章中,我展示了如何设置和配置 Function App 以在 Azure 中运行 PowerShell。在这篇文章中,我将介绍如何将我们的第一个函数部署到其中,以及开发将在 Function App 中运行的 PowerShell 代码时要考虑的事项。

从一个例子开始吧!

有一个关于使用 Visual Studio Code 在 Azure 中构建函数的精彩教程。这将帮助您开始。一旦我们将功能部署到 Azure,我就想更深入地研究一些事情。

设置 scriptFile 去掉所有那些 run.ps1

当我工作时,有时我会有点心不在焉。我也是那些突然拥有 800 个或更多浏览器选项卡的人之一(好吧,我也很不擅长重新启动计算机…)。

现在这与 Azure Functions 有什么关系?! 嗯,这也意味着当我开发函数时,我倾向于至少打开五个名为 run.ps1 的文件。这最终变得非常令人困惑和奇怪!

[玩转系统] 为 PowerShell 设计 Azure Functions

当然有一个解决方案。每个函数都有自己的 function.json。在该文件中,我们可以添加一个名为 scriptFile 的属性,并为其指定应执行的脚本的路径。该路径必须相对于 function.json,但实际文件不需要位于同一文件夹中。

我通常只是将文件命名为与函数相同的名称,并将其保存在同一个文件夹中,这样可以更轻松地跟踪哪些文件所属的位置。以下是将 run.ps1 重命名为 HttpTrigger1.ps1 的示例:

{
  "bindings": [
  ],
  "scriptFile": "HttpTrigger1.ps1"
}

日志级别

从 PowerShell 进行日志记录非常简单,只需使用我们熟悉并喜爱的 cmdlet 进行输出即可,例如 write-error/warning/information/host/output/debug/verbose。然后,函数运行时将拾取不同的输出流并将它们发送到 Application Insights。我们可以通过将日志级别设置为错误(仅错误流)、警告(错误和警告流)、信息 中的任意一个来选择要拾取的流(错误、警告以及输出和信息流),调试(所有先前的加上调试流)或跟踪,还添加详细流和写入的进度消息使用写入进度。

日志级别在 Function App 代码根目录中名为 host.json 的文件中设置。通过配置属性logging.logLevel,我们可以指定一个适用于应用程序中所有函数的默认值,并指定“Function.MyFunction”来覆盖名为MyFunction的特定函数的设置。

  "logging": {
    "logLevel": {
      "Function.HttpTrigger1": "Trace",
      "default": "Warning"
    }
  }

阅读文档中有关登录的更多信息。

PowerShell 简介

我们项目的根目录中还有一个名为 profile.ps1 的文件。这就像我们计算机上的 profile.ps1 一样,每次创建新的运行空间时它都会获得点源。默认情况下,有一个小的 if 语句,用于查找环境变量 MSI_SECRET 和 Az.Accounts 模块是否存在。 MSI_SECRET 是一个自动环境变量,如果您启用函数应用程序使用托管标识,Azure 会将其注入到您的函数应用程序中。 MSI_SECRET 变量包含一个秘密标头,可用于调用内部令牌服务,您的函数可使用该服务通过托管标识获取访问令牌。

Azure PowerShell 内置了对此的支持。如果我们安装了 Az.Accounts 模块,我们只需调用“Connect-AzAccount -Identity”即可使用 Function App 的托管身份向 Azure 进行身份验证。那有多酷不是吗?

但是,如果您不希望您的函数调用 Azure API,我强烈建议您删除此 if 语句,即使只需要几毫秒来评估条件,即添加到冷启动的毫秒数我们的函数调用。更糟糕的是,如果配置了托管标识(通常是这样)并且我们有可用的 Az.Accounts 模块,我们的函数实际上将登录到 Azure,这可能会导致冷启动时间增加几秒钟。

我执行的一些简单测试表明,仅测试 Az.Accounts 是否存在就花费了不到 2 秒的时间,而实际调用 Connect-AzAccount 则花费了大约 12 秒!现在你不想花这 12 秒,除非你真的需要它!

如果您需要在消费层上运行的函数应用程序中向 Azure 进行身份验证,并且需要进行大量冷启动,则可以使用以下超轻量级方法来获取访问令牌来调用 ARM API,而不是使用 Azure PowerShell:

$BaseURI = 'https://management.azure.com/'
$URI = "${Env:MSI_ENDPOINT}?resource=${BaseURI}&api-version=2017-09-01"
$Response = Invoke-RestMethod -Method Get -Headers @{Secret = $Env:MSI_SECRET } -Uri $URI
$Env:Token = $Response.access_token

这通常会在 0.2 秒左右执行!

只要您的托管身份可以访问其他资源,此方法也适用于连接到这些资源。只需将 BaseURI 替换为您要连接的资源的标识符即可。

以下是如何从 Azure Funciton 连接 Microsoft.Graph PowerShell 模块的示例:

$BaseURI = 'https://graph.microsoft.com/'
$URI = "${Env:MSI_ENDPOINT}?resource=${BaseURI}&api-version=2017-09-01"
$Response = Invoke-RestMethod -Method Get -Headers @{Secret = $Env:MSI_SECRET } -Uri $URI
$Env:Token = $Response.access_token
Connect-MgGraph -AccessToken $Env:Token -TenantId $TenantId

当我们这样做时,如果您追求的是速度,请考虑使用 Invoke-RestMethod 而不是使用 Azure PowerShell 调用 ARM API,这样可以节省大量宝贵的时间,但需要更多的编码。

使用模块

与往常一样,在使用 PowerShell 时,我尝试将尽可能多的代码放入可重用模块中。我自己编写的这些模块以及我想要在函数中使用的任何其他模块需要安装在我的函数应用程序中。

本质上有两种方法可以实现此目的,自己将它们与我的代码一起部署,或者让 Function App 从 PowerShell 库下载它们。让 Function App 下载模块并为我安装它们是由称为托管依赖项的功能处理的。让我们看看它是如何工作的。

可以通过在 host.json 中将 ManagedDependency.enabled 设置为 true 来启用托管依赖项。这样做让我们在项目的根目录中创建一个requirements.pd1文件。该文件只是一个包含模块名称和所需版本的哈希表。默认情况下,在 2020 年 9 月撰写本文时,我们获得了对版本“4.*”的模块“Az”的依赖项。当 Funciton 应用程序首次启动时,我们在 dependency.psd1 中设置的任何模块依赖项都将从 PowerShell 库下载启动,导致相当长的等待时间。

乍一看,托管依赖项听起来像是一个诱人的功能,但深入研究后,我觉得它给了我更少的控制权。我更喜欢手动下载我需要的模块并将它们与我的其余代码一起部署。这样我就可以确定自己正在运行什么,不需要依赖 PowerShell 库,也不需要担心 Function App 下载所需模块时的长时间冷启动。作为一个额外的好处,将所有模块与我的函数代码的其余部分打包在一起可以更轻松地在本地运行和调试,因为我也在那里拥有所有依赖项。

那么我们如何手动安装模块呢?简单的!只需在函数项目的根目录中创建一个名为 Modules 的文件夹即可。函数运行时会自动在这里寻找模块。如果我想安装公共模块,我只需运行 Save-Module 并将其指向我的模块文件夹,如下所示:

Save-Module Az.Accounts -Path .\Modules

就那么简单!

以下是 host.json 的示例:

{
  "version": "2.0",
  "managedDependency": {
    "enabled": false
  },
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[1.*, 2.0.0)"
  },
  "logging": {
    "logLevel": {
      "Function.HttpTrigger1": "Trace",
      "default": "Warning"
    }
  }
}

使用应用程序设置设置可配置值

当我创建一个函数应用程序时,我经常需要设置一些对于它当前运行的环境来说是唯一的配置。它可能是标签名称、租户 ID、组织名称,甚至是 API 密钥、证书等秘密,有时甚至是用户名和密码。我绝对不希望在我的代码中硬编码这种东西!

这是可以使用应用程序设置的地方。如果您阅读了我之前关于为生产设计 Azure Functions 的文章,您就会非常了解用于配置 Function App 的应用程序设置。这些相同的设置可用于将配置设置和机密从平台注入到我的 Function App 中。任何应用程序设置的值都将在我的 Function App 中作为环境变量提供。

因此,如果我需要注入秘密令牌,我可以将该令牌放入我的 Key Vault 中,添加名为 MyToken 的应用程序设置并引用我的 Key Vault 秘密。然后我可以通过读取环境变量 $Env:MyToken 从 PowerShell 访问我的秘密令牌。

当然,所有机密和证书都应存储在 Key Vault 中。我还倾向于将配置设置存储在 Key Vault 中,以便将所有内容保留在同一位置。

更多示例

Microsoft 在 GitHub 上有一个关于如何构建 Functions 的优秀示例存储库

概括

总结一下:

  • 确保您使用最新版本的 PowerShell
  • 考虑重命名 run.ps1
  • 管理您自己的依赖项
  • 使用密钥库!

在使用 PowerShell 编写函数时,您还有其他经常使用的提示和技巧或重要信息吗?
请在评论中告诉我!

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯