2014年2月19日水曜日

訂正:RDSのエンドポイントについて考察

こんにちは!

以前のブログ(RDSのエンドポイントについて考察)で設定に誤りがあったことがわりました。
ごめんなさい。

mysql-proxy.cnf内にあらかじめslaveを5台分書いておけば良いとしていましたが、mysql-proxyの起動時に名前引きをしていて、slaveを事前に作っておかないとmysql-proxyが起動しないようです。

そこで対策を考え中です。
良いアイデアがありましたら、コメントください!


また、もう1つの問題点は、そもそもmysql-proxyがダウンした場合について、考えが抜けていました。
そこでこれを解消するために、ELBをもう1つ使います。
ウェブ用のインスタンスのバランシングにHTTPのELBを用意していますが、これと同様にMySQLの3306ポートをバランシングするELBを用意します。

PHPなどで、DBの参照の際は、ELBのエンドポイントに接続するようにしてください。
更新は、masterのエンドポイントを指定します。



2014年2月18日火曜日

CloudFormationを使ってみた

こんにちは!

これまでブログに書かせてもらった内容をCloudFormationを使って、自動で作成してくれるように作ってみました。
図の構成が、自動でできあがります。

以下をテキスト保存して、CloudFormationでお試しください!
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Resources": {
    "VPC": {
      "Type": "AWS::EC2::VPC",
      "Properties": {
        "CidrBlock": "10.0.0.0/16",
        "InstanceTenancy": "default",
        "EnableDnsSupport": "true",
        "EnableDnsHostnames": "true"
      }
    },
    "subnet01": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "CidrBlock": "10.0.1.0/24",
        "AvailabilityZone": "ap-southeast-1a",
        "VpcId": {
          "Ref": "VPC"
        }
      }
    },
    "subnet02": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "CidrBlock": "10.0.2.0/24",
        "AvailabilityZone": "ap-southeast-1b",
        "VpcId": {
          "Ref": "VPC"
        }
      }
    },
    "inetgw": {
      "Type": "AWS::EC2::InternetGateway",
      "Properties": {
      }
    },
    "dhcpopt": {
      "Type": "AWS::EC2::DHCPOptions",
      "Properties": {
        "DomainName": "ap-southeast-1.compute.internal",
        "DomainNameServers": [
          "AmazonProvidedDNS"
        ]
      }
    },
    "nwacl": {
      "Type": "AWS::EC2::NetworkAcl",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        }
      }
    },
    "routetable": {
      "Type": "AWS::EC2::RouteTable",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        }
      }
    },
    "elbaslb": {
      "Type": "AWS::ElasticLoadBalancing::LoadBalancer",
      "Properties": {
        "Subnets": [
          {
            "Ref": "subnet01"
          },
          {
            "Ref": "subnet02"
          }
        ],
        "HealthCheck": {
          "HealthyThreshold": "2",
          "Interval": "30",
          "Target": "HTTP:80/index.html",
          "Timeout": "5",
          "UnhealthyThreshold": "2"
        },
        "SecurityGroups": [
          {
            "Ref": "sgall"
          }
        ],
        "Listeners": [
          {
            "InstancePort": "80",
            "LoadBalancerPort": "80",
            "Protocol": "HTTP",
            "InstanceProtocol": "HTTP"
          }
        ]
      }
    },
    "asgassg": {
      "Type": "AWS::AutoScaling::AutoScalingGroup",
      "Properties": {
        "AvailabilityZones": [
          "ap-southeast-1b",
          "ap-southeast-1a"
        ],
        "Cooldown": "300",
        "DesiredCapacity": "1",
        "MaxSize": "4",
        "MinSize": "2",
        "HealthCheckGracePeriod": "300",
        "HealthCheckType": "ELB",
        "VPCZoneIdentifier": [
          {
            "Ref": "subnet01"
          },
          {
            "Ref": "subnet02"
          }
        ],
        "LaunchConfigurationName": {
          "Ref": "lcaslc"
        },
        "LoadBalancerNames": [
          {
            "Ref": "elbaslb"
          }
        ]
      }
    },
    "rdsmaster": {
      "Type": "AWS::RDS::DBInstance",
      "Properties": {
        "AutoMinorVersionUpgrade": "true",
        "DBInstanceClass": "db.t1.micro",
        "DBInstanceIdentifier": "master",
        "Port": "3306",
        "AllocatedStorage": "5",
        "BackupRetentionPeriod": "1",
        "DBName": "MyDatabase",
        "Engine": "mysql",
        "EngineVersion": "5.5.33",
        "LicenseModel": "general-public-license",
        "MasterUsername": "rdsuser",
        "MasterUserPassword": "MyPassword",
        "PreferredBackupWindow": "16:35-17:05",
        "PreferredMaintenanceWindow": "mon:14:02-mon:14:32",
        "MultiAZ": "true",
        "VPCSecurityGroups": [
          {
            "Ref": "sgall"
          }
        ],
        "DBSubnetGroupName": {
          "Ref": "dbsubnetmultiazsg"
        },
        "Tags": [
          {
            "Key": "workload-type",
            "Value": "production"
          }
        ]
      }
    },
    "rdsslave0": {
      "Type": "AWS::RDS::DBInstance",
      "Properties": {
        "AutoMinorVersionUpgrade": "true",
        "DBInstanceClass": "db.t1.micro",
        "DBInstanceIdentifier": "slave0",
        "Port": "3306",
        "SourceDBInstanceIdentifier": {
          "Ref": "rdsmaster"
        }
      }
    },
    "lcaslc": {
      "Type": "AWS::AutoScaling::LaunchConfiguration",
      "Properties": {
        "ImageId": "ami-56bee804",
        "InstanceType": "t1.micro",
        "KeyName": "astest",
        "SecurityGroups": [
          {
            "Ref": "sgall"
          }
        ],         "BlockDeviceMappings": [
          {
            "DeviceName": "/dev/sda1",
            "Ebs": {
              "VolumeSize": 8
            }
          }
        ]
      }
    },
    "dbsubnetmultiazsg": {
      "Type": "AWS::RDS::DBSubnetGroup",
      "Properties": {
        "DBSubnetGroupDescription": "for Multi-AZ",
        "SubnetIds": [
          {
            "Ref": "subnet01"
          },
          {
            "Ref": "subnet02"
          }
        ]
      }
    },
    "sgall": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupDescription": "allow all",
        "VpcId": {
          "Ref": "VPC"
        },
        "SecurityGroupIngress": [
          {
            "IpProtocol": "-1",
            "CidrIp": "0.0.0.0/0"
          }
        ],
        "SecurityGroupEgress": [
          {
            "IpProtocol": "-1",
            "CidrIp": "0.0.0.0/0"
          }
        ]
      }
    },
    "scalingDecreaseGroupSize": {
      "Type": "AWS::AutoScaling::ScalingPolicy",
      "Properties": {
        "AdjustmentType": "ChangeInCapacity",
        "ScalingAdjustment": "-1",
        "AutoScalingGroupName": {
          "Ref": "asgassg"
        }
      }
    },
    "scalingIncreaseGroupSize": {
      "Type": "AWS::AutoScaling::ScalingPolicy",
      "Properties": {
        "AdjustmentType": "ChangeInCapacity",
        "ScalingAdjustment": "1",
        "AutoScalingGroupName": {
          "Ref": "asgassg"
        }
      }
    },
    "alarmawsec2assgCPUUtilizationadd": {
      "Type": "AWS::CloudWatch::Alarm",
      "Properties": {
        "ActionsEnabled": "true",
        "ComparisonOperator": "GreaterThanOrEqualToThreshold",
        "EvaluationPeriods": "1",
        "MetricName": "CPUUtilization",
        "Namespace": "AWS/EC2",
        "Period": "300",
        "Statistic": "Average",
        "Threshold": "50.0",
        "AlarmActions": [
          {
            "Ref": "scalingIncreaseGroupSize"
          }
        ],
        "Dimensions": [
          {
            "Name": "AutoScalingGroupName",
            "Value": "as-sg"
          }
        ]
      }
    },
    "alarmawsec2assgHighCPUUtilizationremove": {
      "Type": "AWS::CloudWatch::Alarm",
      "Properties": {
        "ActionsEnabled": "true",
        "ComparisonOperator": "LessThanThreshold",
        "EvaluationPeriods": "1",
        "MetricName": "CPUUtilization",
        "Namespace": "AWS/EC2",
        "Period": "300",
        "Statistic": "Average",
        "Threshold": "50.0",
        "AlarmActions": [
          {
            "Ref": "scalingDecreaseGroupSize"
          }
        ],
        "Dimensions": [
          {
            "Name": "AutoScalingGroupName",
            "Value": "as-sg"
          }
        ]
      }
    },
    "acl1": {
      "Type": "AWS::EC2::NetworkAclEntry",
      "Properties": {
        "CidrBlock": "0.0.0.0/0",
        "Egress": true,
        "Protocol": "-1",
        "RuleAction": "allow",
        "RuleNumber": "100",
        "NetworkAclId": {
          "Ref": "nwacl"
        }
      }
    },
    "acl2": {
      "Type": "AWS::EC2::NetworkAclEntry",
      "Properties": {
        "CidrBlock": "0.0.0.0/0",
        "Protocol": "-1",
        "RuleAction": "allow",
        "RuleNumber": "100",
        "NetworkAclId": {
          "Ref": "nwacl"
        }
      }
    },
    "subnetacl1": {
      "Type": "AWS::EC2::SubnetNetworkAclAssociation",
      "Properties": {
        "NetworkAclId": {
          "Ref": "nwacl"
        },
        "SubnetId": {
          "Ref": "subnet01"
        }
      }
    },
    "subnetacl2": {
      "Type": "AWS::EC2::SubnetNetworkAclAssociation",
      "Properties": {
        "NetworkAclId": {
          "Ref": "nwacl"
        },
        "SubnetId": {
          "Ref": "subnet02"
        }
      }
    },
    "gw1": {
      "Type": "AWS::EC2::VPCGatewayAttachment",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "InternetGatewayId": {
          "Ref": "inetgw"
        }
      }
    },
    "subnetroute1": {
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "RouteTableId": {
          "Ref": "routetable"
        },
        "SubnetId": {
          "Ref": "subnet02"
        }
      }
    },
    "subnetroute2": {
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "RouteTableId": {
          "Ref": "routetable"
        },
        "SubnetId": {
          "Ref": "subnet01"
        }
      }
    },
    "route1": {
      "Type": "AWS::EC2::Route",
      "Properties": {
        "DestinationCidrBlock": "0.0.0.0/0",
        "RouteTableId": {
          "Ref": "routetable"
        },
        "GatewayId": {
          "Ref": "inetgw"
        }
      },
      "DependsOn": "gw1"
    },
    "dchpassoc1": {
      "Type": "AWS::EC2::VPCDHCPOptionsAssociation",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "DhcpOptionsId": {
          "Ref": "dhcpopt"
        }
      }
    }
  },
  "Description": ""
}

