news 2026/9/20 15:24:18

Floci 中 ECS(Elastic Container Service)本地仿真完整指南:任务、服务、FireLens 与安全配置

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Floci 中 ECS(Elastic Container Service)本地仿真完整指南:任务、服务、FireLens 与安全配置

【免费下载链接】floci

Light, fluffy, and always free - The AWS Local Emulator alternative

项目地址:https://gitcode.com/gh_mirrors/fl/floci
点击查看免费下载

Floci 是一款轻量、免费的开源 AWS 本地仿真器(AWS Local Emulator)。本文以 Floci 内置的 ECS 仿真能力为主线,系统讲解其 JSON 1.1 协议接入方式、集群/任务定义/任务/服务等全量操作面、Docker 与 Mock 两种运行模式、FireLens 日志路由的底层实现,以及 host 卷、EFS 卷等安全与存储配置,并结合仓库源码给出可验证的实现依据。读完本文,你将能够基于 Floci 在本机完整走通「创建集群 → 注册任务定义 → 运行任务 → 创建服务 → 消费事件」的 ECS 开发/测试闭环,并理解其与真实 AWS 的行为差异。

协议与接入方式

ECS 服务在 Floci 中遵循 AWS 的 JSON 1.1 协议:

  • Protocol:JSON 1.1
  • EndpointPOST /+ 请求头X-Amz-Target: AmazonEC2ContainerServiceV20141113.<Action>

也就是说,任何 AWS SDK 或 CLI 只要把 endpoint 指向 Floci(默认端口4566),并把目标操作名替换成AmazonEC2ContainerServiceV20141113前缀下的对应 Action,就能像调用真实 ECS 一样工作。请求分发与参数解析由 EcsJsonHandler.java 完成,它根据X-Amz-Target头解析出 Action 并路由到 EcsService.java 中的对应方法。

从源码结构看,ECS 仿真覆盖了完整的资源模型:集群(EcsCluster)、任务定义(TaskDefinition)、任务(EcsTask)、服务(EcsServiceModel)、任务集(TaskSet)、容器实例(ContainerInstance)、容量提供方(CapacityProvider)、服务部署与修订(ServiceDeployment/ServiceRevision),以及标签、账号设置、Agent 回调等附属能力,模型类集中在 ecs/model 目录下。

核心运行模式有两种:默认配置下任务以真实 Docker 容器方式运行;设置mock: true(测试中自动启用)后任务以进程内桩方式运行,不依赖 Docker。

支持的操作面

集群(Clusters)

操作说明
CreateCluster创建集群(幂等)
DescribeClusters描述一个或多个集群
ListClusters列出集群 ARN
UpdateCluster更新集群设置
UpdateClusterSettings更新containerInsights等设置
PutClusterCapacityProviders为集群关联容量提供方
DeleteCluster删除空集群

对应的服务端实现见 EcsService.java 中的createClusterupdateClusterputClusterCapacityProvidersdeleteCluster等方法,集群状态字段(statusregisteredContainerInstancesCountrunningTasksCountactiveServicesCount等)由 EcsCluster.java 承载。

任务定义(Task Definitions)

操作说明
RegisterTaskDefinition注册任务定义的新修订版
DescribeTaskDefinitionfamily:revision或 ARN 描述任务定义
ListTaskDefinitions列出任务定义 ARN
ListTaskDefinitionFamilies列出任务定义 family 名称
DeregisterTaskDefinition将某修订版标记为INACTIVE
DeleteTaskDefinitions删除一个或多个任务定义

两个值得注意的兼容性设计:

  • runtimePlatform与容器的logConfiguration原样存储并按原样返回,因此像 Terraform 这类「读回自己写入内容做漂移校验」的客户端不会看到差异。runtimePlatform不影响本地任务的运行位置——Floci 始终以宿主机自身架构启动任务。
  • firelensConfiguration同样原样存储与返回,RegisterTaskDefinition会拒绝缺失或不受支持的type(仅接受fluentdfluentbit),详见下文 FireLens 专节。

volumesFrom条目也被存储并返回;在 Docker 模式下,源容器会先于消费方启动,其声明的卷按请求的只读/读写模式被继承,启动顺序同时尊重 FireLens 路由器的依赖关系,涉及卷继承与日志路由的循环依赖会在容器启动前被拒绝。相关实现位于 EcsContainerManager.java 的orderForDependencieslaunchOrder逻辑,并有 EcsJsonHandlerVolumesFromTest.java 等测试覆盖。

任务(Tasks)

操作说明
RunTask启动一个或多个任务实例
StartTask在指定容器实例上启动任务
StopTask停止运行中的任务
DescribeTasks描述一个或多个任务
ListTasks列出任务 ARN(可按集群、family、服务、状态过滤)
UpdateTaskProtection设置任务的缩容保护
GetTaskProtection获取当前任务保护状态

任务的生命周期模型只占据PENDINGRUNNINGSTOPPED三个状态,但通过事件发布器在 EventBridge 上合成完整的 AWS 阶段阶梯(见下文事件专节)。

服务(Services)

操作说明
CreateService创建长期运行的服务
UpdateService更新期望实例数、任务定义或部署配置
DeleteService删除服务(支持force
DescribeServices描述一个或多个服务(含deployments,见下)
ListServices列出集群中的服务 ARN
ListServicesByNamespace按 Cloud Map 命名空间过滤服务

CreateService时 Floci 会记录并回显deploymentControllerschedulingStrategyavailabilityZoneRebalancing(AWS 在创建时默认ECS/REPLICA/ENABLED),模型见 EcsServiceModel.java。

服务部署(Service deployments)

处于ACTIVE状态的服务在services[].deployments恰好报告一条PRIMARY记录,它是根据服务当前状态合成的,而不是跟踪一次真实滚动发布。这正是 AWS 的ServicesStablewaiter 所接受的形式,因此aws ecs wait services-stable、SDK 内置 waiter 以及 Terraform 的aws_ecs_service都能正常收敛。已删除(INACTIVE)的服务返回空列表。

  • rolloutStaterunningCount达到desiredCount时为COMPLETED,之前为IN_PROGRESS
  • 部署id由服务 ARN 与任务定义派生,因此跨调用、跨重启稳定,任务定义变更时滚动更新。
  • createdAt跟踪的是部署而非服务:它是服务的创建时间,直到任务定义变更开启新部署,此后随新部署移动。

已知与 AWS 的差异:

  • 永远不会出现与PRIMARY并存的第二个ACTIVE排水部署。运行中的任务确实会滚动到新任务定义(先启动新修订版的替换任务,间隔一个 reconciler tick 再排空旧任务),但deployments列表始终只报告单条PRIMARY
  • 每个服务都会报告deployments。AWS 对使用CODE_DEPLOYEXTERNAL部署控制器的服务会省略该字段,Floci 无论控制器类型如何都会合成deployments列表。
  • DAEMON调度策略为每个ACTIVE容器实例恰好运行一个任务,并据此推导desiredCount;与 AWS 一致,Fargate 启动类型以及CODE_DEPLOY/EXTERNAL控制器会拒绝该策略。放置约束不会被评估。
  • pendingCount恒为0,与顶层服务字段一致。
  • forceNewDeployment(任务定义未变化时)会铸造新的部署id并滚动运行中的任务:新部署的替换任务先启动,一个 reconciler tick 后排空旧部署任务;deployments列表全程仍只报告单条PRIMARY
  • updatedAt等于createdAt。AWS 会在滚动推进中更新它,而 Floci 没有中间滚动状态可报告。

上述行为在 EcsDescribeServicesIntegrationTest.java 中有直接断言(如deployments[0].status == "PRIMARY"rolloutState == "COMPLETED"及其 reason),并在 EcsServiceRolloutTest.java、EcsServiceDaemonSchedulingTest.java 中验证滚动与 DAEMON 调度。

ECS EventBridge 事件

Floci 将 AWS 形状的生命周期事件发布到默认EventBridge 总线(source: aws.ecs)。匹配aws.ecs的规则会从 ECS 活动中触发,Docker 与 mock 两种模式均生效。发布逻辑见 EcsEventPublisher.java。

detail-type触发时机关键detail字段
ECS Task State Change任务启动或停止lastStatusdesiredStatustaskDefinitionArngroupstartedBystoppedReasoncontainers[].exitCode
ECS Deployment State Change服务部署启动、进行中或达到稳态eventType(恒为INFO)、eventNamedeploymentId

eventName取值为SERVICE_DEPLOYMENT_STARTEDSERVICE_DEPLOYMENT_IN_PROGRESSSERVICE_DEPLOYMENT_COMPLETED

已知与 AWS 的差异:

  • 任务阶段阶梯是合成的。Floci 的任务模型只占据PENDINGRUNNINGSTOPPED,但启动时依次发出PROVISIONING -> PENDING -> ACTIVATING -> RUNNING,停止时依次发出DEACTIVATING -> STOPPING -> DEPROVISIONING -> STOPPED,每个阶段一条ECS Task State Change,因此按detail.lastStatus过滤的规则行为与 AWS 一致。源码中START_LADDER/STOP_LADDER常量在 EcsEventPublisher.java,且合成过程基于任务快照而非共享实例,避免并发DescribeTasks观察到任务从未真正占据的中间状态。
  • SERVICE_DEPLOYMENT_FAILED与部署熔断器(circuit breaker)不会被发出。
  • SubmitTaskStateChange/SubmitContainerStateChange保持纯 ACK;Floci 自己驱动任务生命周期,而非依赖 agent 提交。

相关测试见 EcsEventBridgeIntegrationTest.java 与 EcsEventPublisherTest.java。

未知服务(Unknown services)

解析不到的服务引用会出现在failures中,reason: MISSING,并携带该服务本应拥有的 ARN,而不是从响应中丢弃。因此DescribeServices返回部分结果而非报错(与 AWS 一致),aws ecs wait services-stable作用于不存在的服务时会立即失败,而不是轮询到超时。以 ARN 形式提供的引用会被原样回显。

任务集(Task Sets)

操作说明
CreateTaskSet在服务内创建任务集
UpdateTaskSet更新任务集的规模
DeleteTaskSet删除任务集
DescribeTaskSets描述服务的任务集
UpdateServicePrimaryTaskSet将任务集提升为主任务集

容器实例(Container Instances)

操作说明
RegisterContainerInstance向集群注册容器实例
DeregisterContainerInstance注销容器实例
DescribeContainerInstances描述容器实例
ListContainerInstances列出容器实例 ARN
UpdateContainerAgent触发 agent 更新(桩)
UpdateContainerInstancesState排空或激活容器实例

容量提供方(Capacity Providers)

操作说明
CreateCapacityProvider创建自定义容量提供方
UpdateCapacityProvider更新容量提供方
DeleteCapacityProvider删除容量提供方
DescribeCapacityProviders描述容量提供方(含 FARGATE 内置项)

服务部署与修订(Service Deployments & Revisions)

操作说明
DescribeServiceDeployments描述服务部署
ListServiceDeployments列出服务部署 ARN
DescribeServiceRevisions描述服务修订

标签(Tags)

操作说明
TagResource为集群、服务、任务或任务定义添加标签
UntagResource移除资源标签
ListTagsForResource列出资源标签

账号设置与属性(Account Settings & Attributes)

操作说明
PutAccountSetting为调用用户设置账号级设置
PutAccountSettingDefault设置默认账号级设置
DeleteAccountSetting删除账号设置
ListAccountSettings列出账号设置
PutAttributes在资源上设置自定义键值属性
DeleteAttributes移除资源属性
ListAttributes列出带指定属性的资源

Agent / 状态变更桩(Agent / State Change Stubs)

操作说明
SubmitTaskStateChangeAgent 回调桩
SubmitContainerStateChangeAgent 回调桩
SubmitAttachmentStateChangesAgent 回调桩
DiscoverPollEndpoint返回 agent 轮询端点

配置

Docker 后端的awsvpc任务会获得一个仿真的 ENI,并且在FLOCI_NETWORK_SECURITY_GROUP_ENFORCEMENT_ENABLED=true时,任务内所有容器共享一个受保护的网络命名空间。没有显式安全组的任务使用其子网 VPC 的默认安全组;同一任务内的容器可以通过 localhost 互相通信。bridge 与 host 网络模式不附加任务级awsvpc安全组。Mock 模式只报告控制面状态,不执行包过滤。安全组强制相关实现见 EcsContainerManager.java 的prepareNetworkSecurityGroupFirewallManager,并有 EcsContainerManagerSecurityGroupTest.java 覆盖。

变量默认值说明
FLOCI_SERVICES_ECS_ENABLEDtrue启用或禁用 ECS 服务
FLOCI_SERVICES_ECS_MOCKfalse跳过 Docker;任务直接进入RUNNING(适合 CI)
FLOCI_SERVICES_ECS_DOCKER_NETWORK(未设置)任务容器使用的 Docker 网络
FLOCI_SERVICES_ECS_DEFAULT_MEMORY_MB512任务定义未提供内存时的默认内存(MB)
FLOCI_SERVICES_ECS_DEFAULT_CPU_UNITS256任务定义未提供 CPU 时的默认 CPU 单位
FLOCI_SERVICES_ECS_HOST_VOLUME_ROOTS(未设置)host 卷绑定挂载(volumes[].host.sourcePath)的受批准父目录
FLOCI_SERVICES_ECS_ALLOW_UNSAFE_HOST_VOLUMESfalse允许任意 host 路径,绕过HOST_VOLUME_ROOTS白名单;路径穿越、裸根目录与 Docker socket 仍始终被拒绝

上述默认值在 EmulatorConfig.java 的EcsServiceConfig接口中有明确声明(enabled默认truemock默认falsedefaultMemoryMb默认512defaultCpuUnits默认256allowUnsafeHostVolumes默认false)。

host 卷安全(Host volume safety)

任务定义中的volumes[].host.sourcePath是调用方控制的文件系统路径,Floci 会将其直接绑定挂载进启动的容器,因此RegisterTaskDefinitionRunTask时实际绑定挂载这两个时机都会校验它(第二次检查缩小了校验与挂载之间的窗口,同时覆盖了本策略出现之前注册的任务定义)。核心实现见 HostVolumePolicy.java,它被EcsJsonHandler(注册时校验一次)与EcsContainerManager(每次绑定挂载前再次校验)共享。

无论何种配置,以下路径始终被拒绝

  • 相对路径,以及任何包含..段的路径。
  • 裸文件系统根目录(/)。
  • Docker daemon socket 及任何包含它的目录(如/var/run/run/var),包括通过符号链接解析到这些路径之一的情况。受保护的 socket 是 Floci 自身 Docker 客户端连接的那个,解析方式与客户端一致:floci.docker.docker-hostDOCKER_HOST→ 当前激活的 Docker context(Colima、OrbStack、Rancher Desktop、Podman)→/var/run/docker.sock。常规位置/var/run/docker.sock/run/docker.sock始终受保护。

从源码看,socket 候选集合还包含 Docker Desktop 的按用户 rootless socket(~/.docker/run/docker.sock),并且只有unix://端点才命名文件系统路径(tcp://与 Windows 命名管道没有可暴露的文件路径),见 HostVolumePolicy.java。

默认情况下,不做任何配置时每个 hostsourcePath都会被拒绝。必须显式选择以下方式之一:

  • FLOCI_SERVICES_ECS_HOST_VOLUME_ROOTS:逗号分隔的受批准父目录白名单。sourcePath必须(含符号链接解析后)位于其中一个目录之下:

    services: floci: image: floci/floci:latest environment: FLOCI_SERVICES_ECS_HOST_VOLUME_ROOTS: /srv/floci/volumes,/data
  • FLOCI_SERVICES_ECS_ALLOW_UNSAFE_HOST_VOLUMES=true:允许任意 host 路径(适用于本地开发时任何 host 路径都应可挂载的场景)。上述穿越、裸根与 Docker socket 拦截不会被该开关绕过。

被拒绝的sourcePath会使RegisterTaskDefinitionInvalidParameterException失败;若在RunTask时才被再次捕获(例如策略出现前注册的任务定义),任务会以该消息作为stoppedReason停止。命名的 Docker 卷、EFS 卷以及没有sourcePath的 host 卷(临时、容器本地存储)不受这些检查影响。相关实现证据也可在HostVolumePolicy.validate()的异常路径(相对路径、..段、裸根、socket、白名单外)中逐一对应。

EFS 卷所有权(EFS volume ownership)

任务的efsVolumeConfiguration卷由共享的本地 Docker 卷支撑(Floci 无法挂载真实的 EFS 文件系统)。Docker 命名卷以root:root 0755创建,因此以非 rootUSER运行镜像的任务无法写入。要模拟 EFS access point 的RootDirectory.CreationInfoPosixUser,可配置floci.storage.efs.*(全部为可选启用;默认是普通命名卷,现有行为不变):

Key(floci.storage.efs.EnvAWS 等价物说明
owner-uidFLOCI_STORAGE_EFS_OWNER_UIDCreationInfo.OwnerUid卷根的所有者 uid(须与owner-gid同时设置)
owner-gidFLOCI_STORAGE_EFS_OWNER_GIDCreationInfo.OwnerGid卷根的所有者 gid(须与owner-uid同时设置)
root-permissionsFLOCI_STORAGE_EFS_ROOT_PERMISSIONSCreationInfo.Permissions3-4 位八进制数字,如0777,或用2775表达 setgid 位
mount-userFLOCI_STORAGE_EFS_MOUNT_USERPosixUser {Uid,Gid}uid[:gid]运行挂载容器
mount-group-addFLOCI_STORAGE_EFS_MOUNT_GROUP_ADDPosixUser补充组追加到挂载容器的补充 gid
init-imageFLOCI_STORAGE_EFS_INIT_IMAGE用于对卷根执行一次性chown/chmod的镜像(默认busybox:stable

owner-uidowner-gid必须同时设置(AWS 上部分的CreationInfo也是非法的)。卷根按卷只初始化一次;setgid 位应通过 4 位root-permissions(如2775)表达,以便子目录继承所有者 gid。EFS 卷挂载的 Docker 集成测试见 EcsContainerManagerEfsIsolationDockerIntegrationTest.java。

Mock 模式

设置FLOCI_SERVICES_ECS_MOCK=true可在无 Docker 环境下运行。此模式下任务跳过容器启动,立即进入RUNNING,停止时再进入STOPPED。这是单元/集成测试与 Docker-in-Docker 不可用的 CI 流水线的推荐模式。

# docker-compose.yml — CI / test environment services: floci: image: floci/floci:latest environment: FLOCI_SERVICES_ECS_MOCK: "true"
# docker-compose.yml — local development (real containers) services: floci: image: floci/floci:latest volumes: - /var/run/docker.sock:/var/run/docker.sock environment: FLOCI_SERVICES_ECS_MOCK: "false" FLOCI_SERVICES_ECS_DOCKER_NETWORK: my_network

Docker socket 要求

mock: false(默认)时,ECS 会启动真实 Docker 容器并需要 Docker socket。挂载它并设置网络,使容器之间可以互相访问。私有 registry 认证及其他 Docker 设置参见 Docker Configuration。

services: floci: image: floci/floci:latest volumes: - /var/run/docker.sock:/var/run/docker.sock environment: FLOCI_SERVICES_ECS_DOCKER_NETWORK: aws-local_default

FireLens 日志路由的源码级剖析

FireLens 是本文档中技术密度最高的部分,其生成逻辑集中在 FirelensConfigGenerator.java,启动编排在 EcsContainerManager.java 的startTask中完成,相关测试包括 EcsJsonHandlerFirelensTest.java、EcsContainerManagerFirelensTest.java、EcsContainerManagerFirelensDockerIntegrationTest.java 与 FirelensConfigGeneratorTest.java。

注册期校验

  • firelensConfiguration原样存储与返回;RegisterTaskDefinition拒绝缺失或不受支持的type(仅fluentdfluentbit)。
  • 使用awsfirelens的任务必须恰好命名一个路由器:带两个 FireLens 路由器、或路由器发布了24224端口(FirelensConfigGenerator.FORWARD_PORT)的任务定义会在启动时被拒绝。

启动期动作

对于fluentbitfluentdFireLens 容器,Floci 会在启动时:

  1. 生成路由器配置:unix socket 输入、bridge/awsvpc 上的 TCP forward、ECS 元数据、可选的config-file-type=files3额外配置 include,以及每个awsfirelens容器一个 output。
  2. 先启动路由器
  3. logDriver: awsfirelens的应用容器指向生成的 unix socket。

配置写入路径固定:Fluent Bit 写入/fluent-bit/etc/fluent-bit.conf;Fluentd 写入/fluentd/etc/fluent.conf,且 output 插件使用@type(而非Name)。

从源码看,生成器常量包括 socket 路径/var/run/fluent.sockSOCKET_PATH)、forward 端口24224FORWARD_PORT)与健康检查端口8877HEALTHCHECK_PORT),TCP forward 的监听地址统一为0.0.0.0——AWS 在 awsvpc 模式下绑定127.0.0.1,因为所有容器共享任务网络命名空间;而 Floci 仅在启用安全组强制时为 awsvpc 任务共享网络命名空间,其余场景下注入的FLUENT_HOST(路由器容器 IP)必须可达,因此路由器必须监听所有接口(tcpListen方法及注释,见 FirelensConfigGenerator.java)。路由器内存缓冲上限为路由器内存的一半,下限 25MB(memBufLimit)。生成器形态参考了 amazon-ecs-agent 的firelensconfig_unix.go

