Cleanup
π§Ή Comprehensive Cleanup
To prevent unexpected charges to your AWS account, it’s essential to clean up all resources created during this workshop. We’ll create and run a cleanup script that automatically identifies and removes all workshop resources.
π Creating and Running the Cleanup Script
Navigate to the AWS Management Console and ensure you’re in the correct region where your CloudFormation stack was previously deployed. Then, open CloudShell by clicking the icon located in the top navigation bar:

Copy and paste the following commands to create, make executable, and run the cleanup script:
cat << 'EOF' > cleanup-workshop.sh
#!/bin/bash
echo "π§Ή Starting comprehensive workshop cleanup..."
# Find and delete all CloudFormation stacks related to the workshop
echo "π Finding CloudFormation stacks..."
STACKS_TO_DELETE=$(aws cloudformation list-stacks --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE --query "StackSummaries[?contains(StackName, 'docker-workshop') || contains(StackName, 'ECSPipeline') || contains(StackName, 'Pipeline') || contains(StackName, 'mod-') || contains(StackName, 'vscode-server')].StackName" --output text)
if [ -n "$STACKS_TO_DELETE" ]; then
echo "ποΈ Deleting CloudFormation stack(s): $STACKS_TO_DELETE"
for stack in $STACKS_TO_DELETE; do
aws cloudformation delete-stack --stack-name $stack
echo "β³ Waiting for stack $stack to be deleted..."
aws cloudformation wait stack-delete-complete --stack-name $stack
echo "β
Stack $stack deleted successfully"
done
else
echo "βΉοΈ No matching CloudFormation stacks found"
fi
# Find and delete ECS resources
echo "π Finding ECS clusters..."
ECS_CLUSTERS=$(aws ecs list-clusters --query "clusterArns[?contains(@, 'rent-a-room') || contains(@, 'workshop')]" --output text)
if [ -n "$ECS_CLUSTERS" ]; then
echo "ποΈ Deleting ECS clusters and services..."
for cluster in $ECS_CLUSTERS; do
# Get cluster name from ARN
CLUSTER_NAME=$(echo $cluster | awk -F/ '{print $2}')
# List services in the cluster
SERVICES=$(aws ecs list-services --cluster $CLUSTER_NAME --query "serviceArns[]" --output text)
# Delete services first
if [ -n "$SERVICES" ]; then
for service in $SERVICES; do
SERVICE_NAME=$(echo $service | awk -F/ '{print $3}')
echo "ποΈ Scaling down service $SERVICE_NAME in cluster $CLUSTER_NAME..."
aws ecs update-service --cluster $CLUSTER_NAME --service $SERVICE_NAME --desired-count 0
echo "ποΈ Deleting service $SERVICE_NAME from cluster $CLUSTER_NAME..."
aws ecs delete-service --cluster $CLUSTER_NAME --service $SERVICE_NAME --force
done
fi
# Wait for services to be deleted
echo "β³ Waiting for services to be deleted..."
sleep 30
# Delete the cluster
echo "ποΈ Deleting ECS cluster $CLUSTER_NAME..."
aws ecs delete-cluster --cluster $CLUSTER_NAME
done
else
echo "βΉοΈ No matching ECS clusters found"
fi
# Find and delete Load Balancers
echo "π Finding Load Balancers..."
LOAD_BALANCERS=$(aws elbv2 describe-load-balancers --query "LoadBalancers[?contains(LoadBalancerName, 'rent-a-room') || contains(LoadBalancerName, 'workshop')].LoadBalancerArn" --output text)
if [ -n "$LOAD_BALANCERS" ]; then
echo "ποΈ Deleting Load Balancers..."
for lb in $LOAD_BALANCERS; do
echo "ποΈ Deleting Load Balancer $lb..."
aws elbv2 delete-load-balancer --load-balancer-arn $lb
done
# Wait a bit for load balancers to be deleted
echo "β³ Waiting for load balancers to be deleted..."
sleep 30
else
echo "βΉοΈ No matching Load Balancers found"
fi
# Find and delete Target Groups
echo "π Finding Target Groups..."
TARGET_GROUPS=$(aws elbv2 describe-target-groups --query "TargetGroups[?contains(TargetGroupName, 'rent-a-room') || contains(TargetGroupName, 'workshop')].TargetGroupArn" --output text)
if [ -n "$TARGET_GROUPS" ]; then
echo "ποΈ Deleting Target Groups..."
for tg in $TARGET_GROUPS; do
echo "ποΈ Deleting Target Group $tg..."
aws elbv2 delete-target-group --target-group-arn $tg
done
else
echo "βΉοΈ No matching Target Groups found"
fi
# Find and delete CodeBuild projects
echo "π Finding CodeBuild projects..."
CODEBUILD_PROJECTS=$(aws codebuild list-projects --query "projects[?contains(@, 'docker') || contains(@, 'scout') || contains(@, 'build')]" --output text)
if [ -n "$CODEBUILD_PROJECTS" ]; then
echo "ποΈ Deleting CodeBuild projects..."
for project in $CODEBUILD_PROJECTS; do
echo "ποΈ Deleting CodeBuild project $project..."
aws codebuild delete-project --name $project
done
else
echo "βΉοΈ No matching CodeBuild projects found"
fi
# Find and delete CodePipeline pipelines
echo "π Finding CodePipeline pipelines..."
PIPELINES=$(aws codepipeline list-pipelines --query "pipelines[?contains(name, 'docker') || contains(name, 'Pipeline') || contains(name, 'ECS')].name" --output text)
if [ -n "$PIPELINES" ]; then
echo "ποΈ Deleting CodePipeline pipelines..."
for pipeline in $PIPELINES; do
echo "ποΈ Deleting pipeline $pipeline..."
aws codepipeline delete-pipeline --name $pipeline
done
else
echo "βΉοΈ No matching CodePipeline pipelines found"
fi
# Find and delete S3 buckets
echo "π Finding S3 buckets related to the workshop..."
S3_BUCKETS=$(aws s3api list-buckets --query "Buckets[?contains(Name, 'codepipeline') || contains(Name, 'artifact') || contains(Name, 'docker-workshop')].Name" --output text)
if [ -n "$S3_BUCKETS" ]; then
echo "ποΈ Deleting S3 buckets..."
for bucket in $S3_BUCKETS; do
echo "ποΈ Emptying and deleting S3 bucket $bucket..."
# Delete all versions of all objects
echo "ποΈ Removing all object versions from bucket..."
aws s3api list-object-versions --bucket $bucket --output json --query '{Objects: Versions[].{Key:Key,VersionId:VersionId}}' | grep -v "null" > /tmp/versions-$bucket.json
if [ -s /tmp/versions-$bucket.json ]; then
aws s3api delete-objects --bucket $bucket --delete file:///tmp/versions-$bucket.json
fi
# Delete all delete markers
echo "ποΈ Removing all delete markers from bucket..."
aws s3api list-object-versions --bucket $bucket --output json --query '{Objects: DeleteMarkers[].{Key:Key,VersionId:VersionId}}' | grep -v "null" > /tmp/markers-$bucket.json
if [ -s /tmp/markers-$bucket.json ]; then
aws s3api delete-objects --bucket $bucket --delete file:///tmp/markers-$bucket.json
fi
# Now delete the bucket itself
echo "ποΈ Deleting bucket $bucket..."
aws s3api delete-bucket --bucket $bucket
# Clean up temporary files
rm -f /tmp/versions-$bucket.json /tmp/markers-$bucket.json
done
else
echo "βΉοΈ No matching S3 buckets found"
fi
# Find and delete Secrets Manager secrets
echo "π Finding Secrets Manager secrets..."
SECRETS=$(aws secretsmanager list-secrets --query "SecretList[?contains(Name, 'docker') || contains(Name, 'github') || contains(Name, 'dockerhub')].Name" --output text)
if [ -n "$SECRETS" ]; then
echo "ποΈ Deleting Secrets Manager secrets..."
for secret in $SECRETS; do
echo "ποΈ Deleting secret $secret..."
aws secretsmanager delete-secret --secret-id $secret --force-delete-without-recovery
done
else
echo "βΉοΈ No matching Secrets Manager secrets found"
fi
# Find and delete Auto Scaling policies and targets
echo "π Finding Auto Scaling policies..."
SCALING_POLICIES=$(aws application-autoscaling describe-scaling-policies --service-namespace ecs --query "ScalingPolicies[?contains(ResourceId, 'rent-a-room')].PolicyARN" --output text 2>/dev/null || echo "")
if [ -n "$SCALING_POLICIES" ]; then
echo "ποΈ Deleting Auto Scaling policies..."
for policy in $SCALING_POLICIES; do
echo "ποΈ Deleting Auto Scaling policy $policy..."
aws application-autoscaling delete-scaling-policy --service-namespace ecs --policy-name $(echo $policy | awk -F/ '{print $NF}') --resource-id $(echo $policy | awk -F: '{print $6}' | awk -F/ '{print $2"/"$3}') --scalable-dimension ecs:service:DesiredCount
done
else
echo "βΉοΈ No matching Auto Scaling policies found"
fi
echo "π Finding Auto Scaling targets..."
SCALING_TARGETS=$(aws application-autoscaling describe-scalable-targets --service-namespace ecs --query "ScalableTargets[?contains(ResourceId, 'rent-a-room')].ResourceId" --output text 2>/dev/null || echo "")
if [ -n "$SCALING_TARGETS" ]; then
echo "ποΈ Deregistering Auto Scaling targets..."
for target in $SCALING_TARGETS; do
echo "ποΈ Deregistering Auto Scaling target $target..."
aws application-autoscaling deregister-scalable-target --service-namespace ecs --resource-id $target --scalable-dimension ecs:service:DesiredCount
done
else
echo "βΉοΈ No matching Auto Scaling targets found"
fi
# Find and delete IAM roles (excluding AWS service-linked roles)
echo "π Finding IAM roles related to the workshop..."
IAM_ROLES=$(aws iam list-roles --query "Roles[?(!contains(RoleName, 'AWSServiceRole')) && (contains(RoleName, 'CodeBuild') || contains(RoleName, 'CodePipeline') || contains(RoleName, 'ECS') || contains(RoleName, 'docker-workshop'))].RoleName" --output text)
if [ -n "$IAM_ROLES" ]; then
echo "ποΈ Deleting IAM roles..."
for role in $IAM_ROLES; do
# Detach policies first
POLICIES=$(aws iam list-attached-role-policies --role-name $role --query "AttachedPolicies[].PolicyArn" --output text)
for policy in $POLICIES; do
echo "ποΈ Detaching policy $policy from role $role..."
aws iam detach-role-policy --role-name $role --policy-arn $policy
done
# Delete role
echo "ποΈ Deleting IAM role $role..."
aws iam delete-role --role-name $role
done
else
echo "βΉοΈ No matching deletable IAM roles found"
fi
# Find and delete EC2 security groups
echo "π Finding EC2 security groups related to the workshop..."
SECURITY_GROUPS=$(aws ec2 describe-security-groups --query "SecurityGroups[?contains(GroupName, 'rent-a-room') || contains(GroupName, 'workshop')].GroupId" --output text)
if [ -n "$SECURITY_GROUPS" ]; then
echo "ποΈ Deleting EC2 security groups..."
for sg in $SECURITY_GROUPS; do
# Check for dependencies
DEPENDENCIES=$(aws ec2 describe-network-interfaces --filters "Name=group-id,Values=$sg" --query 'NetworkInterfaces[].NetworkInterfaceId' --output text)
if [ -n "$DEPENDENCIES" ]; then
echo "β οΈ Security group $sg has dependencies: $DEPENDENCIES"
echo "βΉοΈ Please manually check and remove dependencies before deleting this security group"
else
echo "ποΈ Deleting security group $sg..."
aws ec2 delete-security-group --group-id $sg
fi
done
else
echo "βΉοΈ No matching EC2 security groups found"
fi
# Clean up local repository
echo "π§Ή Cleaning up local Git repository..."
if [ -d "/workshop/Rent-A-Room" ]; then
cd /workshop/Rent-A-Room
git remote -v | grep origin | grep -q github.com && echo "βΉοΈ Consider deleting your GitHub fork of Rent-A-Room if no longer needed"
cd ..
fi
echo "β
Cleanup completed successfully!"
echo "π Note: Please verify in the AWS Console that all resources have been properly deleted."
echo "π‘ Tip: You may also want to delete your GitHub fork of the Rent-A-Room repository if you no longer need it."
EOF
# Make the script executable
chmod +x cleanup-workshop.sh
# Run the cleanup script
./cleanup-workshop.shPlease note that in the above command you will need to use q on the keyboard to quite from the output of command output to go on to the next delete.
π What the Cleanup Script Does
The script automatically:
- Finds and deletes CloudFormation stacks related to the workshop, including the VS Code server stack
- Cleans up ECS resources including clusters and services
- Removes Load Balancers and Target Groups created for the application
- Deletes CodeBuild projects created during the workshop
- Removes CodePipeline pipelines used for CI/CD
- Empties and removes S3 buckets used for artifacts
- Deletes CodeStar connections to GitHub
- Removes Secrets Manager secrets for Docker Hub and GitHub
- Cleans up Auto Scaling policies and targets configured for the ECS service
- Removes IAM roles created for the workshop services
- Deletes EC2 security groups created for the application
- Provides guidance on cleaning up your GitHub fork
β οΈ Manual Verification
After running the script, it’s always a good practice to verify in the AWS Console that all resources have been properly deleted:
- Check the CloudFormation console for any remaining stacks
- Verify in the ECS console that clusters and services are removed
- Check the EC2 console for any remaining load balancers, target groups, or security groups
- Look for any remaining CodePipeline, CodeBuild, or CodeStar resources
- Verify that all S3 buckets related to the workshop have been deleted
- Check Secrets Manager for any remaining secrets
- Look for any remaining IAM roles or policies
π Workshop Completion
Congratulations on completing the AWS and Docker: Better Together workshop! You’ve learned how to:
- Build a complete CI/CD pipeline using AWS services and Docker technologies
- Implement multi-architecture container builds with Docker Build Cloud
- Integrate security scanning with Docker Scout
- Deploy containerized applications to Amazon ECS
- Define infrastructure as code with AWS CloudFormation
- Implement advanced deployment strategies like blue/green and canary deployments
We hope you found this workshop valuable and that you’ll apply these techniques in your own projects!