iT邦幫忙

2025 iThome 鐵人賽

DAY 10
0

小明的固定地址郵政系統

今天我們要學習 Elastic IP (EIP),這就像是為我們的農場申請一個固定的郵政地址。還記得小時候我們家搬來搬去,每次搬家都要通知所有朋友新地址嗎?Elastic IP 解決了這個問題,即使執行個體重新啟動,外部服務依然能找到我們!

什麼是 Elastic IP?

Elastic IP 是 AWS 提供的靜態 IPv4 位址服務:

  • 固定不變:即使執行個體重啟,IP 位址也不會改變
  • 可重新分配:可以從一個執行個體轉移到另一個
  • 區域性資源:在特定 AWS 區域內使用
  • 成本考量:未使用時會產生費用

為什麼量化交易系統需要 Elastic IP?

傳統問題

傳統問題

使用 Elastic IP 的解決方案

使用 Elastic IP 的解決方案

Elastic IP 在我們系統中的應用

架構設計

架構設計

不同使用場景的 EIP 配置

1. NAT Gateway 使用 EIP

為什麼需要?

  • 私有子網路中的交易程式需要存取外部 API
  • 交易所需要白名單我們的 IP 位址
  • 確保出站連線的 IP 位址固定
# 分配 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}]'

2. Application Load Balancer 使用 EIP

# 為 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}]'

3. 備用 EIP 池

# 建立備用 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

EIP 管理策略

分配和關聯

# 分配新的 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

自動化 EIP 管理

Lambda 函數自動切換

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)}')
        }

CloudWatch 告警觸發切換

# 建立執行個體狀態告警
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 成本優化

成本結構

Elastic IP 成本

成本優化策略

  1. 及時釋放不用的 EIP
# 查找未關聯的 EIP
aws ec2 describe-addresses \
    --query 'Addresses[?AssociationId==null].[AllocationId,PublicIp,Tags]' \
    --output table

# 釋放未使用的 EIP
aws ec2 release-address --allocation-id eipalloc-12345678
  1. 自動化監控未使用的 EIP
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 策略

多區域 EIP 策略

Route 53 健康檢查整合

# 建立主要 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

最佳實踐

1. 標籤管理

# 為 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"

2. 安全配置

  • 限制誰可以修改 EIP 關聯
  • 使用 CloudTrail 記錄 EIP 操作
  • 設定適當的 IAM 政策

3. 備份策略

  • 保持少量備用 EIP
  • 定期演練故障轉移流程
  • 文件化恢復程序

小結

今天我們學習了 Elastic IP,這個固定地址服務讓我們的量化交易系統能夠維持穩定的對外連線。就像給農場申請固定的郵政地址一樣,EIP 確保外部服務始終能找到我們。

重要概念回顧:

  1. 固定 IP 位址:即使執行個體變更,IP 位址保持不變
  2. 成本管理:未使用時會產生費用,需要及時釋放
  3. 高可用性:配合故障轉移機制提高系統可用性
  4. 自動化管理:透過 Lambda 和 CloudWatch 實現自動切換
  5. 監控告警:持續監控 EIP 狀態和執行個體健康

到此為止,我們已經完成了 AWS 基礎架構的學習!明天我們將開始學習 GitHub 的功能,為我們的 CI/CD 流程做準備。


下一篇:Day 11 - Github 的功能介紹


上一篇
Day 9: AWS Auto Scaling Group
下一篇
Day 11: Github 的功能介紹
系列文
小資族的量化交易 10111
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言