端点注入与「不覆盖」原则

只有从endpoint属性读取 URL 的 output 插件(s3cloudwatchfirehose)会收到Endpoint,其值被设为 Floci 的容器可达基础 URL。原因:Fluent Bit AWS 插件只从自身配置读取自定义端点,而忽略注入容器中的AWS_ENDPOINT_URL环境变量,若不注入,路由器会把日志发往真实服务。任务定义 log options 中显式设置的endpoint永不被覆盖,因此把某个 output 指向真实 AWS 仍然可行;而在@INCLUDE引入或config-file-type=s3的配置中声明的 output 对 Floci 不可见,会保留其原有的任何 endpoint。

注意:上游 C 插件(cloudwatch_logskinesis_firehosekinesis_streams)被原样保留。它们把endpoint当作裸主机名交给getaddrinfo(而非解析为 URL),并且总是发起 TLS 拨号,因此 Floci 的http://host:port基础 URL 在那里会以Misformatted domain name失败,裸主机名又无法通过证书校验,且没有 output 级开关可以禁用其中任意一项。在aws-for-fluent-bit3.x 系列上这些插件还支持独立的port(对kinesis_firehosecloudwatch_logs未文档化但可用),因此 output 可以指向 Floci 的端口,但仍无法完成 TLS 握手。这些 output 会去往任务定义指向的任何地方。

