There are more AWS SDK examples available in the AWS Doc SDK Examples
Getting started with Amazon EC2
The following code example shows how to:
Create a key pair
Create a security group
Stop and start your instance
Test Elastic IP persistence
Clean up resources
- Bash
-
- AWS CLI with Bash script
-
Note
There's more on GitHub. Find the complete example and learn how to set up and run in the Sample developer tutorials
repository. #!/bin/bash # EC2 Basics Tutorial Script - Revised # This script demonstrates the basics of working with EC2 instances using AWS CLI # Updated to use Amazon Linux 2023 and enhanced security settings # Set up logging LOG_FILE="ec2_tutorial_$(date +%Y%m%d_%H%M%S).log" exec > >(tee -a "$LOG_FILE") 2>&1 # Function to log messages log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" } # Function to handle errors handle_error() { log "ERROR: $1" log "Cleaning up resources..." cleanup exit 1 } # Function to clean up resources cleanup() { log "Resources created:" if [ -n "$ASSOCIATION_ID" ]; then log "- Elastic IP Association: $ASSOCIATION_ID" fi if [ -n "$ALLOCATION_ID" ]; then log "- Elastic IP Allocation: $ALLOCATION_ID (IP: $ELASTIC_IP)" fi if [ -n "$INSTANCE_ID" ]; then log "- EC2 Instance: $INSTANCE_ID" fi if [ -n "$SECURITY_GROUP_ID" ]; then log "- Security Group: $SECURITY_GROUP_ID" fi if [ -n "$KEY_NAME" ]; then log "- Key Pair: $KEY_NAME (File: $KEY_FILE)" fi read -p "Do you want to delete these resources? (y/n): " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then log "Starting cleanup..." # Track cleanup failures CLEANUP_FAILURES=0 # Disassociate Elastic IP if it exists if [ -n "$ASSOCIATION_ID" ]; then log "Disassociating Elastic IP..." if ! aws ec2 disassociate-address --association-id "$ASSOCIATION_ID"; then log "Failed to disassociate Elastic IP" ((CLEANUP_FAILURES++)) fi fi # Release Elastic IP if it exists if [ -n "$ALLOCATION_ID" ]; then log "Releasing Elastic IP..." if ! aws ec2 release-address --allocation-id "$ALLOCATION_ID"; then log "Failed to release Elastic IP" ((CLEANUP_FAILURES++)) fi fi # Terminate instance if it exists if [ -n "$INSTANCE_ID" ]; then log "Terminating instance $INSTANCE_ID..." if ! aws ec2 terminate-instances --instance-ids "$INSTANCE_ID" > /dev/null; then log "Failed to terminate instance" ((CLEANUP_FAILURES++)) else log "Waiting for instance to terminate..." if ! aws ec2 wait instance-terminated --instance-ids "$INSTANCE_ID"; then log "Failed while waiting for instance to terminate" ((CLEANUP_FAILURES++)) fi fi fi # Delete security group if it exists if [ -n "$SECURITY_GROUP_ID" ]; then log "Deleting security group..." if ! aws ec2 delete-security-group --group-id "$SECURITY_GROUP_ID"; then log "Failed to delete security group" ((CLEANUP_FAILURES++)) fi fi # Delete key pair if it exists if [ -n "$KEY_NAME" ]; then log "Deleting key pair..." if ! aws ec2 delete-key-pair --key-name "$KEY_NAME"; then log "Failed to delete key pair" ((CLEANUP_FAILURES++)) fi # Remove key file if [ -f "$KEY_FILE" ]; then log "Removing key file..." if ! rm -f "$KEY_FILE"; then log "Failed to remove key file" ((CLEANUP_FAILURES++)) fi fi fi # Report cleanup status if [ $CLEANUP_FAILURES -eq 0 ]; then log "Cleanup completed successfully." else log "WARNING: Cleanup completed with $CLEANUP_FAILURES failures. Some resources may not have been deleted properly." fi else log "Resources were not deleted." fi } # Generate random identifier for resource names RANDOM_ID=$(openssl rand -hex 4) KEY_NAME="ec2-tutorial-key-$RANDOM_ID" SG_NAME="ec2-tutorial-sg-$RANDOM_ID" # Create a directory for the key file KEY_DIR=$(mktemp -d) KEY_FILE="$KEY_DIR/$KEY_NAME.pem" log "Starting EC2 basics tutorial script" log "Random identifier: $RANDOM_ID" log "Key name: $KEY_NAME" log "Security group name: $SG_NAME" # Step 1: Create a key pair log "Creating key pair..." KEY_RESULT=$(aws ec2 create-key-pair --key-name "$KEY_NAME" --query 'KeyMaterial' --output text) if [ $? -ne 0 ] || [ -z "$KEY_RESULT" ]; then handle_error "Failed to create key pair" fi echo "$KEY_RESULT" > "$KEY_FILE" chmod 400 "$KEY_FILE" log "Created key pair and saved to $KEY_FILE" # Step 2: Create a security group log "Creating security group..." SECURITY_GROUP_ID=$(aws ec2 create-security-group \ --group-name "$SG_NAME" \ --description "Security group for EC2 tutorial" \ --query "GroupId" \ --output text) if [ $? -ne 0 ] || [ -z "$SECURITY_GROUP_ID" ]; then handle_error "Failed to create security group" fi log "Created security group: $SECURITY_GROUP_ID" # Get current public IP address for SSH access MY_IP=$(curl -s http://checkip.amazonaws.com) if [ $? -ne 0 ] || [ -z "$MY_IP" ]; then handle_error "Failed to get current IP address" fi log "Adding SSH ingress rule for IP $MY_IP..." aws ec2 authorize-security-group-ingress \ --group-id "$SECURITY_GROUP_ID" \ --protocol tcp \ --port 22 \ --cidr "$MY_IP/32" > /dev/null if [ $? -ne 0 ]; then handle_error "Failed to add security group ingress rule" fi log "Added SSH ingress rule for IP $MY_IP" # Step 3: Find an Amazon Linux 2023 AMI (updated from AL2) log "Finding latest Amazon Linux 2023 AMI..." AMI_ID=$(aws ssm get-parameters-by-path \ --path "/aws/service/ami-amazon-linux-latest" \ --query "Parameters[?contains(Name, 'al2023-ami-kernel-default-x86_64')].Value" \ --output text | head -1) if [ $? -ne 0 ] || [ -z "$AMI_ID" ]; then handle_error "Failed to find Amazon Linux 2023 AMI" fi log "Selected AMI: $AMI_ID" # Get the architecture of the AMI log "Getting AMI architecture..." AMI_ARCH=$(aws ec2 describe-images \ --image-ids "$AMI_ID" \ --query "Images[0].Architecture" \ --output text) if [ $? -ne 0 ] || [ -z "$AMI_ARCH" ]; then handle_error "Failed to get AMI architecture" fi log "AMI architecture: $AMI_ARCH" # Find a compatible instance type log "Finding compatible instance type..." # Directly use t2.micro for simplicity INSTANCE_TYPE="t2.micro" log "Using instance type: $INSTANCE_TYPE" # Step 4: Launch an EC2 instance with enhanced security log "Launching EC2 instance with IMDSv2 and encryption enabled..." INSTANCE_ID=$(aws ec2 run-instances \ --image-id "$AMI_ID" \ --instance-type "$INSTANCE_TYPE" \ --key-name "$KEY_NAME" \ --security-group-ids "$SECURITY_GROUP_ID" \ --metadata-options "HttpTokens=required,HttpEndpoint=enabled" \ --block-device-mappings "DeviceName=/dev/xvda,Ebs={Encrypted=true}" \ --count 1 \ --query 'Instances[0].InstanceId' \ --output text) if [ $? -ne 0 ] || [ -z "$INSTANCE_ID" ]; then handle_error "Failed to launch EC2 instance" fi log "Launched instance $INSTANCE_ID. Waiting for it to start..." # Wait for the instance to be running aws ec2 wait instance-running --instance-ids "$INSTANCE_ID" if [ $? -ne 0 ]; then handle_error "Failed while waiting for instance to start" fi # Get instance details INSTANCE_DETAILS=$(aws ec2 describe-instances \ --instance-ids "$INSTANCE_ID" \ --query 'Reservations[0].Instances[0].{ID:InstanceId,Type:InstanceType,State:State.Name,PublicIP:PublicIpAddress}' \ --output json) if [ $? -ne 0 ]; then handle_error "Failed to get instance details" fi log "Instance details: $INSTANCE_DETAILS" # Get the public IP address PUBLIC_IP=$(echo "$INSTANCE_DETAILS" | grep -oP '"PublicIP": "\K[^"]+') if [ -z "$PUBLIC_IP" ]; then handle_error "Failed to get instance public IP" fi log "Instance public IP: $PUBLIC_IP" log "To connect to your instance, run: ssh -i $KEY_FILE ec2-user@$PUBLIC_IP" # Pause to allow user to connect if desired read -p "Press Enter to continue to the next step (stopping and starting the instance)..." # Step 6: Stop and Start the Instance log "Stopping instance $INSTANCE_ID..." aws ec2 stop-instances --instance-ids "$INSTANCE_ID" > /dev/null if [ $? -ne 0 ]; then handle_error "Failed to stop instance" fi log "Waiting for instance to stop..." aws ec2 wait instance-stopped --instance-ids "$INSTANCE_ID" if [ $? -ne 0 ]; then handle_error "Failed while waiting for instance to stop" fi log "Instance stopped. Starting instance again..." aws ec2 start-instances --instance-ids "$INSTANCE_ID" > /dev/null if [ $? -ne 0 ]; then handle_error "Failed to start instance" fi log "Waiting for instance to start..." aws ec2 wait instance-running --instance-ids "$INSTANCE_ID" if [ $? -ne 0 ]; then handle_error "Failed while waiting for instance to start" fi # Get the new public IP address NEW_PUBLIC_IP=$(aws ec2 describe-instances \ --instance-ids "$INSTANCE_ID" \ --query 'Reservations[0].Instances[0].PublicIpAddress' \ --output text) if [ $? -ne 0 ] || [ -z "$NEW_PUBLIC_IP" ]; then handle_error "Failed to get new public IP" fi log "Instance restarted with new public IP: $NEW_PUBLIC_IP" log "To connect to your instance, run: ssh -i $KEY_FILE ec2-user@$NEW_PUBLIC_IP" # Step 7: Allocate and Associate an Elastic IP Address log "Allocating Elastic IP address..." ALLOCATION_RESULT=$(aws ec2 allocate-address \ --domain vpc \ --query '[PublicIp,AllocationId]' \ --output text) if [ $? -ne 0 ] || [ -z "$ALLOCATION_RESULT" ]; then handle_error "Failed to allocate Elastic IP" fi ELASTIC_IP=$(echo "$ALLOCATION_RESULT" | awk '{print $1}') ALLOCATION_ID=$(echo "$ALLOCATION_RESULT" | awk '{print $2}') log "Allocated Elastic IP: $ELASTIC_IP with ID: $ALLOCATION_ID" log "Associating Elastic IP with instance..." ASSOCIATION_ID=$(aws ec2 associate-address \ --instance-id "$INSTANCE_ID" \ --allocation-id "$ALLOCATION_ID" \ --query "AssociationId" \ --output text) if [ $? -ne 0 ] || [ -z "$ASSOCIATION_ID" ]; then handle_error "Failed to associate Elastic IP" fi log "Associated Elastic IP with instance. Association ID: $ASSOCIATION_ID" log "To connect to your instance using the Elastic IP, run: ssh -i $KEY_FILE ec2-user@$ELASTIC_IP" # Pause to allow user to connect if desired read -p "Press Enter to continue to the next step (testing Elastic IP persistence)..." # Step 8: Test the Elastic IP by Stopping and Starting the Instance log "Stopping instance $INSTANCE_ID to test Elastic IP persistence..." aws ec2 stop-instances --instance-ids "$INSTANCE_ID" > /dev/null if [ $? -ne 0 ]; then handle_error "Failed to stop instance" fi log "Waiting for instance to stop..." aws ec2 wait instance-stopped --instance-ids "$INSTANCE_ID" if [ $? -ne 0 ]; then handle_error "Failed while waiting for instance to stop" fi log "Instance stopped. Starting instance again..." aws ec2 start-instances --instance-ids "$INSTANCE_ID" > /dev/null if [ $? -ne 0 ]; then handle_error "Failed to start instance" fi log "Waiting for instance to start..." aws ec2 wait instance-running --instance-ids "$INSTANCE_ID" if [ $? -ne 0 ]; then handle_error "Failed while waiting for instance to start" fi # Verify the Elastic IP is still associated CURRENT_IP=$(aws ec2 describe-instances \ --instance-ids "$INSTANCE_ID" \ --query 'Reservations[0].Instances[0].PublicIpAddress' \ --output text) if [ $? -ne 0 ] || [ -z "$CURRENT_IP" ]; then handle_error "Failed to get current public IP" fi log "Current public IP address: $CURRENT_IP" log "Elastic IP address: $ELASTIC_IP" if [ "$CURRENT_IP" = "$ELASTIC_IP" ]; then log "Success! The Elastic IP is still associated with your instance." else log "Something went wrong. The Elastic IP is not associated with your instance." fi log "To connect to your instance, run: ssh -i $KEY_FILE ec2-user@$ELASTIC_IP" # Step 9: Clean up resources log "Tutorial completed successfully!" cleanup exit 0-
For API details, see the following topics in AWS CLI Command Reference.
-
Getting started with Amazon DocumentDB
Getting started with Amazon EMR