跳转到内容

Greengrass Component

greengrass#component 生成器向现有的 Python 或 TypeScript 项目添加 AWS IoT Greengrass v2 组件。它创建配方、入口点、Python 组件的单元测试,以及为核心设备打包组件的 Nx 目标。使用默认的 infra,它还提供可重用的 CDK 构造或 Terraform 模块,用于发布组件版本、拥有工件存储库并描述部署。您可以在自己的基础设施代码中组合这些构建块;生成器本身从不创建设备、车队或部署。

宿主项目必须已经存在。首先使用 py#project 或 ts#project 创建一个。

运行此生成器@aws/nx-plugin:greengrass#component

pnpm nx g @aws/nx-plugin:greengrass#component --project=telemetry --name=pulse --language=python
构建你的命令12

必需

必需

在脚本和文档中明确传递 language。当省略时,生成器会从所选项目中的 tsconfig.json 推断为 typescript,或从 pyproject.toml 推断为 python。同时包含两个文件的项目必须传递 --language;两者都没有的项目不是受支持的宿主。

ipc 对两种语言默认为 false。传递 --ipc=true 以添加 Greengrass IPC 访问,或传递 --ipc=false 以保持禁用。

配方的 ComponentPublisher 默认为工作区的 npm 作用域。传递 --publisher 以设置其他值。aws-nx-plugin.config.mts 中没有 Greengrass 发布者设置。

对于 iac: terraform,在运行此生成器之前,使用 terraform#project 创建 Terraform 应用程序。Greengrass 生成器会将其 awscc 提供程序配置添加到该应用程序。如果您稍后创建 Terraform 应用程序,请重新运行 greengrass#component 以便它可以添加提供程序。

--project 接受非限定的项目名称。生成的项目是命名空间限定的,因此 nx run 需要完整名称:Python 项目为 <scope>.telemetry,TypeScript 项目为 @<scope>/telemetry。下面的示例将该名称写为 <project>,并将在 npm 作用域为 my-scope 的工作区中使用 --name=infra 生成的基础设施项目写为 @my-scope/infra。

platform 选择核心设备的操作系统和 CPU 架构,而不是其板名称。当前目标是带有 glibc 的 64 位 Linux:

设备生成器目标状态
Linux PC、工业网关或 EC2 x86_64 实例linux-amd64支持;已在 EC2 核心上验证
具有 64 位 CPU 和 64 位 Linux 的 Raspberry Pi,或另一个 Linux ARM64 网关linux-arm64支持打包;Raspberry Pi 硬件尚未验证
包含上述两者的车队linux-amd64-arm64一个组件版本,具有特定于架构的清单
运行 32 位 Linux / ARMv7 的 Raspberry Pi无此生成器不支持,尽管经典 Greengrass 核心支持 ARMv7
Raspberry Pi Pico、ESP32 或另一个微控制器无用作核心设备的 IoT 客户端或外围设备

在 Raspberry Pi 上,检查 uname -m 和 getconf LONG_BIT;此路径需要 aarch64 和 64。运行 32 位用户空间的 64 位处理器不是 ARM64 部署目标。设备还需要生成的配方中命名的 Python 解释器或 TypeScript 的 Node.js,以及 Greengrass 核心先决条件。Python 依赖项供应目标为 manylinux_2_28,因此请使用 glibc 2.28 或更高版本。GPIO 库和自定义本机依赖项必须为所选平台提供兼容的二进制文件。生成器不会配置这些外围设备。

生成的 Python 配方将解释器固定到宿主项目的 requires-python 下限,例如 python3.14。在运行组件的每个核心设备上安装该解释器。TypeScript 组件需要核心设备上的 Node.js。

对于 linux-amd64-arm64,配方包含每个架构一个清单。Greengrass 选择其 Platform 与核心设备匹配的第一个清单,因此请保持每个清单的工件和环境设置与其架构配对。

ESP32 固件与这些 Python 和 TypeScript 组件分开运行。它可以向 AWS IoT Core 发送 MQTT 消息,或使用客户端设备支持连接到本地 Greengrass 核心。本地路由需要代理、客户端身份验证和 MQTT 桥接配置;此生成器不会为它们或固件搭建脚手架。ARMv7、Windows、musl Linux 和其他 CPU 架构需要额外的打包和运行时工作。仅更改配方的架构标签是不够的。