注入的http://端点还会附带tls Off。Fluent Bit 1.9(aws-for-fluent-bit2.x 与:latest系列)在 HTTP S3 上仍会调用flb_tls_session_create,并在 NULL TLS context 上 SIGSEGV;仅凭 scheme 不够。任务定义已设置的tls会被保留(disableTlsForHttpEndpoint的实现见 FirelensConfigGenerator.java)。Fluentd output 不注入endpoint(其 AWS 插件是 Ruby gem 而非 Fluent Bit Go/C 插件)。

config-file-type=s3 的边界

Floci 遵循 ECS 自身的边界:

  • RegisterTaskDefinition对 Fargate 兼容的任务定义拒绝config-file-type=s3,报Fargate launch type does not support FirelensConfiguration config file from 's3';对非 S3 对象 ARN 的config-file-valueInvalid arn syntax
  • Fargate 任务仍可按 AWS 文档的方式从 S3 取配置:给 aws-for-fluent-bit init 进程提供aws_fluent_bit_init_s3_*环境变量。ECS 从不检查这些变量,Floci 直接透传,因此这里的注册也被接受;Floci 本地也不拉取任何内容——它不提供 ECS 任务元数据端点,而 init 进程在下载前会先读取该端点。
  • 在 EC2 兼容的任务定义上,Floci 从自身 S3 读取对象,写入生成配置旁的固定external.conf路径(/fluent-bit/etc/external.conf/fluentd/etc/external.conf)并从那里 include,与 ECS agent 使用的路径一致。
  • 对象在任何容器创建之前读取,因此 bucket/key 缺失会使任务以 agent 的原因停止——Unable to download firelens s3 config file: unable to download s3 config <key> from bucket <bucket>: <detail>——而不会泄漏已启动的路由器。

