Kanji
・클라우드 엔지니어 / 프리랜서 ・1993년생 ・에히메현 출신 / 도쿄도 시부야구 거주 ・AWS 경력 5년 프로필 상세
목차
LocalStack은 로컬 환경에서 AWS 클라우드 서비스를 에뮬레이션하기 위한 도구입니다. AWS 서비스를 로컬에서 모방함으로써 개발자는 인터넷 연결 없이 AWS CLI 및 SDK를 사용하여 테스트할 수 있습니다.
무료 플랜을 사용하면 일부 AWS 서비스를 로컬로 에뮬레이션할 수 있지만 모든 서비스를 사용할 수 있는 것은 아닙니다. EC2, VPC, Lambda, S3, DynamoDB, SNS, SQS와 같은 주요 서비스가 지원됩니다.
LocalStack은 Docker 컨테이너로 제공되므로 Docker를 쉽게 설정할 수 있습니다.
Former2는 AWS CloudFormation 템플릿을 생성하는 도구입니다. IAM 사용자 또는 STS 자격 증명을 사용하여 AWS 계정의 리소스를 스캔하고 CloudFormation, CDK, Terraform, Pulumi 등에 대한 IaC(Infrastructure as Code) 템플릿을 생성합니다. Draw.io(Beta)도 지원하는데, 제 경험상 VPC 및 EC2 생성에는 작동하지 않았습니다.
LocalStack과 마찬가지로 Former2는 Docker 컨테이너로 제공되며 Docker로 쉽게 설정할 수 있습니다.
이 문서에서는 다음 세 가지 핵심 사항을 갖춘 LocalStack + Former2 설정을 소개합니다.
LocalStack 계정에는 14일 평가판 기간이 있으며, 이 기간 동안 LocalStack 리소스 브라우저를 사용하여 GUI를 통해 AWS 리소스를 볼 수 있습니다. 평가판 사용 후 GUI를 사용하려면 유료 요금제가 필요합니다. Former2를 사용하면 평가판 기간에 대한 걱정 없이 AWS 리소스 상태를 시각화하고 확인할 수 있습니다.
Former2는 웹 서비스로 제공되지만 오픈 소스 버전은 Docker Compose를 사용하여 LocalStack과 오케스트레이션할 수 있는 Docker 컨테이너로 제공됩니다.
GitHub 리포지토리를 복제하고 아래와 같이 Docker Compose를 사용하여 시작할 수 있습니다.
리포지토리를 복제하거나 Docker Compose 파일을 생성하는 것은 어렵지 않지만 이 글에서는 DinD(Docker-in-Docker)를 사용하여 단일 컨테이너 내에서 Docker 명령을 빌드하고 실행하는 방법을 소개합니다.
Former2는 브라우저의 로컬 저장소에 설정을 저장하므로 브라우저 캐시를 지우면 설정도 지워집니다. Docker 컨테이너에서 실행하는 경우에도 설정을 유지하는 기본 방법이 없으므로 재설정되는 경우 수동으로 재구성해야 합니다. 이 문서에서는 해결 방법을 소개합니다. JavaScript 파일에 Former2 설정을 작성하고 컨테이너 시작 시 적용
계속하기 전에 다음 사항에 유의하세요. 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 을 만듭니다. 핵심 사항:
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-compose.yml
docker.sock
/var/run/docker.sock
volume
# 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의 former2/js/app.js · iann0036/former2 를 기반으로 합니다. 여기에서는 기본 지역, 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 및 Former2를 시작합니다.
--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가 볼륨을 마운트할 수 없음 - 스택 오버플로
${WORK_DIRECTORY}/volume/former2:/usr/share/nginx/html
${WORK_DIRECTORY}/volume/former2
따라서 프로세스는 다음과 같습니다.
${WORK_DIRECTORY}/volume
-v $(pwd)/volume:/volume
CMD
먼저 LocalStack을 사용하도록 AWS CLI를 구성합니다.
환경 변수 또는 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
profile 메서드를 사용하여 AWS CLI를 구성했다고 가정하면 LocalStack이 실행되면 AWS CLI를 사용하여 리소스와 상호 작용할 수 있습니다.
먼저 LocalStack에 대한 AWS CLI 액세스를 확인합니다.
aws sts \ get-caller-identity \ --profile localstack
아래와 같은 응답이 표시되면 구성이 올바른 것입니다(계정 ID는 000000000000 입니다).
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/ 에 접속한 후 “Storage” -> “S3” -> “Buckets”로 이동합니다. 버킷이 아래와 같이 표시되어야 합니다.
Former2에 표시되지 않는 구성 값의 경우 AWS CLI를 사용하십시오. 예를 들어 CloudFormation 스택의 상태를 확인하려면 AWS CLI를 사용하십시오. 다음은 sample-vpc-stack 이라는 스택에 대한 명령 예입니다.출력은 jq를 사용하여 테이블로 형식화됩니다.
sample-vpc-stack
# 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