news 2026/9/20 20:14:56

Floci 本地模拟 AWS Batch:从任务编排到 Docker 执行的控制面实现解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Floci 本地模拟 AWS Batch:从任务编排到 Docker 执行的控制面实现解析

Floci 本地模拟 AWS Batch:从任务编排到 Docker 执行的控制面实现解析

【免费下载链接】flociLight, fluffy, and always free - The AWS Local Emulator alternative项目地址: https://gitcode.com/gh_mirrors/fl/floci

Floci(Light, fluffy, and always free —— AWS Local Emulator)在本地实现了 AWS Batch 控制面(REST JSON 协议),支持计算环境、任务队列、任务定义与任务提交等核心编排能力,并可通过immediatedocker两种运行器模式完成本地契约测试或真实容器执行。本文以 docs/services/batch.md 为主线,结合 BatchService.java、BatchDockerRunner.java、BatchController.java 等源码与 BatchIntegrationTest.java 测试,带你掌握在 Floci 中配置与使用 AWS Batch 的完整实战方案,包括数组任务(Array Jobs)、多节点并行任务(MNP)、EventBridge 联动与 CloudFormation 资源供给。

Batch 服务的定位与端点约定

Floci 的 Batch 实现面向本地集成测试的控制面模拟:它完整保存队列、任务定义与任务的元数据,让 SDK 调用可以像连真实 AWS 一样完成"创建→提交→查询"的闭环,同时刻意简化为测试服务的调度语义(如 immediate 模式下的即时成功)。整体协议为REST JSON,默认端点前缀为http://localhost:4566/v1/...

在源码层面,所有端点由 BatchController.java 暴露,统一走一个handle模板方法:解析请求体(空请求体视为{}),通过 RegionResolver 解析请求区域,然后将异常映射为带X-Amzn-Errortype头的 AWS 风格错误响应(400ClientException、500ServerException)。这意味着你的客户端错误处理逻辑在本地与云端行为一致。

支持的操作(Supported Operations)

Batch 控制面共提供 12 个操作,均以POST调用,端点即 API 名小写化后的路径:

OperationEndpointDescription
CreateComputeEnvironmentPOST /v1/createcomputeenvironment存储本地计算环境并返回其 ARN
DescribeComputeEnvironmentsPOST /v1/describecomputeenvironments描述全部或选定的计算环境
UpdateComputeEnvironmentPOST /v1/updatecomputeenvironment更新计算环境的状态、服务角色与计算资源
DeleteComputeEnvironmentPOST /v1/deletecomputeenvironment删除处于DISABLED且未被任何任务队列引用的计算环境;删除不存在的环境为无操作(no-op)
CreateJobQueuePOST /v1/createjobqueue存储一个挂载到计算环境上的本地任务队列
UpdateJobQueuePOST /v1/updatejobqueue更新任务队列的状态、优先级与计算环境顺序
DeleteJobQueuePOST /v1/deletejobqueue删除处于DISABLED状态的任务队列;删除不存在的队列为无操作
DescribeJobQueuesPOST /v1/describejobqueues描述全部或选定的任务队列
RegisterJobDefinitionPOST /v1/registerjobdefinition注册带修订号(revision)的containermultinode任务定义
DeregisterJobDefinitionPOST /v1/deregisterjobdefinition将任务定义的某个修订标记为INACTIVE
DescribeJobDefinitionsPOST /v1/describejobdefinitions按名称、ARN、修订号与状态列出任务定义
SubmitJobPOST /v1/submitjob提交一个本地 Batch 任务
DescribeJobsPOST /v1/describejobs按任务 ID 描述任务
ListJobsPOST /v1/listjobs按队列、状态、AWSfilters与分页列出任务

控制面的校验与细节

