こつつみ

コツコツ積み上げる

Lambda + CloudWatch EventのインフラをCloudFormationでコード化する

はじめに

この記事は、以下の記事にて説明したSlack botのインフラをCloudFormationでコード化したものです。

kotsutsumi.hatenablog.com

Lambda + CloudWatch Event の CloudFormation

作成するリソースはこちらです。

今回のLambdaは、CloudWatch EventのルールによりLambdaを起動します。 Lambdaのコードは、GitHub ActionsでAWS CLIにより直接配置する予定なので、今回はダミーとして超簡単なコードを記載しています。

def lambda_handler(event, context):
    print('dummy')

今回Yamlファイルで書いていますが、Jsonでも書くことができます。 しかし、Json形式ですとコメントが書けないといったデメリットがあります。

自分の書いたCloudFormationに適宜コメントを入れて解説します。

AWSTemplateFormatVersion: 2010-09-09

Description: Lambda for git commit count bot # 書かなくても良い

Parameters:  # 指定する値が無ければ書かなくても良い
  GitHubAccessToken:  # Parametersで定義したものは、Resourcesで使えるようになる
    Type: String  # Parametersの値は、CLIで指定したり、Web上で入力も出来ます
  SlackApiToken:
    Type: String

Resources:
  GitCommitCountBotLambda:  # 任意の名前に変更する
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: git-commit-count-bot  # 任意の名前に変更する
      Handler : lambda_function.lambda_handler  # 自身のコードに合わせて変更する
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: python3.9
      Timeout: 10  # デフォルトは3秒だが、今回10秒にしている
      Environment:
        Variables:
          GITHUB_ACCESS_TOKEN: !Ref GitHubAccessToken  # 環境変数を設定できる
          SLACK_API_TOKEN: !Ref SlackApiToken  # !RefでParametersでしたいした値を使用できる
      Code:
        ZipFile: |  # ここでコードを書かなくてもS3に配置するなどでも大丈夫
          def lambda_handler(event, context):
              print('dummy')

  LambdaExecutionRole:   # 任意の名前に変更する
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: git-commit-count-bot-role
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup  # ログを取れるように許可を与える
                  - logs:CreateLogStream  # ログがいらなければRoleがなくても良い
                  - logs:PutLogEvents
                Resource:
                  - '*'

  CloudWatchEventRule:  # 任意の名前に変更する
    Type: AWS::Events::Rule
    Properties:
      Name: schedule-every-day-0am-event  # 任意の名前に変更する
      ScheduleExpression: cron(0 15 * * ? *)  # 日本時間で 0:00
      State: ENABLED
      Targets:
        - Arn: !GetAtt GitCommitCountBotLambda.Arn
          Id: git-commit-count-bot-lambda

  LambdaEventPermission:  # 任意の名前に変更する
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref GitCommitCountBotLambda  # Type: AWS::Lambda::Functionで自身がつけた名に変更する
      Principal: events.amazonaws.com
      SourceArn: !GetAtt CloudWatchEventRule.Arn  # CloudWatch Eventと連携させる

番外編: デプロイ

今回AWSに適用する際にはAWS CLIで操作します。もちろんAWSのサイト上でファイルをしてCloudFormationのコードを適用することも出来ます。

自分が使用したコマンドは以下である。自分がハマったエラーとして --capabilities CAPABILITY_NAMED_IAM を指定しなかったことです。

CloudFormationがスタックを作成するために、特定の機能が含まれていることを明示的に示す必要があ理ます。

  • IAMリソースがある場合は、CAPABILITY_IAMかCAPABILITY_NAMED_IAMが必要になる
  • カスタム名のIAMリソースがある場合はCAPABILITY_NAMED_IAMを指定する
  • 指定がないとAWSCloudFormationはInsufficientCapabilitiesエラーを返す

今回、IAM Roleを作成しているので、--capabilitiesで指定する必要があります。 ${{ secrets.~~ }} はGitHub Actionsの指定です。実際には、そこに環境変数の値を入力します。

aws cloudformation deploy --template-file cloudformation/git_commit_count_bot.yml --stack-name git-commit-count-bot-cfn --capabilities CAPABILITY_NAMED_IAM --parameter-overrides GitHubAccessToken=${{ secrets.ACCESS_TOKEN }} SlackApiToken=${{ secrets.SLACK_API_TOKEN }}

ちなみにLambdaにCLIで直接デプロイする方法は以下です。

