Kanji
・云架构工程师 / 自由职业 ・1993年出生 ・爱媛县出身 / 现居东京都涩谷区 ・5年 AWS 实战经验 个人资料详情
目录
LocalStack 是一个用于在本地环境中模拟 AWS 云服务的工具。 通过在本地模仿 AWS 服务,开发人员可以在没有 Internet 连接的情况下使用 AWS CLI 和开发工具包进行测试。
使用免费计划,您可以在本地模拟某些 AWS 服务,但并非所有服务都可用。 支持 EC2、VPC、Lambda、S3、DynamoDB、SNS 和 SQS 等主要服务。
LocalStack 作为 Docker 容器提供,使 Docker 的设置变得简单。
Previous2 是一个用于生成 AWS CloudFormation 模板的工具。 它使用 IAM 用户或 STS 凭证扫描您的 AWS 账户中的资源,并为 CloudFormation、CDK、Terraform、Pulumi 等生成基础设施即代码 (IaC) 模板。 它还支持 Draw.io(测试版),但根据我的经验,它不适用于 VPC 和 EC2 创建。
与 LocalStack 一样,Former2 可作为 Docker 容器使用,并且可以使用 Docker 轻松设置。
本文介绍了LocalStack+Former2的设置,有以下三个要点:
LocalStack 账户有 14 天的试用期,在此期间您可以使用 LocalStack 资源浏览器通过 GUI 查看 AWS 资源。 试用后,您需要付费计划才能使用 GUI。 通过使用Former2,您可以 可视化并检查AWS资源状态,而无需担心试用期。
虽然 Previous2 作为 Web 服务提供,但开源版本作为 Docker 容器提供,可以使用 Docker Compose 与 LocalStack 进行编排。
您可以克隆 GitHub 存储库并使用 Docker Compose 启动它,如下所示:
克隆存储库或创建 Docker Compose 文件并不困难,但 本文介绍了一种使用 DinD (Docker-in-Docker) 在单个容器中构建和运行 Docker 命令的方法。
前者将设置保存在浏览器的本地存储中,因此清除浏览器缓存将删除您的设置。 即使在 Docker 容器中运行,也没有默认的方式来保存设置,因此如果重置它们,您必须手动重新配置它们。 本文介绍了一种解决方法: 将 Previous2 设置写入 JavaScript 文件并在容器启动时应用它们。
在继续之前,请注意以下事项: LocalStack 的行为可能与实际的 AWS 环境不同,因此建议仅用于自学目的。
以下是我观察到的一些行为:
即使部署在 LocalStack 中有效,部署到生产时也可能会出现问题。 使用此环境学习 AWS CLI 或 CloudFormation,或参加内部研讨会,了解这些限制。
本文假设满足以下先决条件:
首先,在工作目录中创建以下三个文件:
${WORK_DIRECTORY}/ ${WORK_DIRECTORY}/docker-compose.yml ${WORK_DIRECTORY}/Dockerfile ${WORK_DIRECTORY}/setting.js # Example directory structure localstack-with-former2/ localstack-with-former2/docker-compose.yml localstack-with-former2/Dockerfile localstack-with-former2/setting.js
您可以在任何地方创建工作目录。 例如:
WORK_DIRECTORY=$(pwd)/localstack-with-former2 mkdir -p ${WORK_DIRECTORY} cd ${WORK_DIRECTORY}
使用以下内容创建“Dockerfile”。 要点:
setting.js
index.html
/root/former2
/volume
docker-compose up
# REF: https://hub.docker.com/r/docker/compose FROM docker/compose:alpine-1.29.1 WORKDIR /root RUN apk add --no-cache git RUN git clone https://github.com/iann0036/former2.git COPY docker-compose.yml . # WORKAROUND: https://stackoverflow.com/questions/37013947/force-a-docker-build-to-rebuild-a-single-step ARG SETTING_TIMESTAMP=YYYYMMDDHHMMSS COPY setting.js . RUN cp setting.js former2/lib/setting.js && \ sed -i '/<\/head>/i <script src="lib/setting.js"></script>' former2/index.html CMD cp -R /root/former2 /volume && \ docker-compose up
创建“docker-compose.yml”文件,如下所示。 要点:
docker.sock
/var/run/docker.sock
EXTRA_CORS_ALLOWED_ORIGINS
# REF: https://docs.docker.jp/compose/compose-file/compose-versioning.html version: "3.8" services: former2: container_name: former2 image: nginx:stable-alpine ports: - "127.0.0.1:8089:80" volumes: - ${WORK_DIRECTORY}/volume/former2:/usr/share/nginx/html - "/var/run/docker.sock:/var/run/docker.sock" # REF: https://docs.localstack.cloud/getting-started/installation/#starting-localstack-with-docker localstack: container_name: localstack image: localstack/localstack ports: - "4566:4566" - "4510-4559:4510-4559" environment: - DEBUG=${DEBUG-} - DOCKER_HOST=unix:///var/run/docker.sock # REF: https://github.com/iann0036/former2 - EXTRA_CORS_ALLOWED_ORIGINS=chrome-extension://fhejmeojlbhfhjndnkkleooeejklmigi volumes: - ${WORK_DIRECTORY}/volume/localstack:/var/lib/localstack - "/var/run/docker.sock:/var/run/docker.sock"
创建“setting.js”文件,如下所示。 这些设置基于 master·iann0036/former2 上的 former2/js/app.js 。 此处仅设置默认区域、CloudFormation 模板缩进和 LocalStack 端点使用情况。
window.localStorage.setItem('region', "ap-northeast-1"); window.localStorage.setItem('cfnspacing',"2"); window.localStorage.setItem('uselocalstackendpoint', "true"); window.localStorage.setItem('logicalidstrategy', "longtypeprefixoptionalindexsuffix"); // default window.localStorage.setItem('defaultoutput', "cloudformation"); // default window.localStorage.setItem('iaclangselect', "typescript"); // default window.localStorage.setItem('skipirrelevantresources', "true"); // default window.localStorage.setItem('relatedresourcessetting', ""); // default window.localStorage.setItem('includedefaultresources', ""); // default
使用“准备步骤 1”中的文件构建 Docker 映像:
--platform=linux/amd64
--build-arg SETTING_TIMESTAMP=$(date +%Y%m%d%H%M%S)
docker build \ --platform=linux/amd64 \ --build-arg SETTING_TIMESTAMP=$(date +%Y%m%d%H%M%S) \ -t localstack-with-former2:latest \ .
启动 LocalStack 和 Previous2:
--detach
docker run \ --name localstack-with-former2 \ --platform=linux/amd64 \ --privileged \ --detach \ --rm \ -it \ -e WORK_DIRECTORY=$(pwd) \ -v /var/run/docker.sock:/var/run/docker.sock \ -v $(pwd)/volume:/volume \ localstack-with-former2:latest
注意: 在构建 Docker 映像的目录中运行这些命令。
在 docker-compose.yml 中,Former2 容器挂载 ${WORK_DIRECTORY}/volume/former2:/usr/share/nginx/html 。 由于“docker-compose up”在容器内运行,您可能期望挂载容器内的“${WORK_DIRECTORY}/volume/former2”,但实际上,源是主机目录。 因此,安装“/root/former2”(仅存在于容器内部)是不可能的。 请参阅: linux - Docker 中的 Docker 无法挂载卷 - 堆栈内存溢出
docker-compose.yml
${WORK_DIRECTORY}/volume/former2:/usr/share/nginx/html
因此,该过程是:
-v $(pwd)/volume:/volume
${WORK_DIRECTORY}/volume
首先,配置 AWS CLI 以使用 LocalStack。
您可以使用环境变量或 AWS CLI 配置文件。 对于环境变量,您每次都必须设置它们。 使用配置文件,您只需配置一次并指定命令的配置文件。
aws configure set aws_access_key_id localstack --profile localstack aws configure set aws_secret_access_key localstack --profile localstack aws configure set region ap-northeast-1 --profile localstack aws configure set aws_endpoint_url http://localhost:4566 --profile localstack
export AWS_ACCESS_KEY_ID=localstack export AWS_SECRET_ACCESS_KEY=localstack export AWS_REGION=ap-northeast-1 export AWS_ENDPOINT_URL=http://localhost:4566
假设您使用配置文件方法配置了 AWS CLI,一旦 LocalStack 运行,您就可以使用 AWS CLI 与资源交互。
首先,验证 AWS CLI 对 LocalStack 的访问:
aws sts \ get-caller-identity \ --profile localstack
如果您看到如下响应,则说明您的配置正确(帐户 ID 为“000000000000”):
# Example output % aws sts get-caller-identity \ --profile localstack { "UserId": "AKIAIOSFODNN7EXAMPLE", "Account": "000000000000", "Arn": "arn:aws:iam::000000000000:root" }
接下来,创建一个示例 S3 存储桶(存储桶名称不需要全局唯一):
aws s3api \ create-bucket \ --bucket hoge-foo-bar \ --create-bucket-configuration LocationConstraint=ap-northeast-1 \ --profile localstack
# Example output % aws s3api \ create-bucket \ --bucket hoge-foo-bar \ --create-bucket-configuration LocationConstraint=ap-northeast-1 \ --profile localstack { "Location": "http://hoge-foo-bar.s3.localhost.localstack.cloud:4566/" }
注意:停止容器时资源将被删除。要保留资源,请保持容器运行。
检查您使用Former2 创建的存储桶。 访问 http://127.0.0.1:8089/ ,然后进入“存储”->“S3”->“存储桶”。 您应该会看到您的存储桶显示如下。
对于在 Previous2 中不可见的配置值,请使用 AWS CLI。 例如,要检查 CloudFormation 堆栈的状态,请使用 AWS CLI。 以下是名为“sample-vpc-stack”的堆栈的命令示例。使用 jq 将输出格式化为表格。
# Stack List aws cloudformation describe-stacks \ --profile localstack \ --query "Stacks[].{StackName: StackName, StackStatus: StackStatus, CreationTime: CreationTime, LastUpdatedTime: LastUpdatedTime}" \ --output json \ | jq -r '["StackName","StackStatus","CreationTime","LastUpdatedTime"], (.[] | [.StackName, .StackStatus, .CreationTime, .LastUpdatedTime]) | @tsv' \ | column -t -s $'\t' # List of Stack Resources stack_name="sample-vpc-stack" aws cloudformation list-stack-resources \ --stack-name "${stack_name}" \ --profile localstack \ --output json \ | jq -r '["LogicalResourceId","PhysicalResourceId","ResourceType","ResourceStatus"], (.StackResourceSummaries[] | [.LogicalResourceId, .PhysicalResourceId, .ResourceType, .ResourceStatus]) | @tsv' \ | column -t -s $'\t' # Stack Events List stack_name="sample-vpc-stack" aws cloudformation describe-stack-events \ --stack-name "${stack_name}" \ --query "StackEvents[].{Timestamp: Timestamp, LogicalResourceId: LogicalResourceId, ResourceType: ResourceType, ResourceStatus: ResourceStatus, ResourceStatusReason: ResourceStatusReason}" \ --profile localstack \ --output json \ | jq -r '["Timestamp","LogicalResourceId","ResourceType","ResourceStatus","ResourceStatusReason"], (.[] | [.Timestamp, .LogicalResourceId, .ResourceType, .ResourceStatus, .ResourceStatusReason]) | @tsv' \ | column -t -s $'\t' # Stack Outputs List stack_name="sample-vpc-stack" aws cloudformation describe-stacks \ --stack-name "${stack_name}" \ --query "Stacks[].Outputs[].{OutputKey: OutputKey, OutputValue: OutputValue, ExportName: ExportName}" \ --profile localstack \ --output json \ | jq -r '["OutputKey","OutputValue"], (.[] | [.OutputKey, .OutputValue, .ExportName]) | @tsv' \ | column -t -s $'\t'
下面是执行结果的示例。本例中使用的VPC的CloudFormation模板将在单独的文章中介绍。
# Execution Result - Stack List % aws cloudformation describe-stacks \ --profile localstack \ --query "Stacks[].{StackName: StackName, StackStatus: StackStatus, CreationTime: CreationTime, LastUpdatedTime: LastUpdatedTime}" \ --output json \ | jq -r '["StackName","StackStatus","CreationTime","LastUpdatedTime"], (.[] | [.StackName, .StackStatus, .CreationTime, .LastUpdatedTime]) | @tsv' \ | column -t -s $'\t' StackName StackStatus CreationTime LastUpdatedTime sample-vpc-stack CREATE_COMPLETE 2025-05-25T01:49:43.238000+00:00 2025-05-25T01:49:43.238000+00:00 # Execution Result - Stack Resource List % stack_name="sample-vpc-stack" aws cloudformation list-stack-resources \ --stack-name "${stack_name}" \ --profile localstack \ --output json \ | jq -r '["LogicalResourceId","PhysicalResourceId","ResourceType","ResourceStatus"], (.StackResourceSummaries[] | [.LogicalResourceId, .PhysicalResourceId, .ResourceType, .ResourceStatus]) | @tsv' \ | column -t -s $'\t' LogicalResourceId PhysicalResourceId ResourceType ResourceStatus VPC1 vpc-4bd2b9a09d788f172 AWS::EC2::VPC CREATE_COMPLETE InternetGateway igw-9bbb17a1eaf64992b AWS::EC2::InternetGateway CREATE_COMPLETE FlowLogsIAMRole AWS::IAM::Role CREATE_COMPLETE PublicSubnet1 subnet-c0c96c0f53f7f1cd7 AWS::EC2::Subnet CREATE_COMPLETE PublicSubnet2 subnet-836137197cc3767a2 AWS::EC2::Subnet CREATE_COMPLETE PrivateSubnet1 subnet-197c985876fcbfdac AWS::EC2::Subnet CREATE_COMPLETE PrivateSubnet2 subnet-a059fb7bd23898fd7 AWS::EC2::Subnet CREATE_COMPLETE ProtectedSubnet1 subnet-1ca041ff52b2493fb AWS::EC2::Subnet CREATE_COMPLETE ProtectedSubnet2 subnet-eff4ebad7049f6c6f AWS::EC2::Subnet CREATE_COMPLETE PublicRouteTable rtb-6f5f999ed1a475a4e AWS::EC2::RouteTable CREATE_COMPLETE PrivateSubnet1RouteTable AWS::EC2::RouteTable CREATE_COMPLETE PrivateSubnet2RouteTable AWS::EC2::RouteTable CREATE_COMPLETE ProtectedRouteTable rtb-453340a863a7a1059 AWS::EC2::RouteTable CREATE_COMPLETE CustomNetworkAcl acl-b0001fb613e8118d2 AWS::EC2::NetworkAcl CREATE_COMPLETE VPCFlowLog1 AWS::EC2::FlowLog CREATE_COMPLETE VPCGatewayAttachment AWS::EC2::VPCGatewayAttachment CREATE_COMPLETE PublicSubnet1RouteTableAssociation rtbassoc-c838b296a6edb9a37 AWS::EC2::SubnetRouteTableAssociation CREATE_COMPLETE PublicSubnet2RouteTableAssociation rtbassoc-5fe392e039de6701d AWS::EC2::SubnetRouteTableAssociation CREATE_COMPLETE PrivateSubnet1RouteTableAssociation AWS::EC2::SubnetRouteTableAssociation CREATE_COMPLETE PrivateSubnet2RouteTableAssociation AWS::EC2::SubnetRouteTableAssociation CREATE_COMPLETE ProtectedSubnet1RouteTableAssociation rtbassoc-896b8d426f6c0d5e4 AWS::EC2::SubnetRouteTableAssociation CREATE_COMPLETE ProtectedSubnet2RouteTableAssociation rtbassoc-8e3ec29094055a5bc AWS::EC2::SubnetRouteTableAssociation CREATE_COMPLETE CustomNetworkAclEntryInbound unknown AWS::EC2::NetworkAclEntry CREATE_COMPLETE CustomNetworkAclEntryOutbound unknown AWS::EC2::NetworkAclEntry CREATE_COMPLETE NaclAssociationPublicSubnet1 unknown AWS::EC2::SubnetNetworkAclAssociation CREATE_COMPLETE NaclAssociationPublicSubnet2 unknown AWS::EC2::SubnetNetworkAclAssociation CREATE_COMPLETE NaclAssociationPrivateSubnet1 unknown AWS::EC2::SubnetNetworkAclAssociation CREATE_COMPLETE NaclAssociationPrivateSubnet2 unknown AWS::EC2::SubnetNetworkAclAssociation CREATE_COMPLETE NaclAssociationProtectedSubnet1 unknown AWS::EC2::SubnetNetworkAclAssociation CREATE_COMPLETE NaclAssociationProtectedSubnet2 unknown AWS::EC2::SubnetNetworkAclAssociation CREATE_COMPLETE NATGateway1EIP AWS::EC2::EIP CREATE_COMPLETE NATGateway2EIP AWS::EC2::EIP CREATE_COMPLETE PublicRoute rtb-6f5f999ed1a475a4e~0.0.0.0/0 AWS::EC2::Route CREATE_COMPLETE NatGateway1 AWS::EC2::NatGateway CREATE_COMPLETE NatGateway2 AWS::EC2::NatGateway CREATE_COMPLETE PrivateSubnet2Route AWS::EC2::Route CREATE_COMPLETE PrivateSubnet1Route AWS::EC2::Route CREATE_COMPLETE # Execution Result - Stack Events List % stack_name="sample-vpc-stack" aws cloudformation describe-stack-events \ --stack-name "${stack_name}" \ --query "StackEvents[].{Timestamp: Timestamp, LogicalResourceId: LogicalResourceId, ResourceType: ResourceType, ResourceStatus: ResourceStatus, ResourceStatusReason: ResourceStatusReason}" \ --profile localstack \ --output json \ | jq -r '["Timestamp","LogicalResourceId","ResourceType","ResourceStatus","ResourceStatusReason"], (.[] | [.Timestamp, .LogicalResourceId, .ResourceType, .ResourceStatus, .ResourceStatusReason]) | @tsv' \ | column -t -s $'\t' Timestamp LogicalResourceId ResourceType ResourceStatus ResourceStatusReason 2025-05-25T01:49:44.440000+00:00 sample-vpc-stack AWS::CloudFormation::Stack CREATE_COMPLETE 2025-05-25T01:49:44.412000+00:00 PrivateSubnet1Route AWS::EC2::Route CREATE_COMPLETE 2025-05-25T01:49:44.411000+00:00 PrivateSubnet2Route AWS::EC2::Route CREATE_COMPLETE 2025-05-25T01:49:44.411000+00:00 NatGateway2 AWS::EC2::NatGateway CREATE_COMPLETE 2025-05-25T01:49:44.411000+00:00 NatGateway1 AWS::EC2::NatGateway CREATE_COMPLETE 2025-05-25T01:49:44.411000+00:00 PublicRoute AWS::EC2::Route CREATE_COMPLETE 2025-05-25T01:49:44.408000+00:00 PublicRoute AWS::EC2::Route CREATE_IN_PROGRESS 2025-05-25T01:49:44.398000+00:00 NATGateway2EIP AWS::EC2::EIP CREATE_COMPLETE 2025-05-25T01:49:44.398000+00:00 NATGateway1EIP AWS::EC2::EIP CREATE_COMPLETE 2025-05-25T01:49:44.398000+00:00 NaclAssociationProtectedSubnet2 AWS::EC2::SubnetNetworkAclAssociation CREATE_COMPLETE 2025-05-25T01:49:44.391000+00:00 NaclAssociationProtectedSubnet1 AWS::EC2::SubnetNetworkAclAssociation CREATE_COMPLETE 2025-05-25T01:49:44.384000+00:00 NaclAssociationPrivateSubnet2 AWS::EC2::SubnetNetworkAclAssociation CREATE_COMPLETE 2025-05-25T01:49:44.377000+00:00 NaclAssociationPrivateSubnet1 AWS::EC2::SubnetNetworkAclAssociation CREATE_COMPLETE 2025-05-25T01:49:44.370000+00:00 NaclAssociationPublicSubnet2 AWS::EC2::SubnetNetworkAclAssociation CREATE_COMPLETE 2025-05-25T01:49:44.363000+00:00 NaclAssociationPublicSubnet1 AWS::EC2::SubnetNetworkAclAssociation CREATE_COMPLETE 2025-05-25T01:49:44.356000+00:00 CustomNetworkAclEntryOutbound AWS::EC2::NetworkAclEntry CREATE_COMPLETE 2025-05-25T01:49:44.346000+00:00 CustomNetworkAclEntryInbound AWS::EC2::NetworkAclEntry CREATE_COMPLETE 2025-05-25T01:49:44.336000+00:00 ProtectedSubnet2RouteTableAssociation AWS::EC2::SubnetRouteTableAssociation CREATE_COMPLETE 2025-05-25T01:49:44.333000+00:00 ProtectedSubnet2RouteTableAssociation AWS::EC2::SubnetRouteTableAssociation CREATE_IN_PROGRESS 2025-05-25T01:49:44.326000+00:00 ProtectedSubnet1RouteTableAssociation AWS::EC2::SubnetRouteTableAssociation CREATE_COMPLETE 2025-05-25T01:49:44.323000+00:00 ProtectedSubnet1RouteTableAssociation AWS::EC2::SubnetRouteTableAssociation CREATE_IN_PROGRESS 2025-05-25T01:49:44.316000+00:00 PrivateSubnet2RouteTableAssociation AWS::EC2::SubnetRouteTableAssociation CREATE_COMPLETE 2025-05-25T01:49:44.316000+00:00 PrivateSubnet1RouteTableAssociation AWS::EC2::SubnetRouteTableAssociation CREATE_COMPLETE 2025-05-25T01:49:44.316000+00:00 PublicSubnet2RouteTableAssociation AWS::EC2::SubnetRouteTableAssociation CREATE_COMPLETE 2025-05-25T01:49:44.313000+00:00 PublicSubnet2RouteTableAssociation AWS::EC2::SubnetRouteTableAssociation CREATE_IN_PROGRESS 2025-05-25T01:49:44.306000+00:00 PublicSubnet1RouteTableAssociation AWS::EC2::SubnetRouteTableAssociation CREATE_COMPLETE 2025-05-25T01:49:44.299000+00:00 PublicSubnet1RouteTableAssociation AWS::EC2::SubnetRouteTableAssociation CREATE_IN_PROGRESS 2025-05-25T01:49:44.292000+00:00 VPCGatewayAttachment AWS::EC2::VPCGatewayAttachment CREATE_COMPLETE 2025-05-25T01:49:44.290000+00:00 VPCGatewayAttachment AWS::EC2::VPCGatewayAttachment CREATE_IN_PROGRESS 2025-05-25T01:49:44.283000+00:00 VPCFlowLog1 AWS::EC2::FlowLog CREATE_COMPLETE 2025-05-25T01:49:44.283000+00:00 CustomNetworkAcl AWS::EC2::NetworkAcl CREATE_COMPLETE 2025-05-25T01:49:44.280000+00:00 CustomNetworkAcl AWS::EC2::NetworkAcl CREATE_IN_PROGRESS 2025-05-25T01:49:44.269000+00:00 ProtectedRouteTable AWS::EC2::RouteTable CREATE_COMPLETE 2025-05-25T01:49:44.267000+00:00 ProtectedRouteTable AWS::EC2::RouteTable CREATE_IN_PROGRESS 2025-05-25T01:49:44.256000+00:00 PrivateSubnet2RouteTable AWS::EC2::RouteTable CREATE_COMPLETE 2025-05-25T01:49:44.256000+00:00 PrivateSubnet1RouteTable AWS::EC2::RouteTable CREATE_COMPLETE 2025-05-25T01:49:44.256000+00:00 PublicRouteTable AWS::EC2::RouteTable CREATE_COMPLETE 2025-05-25T01:49:44.253000+00:00 PublicRouteTable AWS::EC2::RouteTable CREATE_IN_PROGRESS 2025-05-25T01:49:44.242000+00:00 ProtectedSubnet2 AWS::EC2::Subnet CREATE_COMPLETE 2025-05-25T01:49:44.239000+00:00 ProtectedSubnet2 AWS::EC2::Subnet CREATE_IN_PROGRESS 2025-05-25T01:49:44.218000+00:00 ProtectedSubnet1 AWS::EC2::Subnet CREATE_COMPLETE 2025-05-25T01:49:44.215000+00:00 ProtectedSubnet1 AWS::EC2::Subnet CREATE_IN_PROGRESS 2025-05-25T01:49:44.193000+00:00 PrivateSubnet2 AWS::EC2::Subnet CREATE_COMPLETE 2025-05-25T01:49:44.190000+00:00 PrivateSubnet2 AWS::EC2::Subnet CREATE_IN_PROGRESS 2025-05-25T01:49:44.168000+00:00 PrivateSubnet1 AWS::EC2::Subnet CREATE_COMPLETE 2025-05-25T01:49:44.164000+00:00 PrivateSubnet1 AWS::EC2::Subnet CREATE_IN_PROGRESS 2025-05-25T01:49:44.143000+00:00 PublicSubnet2 AWS::EC2::Subnet CREATE_COMPLETE 2025-05-25T01:49:44.140000+00:00 PublicSubnet2 AWS::EC2::Subnet CREATE_IN_PROGRESS 2025-05-25T01:49:44.109000+00:00 PublicSubnet1 AWS::EC2::Subnet CREATE_COMPLETE 2025-05-25T01:49:44.103000+00:00 PublicSubnet1 AWS::EC2::Subnet CREATE_IN_PROGRESS 2025-05-25T01:49:44.042000+00:00 FlowLogsIAMRole AWS::IAM::Role CREATE_COMPLETE 2025-05-25T01:49:44.042000+00:00 InternetGateway AWS::EC2::InternetGateway CREATE_COMPLETE 2025-05-25T01:49:44.040000+00:00 InternetGateway AWS::EC2::InternetGateway CREATE_IN_PROGRESS 2025-05-25T01:49:44.031000+00:00 VPC1 AWS::EC2::VPC CREATE_COMPLETE 2025-05-25T01:49:43.320000+00:00 VPC1 AWS::EC2::VPC CREATE_IN_PROGRESS 2025-05-25T01:49:43.246000+00:00 sample-vpc-stack AWS::CloudFormation::Stack CREATE_IN_PROGRESS 2025-05-25T01:49:43.238000+00:00 sample-vpc-stack AWS::CloudFormation::Stack REVIEW_IN_PROGRESS # Execution Result - Stack Outputs List % stack_name="sample-vpc-stack" aws cloudformation describe-stacks \ --stack-name "${stack_name}" \ --query "Stacks[].Outputs[].{OutputKey: OutputKey, OutputValue: OutputValue, ExportName: ExportName}" \ --profile localstack \ --output json \ | jq -r '["OutputKey","OutputValue"], (.[] | [.OutputKey, .OutputValue, .ExportName]) | @tsv' \ | column -t -s $'\t' OutputKey OutputValue VPCId vpc-4bd2b9a09d788f172 sample-vpc-id PublicSubnet1Id subnet-c0c96c0f53f7f1cd7 sample-public-subnet1-id PublicSubnet2Id subnet-836137197cc3767a2 sample-public-subnet2-id PrivateSubnet1Id subnet-197c985876fcbfdac sample-private-subnet1-id PrivateSubnet2Id subnet-a059fb7bd23898fd7 sample-private-subnet2-id ProtectedSubnet1Id subnet-1ca041ff52b2493fb sample-protected-subnet1-id ProtectedSubnet2Id subnet-eff4ebad7049f6c6f sample-protected-subnet2-id