相关测试见 EcsFirelensS3ConfigTest.java。

Floci 同样不校验任务定义的compatibilities/requiresCompatibilitiesRunTasklaunchType是否匹配:Fargate 兼容定义仍可用launchType=EC2运行(反之亦然),与缺失元数据端点时注册被接受的方式一致。共享网络命名空间(AppConfig agent 在127.0.0.1:2772)尚未实现。

其他日志驱动(包括awslogs)仍通过 Floci 流向 CloudWatch,而不是使用配置的驱动。

实战示例

AWS CLI 完整流程

export AWS_ENDPOINT_URL=http://localhost:4566 export AWS_DEFAULT_REGION=us-east-1 export AWS_ACCESS_KEY_ID=test export AWS_SECRET_ACCESS_KEY=test # Create a cluster aws ecs create-cluster --cluster-name my-cluster \ --endpoint-url $AWS_ENDPOINT_URL # Register a task definition aws ecs register-task-definition \ --family my-task \ --container-definitions '[ { "name": "app", "image": "nginx:latest", "cpu": 256, "memory": 512, "essential": true, "portMappings": [{"containerPort": 80, "protocol": "tcp"}] } ]' \ --requires-compatibilities FARGATE \ --cpu 256 --memory 512 \ --network-mode awsvpc \ --endpoint-url $AWS_ENDPOINT_URL # Run a task aws ecs run-task \ --cluster my-cluster \ --task-definition my-task \ --launch-type FARGATE \ --endpoint-url $AWS_ENDPOINT_URL # Create a service aws ecs create-service \ --cluster my-cluster \ --service-name my-service \ --task-definition my-task \ --desired-count 1 \ --launch-type FARGATE \ --endpoint-url $AWS_ENDPOINT_URL # List running tasks aws ecs list-tasks --cluster my-cluster \ --endpoint-url $AWS_ENDPOINT_URL # Stop a task aws ecs stop-task \ --cluster my-cluster \ --task <task-arn> \ --endpoint-url $AWS_ENDPOINT_URL # Delete a service aws ecs delete-service \ --cluster my-cluster \ --service my-service \ --force \ --endpoint-url $AWS_ENDPOINT_URL

