CloudFormationを使ってみる

AWS

AWSシリーズ最終回(2回目)です。(毎回言うことにする)

筆者の会社では(というか自分のチームでは)、AWSでサーバーレスアーキテクチャを実装し、業務システムに活かす取り組みをしています。

その過程で出てくるのがCloudFormation

たぶんなんのこっちゃ分からないかと思いますが、ざっくりいうと、「テキストファイル1つで色んなAWSリソースを一気に作れる機能」です。

やっぱり訳わからないと思うので、サンプルをお見せします。
(このサンプルはこの記事のために作ったオリジナルのものです、2019年10月6日時点ではちゃんと動きます)

AWSTemplateFormatVersion: "2010-09-09"
Description: Sample Template by pokete.com
Resources:
  LambdaExecutionRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - 
            Effect: "Allow"
            Principal: 
              Service: 
                - "lambda.amazonaws.com"
            Action: 
              - "sts:AssumeRole"
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
  AllowReceiveEventFromS3:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !GetAtt PrintObjectKeyFunc.Arn
      Action: "lambda:InvokeFunction"
      Principal: "s3.amazonaws.com"
  PrintObjectKeyFunc:
    Type: "AWS::Lambda::Function"
    Properties: 
      Handler: "index.handler"
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: "python3.7"
      Code: 
        ZipFile: |
          def handler(event, context):
            s3_event = event['Records'][0]['s3']
            bucket_name = s3_event['bucket']['name']
            object_key = s3_event['object']['key']
            print("You put the file: " + object_key)
            print("at the bucket: " + bucket_name)
  EventBucket:
    Type: "AWS::S3::Bucket"
    Properties:
      NotificationConfiguration:
        LambdaConfigurations:
          -
            Event: "s3:ObjectCreated:*"
            Function: !GetAtt PrintObjectKeyFunc.Arn

これはYAMLという言語で書いた、CloudFormationのテンプレートです。
もっぱらファイル名は「template.yml」(または.yaml)が使われます。

このテンプレートを実際にデプロイすると、以下のようなAWSリソースが作成されます。

  • YAML内の「LambdaExecutionRole」は、IAM Roleです。
    Lambdaに対して、管理ポリシー「AWSLambdaBasicExecutionRole」を許可します。
    ※AWSLambdaBasicExecutionRoleはAWS管理ポリシーで、CloudWatch Logsへログ出力を許可するものです
  • YAML内の「AllowReceiveEventFromS3」は、Lambda Permissionです。
    任意のS3に対して、後述する「PrintObjectKeyFunc」というLambdaを実行(Invoke)する許可を与えます。
  • YAML内の「PrintObjectKeyFunc」は、Lambda Functionです。
    Python3.7で書かれたLambdaです。
    実行時は先述の「LambdaExecutionRole」のロールを使用します。
  • YAML内の「EventBucket」は、S3 Bucketです。
    中にオブジェクトが置かれたら、先述の「PrintObjectKeyFunc」にオブジェクトが置かれた旨を通知します。
  • このYAMLは、「EventBucket」にオブジェクトを入れると、「PrintObjectKeyFunc」が動き、標準出力(CloudWatch Logs)にバケット名とオブジェクト名を吐き出す仕組みを作ります。

…まだ掴めないと思います。
よっぽど乱暴に試さない限り、全部(12ヶ月の)無料枠で収まるので、作ってみましょう。

CloudFormationの画面を開き、「スタックの作成」をクリックします。

前提条件に「テンプレートの準備完了」、
テンプレートの指定で「テンプレートファイルのアップロード」を選択し、
先程のYAMLを保存したやつをアップロードします。(template.yaml以外でもよいです)
するとCloudFormationが勝手にS3バケットを作り、その中に勝手にアップロードしたtemplate.yamlを放り込みます。
(このS3バケットはtemplate.yamlに書いたバケットとは別物で、連動していません)。

「次へ」をクリックします。