生成器选项12 个选项
project必需string

现有的 Python 或 TypeScript 宿主项目

name必需string

组件名称

platformenum默认值: linux-arm64

核心设备平台或多个平台。

linux-amd64linux-arm64linux-amd64-arm64
infraenum默认值: component-version

component-version 生成可重用的 Greengrass 组件基础设施;none 仅支持本地开发。

component-versionnone
iacenum默认值: inherit

IaC 提供商,仅在请求基础设施时解析。

inheritcdkterraform
languageenum

组件语言。仅当宿主项目恰好有一个受支持的语言标记时才省略。

typescriptpython
componentNamestring

配方 ComponentName。默认为从工作区 npm scope 和组件名称派生的反向域名。

componentVersionstring默认值: 1.0.0

配方 ComponentVersion。CDK 在部署时解析 NEXT_*;Terraform 需要显式的语义版本。当 infra=none 时,NEXT_* 将原样写入。

publisherstring

配方 ComponentPublisher。默认为工作区 npm scope。

ipcboolean默认值: false

是否连接 Greengrass IPC 客户端。两种语言默认为 false。

gdkConfigboolean默认值: false

生成 gdk-config.json 以便手动使用 GDK CLI。GDK 支持 NEXT_PATCH,不支持 NEXT_MINOR 或 NEXT_MAJOR。

preferInstallDependenciesboolean默认值: true

是否倾向于在生成器运行后安装依赖项。

language = python
  • 文件夹greengrass
    • 文件夹pulse
      • recipe.yaml 组件配方
      • main.py 组件入口点
  • 文件夹tests
    • 文件夹greengrass
      • test_pulse.py 通过路径加载 main.py 的单元测试

pulse-vendor 目标使用 uv pip install --only-binary :all: 为所选设备平台供应项目的依赖项。使用 platform: linux-amd64-arm64,它为每个架构供应一次,配方为每个架构携带一个清单。

language = typescript
  • 文件夹greengrass
    • 文件夹pulse
      • recipe.yaml 组件配方
  • 文件夹src
    • 文件夹greengrass
      • 文件夹pulse
        • main.ts 组件入口点

项目的 bundle 目标在打包之前捆绑入口点。使用 ipc: true,pulse-vendor 目标还会为所选架构暂存 aws-crt 本机插件。

配方、入口点以及(对于 Python)测试从第一次运行开始就是您的:重新运行永远不会重写它们。目标、元数据和依赖项声明由框架管理,并在每次运行时收敛。packages/common/scripts/src/greengrass/ 下的共享打包脚本创建一次;删除该目录并重新运行生成器以刷新它们。

目标使用短横线命名的组件名称:

目标目的
<component>-vendor供应 Python 依赖项,或在启用 IPC 时供应 TypeScript CRT 插件
<component>-artifact在 dist/<project-root>/greengrass/<component>/greengrass-build/ 下写入已解析的配方和可部署的存档
<component>-deploy-local通过核心设备上的 greengrass-cli 创建本地部署并等待稳定的组件状态
<component>-logs在核心设备上跟踪组件日志

<component>-artifact 是宿主项目的 build 和 assemble 目标的依赖项,因此正常构建会生成工件。

infra = component-version

由于此生成器根据您选择的 iac 提供基础设施即代码,它将在 packages/common 中创建一个项目,其中包含相关的 CDK 构造或 Terraform 模块。

通用基础设施即代码项目的结构如下:

  • 文件夹packages/common/constructs
    • 文件夹src
      • 文件夹app/ Constructs for infrastructure specific to a project/generator
        • …
      • 文件夹core/ Generic constructs which are reused by constructs in app
        • …
      • index.ts Entry point exporting constructs from app
    • project.json Project build targets and configuration