Java SDK 示例

EcsClient ecs = EcsClient.builder() .endpointOverride(URI.create("http://localhost:4566")) .region(Region.US_EAST_1) .credentialsProvider(StaticCredentialsProvider.create( AwsBasicCredentials.create("test", "test"))) .build(); // Create cluster ecs.createCluster(r -> r.clusterName("my-cluster")); // Register task definition ecs.registerTaskDefinition(r -> r .family("my-task") .containerDefinitions(c -> c .name("app") .image("nginx:latest") .cpu(256) .memory(512) .essential(true)) .requiresCompatibilities(Compatibility.FARGATE) .cpu("256") .memory("512") .networkMode(NetworkMode.AWSVPC)); // Run a task RunTaskResponse response = ecs.runTask(r -> r .cluster("my-cluster") .taskDefinition("my-task") .launchType(LaunchType.FARGATE) .count(1)); String taskArn = response.tasks().get(0).taskArn();

从源码结构看,RunTaskcontainerOverrides按容器名匹配:override 的command替换任务定义中的命令,environment则与任务定义环境合并(见 EcsContainerManager.java 附近的处理,并有 EcsContainerManagerOverridesTest.java 覆盖)。端口映射方面,bridge/host 模式下显式hostPort会按字面发布到 Docker 宿主机(与 AWS bridge 模式一致);awsvpc 模式下每个 AWS 任务都有独立 ENI,字面 hostPort 在单一本地 Docker 宿主机上会跨任务冲突,因此 awsvpc 映射在原生模式总是使用动态 host 端口,Docker 模式下则仅暴露端口、由消费者经 Docker 网络 IP 访问(见 EcsContainerManager.java)。容器日志默认以/ecs/<family>作为日志组、<name>/<taskId>作为日志流流向 CloudWatch(见startTasklogStreamer.attach的调用)。

