今天我們要學習 Elastic IP (EIP),這就像是為我們的農場申請一個固定的郵政地址。還記得小時候我們家搬來搬去,每次搬家都要通知所有朋友新地址嗎?Elastic IP 解決了這個問題,即使執行個體重新啟動,外部服務依然能找到我們!
Elastic IP 是 AWS 提供的靜態 IPv4 位址服務:
為什麼需要?
# 分配 Elastic IP 給 NAT Gateway
aws ec2 allocate-address \
--domain vpc \
--tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Name,Value=trading-nat-eip},{Key=Purpose,Value=NAT-Gateway}]'
# 建立 NAT Gateway 時指定 EIP
aws ec2 create-nat-gateway \
--subnet-id subnet-12345678 \
--allocation-id eipalloc-12345678 \
--tag-specifications 'ResourceType=nat-gateway,Tags=[{Key=Name,Value=trading-nat-gateway}]'
# 為 ALB 分配多個 EIP(跨可用區域)
aws ec2 allocate-address \
--domain vpc \
--tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Name,Value=trading-alb-eip-1a}]'
aws ec2 allocate-address \
--domain vpc \
--tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Name,Value=trading-alb-eip-1b}]'
# 建立備用 EIP 池
for i in {1..3}; do
aws ec2 allocate-address \
--domain vpc \
--tag-specifications "ResourceType=elastic-ip,Tags=[{Key=Name,Value=trading-backup-eip-$i},{Key=Status,Value=Reserved}]"
done
# 分配新的 Elastic IP
aws ec2 allocate-address \
--domain vpc \
--tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Environment,Value=production},{Key=Service,Value=trading-bot}]'
# 關聯到執行個體
aws ec2 associate-address \
--instance-id i-1234567890abcdef0 \
--allocation-id eipalloc-12345678
# 關聯到網路介面
aws ec2 associate-address \
--network-interface-id eni-12345678 \
--allocation-id eipalloc-12345678
# 解除關聯
aws ec2 disassociate-address \
--association-id eipassoc-12345678
# 釋放 Elastic IP(注意:會產生費用如果不釋放)
aws ec2 release-address \
--allocation-id eipalloc-12345678
import boto3
import json
def lambda_handler(event, context):
"""
自動切換 Elastic IP 到健康的執行個體
"""
ec2 = boto3.client('ec2')
# 檢查目前關聯的執行個體健康狀態
try:
# 獲取 EIP 資訊
eip_allocation_id = event['eip_allocation_id']
backup_instance_id = event['backup_instance_id']
# 檢查目前執行個體狀態
current_associations = ec2.describe_addresses(
AllocationIds=[eip_allocation_id]
)
current_instance_id = current_associations['Addresses'][0].get('InstanceId')
if current_instance_id:
# 檢查執行個體健康狀態
instance_status = ec2.describe_instance_status(
InstanceIds=[current_instance_id]
)
if not instance_status['InstanceStatuses'] or \
instance_status['InstanceStatuses'][0]['InstanceStatus']['Status'] != 'ok':
# 當前執行個體不健康,切換到備用執行個體
print(f"Switching EIP from {current_instance_id} to {backup_instance_id}")
# 解除當前關聯
ec2.disassociate_address(AllocationId=eip_allocation_id)
# 關聯到備用執行個體
ec2.associate_address(
InstanceId=backup_instance_id,
AllocationId=eip_allocation_id
)
return {
'statusCode': 200,
'body': json.dumps(f'EIP switched to backup instance {backup_instance_id}')
}
return {
'statusCode': 200,
'body': json.dumps('Current instance is healthy, no action needed')
}
except Exception as e:
print(f"Error: {str(e)}")
return {
'statusCode': 500,
'body': json.dumps(f'Error: {str(e)}')
}
# 建立執行個體狀態告警
aws cloudwatch put-metric-alarm \
--alarm-name "trading-instance-health" \
--alarm-description "Trading instance health check" \
--metric-name StatusCheckFailed \
--namespace AWS/EC2 \
--statistic Maximum \
--period 60 \
--threshold 1 \
--comparison-operator GreaterThanOrEqualToThreshold \
--evaluation-periods 2 \
--dimensions Name=InstanceId,Value=i-1234567890abcdef0 \
--alarm-actions "arn:aws:lambda:us-east-1:123456789012:function:eip-failover"
# 查找未關聯的 EIP
aws ec2 describe-addresses \
--query 'Addresses[?AssociationId==null].[AllocationId,PublicIp,Tags]' \
--output table
# 釋放未使用的 EIP
aws ec2 release-address --allocation-id eipalloc-12345678
import boto3
from datetime import datetime, timedelta
def find_unused_eips():
"""查找超過 24 小時未使用的 EIP"""
ec2 = boto3.client('ec2')
addresses = ec2.describe_addresses()
unused_eips = []
for address in addresses['Addresses']:
if 'AssociationId' not in address:
# 檢查標籤中的建立時間
for tag in address.get('Tags', []):
if tag['Key'] == 'CreatedTime':
created_time = datetime.fromisoformat(tag['Value'])
if datetime.now() - created_time > timedelta(hours=24):
unused_eips.append({
'AllocationId': address['AllocationId'],
'PublicIp': address['PublicIp'],
'Age': datetime.now() - created_time
})
return unused_eips
# 建立主要 EIP 的健康檢查
aws route53 create-health-check \
--caller-reference "trading-primary-$(date +%s)" \
--health-check-config '{
"Type": "HTTP",
"ResourcePath": "/health",
"FullyQualifiedDomainName": "52.123.45.67",
"Port": 8080,
"RequestInterval": 30,
"FailureThreshold": 3
}' \
--tags '[
{
"Key": "Name",
"Value": "trading-primary-health"
}
]'
# 建立 DNS 記錄與故障轉移
aws route53 change-resource-record-sets \
--hosted-zone-id Z123456789 \
--change-batch '{
"Changes": [
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "api.trading.example.com",
"Type": "A",
"SetIdentifier": "primary",
"Failover": "PRIMARY",
"TTL": 60,
"ResourceRecords": [{"Value": "52.123.45.67"}],
"HealthCheckId": "health-check-id"
}
}
]
}'
# 監控 EIP 關聯狀態
aws cloudwatch put-metric-alarm \
--alarm-name "eip-association-status" \
--alarm-description "EIP association status monitoring" \
--metric-name EIPAssociationStatus \
--namespace Custom/Trading \
--statistic Average \
--period 300 \
--threshold 1 \
--comparison-operator LessThanThreshold \
--evaluation-periods 1
# 監控執行個體可達性
aws cloudwatch put-metric-alarm \
--alarm-name "instance-reachability" \
--alarm-description "Instance reachability via EIP" \
--metric-name StatusCheckFailed_Instance \
--namespace AWS/EC2 \
--statistic Maximum \
--period 60 \
--threshold 1 \
--comparison-operator GreaterThanOrEqualToThreshold \
--evaluation-periods 2
#!/bin/bash
# /opt/scripts/eip-health-check.sh
EIP_ALLOCATION_ID="eipalloc-12345678"
HEALTH_CHECK_URL="http://localhost:8080/health"
BACKUP_INSTANCE_ID="i-backup123456"
# 檢查本地健康狀態
if ! curl -f "$HEALTH_CHECK_URL" > /dev/null 2>&1; then
echo "Local health check failed, initiating EIP failover"
# 觸發 Lambda 函數進行故障轉移
aws lambda invoke \
--function-name eip-failover \
--payload "{\"eip_allocation_id\":\"$EIP_ALLOCATION_ID\",\"backup_instance_id\":\"$BACKUP_INSTANCE_ID\"}" \
/tmp/lambda-response.json
echo "Failover initiated"
else
echo "Health check passed"
fi
# 為 EIP 添加詳細標籤
aws ec2 create-tags \
--resources eipalloc-12345678 \
--tags "Key=Environment,Value=production" \
"Key=Service,Value=trading-bot" \
"Key=Purpose,Value=NAT-Gateway" \
"Key=CostCenter,Value=trading-team" \
"Key=AutoShutdown,Value=false"
今天我們學習了 Elastic IP,這個固定地址服務讓我們的量化交易系統能夠維持穩定的對外連線。就像給農場申請固定的郵政地址一樣,EIP 確保外部服務始終能找到我們。
重要概念回顧:
到此為止,我們已經完成了 AWS 基礎架構的學習!明天我們將開始學習 GitHub 的功能,為我們的 CI/CD 流程做準備。
下一篇:Day 11 - Github 的功能介紹