从 BatchService.java 的实现可以看到一系列贴近 AWS 的契约细节:

  • 计算环境type仅接受MANAGED/UNMANAGEDstate仅接受ENABLED/DISABLED;创建后状态固定为VALIDUpdateComputeEnvironmentcomputeResources采用局部覆盖语义(只覆盖调用方传入的字段,如minvCpus/maxvCpus/desiredvCpus,不重置整个子对象)。删除前会校验状态为DISABLED且未被任何队列的computeEnvironmentOrder引用(BatchService.java)。
  • 任务队列priority为必填;computeEnvironmentOrder中的每个环境必须是VALID状态;删除ENABLED队列会报ClientException(BatchService.java)。
  • 任务定义修订:同名注册自动递增revision,ARN 形如arn:aws:batch:<region>:<account>:job-definition/<name>:<revision>DeregisterJobDefinition要求引用必须携带修订号(name:revision或 ARN),仅按名称引用会返回 400;按名称提交时解析为最新 ACTIVE 修订(BatchService.java),BatchIntegrationTest.java 完整验证了修订递增、注销与"名称→最新修订"解析行为。
  • 通用校验:标签最多 50 个、键 1-128 字符且不能以aws:开头、值最多 256 字符;环境变量名不能以AWS_BATCH开头;timeout.attemptDurationSeconds最少 60 秒;retryStrategy.attempts取值范围 1-10;jobName需匹配[A-Za-z0-9][A-Za-z0-9_-]{0,127}

运行器模式(Runner Modes)

Batch 的运行模式由配置项floci.services.batch.runner-mode(环境变量FLOCI_SERVICES_BATCH_RUNNER_MODE)控制,在 EmulatorConfig.java 中定义,默认值为immediate

行为
immediate默认值SubmitJob持久化任务、记录生命周期时间戳、生成一个成功 attempt,并在任务变为SUCCEEDED后返回。
docker每个 attempt 从任务定义镜像启动一个 Docker 容器,传入解析后的 command 与环境变量,将MEMORY资源需求应用为容器内存上限,捕获 CloudWatch Logs 日志流名称,并根据容器退出码置为SUCCEEDEDFAILED。超时任务直接失败且不重试,与 AWS Batch 的超时行为一致。

process模式未实现。

immediate模式下,运行循环仍然驱动任务完整经历状态机:PENDING → RUNNABLE → STARTING → RUNNING,随后生成退出码为 0 的 attempt(BatchService.java)。在docker模式下,则调用 BatchDockerRunner.java 执行真实容器。

Docker 运行器的实现细节

BatchDockerRunner.java 是 docker 模式的核心执行引擎,关键行为包括:

  • 容器构建:通过ContainerBuilder构建容器,自动附加host.docker.internal(或 Floci 内置 DNS 后缀)以访问宿主机上的 Floci 端点、嵌入 DNS、日志轮转与资源标签;command 为空时不传入 CMD。
  • 内置 AWS 环境:每个容器注入AWS_REGIONAWS_ACCESS_KEY_ID=testAWS_SECRET_ACCESS_KEY=testAWS_SESSION_TOKEN=testFLOCI_ENDPOINT/AWS_ENDPOINT_URL(指向 Floci 自身端口)、AWS_BATCH_JOB_IDAWS_BATCH_JOB_ATTEMPTAWS_BATCH_JQ_NAMEAWS_BATCH_CE_NAME=local(BatchDockerRunner.java)。
  • 内存限制:遍历resourceRequirements,仅将type == "MEMORY"的需求解析为withMemoryMb应用;非法数值会被忽略并告警。
  • 超时timeout.attemptDurationSeconds转换为容器等待期限,超时返回退出码 137、reason"Job timed out"且标记timedOut=true,从而驱动失败且不重试(BatchDockerRunner.java)。
  • 优雅清理:运行中的容器记录在inFlightContainers映射中,模拟器关闭(SIGTERM)时通过stopManagedContainers()回收,避免中途退出导致孤儿容器。

提交行为(Submit Behavior)

