如何使用Terraform/Terragrunt实现AMI的定时启停自动化?
Got it, let's walk through how to set up automated start/stop for your non-production EC2 instances (since you're using AMIs, we're just targeting the instances launched from those AMIs—no extra hoops for the AMIs themselves). Here are the most reliable, low-cost methods you can implement right now:
This is the go-to combo for AWS automation—it lets you define custom schedules, target instances via tags, and even add extra logic later if you need it.
Step 1: Create an IAM Role for Lambda
First, we need to give Lambda permission to interact with EC2 and log its activity:
- Head to the IAM Console, create a new role, and select Lambda as the trusted entity.
- Instead of attaching a broad full-access policy, create a custom policy with minimal permissions (best practice!):
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ec2:StartInstances", "ec2:StopInstances", "ec2:DescribeInstances" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:*:*:*" } ] } - Name the role something like
Lambda-EC2-StartStop-Roleand save it.
Step 2: Write the Lambda Function
Now let's build the function that actually starts/stops instances:
- Go to the Lambda Console, create a new function from scratch. Name it
EC2-StartStop-Function, pick Python 3.x (or your preferred runtime), and assign the IAM role you just made. - Replace the default code with this Python snippet—this uses tags to target only your non-production instances:
import boto3 def lambda_handler(event, context): ec2 = boto3.client('ec2') # Update this filter to match your non-production instance tags (e.g., Environment=NonProduction) instance_filters = [{'Name': 'tag:Environment', 'Values': ['NonProduction']}] action = event['action'] # Fetch all matching instances reservations = ec2.describe_instances(Filters=instance_filters)['Reservations'] instance_ids = [instance['InstanceId'] for res in reservations for instance in res['Instances']] if instance_ids: if action == 'start': ec2.start_instances(InstanceIds=instance_ids) print(f"Successfully started instances: {', '.join(instance_ids)}") elif action == 'stop': ec2.stop_instances(InstanceIds=instance_ids) print(f"Successfully stopped instances: {', '.join(instance_ids)}") else: print("No non-production instances found matching the filter criteria.") - Save the function, then test it with a sample event like
{"action": "stop"}to make sure it works (check the CloudWatch Logs if you run into issues).
Step 3: Set Up EventBridge Schedules to Trigger Lambda
Now we'll set up timed triggers for start and stop actions:
- Go to the EventBridge Console, create a new rule. Name it
EC2-Stop-NonProduction, add a description like "Stop non-production instances every weekday at 7 PM UTC". - For the trigger, select Schedule → Cron expression. For example, to stop instances daily at 7 PM UTC, use
0 19 * * ? *. If you're using a local timezone (like Beijing time, UTC+8), convert it first—7 PM Beijing is 11 AM UTC, so use0 11 * * ? *. - For the target, select Lambda function and pick your
EC2-StartStop-Function. Under "Configure input", choose Constant (JSON text) and enter{"action": "stop"}. - Repeat this process to create a start rule: name it
EC2-Start-NonProduction, set a cron expression for your desired start time (e.g., 9 AM UTC =0 9 * * ? *), and use{"action": "start"}as the input.
If you don't want to write code, this is a simpler alternative using AWS's pre-built automation documents:
- Head to the Systems Manager Console, go to Automation → Execute automation.
- Search for and select
AWS-StopEC2Instances(orAWS-StartEC2Instancesfor the start action). - In the input parameters, you can either list specific instance IDs or use tags to target non-production instances (e.g.,
tag:Environment=NonProduction). - To make this run on a schedule, pair it with EventBridge just like the Lambda method: create a scheduled rule, target Systems Manager Automation, select the appropriate document, and fill in the parameters.
For larger fleets or if you want a turnkey solution with built-in timezone support and tag-based scheduling, AWS has a pre-built CloudFormation template:
- This solution deploys all the necessary components (Lambda, EventBridge, IAM roles) automatically.
- All you need to do is tag your non-production instances with a schedule tag (e.g.,
Schedule=NonProductionWorkHours), then configure the start/stop times, timezones, and other settings in the solution's parameters. - Note: There's a tiny cost for Lambda executions and CloudWatch logs, but it's negligible for most use cases and saves you from building everything from scratch.
- Tag Consistently: Make sure all non-production instances have a unique tag (like
Environment=NonProduction)—this prevents accidental changes to production instances. - Timezone Math: AWS cron expressions use UTC, so always convert your local desired times to UTC before setting up schedules.
- Test First: Run your automation on a single test instance first to verify it works before rolling it out to all your non-production servers.
- Least Privilege: Stick to minimal IAM permissions—avoid giving full EC2 access unless you have a specific reason.
内容的提问来源于stack exchange,提问作者TheMew2