「スタックの名前」は必須なので何かしら入れておきます。
「次へ」をクリックします。

なんかつらつらと出てきますが、今回はどれも設定せずに最下部の「次へ」をクリックします。

やはり何かつらつらと出てきますが…

最下部の「AWS CloudFormationによってIAMリソースが作成される場合があることを承認します。」という部分にチェックを入れます。

チェックを入れ忘れると Requires capabilities: [CAPABILITY_IAM] と怒られる

わざわざチェックを入れなければならないのは、怪しいIAMロールを何でもかんでも許可すると、最悪誰かにAWSアカウントを乗っ取られてしまうからです。
今回のロールは、自分のAWSアカウント内にあるLambdaがログを吐けるようになるだけのものです。外の誰かに入り込まれることはありません。(私が信用できなければ許可しないほうがいいですが…)

では、最下部の「スタックの作成」を押しましょう。

なんか始まりました。1分ほど待ちましょう。時々右上の更新マークをクリックしてみるとよいでしょう。

こうなれば(左ペインが「CREATE_COMPLETE」になれば)作成完了です。

何が作成完了なんでしょう。

見に行ってみましょう。たとえばLambdaへ。

なんか1つ出来てますね。(PrintObjectKeyFunc-のあとの英数字はランダムです)
クリックして中を見てみると、全部で7行のPythonコードが出てきます。
さっきのYAMLに書いてあるコードのとおりですね。

次にS3を見てみましょう。

なんかバケットが2つありますね。
上のcf-templates-から始まるやつが、CloudFormationが勝手に作ったYAML入れです。
下のexamplestack-eventbucket-から始まるやつが、さっきのYAMLで書いたバケットです。

ちょっと「examplestack-eventbucket-ほにゃらら」の中に、適当なファイルを入れてみましょう。

私は考えるのが億劫なので、さっきのtemplate.yamlを入れちゃいました。
別に何を入れても構いません。

さて、テンプレートがちゃんと動いていれば、これでLambdaが動き出し、CloudWatchに何かが書き出されているはずです。見に行ってみましょう。

CloudWatchの「ログ」を見てみると、なんかありますね。このロググループを見てみましょう。

なんかありますね。このログストリームを見てみましょう。

お、なんか出てますね。どれどれ…
「You put the file: template.yaml」
「at the bucket: examplestack-eventbucket-97kpbizrw2re」
どうやらバケット名もオブジェクト名も取れているようです。

今回は見ませんでしたが、IAMロールのページを見に行くと、1つロールが増えていますよ。

これだけのモノを、CloudFormationだけで勝手に作ってもらっちゃいました。
これがCloudFormationです。そう、「インフラもコードも含めた設計図」なのです。

そしてこれをGitHubで共有すれば、GitHubは名実ともに「設計図共有サイト」


設計図どおりに店開きした後は片付けたくなります。撤収しましょう。

CloudFormationのスタックを削除するだけ、なのですが、ごめんなさい、1つだけ手間をかけてください。

S3バケットの中身は勝手には消してくれない(むしろ安心設計である)ので、「examplestack-eventbucket-」バケットを手動で空っぽにしてください。お手間おかけします。

さてスタックの削除は、CloudFormationの画面から行います。

右上の「削除」ですね。
クリックすると確認ウィンドウが出てくるので、「スタックの削除」をクリックします。

30秒ぐらいで全部消してくれます。
これでIAMロールもLambdaもS3バケットも(CloudFormationが勝手に作ったやつ以外)無くなりました。


どうでしょう、CloudFormation。
個人アカウントでの使い所としては、複数のAWSリソースから成る1つの機能をひとかたまりで作れる部分でしょうか。色んなコンソール画面を開かずとも、1つのYAMLで全部出来上がるのは便利です。
また文字情報なので、CI/CDに向いています。企業でサーバーレスの取り組みをするときは必修と言えるでしょう。

また記事を書く元気があれば、次回からはこの記事でやってる作業を細かく見ていきたいですね…