本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
透過 AWS CLI 建立包含私有子網路與 NAT 閘道的 VPC
此教學課程會示範如何透過 AWS CLI 建立專為生產環境伺服器設計的 VPC。為了提高彈性,您將使用 Auto Scaling 群組與 Application Load Balancer,在兩個可用區域中部署伺服器。為了提高安全性,您將在私有子網路中部署伺服器。伺服器會透過負載平衡器接收請求,並可藉由 NAT 閘道連線至網際網路。為了提高彈性,您將在每個可用區域中部署 NAT 閘道。
下圖提供此教學課程所包含的資源概觀。VPC 具有兩個可用區域中的公有子網路和私有子網路。每個公有子網路都包含一個 NAT 閘道和一個負載平衡器節點。在私有子網路中執行的伺服器會使用 Auto Scaling 群組啟動和終止,並從負載平衡器接收流量。伺服器可以使用 NAT 閘道連線至網際網路。伺服器可以使用閘道 VPC 端點連線至 Amazon S3。
必要條件
在開始本教學課程之前,需要滿足以下條件:
-
已安裝並設定 AWS CLI,且其具備建立 VPC 資源、EC2 執行個體、負載平衡器與 Auto Scaling 群組的許可。如需安裝 AWS CLI 的相關資訊,請參閱安裝或更新 AWS CLI 的最新版本。
-
掌握 VPC 概念的基本知識,包括子網路、路由表與網際網路閘道。
-
已安裝
jq命令列 JSON 處理器。此工具用於剖析 AWS CLI 命令的輸出結果。如需有關安裝 jq 的資訊,請參閱 Download jq。 -
所建立資源需具備足夠的服務配額,包括:
-
至少 2 個可用的彈性 IP 位址
-
至少 2 個 NAT 閘道
-
至少 1 個 VPC
-
至少 4 個子網路
-
至少 1 個 Application Load Balancer
預估成本:在本教學課程中建立的資源會在您的 AWS 帳戶中產生費用:NAT 閘道:每小時約 0.045 USD,外加資料處理費用 彈性 IP 位址:與執行中的執行個體相關聯時免費,無關聯時每小時約 0.005 USD EC2 執行個體:因執行個體類型而異 (本教學課程中使用的是 t3.micro) Application Load Balancer:每小時約 0.0225 USD,外加資料處理費用
建立 VPC 與子網路
首先,您將建立 CIDR 區塊為 10.0.0.0/16 的 VPC,最多可提供 65,536 個私有 IP 位址。
# Create a VPC with CIDR block 10.0.0.0/16 aws ec2 create-vpc --cidr-block 10.0.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=ProductionVPC}]'
此命令會傳回類似以下的輸出:
{ "Vpc": { "CidrBlock": "10.0.0.0/16", "DhcpOptionsId": "dopt-abcd1234", "State": "pending", "VpcId": "vpc-abcd1234", "OwnerId": "123456789012", "InstanceTenancy": "default", "Ipv6CidrBlockAssociationSet": [], "CidrBlockAssociationSet": [ { "AssociationId": "vpc-cidr-assoc-abcd1234", "CidrBlock": "10.0.0.0/16", "CidrBlockState": { "State": "associated" } } ], "IsDefault": false, "Tags": [ { "Key": "Name", "Value": "ProductionVPC" } ] } }
記錄輸出中的 VPC ID (例如 vpc-abcd1234)。後續命令中會用到此 ID。
接下來,您需在所在區域中選定兩個可用區域,用以建立具韌性的架構。
# Get available Availability Zones aws ec2 describe-availability-zones --query 'AvailabilityZones[0:2].ZoneName' --output text
此命令會傳回類似以下的輸出:
us-east-1a us-east-1b
現在,建立四個子網路:兩個公有子網路分別用於負載平衡器與 NAT 閘道,兩個私有子網路用於應用程式伺服器。將vpc-abcd1234 取代為實際的 VPC ID,將 us-east-1a 與 us-east-1b 取代為實際的可用區域。
# Create public subnet in first AZ aws ec2 create-subnet \ --vpc-id vpc-abcd1234 \ --cidr-block 10.0.0.0/24 \ --availability-zone us-east-1a \ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=PublicSubnet1}]' # Create private subnet in first AZ aws ec2 create-subnet \ --vpc-id vpc-abcd1234 \ --cidr-block 10.0.1.0/24 \ --availability-zone us-east-1a \ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=PrivateSubnet1}]' # Create public subnet in second AZ aws ec2 create-subnet \ --vpc-id vpc-abcd1234 \ --cidr-block 10.0.2.0/24 \ --availability-zone us-east-1b \ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=PublicSubnet2}]' # Create private subnet in second AZ aws ec2 create-subnet \ --vpc-id vpc-abcd1234 \ --cidr-block 10.0.3.0/24 \ --availability-zone us-east-1b \ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=PrivateSubnet2}]'
每個命令皆會傳回包含子網路 ID 的輸出結果。記錄這些 ID,供後續命令使用:
-
公有子網路 1:
subnet-abcd1234 -
私有子網路 1:
subnet-abcd5678 -
公有子網路 2:
subnet-efgh1234 -
私有子網路 2:
subnet-efgh5678
建立與設定網際網路連線
在本節中,您將建立網際網路閘道 (用於實現 VPC 與網際網路的通訊),並將其連接至 VPC。
# Create an Internet Gateway aws ec2 create-internet-gateway --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=ProductionIGW}]'
命令會傳回包含網際網路閘道 ID 的輸出結果。記錄此 ID (例如 igw-abcd1234)。
將網際網路閘道連接至 VPC。將 igw-abcd1234 取代為實際的網際網路閘道 ID,將 vpc-abcd1234 取代為實際的 VPC ID。
# Attach the Internet Gateway to the VPC aws ec2 attach-internet-gateway --internet-gateway-id igw-abcd1234 --vpc-id vpc-abcd1234
接著,為公有與私有子網路建立路由表。將 vpc-abcd1234 取代為實際的 VPC ID。
# Create a route table for public subnets aws ec2 create-route-table --vpc-id vpc-abcd1234 --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=PublicRouteTable}]' # Create route table for private subnet in first AZ aws ec2 create-route-table --vpc-id vpc-abcd1234 --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=PrivateRouteTable1}]' # Create route table for private subnet in second AZ aws ec2 create-route-table --vpc-id vpc-abcd1234 --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=PrivateRouteTable2}]'
每個命令皆會傳回包含路由表 ID 的輸出結果。記錄這些 ID:
-
公有路由表:
rtb-abcd1234 -
私有路由表 1:
rtb-efgh1234 -
私有路由表 2:
rtb-ijkl1234
在公有路由表中新增通往網際網路閘道的路由,用以啟用網際網路存取功能。將 rtb-abcd1234 取代為實際的公有路由表 ID,將 igw-abcd1234 取代為實際的網際網路閘道 ID。
# Add a route to the Internet Gateway aws ec2 create-route --route-table-id rtb-abcd1234 --destination-cidr-block 0.0.0.0/0 --gateway-id igw-abcd1234
將子網路與對應的路由表建立關聯。將路由表 ID 與子網路 ID 取代為實際的 ID。
# Associate public subnets with the public route table aws ec2 associate-route-table --route-table-id rtb-abcd1234 --subnet-id subnet-abcd1234 aws ec2 associate-route-table --route-table-id rtb-abcd1234 --subnet-id subnet-efgh1234 # Associate private subnets with their respective route tables aws ec2 associate-route-table --route-table-id rtb-efgh1234 --subnet-id subnet-abcd5678 aws ec2 associate-route-table --route-table-id rtb-ijkl1234 --subnet-id subnet-efgh5678
建立 NAT 閘道
NAT 閘道允許私有子網路中的執行個體連線至網際網路或其他 AWS 服務,但會阻止網際網路啟動與這些執行個體的連線。首先,為 NAT 閘道配置彈性 IP 位址。
# Allocate Elastic IP for NAT Gateway in first AZ aws ec2 allocate-address --domain vpc --tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Name,Value=NAT1-EIP}]' # Allocate Elastic IP for NAT Gateway in second AZ aws ec2 allocate-address --domain vpc --tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Name,Value=NAT2-EIP}]'
每個命令皆會傳回包含配置 ID 的輸出結果。記錄這些 ID:
-
EIP 1 配置 ID:
eipalloc-abcd1234 -
EIP 2 配置 ID:
eipalloc-efgh1234
在每個公有子網路中建立 NAT 閘道。將子網路 ID 與配置 ID 取代為實際的 ID。
# Create NAT Gateway in public subnet of first AZ aws ec2 create-nat-gateway \ --subnet-id subnet-abcd1234 \ --allocation-id eipalloc-abcd1234 \ --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=NAT-Gateway1}]' # Create NAT Gateway in public subnet of second AZ aws ec2 create-nat-gateway \ --subnet-id subnet-efgh1234 \ --allocation-id eipalloc-efgh1234 \ --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=NAT-Gateway2}]'
每個命令皆會傳回包含 NAT 閘道 ID 的輸出結果。記錄這些 ID:
-
NAT 閘道 1:
nat-abcd1234 -
NAT 閘道 2:
nat-efgh1234
NAT 閘道需要幾分鐘的時間完成佈建。等待這些閘道可用後再繼續操作。將 NAT 閘道 ID 取代為實際的 ID。
# Wait for NAT Gateways to be available aws ec2 wait nat-gateway-available --nat-gateway-ids nat-abcd1234 aws ec2 wait nat-gateway-available --nat-gateway-ids nat-efgh1234
在私有路由表中新增通往 NAT 閘道的路由,用以啟用私有子網路中執行個體的網際網路存取功能。將路由表 ID 與 NAT 閘道 ID 取代為實際的 ID。
# Add route to NAT Gateway 1 in private route table 1 aws ec2 create-route \ --route-table-id rtb-efgh1234 \ --destination-cidr-block 0.0.0.0/0 \ --nat-gateway-id nat-abcd1234 # Add route to NAT Gateway 2 in private route table 2 aws ec2 create-route \ --route-table-id rtb-ijkl1234 \ --destination-cidr-block 0.0.0.0/0 \ --nat-gateway-id nat-efgh1234
建立 Amazon S3 的 VPC 端點
Amazon S3 的 VPC 端點能讓私有子網路中的執行個體無需經過 NAT 閘道即可存取 S3,既可降低資料傳輸成本,又能提升網路效能。將 vpc-abcd1234 取代為實際的 VPC ID,將路由表 ID 取代為實際的 ID。
# Get the prefix list ID for S3 in your region S3_PREFIX_LIST_ID=$(aws ec2 describe-prefix-lists --filters "Name=prefix-list-name,Values=com.amazonaws.$(aws configure get region).s3" --query 'PrefixLists[0].PrefixListId' --output text) # Create the VPC endpoint for S3 aws ec2 create-vpc-endpoint \ --vpc-id vpc-abcd1234 \ --service-name com.amazonaws.$(aws configure get region).s3 \ --route-table-ids rtb-efgh1234 rtb-ijkl1234 \ --tag-specifications 'ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=S3-Endpoint}]'
命令會傳回包含 VPC 端點 ID 的輸出結果。記錄此 ID (例如 vpce-abcd1234)。
設定安全群組
安全群組會作為執行個體的虛擬防火牆,控管傳入及傳出流量。為負載平衡器建立安全群組,允許任意來源的 HTTP 傳入流量。將 vpc-abcd1234 取代為實際的 VPC ID。
# Create security group for the load balancer aws ec2 create-security-group \ --group-name LoadBalancerSG \ --description "Security group for the load balancer" \ --vpc-id vpc-abcd1234 \ --tag-specifications 'ResourceType=security-group,Tags=[{Key=Name,Value=LoadBalancerSG}]'
命令會傳回包含安全群組 ID 的輸出結果。記錄此 ID (例如 sg-abcd1234)。
允許傳送至負載平衡器的 HTTP 傳入流量。將 sg-abcd1234 取代為實際的負載平衡器安全群組 ID。
# Allow inbound HTTP traffic from anywhere aws ec2 authorize-security-group-ingress \ --group-id sg-abcd1234 \ --protocol tcp \ --port 80 \ --cidr 0.0.0.0/0
為應用程式伺服器建立安全群組,僅允許來自負載平衡器的傳入流量。將 vpc-abcd1234 取代為實際的 VPC ID。
# Create security group for the application servers aws ec2 create-security-group \ --group-name AppServerSG \ --description "Security group for the application servers" \ --vpc-id vpc-abcd1234 \ --tag-specifications 'ResourceType=security-group,Tags=[{Key=Name,Value=AppServerSG}]'
命令會傳回包含安全群組 ID 的輸出結果。記錄此 ID (例如 sg-efgh1234)。
允許來自負載平衡器安全群組的 HTTP 傳入流量傳送至應用程式伺服器。將 sg-efgh1234 取代為實際的應用程式伺服器安全群組 ID,將 sg-abcd1234 取代為實際的負載平衡器安全群組 ID。
# Allow inbound HTTP traffic from the load balancer security group aws ec2 authorize-security-group-ingress \ --group-id sg-efgh1234 \ --protocol tcp \ --port 80 \ --source-group sg-abcd1234
建立 EC2 執行個體的啟動範本
啟動範本包含用於啟動執行個體的組態資訊,例如 AMI ID、執行個體類型與安全群組。首先,建立一個將在執行個體啟動時執行的使用者資料指令碼。
cat > user-data.sh << 'EOF' #!/bin/bash yum update -y yum install -y httpd systemctl start httpd systemctl enable httpd echo "<h1>Hello from $(hostname -f) in $(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone)</h1>" > /var/www/html/index.html EOF
將使用者資料指令碼編碼為 base64 格式。
USER_DATA=$(base64 -w 0 user-data.sh)
取得最新的 Amazon Linux 2 AMI ID。
# Get the latest Amazon Linux 2 AMI ID aws ec2 describe-images --owners amazon --filters "Name=name,Values=amzn2-ami-hvm-*-x86_64-gp2" "Name=state,Values=available" --query 'sort_by(Images, &CreationDate)[-1].ImageId' --output text
建立包含 AMI ID、執行個體類型、安全群組與使用者資料的啟動範本。將 sg-efgh1234 取代為實際的應用程式伺服器安全群組 ID,將 $AMI_ID 和 $USER_DATA 取代為從先前命令取得的值。
# Create a launch template aws ec2 create-launch-template \ --launch-template-name AppServerTemplate \ --version-description "Initial version" \ --tag-specifications 'ResourceType=launch-template,Tags=[{Key=Name,Value=AppServerTemplate}]' \ --launch-template-data '{ "NetworkInterfaces": [{ "DeviceIndex": 0, "Groups": ["sg-efgh1234"], "DeleteOnTermination": true }], "ImageId": "ami-abcd1234", "InstanceType": "t3.micro", "UserData": "IyEvYmluL2Jhc2gKeXVtIHVwZGF0ZSAteQp5dW0gaW5zdGFsbCAteSBodHRwZApzeXN0ZW1jdGwgc3RhcnQgaHR0cGQKc3lzdGVtY3RsIGVuYWJsZSBodHRwZAplY2hvICI8aDE+SGVsbG8gZnJvbSAkKGhvc3RuYW1lIC1mKSBpbiAkKGN1cmwgLXMgaHR0cDovLzE2OS4yNTQuMTY5LjI1NC9sYXRlc3QvbWV0YS1kYXRhL3BsYWNlbWVudC9hdmFpbGFiaWxpdHktem9uZSk8L2gxPiIgPiAvdmFyL3d3dy9odG1sL2luZGV4Lmh0bWw=", "TagSpecifications": [{ "ResourceType": "instance", "Tags": [{ "Key": "Name", "Value": "AppServer" }] }] }'
建立負載平衡器與目標群組
目標群組會依據您指定的通訊協定與連接埠號碼,將請求路由至一或多個已註冊的目標,例如 EC2 執行個體。為應用程式伺服器建立目標群組。將 vpc-abcd1234 取代為實際的 VPC ID。
# Create a target group aws elbv2 create-target-group \ --name AppTargetGroup \ --protocol HTTP \ --port 80 \ --vpc-id vpc-abcd1234 \ --target-type instance \ --health-check-protocol HTTP \ --health-check-path / \ --health-check-port traffic-port
命令會傳回包含目標群組 ARN 的輸出結果。記錄此 ARN (例如 arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/AppTargetGroup/abcd1234)。
在公有子網路中建立 Application Load Balancer。將子網路 ID 與安全群組 ID 取代為實際值。
# Create a load balancer aws elbv2 create-load-balancer \ --name AppLoadBalancer \ --subnets subnet-abcd1234 subnet-efgh1234 \ --security-groups sg-abcd1234 \ --tags Key=Name,Value=AppLoadBalancer
命令會傳回包含負載平衡器 ARN 的輸出結果。記錄此 ARN (例如 arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/AppLoadBalancer/abcd1234)。
等待負載平衡器處於作用中狀態後再繼續操作。將 arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/AppLoadBalancer/abcd1234 取代為負載平衡器 ARN。
# Wait for load balancer to be active aws elbv2 wait load-balancer-available \ --load-balancer-arns arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/AppLoadBalancer/abcd1234
為負載平衡器建立接聽程式,其可將 HTTP 流量轉送至目標群組。將負載平衡器 ARN 與目標群組 ARN 取代為實際的 ARN。
# Create a listener aws elbv2 create-listener \ --load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/AppLoadBalancer/abcd1234 \ --protocol HTTP \ --port 80 \ --default-actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/AppTargetGroup/abcd1234
建立 Auto Scaling 群組
Auto Scaling 群組包含一群 EC2 執行個體,該群就自動擴展和管理目的而言被視為一個邏輯分組。建立 Auto Scaling 群組,其可使用啟動範本並將執行個體部署於私有子網路。將子網路 ID 與目標群組 ARN 取代為實際的 ID 與 ARN。
# Create an Auto Scaling group aws autoscaling create-auto-scaling-group \ --auto-scaling-group-name AppAutoScalingGroup \ --launch-template LaunchTemplateName=AppServerTemplate,Version='$Latest' \ --min-size 2 \ --max-size 4 \ --desired-capacity 2 \ --vpc-zone-identifier "subnet-abcd5678,subnet-efgh5678" \ --target-group-arns arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/AppTargetGroup/abcd1234 \ --health-check-type ELB \ --health-check-grace-period 300 \ --tags Key=Name,Value=AppServer,PropagateAtLaunch=true
測試組態
Auto Scaling 群組啟動執行個體且這些執行個體通過運作狀態檢查後,即可測試負載平衡器。取得負載平衡器的 DNS 名稱。將負載平衡器 ARN 取代為實際的 ARN。
# Get the DNS name of the load balancer aws elbv2 describe-load-balancers \ --load-balancer-arns arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/AppLoadBalancer/abcd1234 \ --query "LoadBalancers[0].DNSName" \ --output text
使用 curl 透過負載平衡器名稱來測試應用程式。
curl http://LoadBalancerName
如果多次重新整理頁面,您應該會看到不同可用區域中不同執行個體的回應。
清除資源
完成本教學課程後,您應刪除所有資源,避免產生費用。將所有 ID 取代為實際的資源 ID。
# Delete the Auto Scaling group aws autoscaling delete-auto-scaling-group \ --auto-scaling-group-name AppAutoScalingGroup \ --force-delete # Wait for the Auto Scaling group to be deleted sleep 60 # Delete the load balancer aws elbv2 delete-load-balancer \ --load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/AppLoadBalancer/abcd1234 # Wait for the load balancer to be deleted sleep 30 # Delete the target group aws elbv2 delete-target-group \ --target-group-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/AppTargetGroup/abcd1234 # Delete the launch template aws ec2 delete-launch-template \ --launch-template-name AppServerTemplate # Delete the NAT Gateways aws ec2 delete-nat-gateway --nat-gateway-id nat-abcd1234 aws ec2 delete-nat-gateway --nat-gateway-id nat-efgh1234 # Wait for the NAT Gateways to be deleted sleep 90 # Release the Elastic IPs aws ec2 release-address --allocation-id eipalloc-abcd1234 aws ec2 release-address --allocation-id eipalloc-efgh1234 # Delete the VPC endpoint aws ec2 delete-vpc-endpoints --vpc-endpoint-ids vpce-abcd1234 # Wait for security group dependencies to clear sleep 30 # Delete the security groups aws ec2 delete-security-group --group-id sg-efgh1234 aws ec2 delete-security-group --group-id sg-abcd1234 # Detach the Internet Gateway aws ec2 detach-internet-gateway --internet-gateway-id igw-abcd1234 --vpc-id vpc-abcd1234 # Delete the Internet Gateway aws ec2 delete-internet-gateway --internet-gateway-id igw-abcd1234 # Delete the route tables aws ec2 delete-route-table --route-table-id rtb-efgh1234 aws ec2 delete-route-table --route-table-id rtb-ijkl1234 aws ec2 delete-route-table --route-table-id rtb-abcd1234 # Delete the subnets aws ec2 delete-subnet --subnet-id subnet-abcd1234 aws ec2 delete-subnet --subnet-id subnet-efgh1234 aws ec2 delete-subnet --subnet-id subnet-abcd5678 aws ec2 delete-subnet --subnet-id subnet-efgh5678 # Delete the VPC aws ec2 delete-vpc --vpc-id vpc-abcd1234
後續步驟
現在您已建立包含私有子網路與 NAT 閘道的 VPC,接下來可以參閱下列相關主題: