debiancdn

AWS, Content Delivery Network and Debian

タグアーカイブ: cdp

CDPアンチパターンの14つめはバックアップのアンチパターン

今年のクラウドデザインパターンの最大のイベントといえば、ラスベガスでの英語における発表だったでしょう。しかし、東京お台場で9月に行われたクラウドデザインパターンの発表もすばらしいものばかりでした。

そこで、私はアンチパターンのワースト13を発表しました。そのプレゼンの中でも発表しましたが、アンチパターンの目的はただ笑うためにあるものではありません。

  • 失敗に陥るパターンを類型化し、事例の早期発見と対応策に関しての提案を目的とする。
  • 動作やプロセス、構造について、当初は妥当であったのに、最終的に悪い結果が繰り返されるパターン
  • リファクタリングするための方法が存在するパターン

この3つの観点をわすれてはならないと思っています。

13のアンチパータンの後ろに続くワーストは、バックアップにかかわるものばかりでした。特に、AWSでバックアップを考えるとき便利なのはAMI、EBSとスナップショット機能でしょう。

  • 「AMIを一切作らずに本番運用を行う」ことがしばしば見受けられます。これはAMI作りが難しいと思っている場合や、OSからの手順に固執した場合などに見られがちです。ある程度のところまでAMIの形でシステムを用意しておけば、システム構築やトラブル時の対応時間の短縮が可能です。
  • 逆に「AMI作成だけがバックアップ」だと思っているとすれば、それも問題です。AMI作成の最大の問題は、AMI作成を動作中に安全に行うことができないことです。また、EBSを使わない場合にはバックアップできないと思っているとすればさらに問題です。
  • 「スナップショットを使わない」ことも問題です。EBSによるバックアップは残念ながら完璧ではありません。AWSはEBSが壊れかねないことを表明しています。スナップショットを使えば、異なるアベイラビリティゾーンへの移動や、操作ミスによるファイル消失リスクを下げることもできます。
  • 「スナップショットを安全に使えない、使わない」のも時として問題です。EBSはあくまでボリュームでありそのファイルシステムやアプリケーションでキャッシュしている内容はわかりません。スナップショットをバックアップに使うのであれば、ボリュームへの書き込みを確実におこなわければなりません。

繰り返しになりますが、AMI,EBS,スナップショットはAWSでのシステム運用に大きく貢献できる機能です。ぜひこれらの特性を理解して利用しましょう。

さて、13のアンチパターンを見たことがないひとのために復習をしておきます。

  1. プロトタイプを作らずに机上だけで設計を行う
  2. トラフィック代金を心配しすぎる
  3. IPアドレスに頼りすぎる
  4. ひとつのアベイラビリティゾーンだけでシステムを作る
  5. EC2以外のサービスを使わない
  6. S3を共有ストレージ、ブロックストレージとして使う
  7. 事前のキャパシティプランニングに固執する
  8. AWSのセキュリティ機能を使わない
  9. 構築したシステムの見直しをしない
  10. 全機能を使おうとして消化不良に陥る
  11. リージョン選択を間違う
  12. CloudFrontを使わない
  13. 実際の負荷変化と違う負荷テストを行う

中でも、机上の設計だけで本番のシステムを決めてしまうことだけは避けましょう!AWSはまだまだ発展していくシステムです。

そして、逆説的ですが、CDPに固執することなく新たなアーキテクチャに挑戦していきましょう。


VPCのメタパターンもしくは怠惰な私のVPC導入。

皆様、昨日の松井さんの男気あふれる記事に度肝を抜かれた荒木でございます。毎度のことながら彼の軌跡は奇跡として語り継がれるといって間違いないでしょう。

さて、VPC環境構築のメタパターンと予告しました。実際のところCloudformationの出番は無限です。その中でも最も強力なのは、ある状態を保存再現する機能です。VPCのように面倒な環境構築に有効です。

時間のない人のために結論を。

  1. CloudFormationはある時点の状態再現に有効です。
  2. VPCに関しては再現を自動化するのは諦めて、(時としてつまらない)設計を再現するためにCloudFormationを使いましょう。
  3. 実はVPCIDを使えばClassicな環境からの移行は簡単!

というわけで、CloudFormationこそがVPC導入のポイントかもしれません。

これから述べる内容は

  1. ELB
  2. アプリケーションサーバ
  3. データベース(RDS)

のどこにでもある三段構えのサービスを題材にしています。

CloudFormationの意義

AWSを使ったシステム構成工数に関しては多くの方が考える問題です。
システムは机上での設計ではなく、試行錯誤を経てサービスを作るべきだとは思います。

実際のシステムでは、構成変更時にはテストが欠かせません。
また、テストの与える影響の測定や変更前への切り戻しを意識したシステム構成を求められることはまちがいありません。
そのために同一のシステムを構成し、部分的な変更を加えた後にテストを行うのが理想的な体制でしょう!

