aws(学习笔记第十六课)
- 使用负载均衡器(
ELB
)以及输出ELB
的日志到S3
学习内容:
- 使用负载均衡器(
ELB
)解耦web server
- 输出
ELB
的日志到S3
1. 使用负载均衡器(ELB
)
- 全体架构
使用ELB
(Elastic Load Balancer
)能够解耦外部internet
访问和web server
之间的耦合,让外部internet
访问只能认识ELB
,只知道是ELB
为它服务,但是具体的web server
对于外部来说却是不意识的。
2. 代码解析
- 全体代码
{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "AWS in Action: chapter 12 (Load Balancer)", "Parameters": { "KeyName": { "Description": "Key Pair name", "Type": "AWS::EC2::KeyPair::KeyName", "Default": "my-cli-key" }, "NumberOfServers": { "Description": "Number of servers", "Type": "Number", "Default": "2", "MinValue": "2", "MaxValue": "4" } }, "Mappings": { "EC2RegionMap": { "ap-northeast-1": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-cbf90ecb"}, "ap-southeast-1": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-68d8e93a"}, "ap-southeast-2": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-fd9cecc7"}, "eu-central-1": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-a8221fb5"}, "eu-west-1": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-a10897d6"}, "sa-east-1": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-b52890a8"}, "us-east-1": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-1ecae776"}, "us-west-1": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-d114f295"}, "us-west-2": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-e7527ed7"} } }, "Resources": { "VPC": { "Type": "AWS::EC2::VPC", "Properties": { "CidrBlock": "172.31.0.0/16", "EnableDnsHostnames": "true" } }, "InternetGateway": { "Type": "AWS::EC2::InternetGateway", "Properties": { } }, "VPCGatewayAttachment": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { "VpcId": {"Ref": "VPC"}, "InternetGatewayId": {"Ref": "InternetGateway"} } }, "Subnet": { "Type": "AWS::EC2::Subnet", "Properties": { "AvailabilityZone": {"Fn::Select": ["0", {"Fn::GetAZs": ""}]}, "CidrBlock": "172.31.38.0/24", "VpcId": {"Ref": "VPC"} } }, "RouteTable": { "Type": "AWS::EC2::RouteTable", "Properties": { "VpcId": {"Ref": "VPC"} } }, "RouteTableAssociation": { "Type": "AWS::EC2::SubnetRouteTableAssociation", "Properties": { "SubnetId": {"Ref": "Subnet"}, "RouteTableId": {"Ref": "RouteTable"} } }, "RoutePublicNATToInternet": { "Type": "AWS::EC2::Route", "Properties": { "RouteTableId": {"Ref": "RouteTable"}, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": {"Ref": "InternetGateway"} }, "DependsOn": "VPCGatewayAttachment" }, "NetworkAcl": { "Type": "AWS::EC2::NetworkAcl", "Properties": { "VpcId": {"Ref": "VPC"} } }, "SubnetNetworkAclAssociation": { "Type": "AWS::EC2::SubnetNetworkAclAssociation", "Properties": { "SubnetId": {"Ref": "Subnet"}, "NetworkAclId": {"Ref": "NetworkAcl"} } }, "NetworkAclEntryIngress": { "Type": "AWS::EC2::NetworkAclEntry", "Properties": { "NetworkAclId": {"Ref": "NetworkAcl"}, "RuleNumber": "100", "Protocol": "-1", "RuleAction": "allow", "Egress": "false", "CidrBlock": "0.0.0.0/0" } }, "NetworkAclEntryEgress": { "Type": "AWS::EC2::NetworkAclEntry", "Properties": { "NetworkAclId": {"Ref": "NetworkAcl"}, "RuleNumber": "100", "Protocol": "-1", "RuleAction": "allow", "Egress": "true", "CidrBlock": "0.0.0.0/0" } }, "LoadBalancerSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "elb-sg", "VpcId": {"Ref": "VPC"}, "SecurityGroupIngress": [{ "CidrIp": "0.0.0.0/0", "FromPort": 80, "IpProtocol": "tcp", "ToPort": 80 }] } }, "LoadBalancer": { "Type": "AWS::ElasticLoadBalancing::LoadBalancer", "Properties": { "Subnets": [{"Ref": "Subnet"}], "LoadBalancerName": "elb", "Listeners": [{ "InstancePort": "80", "InstanceProtocol": "HTTP", "LoadBalancerPort": "80", "Protocol": "HTTP" }], "HealthCheck": { "HealthyThreshold": "3", "Interval": "10", "Target": "HTTP:80/index.html", "Timeout": "5", "UnhealthyThreshold": "2" }, "SecurityGroups": [{"Ref": "LoadBalancerSecurityGroup"}], "Scheme": "internet-facing" }, "DependsOn": "VPCGatewayAttachment" }, "WebServerSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "awsinaction-sg", "VpcId": {"Ref": "VPC"}, "SecurityGroupIngress": [{ "CidrIp": "0.0.0.0/0", "FromPort": 22, "IpProtocol": "tcp", "ToPort": 22 }, { "FromPort": 80, "IpProtocol": "tcp", "SourceSecurityGroupId": {"Ref": "LoadBalancerSecurityGroup"}, "ToPort": 80 }] } }, "LaunchTemplate": { "Type": "AWS::EC2::LaunchTemplate", "Metadata": { "AWS::CloudFormation::Init": { "config": { "packages": { "yum": { "httpd": [] } }, "files": { "/tmp/config": { "content": {"Fn::Join": ["", [ "#!/bin/bash -ex\n", "PRIVATE_IP=`curl -s http://169.254.169.254/latest/meta-data/local-ipv4`\n", "echo \"<html><head><title>$PRIVATE_IP</title></head><body><h1>$PRIVATE_IP</h1></body></html>\" > index.html\n" ]]}, "mode": "000500", "owner": "root", "group": "root" } }, "commands": { "01_config": { "command": "/tmp/config", "cwd": "/var/www/html" } }, "services": { "sysvinit": { "httpd": { "enabled": "true", "ensureRunning": "true" } } } } } }, "Properties": { "LaunchTemplateData":{ "EbsOptimized": false, "ImageId": {"Fn::FindInMap": ["EC2RegionMap", {"Ref": "AWS::Region"}, "AmazonLinuxAMIHVMEBSBacked64bit"]}, "InstanceType": "t2.micro", "NetworkInterfaces":[ { "DeviceIndex":0, "AssociatePublicIpAddress":true, "Groups":[ {"Ref": "WebServerSecurityGroup"} ], "DeleteOnTermination":true } ], "KeyName": {"Ref": "KeyName"}, "UserData": {"Fn::Base64": {"Fn::Join": ["", [ "#!/bin/bash -ex\n", "yum update -y aws-cfn-bootstrap\n", "/opt/aws/bin/cfn-init -v --stack ", {"Ref": "AWS::StackName"}, " --resource LaunchTemplate --region ", {"Ref": "AWS::Region"}, "\n", "/opt/aws/bin/cfn-signal -e $? --stack ", {"Ref": "AWS::StackName"}, " --resource AutoScalingGroup --region ", {"Ref": "AWS::Region"}, "\n" ]]}} } } }, "AutoScalingGroup": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { "LoadBalancerNames": [{"Ref": "LoadBalancer"}], "LaunchTemplate" : {"LaunchTemplateId" : {"Ref" : "LaunchTemplate"},"Version" : {"Fn::GetAtt" : ["LaunchTemplate","LatestVersionNumber"]}}, "MinSize": {"Ref": "NumberOfServers"}, "MaxSize": {"Ref": "NumberOfServers"}, "DesiredCapacity": {"Ref": "NumberOfServers"}, "VPCZoneIdentifier": [{"Ref": "Subnet"}] }, "CreationPolicy": { "ResourceSignal": { "Timeout": "PT10M" } }, "DependsOn": "VPCGatewayAttachment" } }, "Outputs": { "URL": { "Value": {"Fn::Join": ["", ["http://", {"Fn::GetAtt": ["LoadBalancer", "DNSName"]}]]}, "Description": "Load Balancer URL" } } }
- 主要代码分析
WebServerSecurityGroup
中的SourceSecurityGroupId
这里,WebServerSecurityGroup
的SourceSecurityGroupId
为LoadBalancerSecurityGroup
,表明只有LoadBalancerSecurityGroup
所在的主机,也就是LoadBalancer
才能对web server
访问80
端口。"WebServerSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "awsinaction-sg", "VpcId": {"Ref": "VPC"}, "SecurityGroupIngress": [{ "CidrIp": "0.0.0.0/0", "FromPort": 22, "IpProtocol": "tcp", "ToPort": 22 }, { "FromPort": 80, "IpProtocol": "tcp", "SourceSecurityGroupId": {"Ref": "LoadBalancerSecurityGroup"}, "ToPort": 80 }] } },
LoadBalancer
加入HealthCheck
这里,LoadBalancer
里面,加入了对web server
的HealthCheck
,当web server
的index.hmlt
在80
端口能够访问之后,才能够开始转送到web server
"LoadBalancer": { "Type": "AWS::ElasticLoadBalancing::LoadBalancer", "Properties": { "Subnets": [{"Ref": "Subnet"}], "LoadBalancerName": "elb", "Listeners": [{ "InstancePort": "80", "InstanceProtocol": "HTTP", "LoadBalancerPort": "80", "Protocol": "HTTP" }], "HealthCheck": { "HealthyThreshold": "3", "Interval": "10", "Target": "HTTP:80/index.html", "Timeout": "5", "UnhealthyThreshold": "2" }, "SecurityGroups": [{"Ref": "LoadBalancerSecurityGroup"}], "Scheme": "internet-facing" }, "DependsOn": "VPCGatewayAttachment" },
2. 输出ELB
的日志到S3
- 首先设置
S3 存储桶策略
,允许ELB
写入log
到S3
policy.json
策略文件
事先作成elb-log-20241208
的S3 bucket
,之后写出policy
文件允许logdelivery.elasticloadbalancing.amazonaws.com
这个service
能够putObject
给S3 bucket
。
这里,{ "Id": "Policy1429136655940", "Version": "2012-10-17", "Statement": [{ "Sid": "Stmt1429136633762", "Action": ["s3:PutObject"], "Effect": "Allow", "Resource": "arn:aws:s3:::elb-log-20241208/*", "Principal": { "AWS": [ "127311923021", "027434742980", "797873946194", "156460612806", "054676820928", "582318560864", "114774131450", "783225319266", "507241528517" ] } }] }
127311923021
,027434742980
像是一些magic code
,这到底是什么呢?可以参照enable-access-logging.html,它们是所在地区的 Elastic Load Balancing 的 ID: AWS 账户。- 设置
policy.json
策略文件给S3
的bucket
aws s3api put-bucket-policy --bucket elb-log-20241208 --policy file://policy/elb-log-policy.json
- 配置
cloudformation
让ELB
输入log
到S3 bucket
AccessLoggingPolicy
这里就是设置描述log
输出的设置。"LoadBalancer": { "Type": "AWS::ElasticLoadBalancing::LoadBalancer", "Properties": { "Subnets": [{"Ref": "Subnet"}], "LoadBalancerName": "elb", "Listeners": [{ "InstancePort": "80", "InstanceProtocol": "HTTP", "LoadBalancerPort": "80", "Protocol": "HTTP" }], "HealthCheck": { "HealthyThreshold": "3", "Interval": "10", "Target": "HTTP:80/index.html", "Timeout": "5", "UnhealthyThreshold": "2" }, "AccessLoggingPolicy":{ "ENabled": true, "S3BucketName":"elb-log-20241208", "S3BucketPrefix":"my-application/production" } "SecurityGroups": [{"Ref": "LoadBalancerSecurityGroup"}], "Scheme": "internet-facing" }, "DependsOn": "VPCGatewayAttachment" },
- 重新访问
ELB
- 检查
S3
的log
文件夹
可以看到log
已经开始写入到S3