SubmitJob支持的字段如下:

  • jobName
  • jobDefinition
  • jobQueue
  • parameters
  • containerOverrides.command
  • containerOverrides.environment
  • arrayProperties.size(数组任务)
  • nodeOverrides.numNodesnodeOverrides.nodePropertyOverrides(多节点并行任务)
  • timeout.attemptDurationSeconds
  • retryStrategy.attempts
  • tags

关键合并与解析规则:

  • 命令替换containerOverrides.command覆盖任务定义中的 command;命令条目中的Ref::inputKey形式会在执行前从合并后的参数映射中解析为实际值(BatchService.java)。
  • 环境合并:提交时的环境变量覆盖(overrides)逐键合并到任务定义环境变量之上(definition 为底、overrides 为顶)。
  • 不支持dependsOn:任务依赖未实现,提交时传入dependsOn会直接抛ClientException(BatchService.java)。

任务在本地的状态流转为:

SUBMITTED -> PENDING -> RUNNABLE -> STARTING -> RUNNING -> SUCCEEDED|FAILED

immediate 模式下每个任务强制经过PENDING是本地为测试做的简化——AWS 在无依赖、无容量等待时可能跳过该状态。集成测试 BatchIntegrationTest.java 验证了Ref::命令解析(payloads/input.json等实际入参被注入 command)、环境覆盖生效、attempt 记录退出码 0 等完整链路。

重试与超时语义

retryStrategy.attemptstimeout.attemptDurationSeconds均可由任务定义提供、SubmitJob 覆盖(treeOrDefault语义)。每次失败 attempt 后,任务回到RUNNABLE并标记"Attempt failed; retrying";只有当 attempt 超时、达到最大尝试次数或退出码为 0 时才终态化(BatchService.java)。多节点任务的重试判定则完全由主节点结果驱动(见下文)。

数组任务(Array Jobs)

通过arrayProperties.size(取值范围2-10,000)提交即产生数组任务:

  • 扇出模型:每个索引生成一个子任务(child),共享父任务名称,走与普通任务相同的执行管线;在docker模式下每个子任务拥有独立容器。
  • 实时聚合:父任务的statusarrayProperties.statusSummary并非增量存储,而是在每次DescribeJobs/ListJobs调用时实时从子任务聚合计算arrayRollup方法,BatchService.java),因此大量子任务并发完成时不存在状态竞态。
  • 聚合规则:任一子任务FAILED则父任务FAILED;全部子任务SUCCEEDED则父任务SUCCEEDED;否则按是否有子任务已离开SUBMITTED状态在PENDING/SUBMITTED之间选择;startedAt取子任务最小值,stoppedAt取最大值。
  • 列表视图:队列级ListJobs对每个数组任务只显示一条记录(父任务);传入arrayJobId可列出子任务(每个子任务附带arrayProperties.index)。
  • 原子写入:父任务与全部子任务在同一把锁内一次性写入,读取方永远不会看到"半成品"数组(BatchService.java)。

由于TerminateJob/CancelJob均未实现,数组任务的级联取消不适用(见 Limitations)。

多节点并行任务(Multi-node Parallel, MNP)

注册"type": "multinode"且带nodePropertiesnumNodesmainNodenodeRangeProperties)的任务定义即为 MNP 任务定义;对其SubmitJob(可带nodeOverrides)的行为:

  • 并发执行docker模式下每个节点并发启动一个容器,并注入AWS_BATCH_JOB_NODE_INDEXAWS_BATCH_JOB_MAIN_NODE_INDEXAWS_BATCH_JOB_NUM_NODES三个节点环境变量(BatchDockerRunner.java)。
  • 主节点裁决:任务的最终状态、重试决策与startedAt/stoppedAt/statusReason完全由**主节点(main node)**决定——与 AWS 一致,从节点失败不会导致任务失败或重试(BatchService.java)。
  • 节点范围解析nodeRangePropertiestargetNodes支持"0:3"":3"(起点 0)、"4:"(到末节点)或裸索引;多个范围覆盖同一索引时按提交顺序最后一个覆盖生效(对齐 AWS 的 "nested ranges override");注册时强制要求所有节点索引被完整覆盖(BatchService.java)。
  • numNodes 覆盖nodeOverrides.numNodes允许扩缩节点数,但要求任务定义中存在开放区间(如"n:"),且新节点数必须大于mainNode索引。
  • 描述视图DescribeJobs与队列级ListJobs返回整个任务一条记录(带nodeProperties、无 per-nodecontainer);传入multiNodeJobId调用ListJobs则按节点拆分,每个节点带自己的containernodeProperties.nodeIndex
  • 约束:MNP 任务定义不支持containerOverrides与数组任务,请改用nodeOverrides(BatchService.java)。