2014年2月13日木曜日

コンテンツの同期

こんにちは!

AutoScaleで増えていくWebサーバのコンテンツの同期についてです。

awsコマンドを使ってS3のデータを同期するのが良いかと思います。

aws s3 sync s3://bucketname/ /var/www/html/ --region ap-southeast-1

という感じです。
rc.localに書いておけば良いと思います!

2014年2月12日水曜日

Route53の文字列によるHealthCheckを試してみた

こんにちは!

AWSのRoute53を使って、サイト内の文字列によるHealthCheckを試してみました。

結論:

  • おそらく英数字記号のみ
  • おそらく問題無い場合が1、問題有りが0


最初に、Search Stringに日本語で書いたところ、結果が0でした。
文字列を変えてみたけど、結果は同じでした。
次に、英語で書いてみたところ、結果が1になりました。

0が正常なのか、1が正常なのかわからなかったので、サイト内に含まれていない英語を書いてみました。
結果は、0でした。

ですので、結論の内容が正しいかと思います。

トップページにDBから英数字をひっぱってくるようなPHPを用いて、この仕組みを使えば、WebとDBの連携が正常にできていることを監視できそうです!

追記
ちなみに、body内の文字列が対象と書いてあったけど、headタグ内のtitleに書いた文字列も対象になってました。