aws lambda update-function-code --function-name git-commit-count-bot --zip-file fileb://${{ env.ZIP_FILE_NAME }} --publish

自分は上記のことをGitHub Actionsで行っています。参考にコードを置いておきます。

github.com

最後に

今回CloudFormationでコード化に至ったのには、以下の理由からである。

  • AWS初学者を導く体系的な動画学習サービス AWS CloudTech で学んだ
  • 会社でCloudFormationを使うことになった
  • CI/CDを構築したい

自動テストは大体行える環境を作ってはいるが、自動デプロイに関しては無知だったので、とても良い経験になった。 今回CloudFormationを学んだことで、会社でもすんなり実装できて良かった。

CloudFomationは、AWS CloudTechで学んだ。とても分かりやすく初学者にとって有効だった。 自分は、AWS CloudTechに入ってAWS SAAの資格をとって、組み込みエンジニアからWebエンジニアに社内転職した人なので、おすすめします。

aws-cloud-tech.com

AWS Lambda + GraphQLでGitHubのコミット数を通知してくれるSlack botを作った

はじめに

2021年10月ごろより、出来るだけ毎日GitHubの草を生やそうと決めました。 また、Pythonのコードの書き方を身につけることも目的です。

そのために、Slackの自分のチャンネルに通知してくれるbotを作ろうと考えました。

機能

f:id:ue-sho:20211003152642p:plain

上記のように1日のコミット数をSlackに通知してくれる。

  • Lambdaと連携させたCloudWatch Eventを使って 0:00 にイベントを発火する
  • Slackの自分の #times_uesho に通知する
  • GitHubの GraphQL API を使ってコミット数を取得する
  • プライベートリポジトリのコミット数まで取得する
  • CloudFormationでインフラをコード化する ※別記事にて解説予定
  • GitHub Actions でmasterにpushしたら自動でデプロイする ※別記事にて解説予定

GitHubの GraphQL API

当初、コントリビューションからコミット数を取得していたが、どうもプライベートリポジトリの値は取れなかった。

        query (
            $name: String!,
            $from: DateTime!,
            $to: DateTime!
        ) {
            user(login: $name) {
                name
                contributionsCollection(from: $from, to: $to) {
                    totalRepositoryContributions
                    totalCommitContributions
                    commitContributionsByRepository {
                        repository {
                            nameWithOwner
                        }
                        contributions {
                            totalCount
                        }
                    }
                }
            }
        }

そこで、リポジトリごとにコミット数を調べる方法に変更した。(デフォルトブランチのコミット数しか取れなそう)

        query($date: GitTimestamp!) {
          viewer {
            repositories(last: 100) {
              nodes {
                nameWithOwner
                defaultBranchRef {
                  target {
                    ... on Commit {
                      history(since: $date) {
                          totalCount
                      }
                    }
                  }
                }
              }
            }
          }
        }

こうすることで以下のようなレスポンスが得られる。

{
        "data": {
            "viewer": {
                "repositories": {
                    "nodes": [
                        {
                            "nameWithOwner": "ue-sho/pycabook_rentomatic",
                            "defaultBranchRef": {
                                "target": {
                                    "history": {
                                        "totalCount": 0
                                    }
                                }
                            }
                        },
                        {
                            "nameWithOwner": "ue-sho/Calculator",
                            "defaultBranchRef": {
                                "target": {
                                    "history": {
                                        "totalCount": 0
                                    }
                                }
                            }
                        },
                        {
                            "nameWithOwner": "ue-sho/rent_price_forecast",
                            "defaultBranchRef": {
                                "target": {
                                    "history": {
                                        "totalCount": 0
                                    }
                                }
                            }
                        },
                        {
                            "nameWithOwner": "ue-sho/telescopic-sidebar",
                            "defaultBranchRef": {
                                "target": {
                                    "history": {
                                        "totalCount": 0
                                    }
                                }
                            }
                        },
                        {
                            "nameWithOwner": "ue-sho/git-commit-count-bot",
                            "defaultBranchRef": {
                                "target": {
                                    "history": {
                                        "totalCount": 5
                                    }
                                }
                            }
                        },
                        {
                            "nameWithOwner": "ue-sho/auto_testing",
                            "defaultBranchRef": {
                                "target": {
                                    "history": {
                                        "totalCount": 4
                                    }
                                }
                            }
                        }
                    ]
                }
            }
        }
    }

取得したレスポンスを整形し、SlackのAPIchat.postMessage を使用して自分のチャンネルに通知した。Slack Botの記事は多くあるので割愛します。