その一方で、この師走のなか、毎回同じことを繰り返す時間はない、というのが本当のところではないでしょうか。
何度でも速やかに構成(クローニング)できるようにして、ある時点でのシステムにもどせれば、どんどんチャレンジすることができるはずです。

そこで役に立つのがCloudFormationです。

テンプレート作成には3つの方法があります。

  • テンプレートの文法をAWS CloudFormation User Guideを読み、いちから作成する方法
  • AWS CloudFormationサンプルテンプレート(http://aws.amazon.com/jp/cloudformation/aws-cloudformation-templates/) として集められたサンプルを流用する方法
  • CloudFormerを使って、既存のAWSリソースからCloudFormationテンプレートを作成する方法

正直、最初の2つの方法は「部分的に変更を加えてきたシステム」において現実的な方法ではないでしょう。そこで3番目のCloudFormerの登場です。

一旦、CloudFormer で作成した AWS CloudFormation テンプレートを使うと、AWS Management Consoleで数回クリックするだけで既存のシステムのコピーを起動可能です。

準備:まずは、CloudFormer自体を用意する。

https://console.aws.amazon.com/cloudformation/home?region=ap-northeast-1#cstack=sn~AWSCloudFormer|turl~https://s3.amazonaws.com/cloudformation-samples-ap-northeast-1/AWSCloudFormer.templateをクリックして、早速使ってみましょう。

起動すると、次のような画面があらわれるはずです。

CF first

CloudFormerはIAMのアカウントを使用するため、その確認のチェックはさくっと終わらせて前にすすみましょう。

すると、こんな具合で最終的にシステムを作っていいかどうかの確認がはいります。もちろん躊躇せずにContinueしましょう。

無事起動するとStatusがCREATE_COMPLETEに変わります。それまでは、Eventsでもみてニヤニヤしましょう。

CloudFormerの使用

CloudFormerを使用するには、CloudFormerの作成したURLにwebブラウザでアクセスします。そのURLはOutputsタブの中で確認します。

するとこんな画面があらわれます。テンプレート作成対象リージョンを選択しましょう。

あとは一本道です!

含めるドメイン名を確認したり、EC2を確認したり、RDSを確認したり、セキュリティグループを確認したり。。

数個の画面でチェックをつづけると、S3に保存するように促されます。保存されたテンプレートはJSON形式で、その頭のほうが確認できます。

ここまできたら、このテンプレートをつかってたちあげてみましょう。Congratulationsがきたら、即座にLaunch Stackです。

とはいえみなさん時間もないことですし、上がりそうだ!という雰囲気だけつかんでおきましょうか。

とりあえず、作成したテンプレートの置き場だけは確認しておきましょう。このテンプレートがスタート地点になります。

とはいえ、これで完璧か!といわれるとそんなことはありません。

CloudFormerはまりポイント1:AMIは動作時インタンスのAMIである

個人的にCloudFormerのハマリポイントはなんだと問われれば、AMI情報は動作時のインスタンスが起動した時点でのAMIであって、CloudFormerがAMIを作るわけではないところです。

    "instancei2d5f6a2d": {
      "Type": "AWS::EC2::Instance",
      "Properties": {
        "AvailabilityZone": "ap-northeast-1b",
        "DisableApiTermination": "FALSE",
        "ImageId": "ami-c857e5c9",
        "InstanceType": "m1.small",
(以下略)

こんなテンプレートがあるときは、このAMIの内容を変更したならば、自分でつくりなおさなければなりません。あえてつくりなおさなければならないときは、マネージメントコンソールでインスタンスから右クリックして作りなおせばよいでしょう。

CloudFormerはまりポイント2:Route53で指定している値は動作時ELBのCNAMEである

こう言われてもピンとこないかもしれません。

    "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" ] }

CloudFormerはまりポイント3:RDSの内容は動作時である

これもELBと同じですが、データが消えるという意味ではもっと問題がおおきいかもしれません。

スナップショットを作成したら、DBSnapshotIdentifierパラメータで指定しましょう。

CloudFormerはまりポイント4:手修正でフォーマットを破壊する

ここまでうまく行っても、人間には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

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の万能感は異常です。

VPCに関しては再現を自動化するのは諦めて、(時としてつまらない)設計を再現するためにCloudFormationを使いましょう。

とまあ、こんなことを書くのは、CloudFormerがVPCに対応していない試行錯誤したシステムの保存にフォーカスしていて、なおかつ、繰り返し単調な設計がつづくネットワーク再現に最適だからなのです。

たとえば、こんなことやってられますか?

1        VPCとして10.1.0.0/16を定義 

2        ELB用にPublicサブネットを定義 

2.1       ZoneAELBsubnet 10.1.10.0/24を定義

2.2       ZoneBELB subnet 10.1.11.0/24を定義

3        eccube用にPrivateサブネットを定義

3.1       ZoneAeccubesubnet 10.1.20.0/24を定義

3.2       ZoneBeccube subnet 10.1.21.0/24を定義

4        RDS用にPrivateサブネットを定義

4.1       ZoneARDSsubnet 10.1.30.0/24を定義

4.2       ZoneBRDS subnet 10.1.31.0/24を定義

5        インターネットゲートウェイを定義

5.1       インターネットゲートウェイをVPCに関連づけ

6        2Publicサブネットの経路表を定義

6.1       Publicサブネットの経路表にデフォルトゲートウェイとしてインターネットゲートウェイを向ける

6.2       ZoneAELBsubnetに対して経路表を関連づけ

6.3       ZoneBELBsubnetに対して経路表を関連づけ

7        2PublicサブネットにNACLを定義

7.1       Inbound用にHTTPポートを許可

7.2       Inbound用に1024から65535のダイナミックポートを許可

7.3       Outbound用にHTTPポートを許可

7.4       Outbound用に1024から65535のダイナミックポートを許可

7.5       ZoneAELBsubnetに対してNACLを関連づけ

7.6       ZoneBELBsubnetに対してNACLを関連づけ

8        PrivateサブネットにNACLを定義

8.1       Inbound用にVPC内部からの接続を許可

8.2       Outbound用にVPC内部への接続を許可

8.3       ZoneAeccubesubnetNACLを関連づけ

8.4       ZoneBeccubesubnetNACLを関連づけ

8.5       ZoneARDSsubnetNACLを関連づけ

8.6       ZoneBRDSsubnetNACLを関連づけ

 

 

あたまがクラクラしてきませんか? 正直私はこんな指示書を渡されて、マネージメントコンソールから設定しろと言われたらいやになります。正直いくららくらくページを稼げるといわれてもスクリーンショットなんてとってられません。

一方で、こういう繰り返しはCloudFormationならばコピペ一発です。なんという楽でしょう。しかも失敗もへります!

もっとも、コピペの結果はこんなダラダラとしたJSONになります。

VPCの中へのサービス配置

VPC内部のサブネット作成が完了したら、実際のサービス配置をはじめます。

CloudFormationテンプレートの入れ子呼び出し

まず最初のテクニックは、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内で使用を定義するために特別なパラメータをあたえなければならないリソースタイプは

  • AWS::ElasticLoadBalancing::LoadBalancer
  • AWS::EC2::SecurityGroup
  • AWS::EC2::Instance
  • AWS::RDS::DBSubnetGroup
  • AWS::RDS::DBSecurityGroup

という5つです。

AWS::ElasticLoadBalancing::LoadBalancer

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

セキュリティグループは、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" } ]}},

AWS::EC2::Instance

EC2インスタンスもVPC内で起動させるためには、SubnetIdを指定します。

        "instanceib3ba90b3": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
         "SubnetId": {"Fn::GetAtt":["vpcMake", "Outputs.ECSubnetAId"]},
                …… (略)

AWS::RDS::DBSubnetGroup

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"] }
                ]}},