默认的 infra: component-version 在缺少时添加下面的 Greengrass 核心文件,并为每个组件添加一个应用包装器。现有的核心文件会被保留,因此本地编辑在以后的运行中幸存。它不会创建设备、事物组或部署。

  • 文件夹packages/common/constructs/src
    • 文件夹core/greengrass
      • artifact-bucket.ts GreengrassArtifactBucket:保留的、版本化的、仅 TLS 的存储库,带有 grantReadTo
      • component-version.ts GreengrassComponentVersion:上传工件并发布版本
      • deployment.ts GreengrassDeployment:部署、可选的事物组和 addComponent
      • next-version.ts NEXT_PATCH、NEXT_MINOR 和 NEXT_MAJOR 的部署时解析器
      • recipe.ts 在合成时读取配方和工件 URI 替换
    • 文件夹app/greengrass
      • pulse.ts Pulse,固定到此组件构建输出的 GreengrassComponentVersion

共享构造项目的 build 和 assemble 目标依赖于宿主项目的,因此基础设施构建或部署始终读取新的工件。

组件版本将构建的工件发布到明确拥有的存储库中。您的堆栈或根模块授予核心设备的令牌交换角色读取访问权限,并将版本添加到一个或多个部署中。默认的读取授权范围限定为工作区的组件命名空间;当角色的设备只需要这些组件的子集时,进一步缩小范围。

Loading the diagram…

infra = none

infra: none 仅创建配方、入口点、Python 测试、目标和共享脚本。不会创建或更改基础设施项目或共享构造。稍后使用 infra: component-version 重新运行以添加基础设施。重新运行无法将已经拥有基础设施的组件切换回 none。

在开发机器上构建工件:

Terminal window
pnpm nx run <project>:pulse-artifact

dist/<project-root>/greengrass/pulse/greengrass-build/ 下的输出包含带有已解析配方的 recipes/ 和带有存档的 artifacts/<ComponentName>/<ComponentVersion>/。Python 组件为每个清单构建一个存档,当它针对两个架构时命名为 <component>-<architecture>.zip。TypeScript 组件构建一个所有清单共享的存档;使用 ipc: true,它为每个架构携带 aws-crt 插件,每个清单的 Setenv 选择自己的。配方的工件 URI 中的 BUCKET_NAME、COMPONENT_NAME 和 COMPONENT_VERSION 占位符在发布时被替换,存档基本名称必须保持 Run 步骤解压缩到的名称。

接下来的两个目标在安装了经典 Greengrass 核心和 greengrass-cli 的机器上运行,而不是在普通工作站上:

Terminal window
pnpm nx run <project>:pulse-deploy-local
pnpm nx run <project>:pulse-logs

GREENGRASS_ROOT 默认为 /greengrass/v2。pulse-deploy-local 提交本地部署,然后轮询组件的生命周期状态,除非它在三次检查中保持 RUNNING 或 FINISHED,否则以非零退出。本地部署将该版本固定在设备上,并与稍后对不同版本的云部署冲突;请参阅本地和云部署。

infra = component-version

部署组合存在于您的基础设施项目中。正常流程是每个目标一个存储库、一个读取授权、每个组件一个应用包装器和一个部署。对现有的事物组或事物使用一个部署并设置其 targetArn;为不同的目标创建另一个部署。

如果工作区没有 CDK 应用程序,请创建一个:

运行此生成器@aws/nx-plugin:ts#infra

pnpm nx g @aws/nx-plugin:ts#infra --name=infra
构建你的命令5

必需

令牌交换角色和目标事物组已经存在于账户中:该角色是您的核心设备承担的角色,该组是它们注册的位置。堆栈通过 CloudFormation 参数导入两者。

packages/infra/src/stacks/application-stack.ts
import {
GreengrassArtifactBucket,
GreengrassDeployment,
Pulse,
} from '@my-scope/common-constructs';
import { CfnParameter, Stack, type StackProps } from 'aws-cdk-lib';
import { Role } from 'aws-cdk-lib/aws-iam';
import type { Construct } from 'constructs';
export class ApplicationStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const tokenExchangeRoleArn = new CfnParameter(
this,
'TokenExchangeRoleArn',
{ type: 'String' },
);
const thingGroupArn = new CfnParameter(this, 'ThingGroupArn', {
type: 'String',
});
// One explicitly owned repository, and the grant the devices need.
const artifacts = new GreengrassArtifactBucket(this, 'Artifacts');
const tokenExchangeRole = Role.fromRoleArn(
this,
'TokenExchangeRole',
tokenExchangeRoleArn.valueAsString,
);
artifacts.grantReadTo(tokenExchangeRole);
// The generated wrapper takes the repository construct itself.
const pulse = new Pulse(this, 'Pulse', { bucket: artifacts });
// addComponent records the resolved version and orders the deployment
// resource after the component version resource.
const fleet = new GreengrassDeployment(this, 'Fleet', {
targetArn: thingGroupArn.valueAsString,
});
fleet.addComponent(pulse);
}
}