测试与验证

仓库在 src/test/java/io/github/hectorvent/floci/services/ecs 下提供了大量 ECS 相关测试,可作为行为契约继续深入研究:

  • JSON 处理与持久化EcsJsonHandler*系列覆盖 FireLens、健康检查、runtimePlatform/logConfiguration原样回读、任务定义持久化、卷与volumesFrom、command/entryPoint 覆盖等。
  • 容器生命周期EcsContainerManager*系列覆盖 Docker 集成下的端口映射、卷、EFS 卷隔离与命名、FireLens、安全组、Secrets、ECR 镜像重写、生命周期与 teardown。
  • 服务行为EcsServiceRolloutTestEcsServiceDaemonSchedulingTestEcsDescribeServicesIntegrationTestEcsServicePersistenceTestEcsReconcilerMultiAccountServiceTest等覆盖滚动、DAEMON 调度、PRIMARY部署合成、持久化与多账号 reconciler。
  • 事件EcsEventBridgeIntegrationTestEcsEventPublisherTest验证任务阶梯与部署事件。
  • SecretsEcsServiceContainerSecretsTestSecretsManagerSelectorTest覆盖容器 secret 选择逻辑。

此外,兼容性测试套件(compatibility-tests)中的 Terraform、OpenTofu、CDK 用例也可用于端到端验证 ECS 与 IaC 工具的协同行为。