コード量はそんな多くないので、詳細をみたい人はリポジトリを見てください!Pythonです( ◠‿◠ )

github.com

AWS Lambda

構成はとても簡素です。なぜLambdaを使ったかと言うと、EC2などに上げるより簡単かつ時間のイベント発火も簡単にできるためです。しかも無料で使える!ところが決め手です。

AWS Lambda の無料利用枠には、1 か月ごとに 100 万件の無料リクエスト、および 40 万 GB-秒のコンピューティング時間が、それぞれ含まれます。 引用: 料金 - AWS Lambda |AWS

f:id:ue-sho:20211003153957p:plain

今回に必要な設定は以下です。

  • Lambda Functionの作成
  • CloudWatch Eventの定義
  • LambdaとCloudWatch Eventの連携

Lambda Functionの作成

コンソール上の「関数を作成」から作る。

  • 関数名をつける (今回は「git-commit-count-bot」(下の画像のサンプルは「test」)という名前をつけた)
  • ランタイムを選択 (今回はPython 3.9)
  • その他はデフォルトでOK

CloudWatch Eventの定義 & 連携

f:id:ue-sho:20211003161014p:plain

上記の画面のトリガーを追加からEventBridge(CloudWatch Event)を選択する。

「新規ルールの作成」を選択して今回は0時にイベントが発火するようにする。 自分はバッチ処理などでよく使われるcronコマンドの方式で設定しました。

UTC(協定世界時) になっており、日本の時刻から-9時間する必要があります。 つまり、cron(0 15 * * ? *) することで、毎日0時にイベントが発火します。

ルールのスケジュール式 - Amazon CloudWatch Events

これにて完成!

最後に

GitHubの草も9月くらいからよく生えるようになりました。

f:id:ue-sho:20211003161717p:plain

この記事はAWS初学者を導く体系的な動画学習サービス AWS CloudTech を参考に作成しました。(AWS関連)

aws-cloud-tech.com

逆ポーランド記法電卓 を作ってみた

はじめに

Twitterで #uesho開発 というタグで、簡単なものから開発したものを公開していくことにしました。 これによって、将来見返した際に成長具合が可視化できると考えています。

その第一弾として、逆ポーランド記法電卓 を作ってみました。

逆ポーランド記法 とは?

以下、引用Wikipedia

逆ポーランド記法(ぎゃくポーランドきほう、英語: Reverse Polish Notation, RPN)は、数式やプログラムの記法の一種。演算子を被演算子の後にすることから、後置記法 (Postfix Notation) とも言う。

その他の記法として、演算子を被演算子の中間に記述する中置記法、前に記述する前置記法(ポーランド記法)がある。 名称の由来は、演算子と被演算子の順序がポーランド記法の逆になっていることによる。

目的

Pythonを使い始めてまだ二ヶ月経っていなかったので、まずはPythonに慣れること。 そして、Pythonでのオブジェクト指向を学ぶこと。

やったこと

実は会社の研修でPythonではなかったですが、似たようなものを作ったため、思い出しながら作っていきました。

振り返り

学びとしては、Pythonでのabcモジュールを使った抽象クラスの作り方を知った。この抽象クラスを作ったことで演算子を追加した際に、簡単に実装することができた。 Pythonでも抽象クラスを作ることが有用に感じた。しかし、逆にPythonは動的型付け言語なので一般的にどうするべきなのかがいまいち分からなかった。 もしかしたら、抽象クラスを作らなくても綺麗にできたのかもしれない。(気づいた人は教えていただきたい)

設計の観点では、電卓への入力値が正しいか判定するクラスを作成し、正しいデータだった場合にrequestデータとしてCaluculateクラスに渡す設計にした。 現在(2021/09/26)は、CLIだけでの実装だけである。しかし、今後GUIでもできるように設計したつもりなので、時間と余力があればGUIも作っていきたい。

【反省】今まで記事はネタバレブログだった

最近、Twitterでは書籍図解などが流行っているように思う。

漫画のネタバレなどは忌み嫌われるものである。しかし、書籍図解はみんなに感謝される。 全てが同じではないにせよ、本を読む時間がない人向けに書かれた図解はどう考えてもNGだ。

書籍の購買意欲を高める図解は好意的に受け取られるが、読んだ気にさせて「買わなくていいや」と思わせる図解は問題だと思うようになった。

いざ自分を振り返ってみると、書籍の紹介をしていく中で引用がたくさんあるので大まかな内容がわかってしまっている。 自分の中では文章書いた気になっているけど、自分の全然考察されていないので、全く独自性がない。自分の考えが全然ないのだ。