2014年2月7日金曜日

AMI公開しました

こんにちは!

AMIを公開しましたので、こちらで告知します。
Tokyo: ami-a7640ea6
Singapore: ami-56bee804

内容は、
Amazon Linux
Apache
PHP
MySQL-Proxy
td-agent

がyumを使ってインストールしてあります。

rc.localにyum updateの実行と、
td-agent.confのS3バケット内に、IPアドレスでフォルダを作るように、sedで設定の一部を書き換えるコマンドを記載しています。

httpd.confやphp.iniはデフォルトです。

mysql-proxy.cnfは、RDSのエンドポイントを書き換えて使ってください!

2014年2月6日木曜日

RDSのエンドポイントについて考察

こんにちは!

前回のブログでRead Replicaを増やしたときのことを考えるってことでしたが、
そもそもMySQL Proxyにあらかじめ想定範囲の台数分を設定してしまえば良いと思いました。

つまり、最初はslave2台で構成するとしても、将来的に5台まで増やしちゃうかもと想定するなら、あらかじめ5台に分散する設定を書いてしまえばいいということです。

MySQL Proxyの設定ファイルでいうと、

proxy-backend-addresses=master.ckj5g4ick5ri.ap-southeast-1.rds.amazonaws.com:3306,slave01.ckj5g4ick5ri.ap-southeast-1.rds.amazonaws.com:3306,slave02.ckj5g4ick5ri.ap-southeast-1.rds.amazonaws.com:3306,slave03.ckj5g4ick5ri.ap-southeast-1.rds.amazonaws.com:3306,slave04.ckj5g4ick5ri.ap-southeast-1.rds.amazonaws.com:3306,slave05.ckj5g4ick5ri.ap-southeast-1.rds.amazonaws.com:3306