同步项目引用,引导账户和区域一次,然后部署。deploy 目标在 ^assemble 之后在基础设施项目中运行 cdk deploy --require-approval=never,它首先重建组件工件。生成的 main.ts 将每个堆栈放在以项目命名的阶段中,@my-scope/infra 为 my-scope-infra-sandbox,因此 cdk deploy 需要该阶段的选择器。从 packages/infra/src/main.ts 获取阶段名称,并在 -- 之后与参数值一起传递 /**:

Terminal window
AWS_PROFILE=<profile> AWS_REGION=<region> pnpm nx sync
pnpm nx run @my-scope/infra:bootstrap
pnpm nx run @my-scope/infra:deploy -- 'my-scope-infra-sandbox/**' --parameters TokenExchangeRoleArn=<role-arn> --parameters ThingGroupArn=<thing-group-arn>

deploy 等待完全稳定并接受替换更新。deploy-sandbox 使用快速模式,除非您传递 --rollback,否则拒绝替换更新。对常规修订使用 deploy,或在使用 deploy-sandbox 时传递 --rollback。

fleet.addComponent(pulse) 是必需的,而不是装饰性的。使用固定的 ComponentVersion,部署的组件映射保存文字字符串,因此 CloudFormation 看不到部署和组件版本之间的依赖关系,并并行创建它们。然后 IoT 作业可以在版本存在之前到达设备,它们会失败并显示 FAILED_NO_STATE_CHANGE。使用 NEXT_PATCH,映射保存组件版本资源的 ComponentVersion 属性,如果原始 NEXT_* 字符串到达部署,合成会失败并显示命名 addComponent 的消息。

将第二个组件生成到同一个或另一个项目中,然后将两者添加到一个部署中。覆盖替换该组件条目的命名顶级字段;版本始终来自构造。

const pulse = new Pulse(this, 'Pulse', { bucket: artifacts });
const uploader = new Uploader(this, 'Uploader', { bucket: artifacts });
const cameras = new GreengrassDeployment(this, 'Cameras', {
thingGroupName: 'cameras',
});
cameras.addComponent(pulse);
cameras.addComponent(uploader, {
configurationUpdate: { merge: { uploadIntervalSeconds: 60 } },
});

thingGroupName 创建一个新的 AWS::IoT::ThingGroup。它不会注册设备;设备通过其配置过程加入组。对已经存在的组或事物使用 targetArn 或 thingName。

向两个部署注册相同的构造。每个部署都有自己的配置:

new GreengrassDeployment(this, 'WestFleet', {
thingGroupName: 'west-fleet',
}).addComponent(pulse);
new GreengrassDeployment(this, 'EastFleet', {
thingGroupName: 'east-fleet',
}).addComponent(pulse, {
configurationUpdate: { merge: { sampleIntervalSeconds: 60 } },
});

将相同的构造两次添加到一个部署是无操作的,除非第二次调用提供覆盖,这会更新条目。将同一组件名称下的不同构造添加到一个部署在构造时失败。

您未在此工作区中构建的组件进入 components 映射。已发布的公共组件不需要依赖项,因为它已经存在。在同一堆栈中创建的版本的原始条目,例如手写的 CfnComponentVersion,需要您从 addComponent 获得的排序边:

import { CfnComponentVersion } from 'aws-cdk-lib/aws-greengrassv2';
const fleet = new GreengrassDeployment(this, 'Fleet', {
targetArn: thingGroupArn.valueAsString,
components: {
// Published by AWS; pick a version from
// `aws greengrassv2 list-component-versions`.
'aws.greengrass.LogManager': {
componentVersion: '2.3.8',
configurationUpdate: {
merge: {
logsUploaderConfiguration: {
systemLogsConfiguration: { uploadToCloudWatch: 'true' },
},
},
},
},
// Created in this stack, so the deployment must wait for it.
'com.example.Handwritten': { componentVersion: '1.2.0' },
},
});
fleet.addComponent(pulse);
const handwritten = new CfnComponentVersion(this, 'Handwritten', {
inlineRecipe: handwrittenRecipe,
});
fleet.deployment.node.addDependency(handwritten);

configurationUpdate.merge 在这里是一个普通对象。构造将其序列化为 CloudFormation 期望的 JSON 字符串。

一个堆栈拥有存储库。每个其他堆栈按名称导入它,并在拥有堆栈中添加自己的授权,或将等效的 s3:GetObject 策略附加到令牌交换角色本身:

const artifacts = new GreengrassArtifactBucket(this, 'Artifacts', {
existingBucketName: 'central-greengrass-artifacts',
});
const pulse = new Pulse(this, 'Pulse', { bucket: artifacts });

导入的存储桶保留其自己的加密、版本控制和访问设置。解析器在 NEXT_* 版本的内容标识中包含存储桶名称,因此将组件移动到另一个存储库会为未更改的字节分配新版本。

完成的堆栈更新或应用证明部署资源存在。部署及其 IoT 作业都可以报告 SUCCEEDED,而设备上的组件是 BROKEN。在每次部署后检查设备和组件状态:

终端窗口
aws --profile <profile> --region <region> greengrassv2 get-core-device \
--core-device-thing-name <thing-name> --query status
aws --profile <profile> --region <region> greengrassv2 list-installed-components \
--core-device-thing-name <thing-name>

如果设备报告损坏状态,请使用 <component>-logs 检查进程日志。

使用默认的 ipc: false,main.py 每 30 秒记录一行,配方没有 IPC 访问控制。使用 ipc: true,它通过 GreengrassCoreIPCClientV2 每 30 秒向组件自己的本地主题发布心跳:

greengrass/pulse/main.py
client.publish_to_topic(
topic=TOPIC,
publish_message=PublishMessage(json_message=JsonMessage(message={"sequence": sequence})),
)

配方在 aws.greengrass.ipc.pubsub 下授予 <ComponentName>/heartbeat 上的 aws.greengrass#PublishToTopic。本地发布/订阅到达同一核心设备上的其他组件,而不是 AWS IoT Core。要发布到 AWS IoT Core,请调用 publish_to_iot_core,在配方中的 aws.greengrass.ipc.mqttproxy 下授予 aws.greengrass#PublishToIoTCore,并在设备的 IoT 策略中授予确切主题的 iot:Publish。

配方中的访问控制由设备上的核心强制执行。仅依赖 SDK 不授权任何内容,因此随着组件的增长扩大 operations 和 resources。

生成的配方针对经典的 aws.greengrass.Nucleus。Nucleus Lite 实现了 IPC 操作的子集,不运行插件组件,并且仅在 v2.15 中获得容器支持。根据您的车队运行的核心验证配方;生成器不检测核心功能。

在 Ubuntu 25.10 及更高版本上,sudo-rs 可以阻止 IPC 组件使用 Greengrass Nucleus 2.18.3 启动,因为 IPC 环境丢失。生成器不会更改主机的 sudo 安全配置。当需要 IPC 时,使用提供经典 sudo 行为的设备设置。

对于 CDK 部署,将 recipe.yaml 中的 ComponentVersion 设置为 NEXT_PATCH、NEXT_MINOR 或 NEXT_MAJOR,以要求插件的解析器从账户和区域中已发布的最高严格语义版本分配版本:

哨兵最高发布的 1.4.2 变为尚未发布任何内容
NEXT_PATCH1.4.31.0.0
NEXT_MINOR1.5.01.0.0
NEXT_MAJOR2.0.01.0.0

第一个版本是 1.0.0。当其内容标签匹配且版本可部署时,解析器重用最高发布的版本;否则它发布由哨兵选择的下一个版本。标签涵盖没有版本行的配方、工件字节和工件存储桶名称。因此,未更改的内容重用版本,而更改内容或存储桶会发布新版本。生成器永远不会重写 recipe.yaml。

NEXT_* 是 Nx 插件约定,而不是 Greengrass 版本。CDK 在部署期间解析哨兵,<project>:pulse-deploy-local 针对设备上可用的版本解析它。GDK 在 gdk-config.json 中使用 NEXT_PATCH 作为设置,而不是作为配方字段,并且不支持 NEXT_MINOR 或 NEXT_MAJOR。插件不调用 GDK。

Terraform 需要显式语义版本。每个更改的工件都需要一个新的 ComponentVersion,因为 Greengrass 版本是不可变的。Terraform 不解析 NEXT_*。

CDK 解析器在生成的 Lambda 执行角色下的 CloudFormation 部署期间运行,范围限定为堆栈的组件名称。不要为同一组件运行并发发布:部署可以选择相同的下一个版本,导致一个发布失败。

每个账户和区域使用一个工件存储库,由一个堆栈或根模块拥有。在 CDK 中使用 existingBucketName 或在 Terraform 中使用 existing_bucket_name 在其他地方导入它。生成的存储桶是版本化的、使用 SSE-S3 加密的、私有的,并且需要 TLS。Greengrass 工件不是 CDK 资产;cdk gc 可以删除组件版本仍然需要的资产。

两个 IaC 路径使用相同的 S3 对象键布局:<ComponentName>/<first 32 hex characters of sha256>/<file>。摘要对排序的工件名称及其完整的 SHA-256 哈希进行哈希,对一个或多个工件使用相同的公式。仅缩短键前缀;工件摘要和自动版本标识保留完整哈希。CDK 的存储桶部署标签将前缀限制为 102 个字符,为组件名称留下 68 个字符。当选择 CDK 基础设施时,生成器会检查该限制,合成会检查对配方的编辑。Terraform 的对象上传没有此 CDK 限制。

在部署或回滚可能需要其组件版本时,保持已发布的工件可用。CDK 默认保留替换的组件版本及其上传。Terraform 删除替换的版本和旧对象键;在提升多个组使用的版本之前,请参阅分阶段推出和保留版本。删除注册表版本不会从已在设备上运行的组件中卸载组件。Terraform 的存储库设置 prevent_destroy;仅在其工件不再需要后进行故意拆除时才删除该文字生命周期设置。

默认令牌交换角色授权允许工作区组件命名空间中的 s3:GetObject。对于更窄的授权,在 CDK 中设置 keyPrefix 或在 Terraform 中设置 token_exchange_key_prefix。导入的存储桶保留其自己的策略,因此在拥有存储桶或角色的地方管理授权。

更改组件版本或部署配置会替换部署资源。CloudFormation 允许在一个堆栈操作中添加或删除最多 10 个部署资源;将大型推出拆分为批次。对替换使用常规 deploy 目标。deploy-sandbox 使用 CloudFormation 快速模式,对于替换更新需要 --rollback。

删除部署资源会删除云管理状态,但不会从设备卸载组件。首先部署省略组件的修订,等待它从 list-installed-components 中消失,然后删除其 IaC 资源。

来自 <component>-deploy-local 的本地部署将组件版本固定在该设备上。请求不同版本的云部署无法满足固定。在从云更新该设备之前删除本地部署:

终端窗口
sudo /greengrass/v2/bin/greengrass-cli deployment create --remove com.example.Pulse

对开发设备使用本地部署,对车队目标使用云部署。

云部署后,检查 Greengrass 部署状态和组件的设备状态:

终端窗口
aws --profile <profile> --region <region> greengrassv2 get-core-device \
--core-device-thing-name <thing-name> --query status
aws --profile <profile> --region <region> greengrassv2 list-installed-components \
--core-device-thing-name <thing-name>

作业可以报告 SUCCEEDED,而组件是 BROKEN。使用 <component>-logs 检查其进程日志。Ubuntu 25.10 及更高版本上的 IPC 组件也可能在 Nucleus 2.18.3 下使用 sudo-rs 失败;生成器不会更改主机的安全设置。

Greengrass 将一个组件限制为每个区域 5,000 个版本,将 CreateComponentVersion 限制为每个区域每秒一个请求。配方限制为 16 KB,部署文档限制为事物组 31 KB 或单个事物 7 KB。避免使用新版本作为心跳,并将大型部署拆分为较小的批次。