与 EventBridge 联动

指向 Batch 任务队列的 EventBridge 规则目标可携带:

{ "BatchParameters": { "JobDefinition": "my-job:1", "JobName": "nightly-job", "ArrayProperties": {"Size": 2}, "RetryStrategy": {"Attempts": 2} } }

规则触发时,Floci 通过submitFromEventBridge向目标队列提交一个等价 Batch 任务(BatchService.java):

  • 若目标负载包含根级Parameters对象,其键值对会被字符串化并作为 Batch 提交参数传入;扁平负载字段不会被转换为 Batch 参数
  • RetryStrategy.Attempts被映射为提交请求的retryStrategy.attempts
  • ArrayProperties会作为目标元数据被接受与回显(用于本地部署兼容),但 Batch 仍只提交一个本地任务,不会扇出数组子任务——只有直接调用SubmitJob才能触发数组/MNP 展开(见 Limitations)。

CloudFormation 资源供给

Floci 为 Batch 提供以下 CloudFormation 资源类型的本地供给:

  • AWS::Batch::ComputeEnvironment
  • AWS::Batch::JobQueue
  • AWS::Batch::JobDefinition

IAM 角色、VPC 字段、Fargate 声明、日志配置、存储与资源需求均作为元数据接受。docker 模式会把MEMORY需求应用为容器内存上限;但本地调度不模拟AWS 的容量、VCPU 分配与 VPC 网络。注意:CloudFormation 的AWS::Batch::JobDefinition供给器只注册container类型任务定义,multinode任务定义只能通过直接调用RegisterJobDefinition供给(见 Limitations)。

配置项(Configuration)

Batch 的完整配置项如下(源码定义于 EmulatorConfig.java):

变量默认值描述
FLOCI_SERVICES_BATCH_ENABLEDtrue启用或禁用 Batch 服务
FLOCI_SERVICES_BATCH_RUNNER_MODEimmediate运行器模式:immediatedocker
FLOCI_SERVICES_BATCH_DOCKER_NETWORK(未设置)Batch 容器使用的 Docker 网络
FLOCI_STORAGE_SERVICES_BATCH_MODE(继承全局)可选的存储模式覆盖
FLOCI_STORAGE_SERVICES_BATCH_FLUSH_INTERVAL_MS5000持久化存储的刷盘间隔(毫秒)

对应 YAML 配置方式(application.yml)可写作:

floci: services: batch: enabled: true runner-mode: immediate # 或 docker docker-network: my-batch-net storage: services: batch: mode: file flush-interval-ms: 5000

存储实现

Batch 的状态持久化由 BatchService.java 中的StorageFactory完成,共四个存储后端:

  • batch-job-definitions.json:任务定义(按 ARN 索引)
  • batch-job-queues.json:任务队列
  • batch-compute-environments.json:计算环境
  • batch-jobs.json:任务(按 jobId 索引)

当存储后端为AccountAwareStorageBackend时,任务的读写按账号(accountId)隔离(getForAccount/putForAccount),多账号测试场景下互不串扰。

限制(Limitations)