これからはブログを読んだ人が書籍を購入したくするべき。(アフィリエイト感が増してしまうけど...) 自分の考えを載せて解釈して自分に落とし込めて、初めて自分の中で腹落ちすると思う。そういう意味でも今のままの記事内容じゃ全然身につかない。 実際にも、ブログに書いた内容は忘れていることが多い。

アウトプットを意識して発信を続けていきたい。

「モデリングの学び方:座談会」に参加しました

2021/9/7 モデリングの学び方:座談会がオンライン上で開催されたので参加しました。

modeling-how-to-learn.connpass.com

まず今回申し込みが1000人超え、参加者700人だった。これだけモデリングに興味がある人がいるのかと驚いた。 そして、自分も含めてモデリングの仕方に困っている人が多そうだなと感じた。

自分のレベル感としては、以下の本は読んだが全く実践できていないという状況だ。

speakerdeck.com

まず、座談会として7人の話しての方に2つの質問が投げかけられた。

1. 普段はどんなモデリングをしているか?

皆さんのやり方は少し違えど、「ドメイン(ビジネス)モデルをしっかり知る」という点は共通していた。 あとは、しっかりクラス図を書く人もいれば、ホワイトボードで議論したり、ソースコードを作ったり消したりなど試行錯誤していたりなどあった。

自分の場合、モデリングの正解があれば聞きたいなと思っていたが、気づいてはいたが人それぞれ違うことを改めて知った。 しかし、先ほども書いたが、SIerならお客さんのサービス・自社開発なら自社サービスがどういうビジネスについて、 コンテキストマップに起こしたり、「概念モデル」をベースにユースケースロバストネス図を作成したり、オブジェクト図にしたりと、 それぞれのやり方でモデリングしているようだ。

話聞いていて思ったのは、エヴァンス本でも強く言われているがドメインのことをよく知っている人から聞いて、しっかりとドメインのことを理解することがモデリングには必要なんだと感じた。

2. どうやってモデリングを学んできた感じですか? 学び方のお勧めはありますか?

実践の中での問題を解決するためにモデリングについて学び始めた人が多いなと感じた。

自分は前の職場はC言語で書かれており、コードがとても汚くどうにかしたいという思いで色んな技術書を漁って読んでいた。 リファクタリングを実際にしたが、3ヶ月前にリファクタリングしたブランチのマージリクエストを出しているが、本番コードを修正してエラーが出るかもしれないからと未だにマージされていない。 単体テストも書いてやっていたが、どうすれば良かったのか分からずに部署が移動してしまった。(多分、マージされなそう)

現在の部署は、基本的にマイクロサービスになっておりモデリングする必要もないくらいのコードの大きさなのでモデリングしない。(全体を見ればモデリングできるとは思うが、現状する必要がない) 実務の中でモデリングについて学ぶのがかなり難しいなと思っている。現在は個人で試行錯誤しているが難しい。

ミノ駆動さんが言っていたペアプロリファクタリングをしていくのはとても良いなと思った。有識者の意見を聞きながらモデリング・設計をする機会があれば、自分の中のやり方というのが固まっていくのかなと思った。

あと良かったと思ったことは、「Tell, Don't Ask」だけは一番意識していると聞けたこと。有識者の気をつけているポイントを知れるのは良い。

TellDontAsk

他にもモデリングオブジェクト指向の学び方として以下が紹介されていた。

  • オブジェクト指向エクササイズ :これは賛否両論あるが、とっかかりとしては良さそうに感じた。

www.slideshare.net

www.ogis-ri.co.jp

最後に

なぜか一番印象に残ったのは、hiroさんがサーバーサイドには必ずクラス図を書いているということだ。

UMLについて研修を通して学んできて自分でも有用性を感じていたが、実際に実務で使うことがなく使っている人は現代ではいないのか?という気持ちになっていたので、 hiroさんがガッツリ使っていることを聞き、自分も書いていこうという気になった。ありがとうございます笑

個人だと小規模になりドメインモデルを考えるほどでもないので、手段が目的になってしまいがちになるのかな?と思っているが、 やっぱり手を動かして実践していくしか身につかないと思うので、個人開発でも積極的にモデリングの練習をしていきたい。

まだまだ自分の中に落とし込めていないので、「モデリングの学び方:座談会」の第二回があれば、また参加したい。

「思考・論理・分析」を読んだ