あとは負荷に応じて、3台目のRead Replicaをslave03という名前で、4台目をslave04という名前で・・・
と作っていけば良いと思います。

もちろん負荷が低くなったら、Read ReplicaをdeleteしてしまってもOKです。

そうなると、今度はRead Replicaを増減させるようなAuto Scalingのようなことができたら、もっとうれしいですね

何か方法があるか探してみます。

2014年2月5日水曜日

突発的なアクセス集中に耐える構成案

こんにちは!

これまでのブログの内容から、自分は図のような構成を提案します。
Instanceを作り込むのは大変ですが、1つ作ってAMIにして、AutoScaleで拡張していく構成です。


Instanceの中身は、

  • Apache
  • PHPなどのアプリ用の言語
  • MySQL Proxy
  • td-agent(fluentd)

といった感じです。

注意点は、MySQLの更新系は必ずRDSのmasterに接続するように、PHPなどで制御してください。
逆に参照系は、ローカルホストに接続するようにして、MySQL-Proxyが勝手に分散してくれます。

Apacheのアクセスログは、S3に保存されますが、アクセスログからサイトのアクセス分析をするのは、あまり現実的ではないと思ってます。GoogleAnalyticsなどの外部の分析ツールをページに埋め込んだ方がよいと思います。

※RDSのRead Replicaが増えたときの対処を、これから検討していきます。