您可能会用到的AWS CLI Shell脚本。主要功能有根据名字/类别管理EC2、RDS资源,创建资源时自动添加标签,创建EC2实例时可附加卷、定义用户数据文件。可用-h或--help查看支持的命令和参数,GitHub源码。
支持的命令: EC2
Usage: ./ec2.sh [command] [args ...]
Commands:
create-image [instance_name] [image_name] [tags] Create an AMI from an EC2 instance
delete-image [image_name] Delete image by name
start-instance [instance_name] Start an EC2 instance
start-instances [category_name] Start EC2 instances by category
stop-instance [instance_name] Stop an EC2 instance
stop-instances [category_name] Stop EC2 instances by category
reboot-instance [instance_name] Reboot an EC2 instance
reboot-instances [category_name] Reboot EC2 instances by category
terminate-instance [instance_name] Terminate an EC2 instance
terminate-instances [category_name] Terminate EC2 instances by category
run-instance [instance_name] [image_name] [options] Launch an instance using an AMI
Options:
--device-snapshot-name One block device snapshot name
--init-file an user data file
--tags One or more tags
create-snapshot [instance_name] [device] [snapshot_name] [tags] Creates a snapshot of the specified volume for an instance
delete-snapshot [snapshot_name] Deletes the specified snapshot
attach-volume [snapshot_name] [instance_name] [device] [tags] Create a volume from a snapshot, and then attach the volume to an instance
associate-address [instance_name] [public_ip] Associates an Elastic IP address with an instance
replace-route [route_table_name] [nat_instance_name] [cidr] Replaces an existing route within a route table in a VPC
RDS
Usage: ./rds.sh [delete|restore] [args ...]
Commands:
delete [db-instance-identifier] Delete a DB instance
restore [db-instance-identifier] [vpc-security-group-ids] Create a new DB instance from a DB snapshot
Cloud Watch
Usage: ./cloudwatch.sh [cpu] [instance_name] [sns_topic_arn]
EC2
公用方法common.sh
#!/bin/bash
INSTANCE_ID_REGEX="i-\w{8,17}"
IMAGE_ID_REGEX="ami-\w{8,17}"
VOLUME_ID_REGEX="vol-\w{8,17}"
SNAPSHOT_ID_REGEX="snap-\w{8,17}"
ROUTETABLE_ID_REGEX="rtb-\w{8,17}"
query_instance_id_by_name() {
instance_id=$(aws ec2 describe-instances --filter Name=tag:Name,Values="$1" Name=instance-state-name,Values=pending,running,stopped \
--query 'Reservations[0].[Instances[0].InstanceId]' | grep -o -E "$INSTANCE_ID_REGEX")
echo ${instance_id}
}
query_instance_ids_by_category() {
instance_ids=$(aws ec2 describe-instances --filter Name=tag:Category,Values="$1" Name=instance-state-name,Values=pending,running,stopped \
--query 'Reservations[*].[Instances[*].InstanceId]' | grep -o -E "$INSTANCE_ID_REGEX")
echo ${instance_ids}
}
wait_instance_ok() {
instance_id=$(aws ec2 describe-instances --filter Name=tag:Name,Values="$1" Name=instance-state-name,Values=pending,running \
--query 'Reservations[0].[Instances[0].InstanceId]' | grep -o -E "$INSTANCE_ID_REGEX")
check_instance_status ${instance_id}
}
check_instance_status() {
while true
do
ok_count=$(aws ec2 describe-instance-status --instance-id $1 | grep -c ok)
if [[ "$ok_count" -eq 2 ]]; then
break
else
echo "Waiting ..."
sleep 5
fi
done
}
describe_running_instances() {
instances=$(aws ec2 describe-instances --filter Name=instance-state-name,Values=running \
--query 'Reservations[*].Instances[*].{State:State.Name,Ip:PrivateIpAddress,InstanceId:InstanceId,Name:Tags[0].Value}')
echo ${instances}
}
query_image_id_by_name() {
image_id=$(aws ec2 describe-images --filter Name=name,Values="$1" --query Images[0].[ImageId] | grep -o -E "$IMAGE_ID_REGEX")
echo ${image_id}
}
query_volume_id_by_name() {
id=$(aws ec2 describe-volumes --filter Name=tag:Name,Values="$1" --query Volumes[0].[VolumeId] | grep -o -E "$VOLUME_ID_REGEX")
echo ${id}
}
query_volume_ids_by_name() {
id=$(aws ec2 describe-volumes --filter Name=tag:Name,Values="$1" --query Volumes[*].[VolumeId] | grep -o -E "$VOLUME_ID_REGEX")
echo ${id}
}
query_volume_id_by_instance_id_and_device() {
id=$(aws ec2 describe-volumes --filter Name=attachment.instance-id,Values="$1" Name=attachment.device,Values=$2 \
--query Volumes[0].[VolumeId] | grep -o -E "$VOLUME_ID_REGEX")
echo ${id}
}
query_snapshot_id_by_name() {
snapshot_id=$(aws ec2 describe-snapshots --filter Name=tag:Name,Values="$1" --query Snapshots[0].[SnapshotId] | grep -o -E "$SNAPSHOT_ID_REGEX")
echo ${snapshot_id}
}
query_snapshot_ids_by_image_id() {
snapshot_ids=$(aws ec2 describe-snapshots --query Snapshots[*].[SnapshotId][*] --filter Name=description,Values=*"$1"* | grep -o -E "$SNAPSHOT_ID_REGEX")
echo ${snapshot_ids}
}
query_route_table_id_by_name() {
id=$(aws ec2 describe-route-tables --filter Name=tag:Name,Values="$1" --query RouteTables[0].RouteTableId | grep -o -E "$ROUTETABLE_ID_REGEX")
echo ${id}
}
query_elb_instance_ids() {
ids=$(aws elb describe-load-balancers --load-balancer-name "$1" --query LoadBalancerDescriptions[0].[Instances[*].[InstanceId]] | grep -o -E "$INSTANCE_ID_REGEX")
echo ${ids}
}
create_tags_with_name() {
resource_id=$1
name=$2
tags=$3;
if [[ -z ${resource_id} ]]; then
return 1
fi
if [[ ${tags} ]]; then
echo "Add tags: ${tags}"
fi
aws ec2 create-tags --resources ${resource_id} --tags Key=Name,Value="${name}" ${tags}
echo
}
EC2脚本ec2.sh
#!/bin/bash
. $(dirname $0)/common.sh
# 根据Instance Name创建image并添加标签
create_image() {
instance_name=$1
image_name=$2
tags=$3
echo "Create image for instance ${instance_name}"
instance_id=$(query_instance_id_by_name "${instance_name}")
image_id=$(aws ec2 create-image --instance-id "${instance_id}" --name "${image_name}" --description "${image_name}" --no-reboot --query ImageId)
image_id=${image_id//\"/}
echo "ImageId: $image_id"
create_tags_with_name "${image_id}" "${image_name}" "${tags}"
}
# 删除AMI
delete_image() {
image_name=$1
echo "Delete image ${image_name}"
image_id=$(query_image_id_by_name "${image_name}")
echo "Image id: ${image_id}"
echo "Deregister image $image_id"
aws ec2 deregister-image --image-id "${image_id}"
snapshot_ids=$(query_snapshot_ids_by_image_id "${image_id}")
for snapshot_id in ${snapshot_ids}
do
echo "Delete snapshot ${snapshot_id}"
aws ec2 delete-snapshot --snapshot-id "${snapshot_id}"
done
echo
}
# 根据Name启动EC2 Instance
start_instance() {
id=$(query_instance_id_by_name "$1")
aws ec2 start-instances --instance-ids ${id}
}
# 根据类别启动EC2 Instance
start_instances() {
ids=$(query_instance_ids_by_category "$1")
aws ec2 start-instances --instance-ids ${ids}
}
# 根据Name停止EC2 Instance
stop_instance() {
id=$(query_instance_id_by_name "$1")
aws ec2 stop-instances --instance-ids ${id}
}
# 根据类别停止EC2 Instance
stop_instances() {
ids=$(query_instance_ids_by_category "$1")
aws ec2 stop-instances --instance-ids ${ids}
}
# 根据Name重启EC2 Instance
reboot_instance() {
id=$(query_instance_id_by_name "$1")
aws ec2 reboot-instances --instance-ids ${id}
}
# 根据类别重启EC2 Instance
reboot_instances() {
ids=$(query_instance_ids_by_category "$1")
aws ec2 reboot-instances --instance-ids ${ids}
}
# 根据Name终止EC2 Instance
terminate_instance() {
id=$(query_instance_id_by_name "$1")
echo "terminate instance, instance name: $1 instance id: ${id}"
aws ec2 modify-instance-attribute --instance-id "${id}" --no-disable-api-termination
aws ec2 terminate-instances --instance-ids ${id}
echo
}
# 根据类别终止EC2 Instance
terminate_instances() {
ids=$(query_instance_ids_by_category "$1")
echo "terminate instances, category: $1 instance-ids: ${ids}"
for id in ${ids}
do
aws ec2 modify-instance-attribute --instance-id "${id}" --no-disable-api-termination
done
aws ec2 terminate-instances --instance-ids ${ids}
echo
}
# 从Image创建EC2 Instance,EC2配置从JSON文件读取,可以附加一个Volume,可以使用用户数据文件,可以添加标签
run_instance() {
instance_name=$1
image_name=$2
device_snapshot_name=$3
init_file=$4
tags=$5
block_device_mappings=" "
if [[ "${device_snapshot_name}" ]]; then
snapshot_id=$(query_snapshot_id_by_name "${device_snapshot_name}")
if [[ "${snapshot_id}" ]]; then
block_device_mappings="--block-device-mappings DeviceName=/dev/sdf,Ebs={SnapshotId=${snapshot_id},DeleteOnTermination=true,VolumeType=gp2}"
else
echo "Please provide a valid volume snapshot name"
exit 1
fi
fi
image_id=$(query_image_id_by_name "${image_name}")
echo "Create EC2 instance ${instance_name} from image ${image_name}(${image_id})"
if [[ "$init_file" ]]; then
instance_id=$(aws ec2 run-instances --image-id "${image_id}" ${block_device_mappings} --cli-input-json file://json/"${instance_name}".json \
--user-data file://"${init_file}" --query 'Instances[0].[InstanceId]' | grep -o -E "${INSTANCE_ID_REGEX}")
else
instance_id=$(aws ec2 run-instances --image-id "${image_id}" ${block_device_mappings} --cli-input-json file://json/"${instance_name}".json \
--query 'Instances[0].[InstanceId]' | grep -o -E "${INSTANCE_ID_REGEX}")
fi
create_tags_with_name "${instance_id}" "${instance_name}" "${tags}"
}
# 为EC2 Instance的指定卷创建快照并删除以前同名快照
create_snapshot() {
instance_name=$1
device=$2
snapshot_name=$3
tags=$4
instance_id=$(query_instance_id_by_name "${instance_name}")
delete_snapshot "${snapshot_name}"
volume_id=$(query_volume_id_by_instance_id_and_device ${instance_id} ${device})
if [[ "${volume_id}" ]]; then
echo "create snapshot for volume: ${device} of instance ${instance_name}"
snapshot_id=$(aws ec2 create-snapshot --volume-id ${volume_id} | grep -o -E "${SNAPSHOT_ID_REGEX}")
create_tags_with_name "${snapshot_id}" "${snapshot_name}" "${tags}"
fi
}
# 根据名称删除快照
delete_snapshot() {
snapshot_id=$(query_snapshot_id_by_name "$1")
if [[ "${snapshot_id}" ]]; then
echo "delete snapshot: $1"
aws ec2 delete-snapshot --snapshot-id ${snapshot_id}
fi
}
# 从快照创建卷并删除旧的重名卷,然后将卷连接到Instance的指定device
attach_volume() {
snapshot_name=$1
instance_name=$2
device=$3
tags=$4
availability_zone="cn-north-1a"
volume_name="$1-1a"
snapshot_id=$(query_snapshot_id_by_name ${snapshot_name})
instance_id=$(query_instance_id_by_name ${instance_name})
if [[ -z "${snapshot_id}" ]]; then
echo "Please provide valid snapshot name"
exit 1
fi
if [[ -z "${instance_id}" ]]; then
echo "Please provide valid instance name"
exit 1
fi
old_volume_ids=$(query_volume_ids_by_name "${volume_name}")
for id in ${old_volume_ids}
do
echo "delete old volume: $id"
aws ec2 delete-volume --volume-id ${id}
done
echo "create volume ${volume_name} from snapshot ${snapshot_name}(${snapshot_id})"
volume_id=$(aws ec2 create-volume --snapshot-id ${snapshot_id} --availability-zone ${availability_zone} --volume-type gp2 --query 'VolumeId' \
| grep -o -E "${VOLUME_ID_REGEX}")
count=0
while [[ "${count}" -le 0 ]]
do
echo "Creating volume ${volume_name} ..."
count=$(aws ec2 describe-volumes --volume-ids ${volume_id} --query Volumes[0].State | grep -c available)
sleep 3
done
echo "attach volume: ${volume_name} to instance ${instance_name}"
aws ec2 attach-volume --volume-id ${volume_id} --instance-id ${instance_id} --device ${device}
create_tags_with_name "${volume_id}" "${volume_name}" "${tags}"
}
# 关联弹性IP到Instance
associate_address() {
instance_id=$(query_instance_id_by_name "$1")
aws ec2 associate-address --instance-id ${instance_id} --public-ip $2
}
# 更新NAT Instance路由
replace_route() {
echo "update route table: $1"
route_table_id=$(query_route_table_id_by_name "$1")
nat_instance_id=$(query_instance_id_by_name "$2")
cidr=$3
aws ec2 replace-route --route-table-id ${route_table_id} --destination-cidr-block ${cidr} --instance-id ${nat_instance_id}
}
echo_usage() {
echo "Usage: $0 [command] [args ...]"
echo "Commands:"
echo " create-image [instance_name] [image_name] [tags] Create an AMI from an EC2 instance"
echo " delete-image [image_name] Delete image by name"
echo " start-instance [instance_name] Start an EC2 instance"
echo " start-instances [category_name] Start EC2 instances by category"
echo " stop-instance [instance_name] Stop an EC2 instance"
echo " stop-instances [category_name] Stop EC2 instances by category"
echo " reboot-instance [instance_name] Reboot an EC2 instance"
echo " reboot-instances [category_name] Reboot EC2 instances by category"
echo " terminate-instance [instance_name] Terminate an EC2 instance"
echo " terminate-instances [category_name] Terminate EC2 instances by category"
echo " run-instance [instance_name] [image_name] [options] Launch an instance using an AMI"
echo " Options:"
echo " --device-snapshot-name One block device snapshot name"
echo " --init-file an user data file"
echo " --tags One or more tags"
echo " create-snapshot [instance_name] [device] [snapshot_name] [tags] Creates a snapshot of the specified volume for an instance"
echo " delete-snapshot [snapshot_name] Deletes the specified snapshot"
echo " attach-volume [snapshot_name] [instance_name] [device] [tags] Create a volume from a snapshot, and then attach the volume to an instance"
echo " associate-address [instance_name] [public_ip] Associates an Elastic IP address with an instance"
echo " replace-route [route_table_name] [nat_instance_name] [cidr] Replaces an existing route within a route table in a VPC"
}
if test @$1 = @--help -o @$1 = @-h; then
echo_usage
exit 0
fi
if [[ $# -lt 2 ]]; then
echo_usage
exit 1
fi
case "$1" in
create-image)
create_image "$2" "$3" "$4"
;;
delete-image)
delete_image "$2"
;;
start-instance)
start_instance "$2"
;;
start-instances)
start_instances "$2"
;;
stop-instance)
stop_instance "$2"
;;
stop-instances)
stop_instances "$2"
;;
reboot-instance)
reboot_instance "$2"
;;
reboot-instances)
reboot_instances "$2"
;;
terminate-instance)
terminate_instance "$2"
;;
terminate-instances)
terminate_instances "$2"
;;
run-instance)
args=`getopt -l init-file:,device-snapshot-name:,tags: -- "$@"`
if [[ $? != 0 ]] ; then
exit 1
fi
instance_name=$2
image_name=$3
device_snapshot_name=""
init_file=""
tags=""
eval set -- "${args}"
while true
do
case "$1" in
--device-snapshot-name)
device_snapshot_name="$2"
shift 2
;;
--init-file)
init_file="$2"
shift 2
;;
--tags)
tags="$2"
shift 2
;;
--)
shift
break
;;
esac
done
run_instance "${instance_name}" "${image_name}" "${device_snapshot_name}" "${init_file}" "${tags}"
;;
create-snapshot)
create_snapshot "$2" "$3" "$4" "$5"
;;
delete-snapshot)
delete_snapshot "$2"
;;
attach-volume)
attach_volume "$2" "$3" "$4" "$5"
;;
associate-address)
associate_address "$2" "$3"
;;
replace-route)
replace_route "$2" "$3" "$4"
;;
*)
exit 1
;;
esac
从image运行instance时需要使用json配置文件,位置在json目录下,名称要与instance name相同,内容如下; 示例ec2.json
{
"DryRun": false,
"KeyName": "AWS Prod Key Pair",
"SecurityGroupIds": [
"sg-1361c577"
],
"InstanceType": "m4.large",
"Placement": {
"AvailabilityZone": "cn-north-1a",
"Tenancy": "default"
},
"Monitoring": {
"Enabled": false
},
"DisableApiTermination": true,
"InstanceInitiatedShutdownBehavior": "stop",
"NetworkInterfaces": [
{
"DeviceIndex": 0,
"SubnetId": "subnet-d45208b1",
"PrivateIpAddress": "10.184.12.246",
"DeleteOnTermination": true,
"AssociatePublicIpAddress": false
}
],
"EbsOptimized": false
}
示例
$ ./ec2.sh run-instance test-app1 test-app1 --tags "Key=CCX,Value=DSC003 Key=Project,Value=Test"
RDS
rds.sh
#!/bin/bash
# 根据db-instance-identifier删除数据库,删除前先创建快照,并将db-snapshot-identifier保存在文件中
delete() {
echo "deleting database $1 ..."
snapshot_id="$1-$(date +%Y%m%d)"
aws rds delete-db-instance --db-instance-identifier "$1" --no-skip-final-snapshot --final-db-snapshot-identifier "${snapshot_id}"
echo "${snapshot_id}" > "$(dirname $0)/$1.snapshot.id"
}
# 从最近的快照恢复数据库,数据库配置从json文件读取,恢复成功后指定security group,并输出恢复日志到文件中
restore() {
log_file="$(dirname $0)/restore.log"
id_file="$(dirname $0)/$1.snapshot.id"
snapshot_id=$(cat ${id_file})
echo "Restore database $1 from snapshot ${snapshot_id}" | tee ${log_file}
aws rds restore-db-instance-from-db-snapshot --db-snapshot-identifier "${snapshot_id}" --cli-input-json file://json/"$1".json | tee ${log_file}
count=0
while [[ "${count}" -le 0 ]]
do
echo "Creating database $1 ..."
count=$(aws rds describe-db-instances --db-instance-identifier "$1" --query 'DBInstances[0].[DBInstanceStatus]' | grep -c available)
sleep 5
done
echo "Modify database $1" | tee ${log_file}
aws rds modify-db-instance --db-instance-identifier "$1" --vpc-security-group-ids $2 | tee ${log_file}
}
echo_usage() {
echo "Usage: $0 [delete|restore] [args ...]"
echo "Commands:"
echo " delete [db-instance-identifier] Delete a DB instance"
echo " restore [db-instance-identifier] [vpc-security-group-ids] Create a new DB instance from a DB snapshot"
}
if test @$1 = @--help -o @$1 = @-h; then
echo_usage
exit 0
fi
if [[ $# -lt 2 ]]; then
echo_usage
exit 1
fi
case "$1" in
delete)
delete "$2"
;;
restore)
restore "$2" "$3"
;;
*)
exit 1
;;
esac
示例dn.json
{
"DBInstanceIdentifier": "test",
"DBInstanceClass": "db.r3.large",
"Port": 1521,
"AvailabilityZone": "cn-north-1a",
"DBSubnetGroupName": "test-db",
"MultiAZ": false,
"PubliclyAccessible": false,
"AutoMinorVersionUpgrade": true,
"LicenseModel": "license-included",
"DBName": "test",
"Engine": "oracle-se1",
"OptionGroupName": "default:oracle-se1-11-2",
"StorageType": "standard",
"CopyTagsToSnapshot": true
}
CloudWatch
cloudwatch.sh
#!/bin/bash
. $(dirname $0)/common.sh
# 当EC2 Instance CPU利用率超过90%时发送邮件告警
cpu() {
instance_name=$1
sns_topic_arn=$2
instance_id=$(query_instance_id_by_name "${instance_name}")
aws cloudwatch put-metric-alarm --alarm-name "cpu-${instance_name}" --alarm-description "Alarm when CPU exceeds 90 percent" --metric-name CPUUtilization \
--namespace AWS/EC2 --statistic Average --period 300 --threshold 90 --comparison-operator GreaterThanThreshold \
--dimensions "Name=InstanceId,Value=${instance_id}" --evaluation-periods 2 --unit Percent --alarm-actions $2
}
echo_usage() {
echo "Usage: $0 [cpu] [instance_name] [sns_topic_arn]"
}
if test @$1 = @--help -o @$1 = @-h; then
echo_usage
exit 0
fi
if [[ $# -lt 2 ]]; then
echo_usage
exit 1
fi
case "$1" in
"cpu")
cpu "$2" "$3"
;;
*)
exit 1
;;
esac