本の基本情報

本の基本情報について紹介する。

  • 著者名:波頭亮
  • 書籍名:思考・論理・分析―「正しく考え、正しく分かること」の理論と実践
  • 出版社:産能大出版部
  • 発売日:2004/7/15
  • 頁 数:241ページ

本の目次

以下は本書の目次です。

  • 第1章 思考
  • 第2章 論理
  • 第3章 分析

考えたこと

この本は割と言われてみると当たり前のことが書かれているが、その当たり前を言語化し図を用いながら体系的に「正しく考え、正しく分かること」について説明している。 間違いなく良書である。

自分は全然自分で考えられていないと思うことが多々あるが、なんで考えがまとまらないか分かっていなかった。この本を読んでみて当たり前ができていなかったんだと気付かされた。

思考の段階では、あらゆる情報を分けて構造化させ、それぞれの情報について”それが何であるのか” そして、”それがどのようなものであるか”ということを理解する。

論理の段階では、命題から正しく推論し、新しい意味内容を得る。

分析段階では、分析プロセスの設計をして、情報を集め、分析し、意味合いを抽出する。 分析作業を進めていくと「分析すること」自体が目的となってしまいがちになるのは分析作業のあるあるだが「正しい思考過程」「正しい論理」「正しい分析手順」を踏むことで、意思決定やアクションに結びつく「優れた分析」を行えるようにする。

この本は、上のような実践的な話から、そもそも「思考」とは何か?「論理」とは?「分析」とは?というところから説明されている。 「ロジカルシンキング」の本として何個か読んできたが、方法が書かれているものは多くあったが、「思考・論理・分析」がそもそも何なのか説明されているものは、他にはなかった。 そのため、一度ロジックツリーやMECEなど知っているが、使いこなせていない人(自分はこれ)は、考え方を知ることができるので本書を一度読んで見ることを見ると良い。

なぜ「論理的」に考えることが必要なのかということにも言及されている。 思考という行為は属人的であり、思考者によって左右されるからである。 その思考を「客観的」に行なうために「論理的思考」が必要であると筆者はいう。 属人性の扱いに対してどれだけ丁寧に考えられていたのか?知識に偏りがないか?心理的バイアスが発生して、先入観や思い込みに捉われていないか?など の観点はまだまだ自分にはできていない。そもそも自分のアウトプットの質が低い。 今からでも、毎日「正しく考え、正しく分かること」を実践していかないと身についていきたい。

「Clean Architectures in Python」を読んだ

クリーンアーキテクチャの書籍は読んでいたものの、実際にコードに落とし込めなかった。 なので、Pythonでのクリーンアーキテクチャ的な設計ってあるのかな?と検索していると、以下リンクの「Clean Architectures in Python」を見つけ無料で読めることを知った。

github.com

「Clean Architectures in Python」は2020年のEuroPythonで発表していたみたいです。

ep2020.europython.eu

目次

「Clean Architectures in Python」の目次を書いておく。

  • Introduction
  • About the book
  • Chapter1 : A day in the life of a clean system
  • Chapter2 : Components of a clean architecture
  • Chapter3 : A basic example
  • Chapter4 : Add a web application
  • Chapter5 : Error management
  • Chapter6 : Integration with a real external system postgres
  • Chapter7 : Integration with a real external system mongodb
  • Chapter8 : Run a production ready system

学んだこと

まず英語で書かれているので、Google翻訳を使いつつ読んでいった。

この本では、前半はCLIで物件情報を一覧表示するアプリを作り、 後半は前半で作ったものをもとにFlaskというフレームワークを用いて、WebAPIにしていきながらクリーンアーキテクチャが解説されている。 ビジネスロジックさえ作っていればCLIでもWebAPIでも簡単に変更できることや、 DBをpostgresからmongoDBに変更するなど変更容易性の観点や、エラーマネジメントの話はとても参考になる。

最初から最後までテスト駆動開発(TDD)で進められており、その点も非常に参考になる。

他にも、Pythondataclassやレスポンスの設計やユースケースについても知ることが出来た。

まとめ

クリーンアーキテクチャもそうだが、Pythonを始めたばかりの自分にとってはpythonでのテストの書き方、テスト駆動開発やDBへの接続などがとても参考になった。 全体を通して、今の自分にとっては知りたいことが具体例として書いてあり、すべてのページで学びがあった。

PythonでWeb開発に携わる人は、そんなに長くなく2, 3日くらいで読めたので、一度読んでみることをオススメする。