当前实现的边界(与文档一致,均可在源码中印证):

  • 无 IAM 强制:不校验任何 IAM 权限。
  • 无 VPC/子网/安全组模拟
  • 无 AWS 忠实容量调度:不模拟容量、VCPU 分配。
  • 无任务依赖(dependsOn:提交即报错。
  • CancelJobTerminateJob未实现:普通任务、数组子任务、MNP 节点均无法取消/终止——这是与普通任务相同的既有缺口,并非数组/MNP 引入的新问题。
  • EventBridge input transformers:走既有 EventBridge 目标输入路径,Batch 专属的 input-transformer 完全对等未实现。
  • MNP 结束时机差异:AWS 在主节点退出时立即停止整个任务(含剩余节点);Floci 会等待每个节点容器都退出后才评定该 attempt,因此存活时间超过主节点的从节点会让任务保持RUNNING更久。关闭这一差异需要BatchDockerRunner具备从节点自身运行循环外部停止其容器的能力(当前不存在)。

数组/MNP 表面的已知后续项(不影响SubmitJob/DescribeJobs/ListJobs的正确性,刻意延后):

  • submitFromEventBridge不转发规则目标BatchParameters中的arrayProperties/nodeOverrides(虽然ArrayProperties作为目标元数据被接受并回显):EventBridge 触发的 Batch 任务今天无法扇出数组或运行 MNP,只有直接SubmitJob可以。
  • CloudFormation 的AWS::Batch::JobDefinition供给器只注册container类型,无法通过 CloudFormation 供给multinode任务定义。
  • ListJobs使用arrayJobId时忽略filters参数(仅jobStatus对子任务生效)——与 AWS 自身"filters 不适用于子任务"的说明一致,但代价是数组子任务无法按JOB_NAME/JOB_DEFINITION等过滤。
  • ListJobs使用multiNodeJobId时无分页(maxResults/nextToken无效),始终在一次响应中返回全部节点。

实践建议

  1. 契约测试首选immediate模式:无需 Docker 环境即可完成"注册定义→提交→描述/列出"全链路,毫秒级返回,BatchIntegrationTest.java 展示了这类测试的典型写法。
  2. 需要真实执行则切换docker模式:任务会在独立容器中真实运行,借助注入的AWS_ENDPOINT_URL可访问 Floci 上其他模拟服务,适合端到端验证;记得为 Batch 容器规划 Docker 网络与镜像拉取策略。
  3. 用数组/MNP 覆盖并行场景:数组任务适合参数化扇出(2-10,000),MNP 适合多节点协同(主节点裁决);注意 EventBridge 触发的任务暂不支持这两者。
  4. 关注超时与重试timeout.attemptDurationSeconds最小 60 秒、retryStrategy.attempts最大 10,docker 模式超时任务以 137 退出且不重试。

参考文件索引

  • 服务文档:docs/services/batch.md
  • HTTP 端点层:BatchController.java
  • 控制面核心逻辑:BatchService.java
  • Docker 执行器:BatchDockerRunner.java
  • 配置定义:EmulatorConfig.java
  • 集成测试:BatchIntegrationTest.java、BatchServiceTest.java、BatchDockerRunnerTest.java

【免费下载链接】flociLight, fluffy, and always free - The AWS Local Emulator alternative项目地址: https://gitcode.com/gh_mirrors/fl/floci

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 20:11:28

DeviceNet从站转SPI调试实战:梳理链路、排查故障、选型网关

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 20:11:27

GetQzonehistory:QQ空间历史说说全量备份与Excel导出完整指南

GetQzonehistory&#xff1a;QQ空间历史说说全量备份与Excel导出完整指南 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 十年前的说说&#xff0c;为什么需要一份档案副本 你翻手机相…

作者头像 李华
网站建设 2026/9/20 20:11:01

猫抓扩展使用教程:如何嗅探网页视频并下载到本地

猫抓扩展使用教程&#xff1a;如何嗅探网页视频并下载到本地 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 猫抓&#xff08;Cat-Catch&#xff0…

作者头像 李华
网站建设 2026/9/20 20:10:37

Dijkstra算法详解:从图论原理到C++课程设计实战与答辩指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 20:05:44

Rocky Linux 部署 Hermes Agent 与 Web-UI 完整实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华