AWS::RDS::DBSecurityGroup

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
に置いておきます!ながーいのでニヤニヤする程度にとどめてくださいませ!

結論

  1. CloudFormationはある時点の状態再現に有効です。
  2. VPCに関しては再現を自動化するのは諦めて、(時としてつまらない)設計を再現するためにCloudFormationを使いましょう。
  3. 実はVPCIDを使えばClassicな環境からの移行は簡単!

というわけで、CloudFormationこそがVPC導入のポイントです。異論は大いにあるでしょうけれども、今あるシステムを移行するほうが新規に設計するよりは難しいとおもいます。そんな手助けに(主に試行錯誤のためですが)なると幸いです。

JAWS仙台でキューイングとストリーミングの話をした

SlideShareにうpした。昨日発表した新ネタです。メディア配信をネタにキューイングのCDPを2つ使いました。 そしてファイル配信からストリームにかえるパターンに名前をつけるんだった。

この発表のキモは

  • キューイングをつかってffmpegの利用を最適化しよう
  • 重みづけキューイングをつかうと優先会員なんかもつくれる
  • ファイル全体をdownloadさせると金ばっかりかかるダウンロード厨が避けられなくなるので、ストリームも活用しましょう

それにしても仙台の復興需要はすごい。ホテルはとれなかったので急ぎでかえることになった。

そうなれば夕飯を駅弁にしようかとおもったが、仙台なのに駅弁が全滅! この駅弁激戦駅なのに、おかししか食っとらん状態でのりこみ。。せつないねえ。