最近の投稿
人気のページと投稿
アーカイブ
月 | 火 | 水 | 木 | 金 | 土 | 日 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
AWS, Content Delivery Network and Debian
今年のクラウドデザインパターンの最大のイベントといえば、ラスベガスでの英語における発表だったでしょう。しかし、東京お台場で9月に行われたクラウドデザインパターンの発表もすばらしいものばかりでした。
そこで、私はアンチパターンのワースト13を発表しました。そのプレゼンの中でも発表しましたが、アンチパターンの目的はただ笑うためにあるものではありません。
この3つの観点をわすれてはならないと思っています。
13のアンチパータンの後ろに続くワーストは、バックアップにかかわるものばかりでした。特に、AWSでバックアップを考えるとき便利なのはAMI、EBSとスナップショット機能でしょう。
繰り返しになりますが、AMI,EBS,スナップショットはAWSでのシステム運用に大きく貢献できる機能です。ぜひこれらの特性を理解して利用しましょう。
さて、13のアンチパターンを見たことがないひとのために復習をしておきます。
中でも、机上の設計だけで本番のシステムを決めてしまうことだけは避けましょう!AWSはまだまだ発展していくシステムです。
そして、逆説的ですが、CDPに固執することなく新たなアーキテクチャに挑戦していきましょう。
皆様、昨日の松井さんの男気あふれる記事に度肝を抜かれた荒木でございます。毎度のことながら彼の軌跡は奇跡として語り継がれるといって間違いないでしょう。
さて、VPC環境構築のメタパターンと予告しました。実際のところCloudformationの出番は無限です。その中でも最も強力なのは、ある状態を保存再現する機能です。VPCのように面倒な環境構築に有効です。
時間のない人のために結論を。
というわけで、CloudFormationこそがVPC導入のポイントかもしれません。
これから述べる内容は
のどこにでもある三段構えのサービスを題材にしています。
AWSを使ったシステム構成工数に関しては多くの方が考える問題です。
システムは机上での設計ではなく、試行錯誤を経てサービスを作るべきだとは思います。
実際のシステムでは、構成変更時にはテストが欠かせません。
また、テストの与える影響の測定や変更前への切り戻しを意識したシステム構成を求められることはまちがいありません。
そのために同一のシステムを構成し、部分的な変更を加えた後にテストを行うのが理想的な体制でしょう!
その一方で、この師走のなか、毎回同じことを繰り返す時間はない、というのが本当のところではないでしょうか。
何度でも速やかに構成(クローニング)できるようにして、ある時点でのシステムにもどせれば、どんどんチャレンジすることができるはずです。
そこで役に立つのがCloudFormationです。
テンプレート作成には3つの方法があります。
正直、最初の2つの方法は「部分的に変更を加えてきたシステム」において現実的な方法ではないでしょう。そこで3番目のCloudFormerの登場です。
一旦、CloudFormer で作成した AWS CloudFormation テンプレートを使うと、AWS Management Consoleで数回クリックするだけで既存のシステムのコピーを起動可能です。
起動すると、次のような画面があらわれるはずです。
CloudFormerはIAMのアカウントを使用するため、その確認のチェックはさくっと終わらせて前にすすみましょう。
すると、こんな具合で最終的にシステムを作っていいかどうかの確認がはいります。もちろん躊躇せずにContinueしましょう。
無事起動するとStatusがCREATE_COMPLETEに変わります。それまでは、Eventsでもみてニヤニヤしましょう。
CloudFormerを使用するには、CloudFormerの作成したURLにwebブラウザでアクセスします。そのURLはOutputsタブの中で確認します。
するとこんな画面があらわれます。テンプレート作成対象リージョンを選択しましょう。
あとは一本道です!
含めるドメイン名を確認したり、EC2を確認したり、RDSを確認したり、セキュリティグループを確認したり。。
数個の画面でチェックをつづけると、S3に保存するように促されます。保存されたテンプレートはJSON形式で、その頭のほうが確認できます。
ここまできたら、このテンプレートをつかってたちあげてみましょう。Congratulationsがきたら、即座にLaunch Stackです。
とはいえみなさん時間もないことですし、上がりそうだ!という雰囲気だけつかんでおきましょうか。
とりあえず、作成したテンプレートの置き場だけは確認しておきましょう。このテンプレートがスタート地点になります。
とはいえ、これで完璧か!といわれるとそんなことはありません。
個人的にCloudFormerのハマリポイントはなんだと問われれば、AMI情報は動作時のインスタンスが起動した時点でのAMIであって、CloudFormerがAMIを作るわけではないところです。
"instancei2d5f6a2d": {
"Type": "AWS::EC2::Instance",
"Properties": {
"AvailabilityZone": "ap-northeast-1b",
"DisableApiTermination": "FALSE",
"ImageId": "ami-c857e5c9",
"InstanceType": "m1.small",
(以下略)
こんなテンプレートがあるときは、このAMIの内容を変更したならば、自分でつくりなおさなければなりません。あえてつくりなおさなければならないときは、マネージメントコンソールでインスタンスから右クリックして作りなおせばよいでしょう。
こう言われてもピンとこないかもしれません。
"dnscdpshoparakiin": {
"Type": "AWS::Route53::RecordSet",
"Properties": {
"HostedZoneId": "/hostedzone/xxxxxxxxxxxx",
"Name": "xxxxxxx.araki.in.",
"Type": "CNAME",
"TTL": "300",
"Comment": "araki.in ",
"ResourceRecords": [
"xxxxxxx-444735762.ap-northeast-1.elb.amazonaws.com"
]
}
},
この、ResourceRecordsの内容はそのものずばりELBのCNAMEを指定しています。
このままでは、ELBの定義ではなく、ELBのエンドポイントそのものを指定しているため、作成したELBからFn::GetAttを使って値を得る形式に変更します。
例えばこんな具合に。
{ "Fn::GetAtt" : [ "elbeccube", "DNSName" ] }
これもELBと同じですが、データが消えるという意味ではもっと問題がおおきいかもしれません。
スナップショットを作成したら、DBSnapshotIdentifierパラメータで指定しましょう。
ここまでうまく行っても、人間にはJSONやSGMLやXMLは無理だという説があります!
もちろん慎重にやれとか、ダブルチェックしろとか、トリプルチェックしろ。。N重チェックというループに陥いるのもいとおかしというところですが、そんなくだらないチェックには機械にやらせましょう。
そこで登場するのがcfn-validate-templateコマンドです。
$ cfn-validate-template –template-file テンプレートファイル名
で、テンプレートがValidと言われるまでこころのままに修正しましょう。
今時の人なら、こんなコマンドよりもVisualなアプローチのほうがいいかもしれません。たとえばMacならVisualJSONをつかってみましょう。構造も一発で確認できます。
それでは準備したCloudformationを実行してみましょう。
クローニングの実行は、CloudFormationのタブ内、Create New Stackボタンを押すところからはじまります。
つづいてStackNameとJSONファイルの在り処を指定します。
後は、CloudFormation Stacksの画面から、Statusの変化と、Eventsの出力適宜Refreshしながら眺めて待ちましょう。
CloudFormationによって骨格はほぼ完成したもののたとえば、アプリケーション固有の設定はカバーできません。
ここで登場するのが、UserDataです。
"instanceib3ba90b3": { "Type": "AWS::EC2::Instance", "Properties": { "AvailabilityZone": "ap-northeast-1a", "DisableApiTermination": "FALSE", "ImageId": "ami-5259eb53", "UserData": { "Fn::Base64" : { "Fn::Join" : ["", [ "#!/bin/bash \n", "sed -i \"s/yyyyyy.araki.in/", {"Ref":"SiteURL"}, "/g\" /home/ec2-user/cdp/eccube/data/config/config.php\n", "#EOF" ]]}},
この例では、/home/ec2-user/cdp/eccube/data/config/config.php に含まれる yyyyyy.araki.inをSiteURLというリファレンスに書き換えています。ある意味かなり力技ですが、UserDataの万能感は異常です。
とまあ、こんなことを書くのは、CloudFormerがVPCに対応していない試行錯誤したシステムの保存にフォーカスしていて、なおかつ、繰り返し単調な設計がつづくネットワーク再現に最適だからなのです。
たとえば、こんなことやってられますか?
1 VPCとして10.1.0.0/16を定義
2 ELB用にPublicサブネットを定義
2.1 ZoneAのELB用subnet 10.1.10.0/24を定義
2.2 ZoneBのELB用 subnet 10.1.11.0/24を定義
3 eccube用にPrivateサブネットを定義
3.1 ZoneAのeccube用subnet 10.1.20.0/24を定義
3.2 ZoneBのeccube用 subnet 10.1.21.0/24を定義
4 RDS用にPrivateサブネットを定義
4.1 ZoneAのRDS用subnet 10.1.30.0/24を定義
4.2 ZoneBのRDS用 subnet 10.1.31.0/24を定義
5 インターネットゲートウェイを定義
5.1 インターネットゲートウェイをVPCに関連づけ
6 2のPublicサブネットの経路表を定義
6.1 Publicサブネットの経路表にデフォルトゲートウェイとしてインターネットゲートウェイを向ける
6.2 ZoneAのELB用subnetに対して経路表を関連づけ
6.3 ZoneBのELB用subnetに対して経路表を関連づけ
7 2のPublicサブネットにNACLを定義
7.1 Inbound用にHTTPポートを許可
7.2 Inbound用に1024から65535のダイナミックポートを許可
7.3 Outbound用にHTTPポートを許可
7.4 Outbound用に1024から65535のダイナミックポートを許可
7.5 ZoneAのELB用subnetに対してNACLを関連づけ
7.6 ZoneBのELB用subnetに対してNACLを関連づけ
8 PrivateサブネットにNACLを定義
8.1 Inbound用にVPC内部からの接続を許可
8.2 Outbound用にVPC内部への接続を許可
8.3 ZoneAのeccube用subnetにNACLを関連づけ
8.4 ZoneBのeccube用subnetにNACLを関連づけ
8.5 ZoneAのRDS用subnetにNACLを関連づけ
8.6 ZoneBのRDS用subnetにNACLを関連づけ
あたまがクラクラしてきませんか? 正直私はこんな指示書を渡されて、マネージメントコンソールから設定しろと言われたらいやになります。正直いくららくらくページを稼げるといわれてもスクリーンショットなんてとってられません。
一方で、こういう繰り返しはCloudFormationならばコピペ一発です。なんという楽でしょう。しかも失敗もへります!
もっとも、コピペの結果はこんなダラダラとしたJSONになります。
VPC内部のサブネット作成が完了したら、実際のサービス配置をはじめます。
まず最初のテクニックは、VPCサブネットを作成するために使ったCloudFormationテンプレートの呼び出しです。
呼び出しは、AWS::CloudFormation::StackのPropertiesにTemplateURLとして与えます。
"Resources" : { "vpcMake" : { "Type" : "AWS::CloudFormation::Stack", "Properties" : { "TemplateURL" : "https://s3-ap-northeast-1.amazonaws.com/arakisa /CloudFormation/eccube-vpc-05vpc.json", "TimeoutInMinutes" : "60" } },
このテンプレートでは、呼び出し元となるCloudFormationテンプレートに実行結果の値を渡すために、Outputsを定義しています。
"Outputs":{ "ELBSubnetAId":{ "Value":{"Ref": "ELBSubnetA"}, "Description":"Id of ELBSubnetA" }, "ELBSubnetBId":{ "Value":{"Ref": "ELBSubnetB"}, "Description":"Id of ELBSubnetB" }, "ECSubnetAId":{ "Value":{"Ref": "ECSubnetA"}, "Description":"Id of ECSubnetA" }, "ECSubnetBId":{ "Value":{"Ref": "ECSubnetB"}, "Description":"Id of ECSubnetB" }, "RDSSubnetAId":{ "Value":{"Ref": "RDSSubnetA"}, "Description":"Id of RDSSubnetA" }, "RDSSubnetBId":{ "Value":{"Ref": "RDSSubnetB"}, "Description":"Id of RDSSubnetB" }, "VPCID":{ "Value":{ "Ref" : "VPC" }, "Description":"Id of VPC" } }
たとえばこんな具合です。ネットワークに関連するIdをVPCID, ELBSubnetAId, ELBSubnetBId, ECSubnetAId, ECSubnetBId, RDSSubnetAId, RDSSubentBIdとして定義しています。
呼び出し元で上のVPCIDを使うためには、
{ "Fn::GetAtt" :["vpcMake", "Outputs.VPCID"] }
のように、Fn::GetAttを使っていつでも呼び出すことができます。
親となるCloudFormationテンプレートでは、VPC環境に対応した修正が必要です。
今回、VPC内で使用を定義するために特別なパラメータをあたえなければならないリソースタイプは
という5つです。
ELBはVPCにおいては、配置するサブネットと、セキュリティグループを指定します。
ELBを配置するサブネットの指定は、AWS::ElasticLoadBalancing::LoadBalancerの中で、Subnetsで指定し、セキュリティグループも同様にSecurityGroupsとして指定する。
"elbeccube": { "Type": "AWS::ElasticLoadBalancing::LoadBalancer", "Properties": { "Subnets": [ { "Fn::GetAtt" :["vpcMake", "Outputs.ELBSubnetAId"] }, { "Fn::GetAtt" :["vpcMake", "Outputs.ELBSubnetBId"] } ], "SecurityGroups" : [{"Ref" : "LoadBalancerSecurityGroup"}], ……(略)
セキュリティグループは、AWS::EC2::SecurityGroupを使って指定します。
VPC内においては、セキュリティグループも、どのVPCに所属しているかをProperties中にVpcIdとして宣言します。
"LoadBalancerSecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "Enable HTTP access on port 80", "VpcId" : { "Fn::GetAtt" :["vpcMake", "Outputs.VPCID"] }, "SecurityGroupIngress" : [ { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0" } ], "SecurityGroupEgress" : [ { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0" } ]}},
EC2インスタンスもVPC内で起動させるためには、SubnetIdを指定します。
"instanceib3ba90b3": { "Type": "AWS::EC2::Instance", "Properties": { "SubnetId": {"Fn::GetAtt":["vpcMake", "Outputs.ECSubnetAId"]}, …… (略)
RDSが使用するサブネットにはSubnetIdを指定します。
"MyDBSubnetGroup" : { "Type" : "AWS::RDS::DBSubnetGroup", "Properties" : { "DBSubnetGroupDescription" : "Subnets available for the RDS DB Instance", "SubnetIds" : [ { "Fn::GetAtt" :["vpcMake", "Outputs.RDSSubnetAId"] }, { "Fn::GetAtt" :["vpcMake", "Outputs.RDSSubnetBId"] } ]}},
RDSはさらにDBSecurityGroupも定義します。この例では、CIDRブロックを使っています。
"dbsgdefault": { "Type": "AWS::RDS::DBSecurityGroup", "Properties":{ "GroupDescription": "RDS security group in private", "EC2VpcId" : { "Fn::GetAtt" :["vpcMake", "Outputs.VPCID"] }, "DBSecurityGroupIngress": [{ "CIDRIP": "10.1.20.0/23" } ]}}
以上の修正を加えたCloudFormationテンプレートを
https://arakisa.s3.amazonaws.com/CloudFormation/eccube-vpc-06instance.json
に置いておきます!ながーいのでニヤニヤする程度にとどめてくださいませ!
というわけで、CloudFormationこそがVPC導入のポイントです。異論は大いにあるでしょうけれども、今あるシステムを移行するほうが新規に設計するよりは難しいとおもいます。そんな手助けに(主に試行錯誤のためですが)なると幸いです。
SlideShareにうpした。昨日発表した新ネタです。メディア配信をネタにキューイングのCDPを2つ使いました。 そしてファイル配信からストリームにかえるパターンに名前をつけるんだった。
この発表のキモは
それにしても仙台の復興需要はすごい。ホテルはとれなかったので急ぎでかえることになった。
そうなれば夕飯を駅弁にしようかとおもったが、仙台なのに駅弁が全滅! この駅弁激戦駅なのに、おかししか食っとらん状態でのりこみ。。せつないねえ。