与真实 AWS 的关键差异速查

  • 任务生命周期只有PENDING/RUNNING/STOPPED,中间阶段由事件发布器在 EventBridge 上合成。
  • deployments始终单条PRIMARY,无并行的ACTIVE排水部署;pendingCount恒为 0;updatedAt等于createdAt
  • SERVICE_DEPLOYMENT_FAILED与部署熔断器不发出;SubmitTaskStateChange/SubmitContainerStateChange为纯 ACK。
  • 不校验compatibilitieslaunchType的匹配;CODE_DEPLOY/EXTERNAL控制器下仍合成deployments
  • runtimePlatform不影响任务实际运行架构(始终宿主机架构)。
  • 默认拒绝所有 host 卷挂载,需显式配置白名单或启用不安全开关。
  • EFS 卷由共享本地 Docker 卷模拟,EFS access point 的创建信息与 POSIX 用户通过floci.storage.efs.*可选配置模拟。

【免费下载链接】floci

Light, fluffy, and always free - The AWS Local Emulator alternative

项目地址:https://gitcode.com/gh_mirrors/fl/floci
点击查看免费下载
上一篇:UE4SS项目在《皇牌空战7》中的兼容性问题分析与解决方案
下一篇:Cellpose模型加载失败问题分析与解决方案

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

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

SAE J200标准解读:橡胶材料分类系统与选型实战指南

简介&#xff1a;这份PDF为SAE J200-2005《橡胶材料分类系统》的中文翻译版&#xff0c;面向汽车、航空航天、医疗等行业的橡胶制品设计、采购与质量工程师。标准将硫化橡胶按耐热老化性能与耐油溶胀性能划分为基本等级&#xff0c;并结合后缀数值形成完整命名体系&#xff0c;…

作者头像 李华
网站建设 2026/9/20 15:21:25

基于51单片机与Proteus的十字路口交通灯控制系统设计

简介&#xff1a;这是一份基于Proteus仿真平台的十字路口交通信号灯控制系统课程设计文档&#xff0c;面向单片机、嵌入式或自动化相关专业学生&#xff0c;帮助完成交通灯控制系统的方案设计、硬件电路搭建与程序调试。文档以AT89C52单片机为核心&#xff0c;覆盖选题背景、交…

作者头像 李华
网站建设 2026/9/20 15:21:09

Linux与C++多线程编程实战指南

1. 线程基础与Linux原生线程实战在Linux系统编程中&#xff0c;线程是轻量级的执行单元&#xff0c;相比进程创建和切换的开销更小。我们先从最底层的pthread库开始&#xff0c;这是POSIX标准定义的线程接口。创建线程的基本模式是这样的&#xff1a;#include <pthread.h>…

作者头像 李华
网站建设 2026/9/20 15:21:04

python-docx解析公共基础知识题库并建SQLite FTS5检索组卷

/* 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 15:19:58

IPC-A-620线束验收标准全解析:从压接到绝缘防护的判定要点

简介&#xff1a;IPC-A-620线束加工标准PDF文档&#xff0c;是面向电缆组装与线束加工行业从业者、质量检验人员及工艺工程师的规范性参考。资源完整呈现电缆组装的外观接受标准&#xff0c;涵盖检查与测试要求、术语定义、产品等级划分&#xff08;一般、专用、高科技电子产品…

作者头像 李华