TECH PLAY

電通総研

電通総研 の技術ブログ

834

こんにちは。 電通国際情報サービス (ISID) 金融ソリューション事業部の若本です。AIを活用した新規事業に取り組んでおり、業務では主に 自然言語処理 の実装に携わっていますが、今回は画像処理分野の記事になります。 私は趣味で ブレイクダンス を練習しているのですが、自分の練習動画を見ていると「この動きは最近癖になっているな」ですとか、「あの動きは最近していないな」といった気付きを得ることが多々あります。しかし、過去の動画をいちいち見返すのはかなり億劫な作業です。 そこで、 過去の自分の練習動画から同じような動きを取得する ことを考えました。BlazePoseを使い、他の動画の中から似ている動きを検索します。 BlazePoseとは? Google が開発した、 動画から骨格情報を検出するAIモデル です 1 。BlazePoseを使用することで、手軽かつ高速に骨格検出を実施できます。奥行情報の推定やセグメンテーション(人が映っている場所だけを切り出すこと)も可能です。それでいて、リアルタイム検出に対応できる動作速度を持ち合わせています。 類似の骨格検出AIにはMoveNet 2 などもあります。こちらはモーションブラー(動きのブレ)に強いことが特長です。 動きの激しい ブレイクダンス を解析対象としているため、本来であればMoveNetを使いたいところですが、今回は奥行の情報も使いたいためBlazePoseを採用しました。以下がBlazePoseの出力例になります。 類似度の計算 以前に撮影した複数の練習動画を入力として、他の動画に似た動きがないか検索します。処理の概要は以下の図のようになります。 1つの動画内には多くの動きが含まれているため、まず動画を小分けに保存してBlazePoseにかけています。 BlazePoseを使い、小分けにした動画の各フレームの骨格情報を取得することができれば、あとは骨格情報の推移から類似度を計算するだけです。 これらを以下の手順で実装します。 ① 座標の情報を変換する ② 他の動画と比較して類似度を算出する ① 座標の情報を変換する BlazePoseで取得した骨格情報は、部位ごとに空間座標(X、Y、Z)の情報を持っています。 このとき、全く同じ動きをしていても空間座標の値は異なります。なぜなら、 動画を撮影している角度や位置などが動画ごとに異なる からです。 これらを統一するため、座標を以下のようにして変換します。 基準となる1つの部位を決め、その部位が原点になるよう全ての空間座標を平行移動させる 基準となる部位をもとに全ての空間座標を回転させる ここでは、体の場所と向きの情報をそろえています。体の向きさえ一致させることができれば、上記の方法でなくとも問題はありません。 ② 他の動画と比較して類似度を算出する ブレイクダンス について、以下のような特徴を考慮して類似度を計算します。 Ⅰ. 動きに個人差の大きい部位がある Ⅱ. 同じ動きでも早かったり遅かったりする Ⅰ. には部位ごとの重みづけを、Ⅱ. には類似度計算に DTW(Dynamic Time Warping) を使うことで対応すればよさそうです。このとき、類似度の計算は以下のように行います。 部位ごとにDTWを計算する 部位ごとに設定した重みをスコアにかけ、総和を取る 総和が 閾値 より小さければ、類似している動画とみなす 上記を小分けにした動画のすべての組み合わせについて繰り返す また、BlazePoseから出力される骨格情報は33箇所もあるため、特定の部位の情報のみを使用して類似度を算出しています。 結果 以下が類似と判定された動きのキャプションになります。 服装が似ていることもあってわかりづらいですが、別動画から類似モーションを取得することには成功しています。ただ、BlazePoseで取得した奥行の情報が不正確なためか、似た角度の動画が多く見られました。現時点のロジックでは、少なくとも撮影角度が似ているほうが有利になる傾向はありそうです。 おわりに 今回は ブレイクダンス の練習動画をもとに、類似モーション検索のチューニング・検証を行いました。 今後はより複雑な動き・速い動きでも類似モーションを取得できるよう改良したいと思います。また、撮影角度によっては類似モーションの見逃しが発生していることも今後の課題です。とはいえ、近年の骨格検出AIの発展は目覚ましく、より安定して骨格情報を捉えられるようになってきているため、改良するより早く解決してしまうかもしれません。 今後も単眼カメラの情報をベースとした様々な骨格検出モデルの登場が予想されます。今後どのように技術が発展していくのか、そしてどのように応用されていくのか、非常に楽しみです。 執筆: @wakamoto.ryosuke 、レビュー: @sato.taichi ( Shodo で執筆されました ) BlazePose: On-device Real-time Body Pose tracking( https://arxiv.org/abs/2006.10204 ) ↩ MoveNet: A Deep Neural Network for Joint Profile Prediction Across Variable Walking Speeds and Slopes( https://ieeexplore.ieee.org/document/9406043 ) ↩
お疲れさまです。XI本部、 AIトランスフォーメーションセンター の徳原 光です。 この記事で2回目の投稿になります。今回は所属センターで開発しているAI製品、 TexAIntelligence を使用して、 SNS での投稿に感情ラベルを付与したデー タセット である WRIMEデータセット ver.2をAIモデルに学習させた結果をまとめたいと思います。 感情分析とは? 感情分析は NLP 、 自然言語処理 の一手法で文章に込められた感情をAIによって検出する技術です。 例えば、「お風呂の水漏れが治らない・・・。今月でもう3度目だよ」という文章には「悲しみ」が込められていますよね(もしかしたら「怒り」もあるかも)。 「〇〇大学に合格できた!春からはれて大学生だ!!」という文章だったら「喜び」でしょうか? もし、「〇〇大学に合格できた!春からはれて大学生だ!!嬉しいなぁ」というように「嬉しい」とか、「やったー」という言葉が含まれていれば、ルールベースによる手法や従来の 機械学習 の手法で文章が意味する感情を判別することが可能です。 しかし、そのような感情を表す言葉が含まれていない場合、文章の文脈を理解する必要があるので、感情分析は NLP のタスクの中でも難しい課題と言えます。 WRIME 主観と客観の感情分析デー タセット こちらのデー タセット は 愛媛大学 の 梶尾先生 が作成されたデー タセット です。 BERTの学習用のデー タセット として作成されたので、 機械学習 で使用するデー タセット としては非常に使い勝手がいいデー タセット になります。 ver1では43,200件、ver2では35,000件の SNS から収集した文章データに基本8感情(喜び、悲しみ、期待、驚き、怒り、恐れ、嫌悪、信頼)の感情極性が書き手と3人の読み手ごとに4段階(0:無、1:弱、2:中、3:強)でラベル付けされています。 さらに、ver2では肯定的か否定的かのラベルも5段階で付いていて、今回はそれを利用しました。 NLP の世界では、いつの世でも学習データが不足してしまうものですが、数万件の文章データがあるのでデータ数で困ることはありません。しかも、一つの文章に複数のラベルが付けられているので、ア イデア しだいでいろいろな応用ができます。 また、ver1では80人、ver2では60人の書き手から文章を収集しているのでいろいろな文体の文章が収録されており、さらに SNS の特性上、内容のジャンルは様々なので非常に汎用性の高いデー タセット になっています。 TexAIntelligence TexAIntelligenceは、私が所属しているAIトランスフォーメーションセンターで開発している、文章分析のためのアプリケーションになります。 AIに知見がない人でも高度なAI技術を使いこなせるというコンセプトのもと開発を進めていて、webの画面をポチポチ操作するだけで、AIモデルを構築し利用できます。 使用できる アルゴリズム はTF-IDFと日本語の文章認識に特化したBERTモデルであるISID-BERTの2つです。 ISID-BERTを利用する場合、予め学習により日本語の認識精度を高めた状態のモデルをユーザーが用意したデー タセット で転移学習(ファインチューニング)させ、目的のタスクを実行するAIモデルを構築することになります。 今回の場合では、WRIMEデー タセット を予めアップロードしておき、デー タセット に含まれる感情に関するラベルをISID-BERTに学習させることで、TexAIntelligence上で感情分析を実施していきます。 感情分析をやってみる 新人研修の一環として今年度の新入社員向けに、 NLP と社内製品であるTexAIntelligenceを紹介することになり、ISID-BERTを使うメリットがわかりやすく説明できる題材を探していました。 あまりにも簡単だと、高度な深層学習を行うISID-BERTを利用する意味が伝わらないので、単語レベルではなく文脈を理解しないと正解できないタスクに挑戦する必要があり、感情分析がベストだと思いました。 さらに、新入社員の人も自分でTexAIntelligenceを使いたくなるような汎用的な ユースケース にしたかったので、 文章が肯定的なものか、否定的なものか、中立的なものか判断するタスクを実施します。 セミ ナーやイベントで集めたアンケート回答の自由記述欄が肯定的な意見なのか、否定的な意見なのか分類したいというニーズは社内でもありますし、お客様向けに開発しているシステムにも取り入れやすい機能だと思います。 ## データ準備 WRIMEデー タセット には肯定的か否定的かのラベルが5段階(肯定強、肯定弱、中立、否定弱、否定強)でついていますが、そのまま5段階での分析をAIモデルにさせると、かなり肯定的な文章とちょっと肯定的な文章の区別をAIにさせることになり、タスクの難易度が上がってしまいます。 人がこれらのタスクをやる場合でも、肯定しているのか、否定しているのかの判断は容易にできますが、どのくらい肯定しているのか、否定しているのか判断は難しいですよね・・・。WRIMEデー タセット 上でも3人の読みての判断が一致していないことが多々あります。 なので、タスクをよりシンプルにするように、肯定強、肯定弱は同じ肯定的に、否定弱、否定強は同じ否定的にまとめて、肯定、中立、否定の3段階にラベルを作成しておきました。 また、WRIMEデー タセット には書き手と読み手の合わせて4人分の文章の評価が記録されていましたが、読み手の3人の評価を平均したものをISID-BERTに予測させるラベルとしました。 学習データのアップロード ここからはTexAIntelligenceの画面上で操作を行います。 学習データ数は10,000件で実施しました(実際はそのうち2割が評価用になるので8000件が学習データになります)。デー タセット にはそれ以上のデータが収録されていますが、学習時間の都合上1万件としました。 学習実施 GUI の画面上の操作について軽く説明します。ただし、この記事は製品紹介ではありませんので詳細な操作方法については割愛しています。 学習の設定としてやることは、文章に対応する行と、AIに判定させたい感情を表すラベルを指定するだけです。細かい学習パラメータを設定することも可能ですが、今回は特にこちらからパラメータを指定しませんでした。 BERTの学習が走る VM によってかかる時間は変わりますが、この時利用した環境(K80搭載)では10,000件の学習を約2時間で完了しました。 もうちょいマシな GPU (例えばT4やV100、RTX3080 tiやRTX 3090)を積んだ環境を利用すればもっと早く学習が終わると思います。 学習結果 64%正解という微妙な結果になってしまいましたが、今回は肯定的、中立的、否定的と3段階のラベル付けを行っており、肯定的を否定的に、もしくは否定的を肯定的に間違えた件数は2000件中、68件だったのでそれほど多くありませんでした。 学習データを工夫すればもうちょっと精度をあげられるかもしれませんね。 例えば、学習データに含まれる肯定的、中立的、否定的の割合を調整するとか、評価者によって判断が分かれているデータを除外するなど、やりようはいくらでもあると思いますが、今回はあくまでお試しなのでこれで良しとします。 また、アンケート分析という ユースケース での利用を検証するために、自分で一文一文作成したアンケート回答の自由記述のサンプルデータを使ってモデルをテストしてみました。 結果は83%正解。まずまずの結果だと思います。アンケートのサンプルデータは30回答分しかないので明らかにデータ数が足りませんが、試した結果だけ見ると自由記述のサンプルデータの方が精度が高いようですね。 理由は単純にアンケートの自由回答よりも、WRIMEデー タセット の SNS の投稿文のほうが、感情を分析するのが難しいからでしょうか。 SNS の文章は前後の投稿の関係性や投稿された時節、投稿者の気分によって言葉のニュアンスが変化してしまいます。 ちなみに、書き手ではなく読み手の評価をラベルとして採用したのもこれが理由で、投稿者の評価をラベルにしてしまうと完全に同じ文章なのにラベルが違うってことが増えてしまうんですよね。 ここら辺の話は梶原先生の こちらの論文 で考察されているので気になる方は読んでみてください。 アンケートの自由記述は他人に読まれることを前提に書かれた文章なので、その文章単体で読み手が意味を理解できるように必要な情報は全て盛り込まれているはずです(そうじゃないこともありますが・・・)。なので、AIが文章のみから肯定的か否定的かを判断するのは比較的に簡単だったんだと思います。 以下はアンケートのサンプルデータの文章と正解ラベル、予測ラベルの一部になります。 文章 正解ラベル AIが予測したラベル UIが素晴らしいと思う。直感的に操作できるので操作方法を調べなくても利用できる positive positive 直近で大量のアンケートを集計する必要があり、このソフトを用いたことろ効率的にアンケート集計ができた。便利だったので今後も利用したい。 positive positive 日本語の認識精度が高くて驚いた positive negative 最高! positive positive ぜひ継続して利用したい positive positive 他の製品と違いはないと感じた neutral neutral 価格は普通だと感じた。 neutral neutral 月に3回ほど利用した。費用頻度はそれほどでもないと思う。 neutral neutral AIについて今後勉強したいと思う neutral positive ノーコメント neutral neutral 競合のA社も利用しているのでしょうか neutral neutral 利用していない neutral negative 特になし neutral neutral 利用方法が理解できなかった。もっとマニュアルを整理しないと活用できないと思う negative negative 精度が低い、使いものにならない negative negative 機能に対して利用料金が高すぎると思う。また、 クラウド に文章データを送るのでセキュリティも不安に思っている negative negative 導入する意味はない negative neutral UIがわかりにくい。使っているとイライラする。 negative negative ちょっと考察 唯一、肯定的を否定的と間違えたのは下の文章でした(否定を肯定に間違えることはありませんでした)。 日本語の認識精度が高くて驚いた この文章は肯定的な文章ですが、認識精度が高いことが良いことなのか悪いことなのか判断できないと、文章全体が肯定なのか、否定なのか判断できないですよね。ちなみに、学習データの中には「認識精度」という言葉は含まれてなく、「精度」という言葉も2回しか出てきません。 上の図はTexAIntelligenceに搭載されている SHAP (AIの判断根拠を可視化する技術)によって単語別の否定の判断の寄与度を表したものです。「高くて驚いた」の部分が否定の判断根拠になっています。例えば価格が高い場合この文章は否定的なものになりますよね。 肯定的と中立的、もしくは中立的と否定的の区別で他にも間違えはありましたが、共通して言えることは文章が短いと間違いやすいということです SNS の文章は短いと書き手のメタな情報を理解していないと意味がわかりづらくなるので、AIがその文章だけで正解のラベルを判断するのは難しいのだと思います。 逆に長い文章ならば、主張の背景的な情報も投稿に含まれるようになるため、AIが文章から感情を推測することも可能になります。 例えば、「ヤバかった!」と一言だけの文章では、ポジティブなヤバいなのか、ネガティブなヤバいなのかわかりませんが、もしこの投稿に文章をたして、 「一昨日ライブで披露された新曲がマジでヤバかった!」 となっていれば、AIはライブでの出来事だったことや、新曲に対する意見ということでヤバいが肯定的な評価だと推測できるわけです。 ただ、これは SNS に限った話で、一般的にビジネス文章に関しては文章が短いと精度が上がると言われていいます。 それは、ビジネス文章は読み手に正しく伝えたいことを理解してもらうことが目的に書かれるため、メタな情報も含め判断の根拠となる情報は全て文中で述べられることが多く、推測に必要な情報が不足しにくいからです。 逆に、文章が長いと主張とは関係ない補足情報が増えていくため、文に含まれる単語数が増えるほどAIは文脈の流れを見誤る可能性が増えます。サンプルのアンケート文章はどちらの特性が強いかというと、ビジネス文章に近いと言えます。 個人的にはアンケートの回答と趣が違う SNS の文章を学習して、ここまで精度が出たのが驚きですが、 SNS の文章のほうがより多くのジャンルや概念を含んでおり汎用的だったということだと思います。 すこし実験 日本語の認識精度が高くて驚いた 先程、これを間違えて否定的と捉えたのは「〇〇が高い」だけでは肯定か否定か判断できず、「認識精度が高い」 という組み合わせが学習データになかったので正しい判断ができなかったと書きました。 それなら、同じような文章を学習データに仕込んでおけば正解できるはずです。そして、TexAIntelligenceに搭載しているISID-BERTは日本語の コーパス を学習させているので、完全に同じ言葉ではなくても似た意味を持つ単語が含まれていれば文脈の意味を理解できます。 ということで、文章:「予測の正確性が高水準になっている」ラベル:肯定的というデータを学習データに追加しました。 これで、間違えてしまった「日本語の認識精度が高くて驚いた」も正しく文意を捉えられるはずです。 結果は・・・ 素晴らしいですね。スッキリしました。これで今日もよく眠れそうです。 まとめ WRIMEデー タセット はめっちゃ イカ したデー タセット でした。 今回はサクッと使わせていただきましたが、それだけでも十分な結果が得られました。 豊富なデータ数と複数のラベルが存在しているので他にもいろんな応用の仕方ができると思います。 研究目的で作成されたデー タセット ということでビジネス利用は難しいかもしれませんが、 NLP 技術の研究にはかなり有効なデー タセット ですね。 これだけのデー タセット を作成するのはとても大変だったかと思います。構築に関わった方々に感謝です。 それでは。 執筆: @tokuhara.hikaru 、レビュー: @sato.taichi ( Shodo で執筆されました )
お疲れさまです。XI本部、 AIトランスフォーメーションセンター の徳原 光です。 この記事で2回目の投稿になります。今回は所属センターで開発しているAI製品、 TexAIntelligence を使用して、 SNS での投稿に感情ラベルを付与したデー タセット である WRIMEデータセット ver.2をAIモデルに学習させた結果をまとめたいと思います。 感情分析とは? 感情分析は NLP 、 自然言語処理 の一手法で文章に込められた感情をAIによって検出する技術です。 例えば、「お風呂の水漏れが治らない・・・。今月でもう3度目だよ」という文章には「悲しみ」が込められていますよね(もしかしたら「怒り」もあるかも)。 「〇〇大学に合格できた!春からはれて大学生だ!!」という文章だったら「喜び」でしょうか? もし、「〇〇大学に合格できた!春からはれて大学生だ!!嬉しいなぁ」というように「嬉しい」とか、「やったー」という言葉が含まれていれば、ルールベースによる手法や従来の 機械学習 の手法で文章が意味する感情を判別することが可能です。 しかし、そのような感情を表す言葉が含まれていない場合、文章の文脈を理解する必要があるので、感情分析は NLP のタスクの中でも難しい課題と言えます。 WRIME 主観と客観の感情分析デー タセット こちらのデー タセット は 愛媛大学 の 梶尾先生 が作成されたデー タセット です。 BERTの学習用のデー タセット として作成されたので、 機械学習 で使用するデー タセット としては非常に使い勝手がいいデー タセット になります。 ver1では43,200件、ver2では35,000件の SNS から収集した文章データに基本8感情(喜び、悲しみ、期待、驚き、怒り、恐れ、嫌悪、信頼)の感情極性が書き手と3人の読み手ごとに4段階(0:無、1:弱、2:中、3:強)でラベル付けされています。 さらに、ver2では肯定的か否定的かのラベルも5段階で付いていて、今回はそれを利用しました。 NLP の世界では、いつの世でも学習データが不足してしまうものですが、数万件の文章データがあるのでデータ数で困ることはありません。しかも、一つの文章に複数のラベルが付けられているので、ア イデア しだいでいろいろな応用ができます。 また、ver1では80人、ver2では60人の書き手から文章を収集しているのでいろいろな文体の文章が収録されており、さらに SNS の特性上、内容のジャンルは様々なので非常に汎用性の高いデー タセット になっています。 TexAIntelligence TexAIntelligenceは、私が所属しているAIトランスフォーメーションセンターで開発している、文章分析のためのアプリケーションになります。 AIに知見がない人でも高度なAI技術を使いこなせるというコンセプトのもと開発を進めていて、webの画面をポチポチ操作するだけで、AIモデルを構築し利用できます。 使用できる アルゴリズム はTF-IDFと日本語の文章認識に特化したBERTモデルであるISID-BERTの2つです。 ISID-BERTを利用する場合、予め学習により日本語の認識精度を高めた状態のモデルをユーザーが用意したデー タセット で転移学習(ファインチューニング)させ、目的のタスクを実行するAIモデルを構築することになります。 今回の場合では、WRIMEデー タセット を予めアップロードしておき、デー タセット に含まれる感情に関するラベルをISID-BERTに学習させることで、TexAIntelligence上で感情分析を実施していきます。 感情分析をやってみる 新人研修の一環として今年度の新入社員向けに、 NLP と社内製品であるTexAIntelligenceを紹介することになり、ISID-BERTを使うメリットがわかりやすく説明できる題材を探していました。 あまりにも簡単だと、高度な深層学習を行うISID-BERTを利用する意味が伝わらないので、単語レベルではなく文脈を理解しないと正解できないタスクに挑戦する必要があり、感情分析がベストだと思いました。 さらに、新入社員の人も自分でTexAIntelligenceを使いたくなるような汎用的な ユースケース にしたかったので、 文章が肯定的なものか、否定的なものか、中立的なものか判断するタスクを実施します。 セミ ナーやイベントで集めたアンケート回答の自由記述欄が肯定的な意見なのか、否定的な意見なのか分類したいというニーズは社内でもありますし、お客様向けに開発しているシステムにも取り入れやすい機能だと思います。 ## データ準備 WRIMEデー タセット には肯定的か否定的かのラベルが5段階(肯定強、肯定弱、中立、否定弱、否定強)でついていますが、そのまま5段階での分析をAIモデルにさせると、かなり肯定的な文章とちょっと肯定的な文章の区別をAIにさせることになり、タスクの難易度が上がってしまいます。 人がこれらのタスクをやる場合でも、肯定しているのか、否定しているのかの判断は容易にできますが、どのくらい肯定しているのか、否定しているのか判断は難しいですよね・・・。WRIMEデー タセット 上でも3人の読みての判断が一致していないことが多々あります。 なので、タスクをよりシンプルにするように、肯定強、肯定弱は同じ肯定的に、否定弱、否定強は同じ否定的にまとめて、肯定、中立、否定の3段階にラベルを作成しておきました。 また、WRIMEデー タセット には書き手と読み手の合わせて4人分の文章の評価が記録されていましたが、読み手の3人の評価を平均したものをISID-BERTに予測させるラベルとしました。 学習データのアップロード ここからはTexAIntelligenceの画面上で操作を行います。 学習データ数は10,000件で実施しました(実際はそのうち2割が評価用になるので8000件が学習データになります)。デー タセット にはそれ以上のデータが収録されていますが、学習時間の都合上1万件としました。 学習実施 GUI の画面上の操作について軽く説明します。ただし、この記事は製品紹介ではありませんので詳細な操作方法については割愛しています。 学習の設定としてやることは、文章に対応する行と、AIに判定させたい感情を表すラベルを指定するだけです。細かい学習パラメータを設定することも可能ですが、今回は特にこちらからパラメータを指定しませんでした。 BERTの学習が走る VM によってかかる時間は変わりますが、この時利用した環境(K80搭載)では10,000件の学習を約2時間で完了しました。 もうちょいマシな GPU (例えばT4やV100、RTX3080 tiやRTX 3090)を積んだ環境を利用すればもっと早く学習が終わると思います。 学習結果 64%正解という微妙な結果になってしまいましたが、今回は肯定的、中立的、否定的と3段階のラベル付けを行っており、肯定的を否定的に、もしくは否定的を肯定的に間違えた件数は2000件中、68件だったのでそれほど多くありませんでした。 学習データを工夫すればもうちょっと精度をあげられるかもしれませんね。 例えば、学習データに含まれる肯定的、中立的、否定的の割合を調整するとか、評価者によって判断が分かれているデータを除外するなど、やりようはいくらでもあると思いますが、今回はあくまでお試しなのでこれで良しとします。 また、アンケート分析という ユースケース での利用を検証するために、自分で一文一文作成したアンケート回答の自由記述のサンプルデータを使ってモデルをテストしてみました。 結果は83%正解。まずまずの結果だと思います。アンケートのサンプルデータは30回答分しかないので明らかにデータ数が足りませんが、試した結果だけ見ると自由記述のサンプルデータの方が精度が高いようですね。 理由は単純にアンケートの自由回答よりも、WRIMEデー タセット の SNS の投稿文のほうが、感情を分析するのが難しいからでしょうか。 SNS の文章は前後の投稿の関係性や投稿された時節、投稿者の気分によって言葉のニュアンスが変化してしまいます。 ちなみに、書き手ではなく読み手の評価をラベルとして採用したのもこれが理由で、投稿者の評価をラベルにしてしまうと完全に同じ文章なのにラベルが違うってことが増えてしまうんですよね。 ここら辺の話は梶原先生の こちらの論文 で考察されているので気になる方は読んでみてください。 アンケートの自由記述は他人に読まれることを前提に書かれた文章なので、その文章単体で読み手が意味を理解できるように必要な情報は全て盛り込まれているはずです(そうじゃないこともありますが・・・)。なので、AIが文章のみから肯定的か否定的かを判断するのは比較的に簡単だったんだと思います。 以下はアンケートのサンプルデータの文章と正解ラベル、予測ラベルの一部になります。 文章 正解ラベル AIが予測したラベル UIが素晴らしいと思う。直感的に操作できるので操作方法を調べなくても利用できる positive positive 直近で大量のアンケートを集計する必要があり、このソフトを用いたことろ効率的にアンケート集計ができた。便利だったので今後も利用したい。 positive positive 日本語の認識精度が高くて驚いた positive negative 最高! positive positive ぜひ継続して利用したい positive positive 他の製品と違いはないと感じた neutral neutral 価格は普通だと感じた。 neutral neutral 月に3回ほど利用した。費用頻度はそれほどでもないと思う。 neutral neutral AIについて今後勉強したいと思う neutral positive ノーコメント neutral neutral 競合のA社も利用しているのでしょうか neutral neutral 利用していない neutral negative 特になし neutral neutral 利用方法が理解できなかった。もっとマニュアルを整理しないと活用できないと思う negative negative 精度が低い、使いものにならない negative negative 機能に対して利用料金が高すぎると思う。また、 クラウド に文章データを送るのでセキュリティも不安に思っている negative negative 導入する意味はない negative neutral UIがわかりにくい。使っているとイライラする。 negative negative ちょっと考察 唯一、肯定的を否定的と間違えたのは下の文章でした(否定を肯定に間違えることはありませんでした)。 日本語の認識精度が高くて驚いた この文章は肯定的な文章ですが、認識精度が高いことが良いことなのか悪いことなのか判断できないと、文章全体が肯定なのか、否定なのか判断できないですよね。ちなみに、学習データの中には「認識精度」という言葉は含まれてなく、「精度」という言葉も2回しか出てきません。 上の図はTexAIntelligenceに搭載されている SHAP (AIの判断根拠を可視化する技術)によって単語別の否定の判断の寄与度を表したものです。「高くて驚いた」の部分が否定の判断根拠になっています。例えば価格が高い場合この文章は否定的なものになりますよね。 肯定的と中立的、もしくは中立的と否定的の区別で他にも間違えはありましたが、共通して言えることは文章が短いと間違いやすいということです SNS の文章は短いと書き手のメタな情報を理解していないと意味がわかりづらくなるので、AIがその文章だけで正解のラベルを判断するのは難しいのだと思います。 逆に長い文章ならば、主張の背景的な情報も投稿に含まれるようになるため、AIが文章から感情を推測することも可能になります。 例えば、「ヤバかった!」と一言だけの文章では、ポジティブなヤバいなのか、ネガティブなヤバいなのかわかりませんが、もしこの投稿に文章をたして、 「一昨日ライブで披露された新曲がマジでヤバかった!」 となっていれば、AIはライブでの出来事だったことや、新曲に対する意見ということでヤバいが肯定的な評価だと推測できるわけです。 ただ、これは SNS に限った話で、一般的にビジネス文章に関しては文章が短いと精度が上がると言われていいます。 それは、ビジネス文章は読み手に正しく伝えたいことを理解してもらうことが目的に書かれるため、メタな情報も含め判断の根拠となる情報は全て文中で述べられることが多く、推測に必要な情報が不足しにくいからです。 逆に、文章が長いと主張とは関係ない補足情報が増えていくため、文に含まれる単語数が増えるほどAIは文脈の流れを見誤る可能性が増えます。サンプルのアンケート文章はどちらの特性が強いかというと、ビジネス文章に近いと言えます。 個人的にはアンケートの回答と趣が違う SNS の文章を学習して、ここまで精度が出たのが驚きですが、 SNS の文章のほうがより多くのジャンルや概念を含んでおり汎用的だったということだと思います。 すこし実験 日本語の認識精度が高くて驚いた 先程、これを間違えて否定的と捉えたのは「〇〇が高い」だけでは肯定か否定か判断できず、「認識精度が高い」 という組み合わせが学習データになかったので正しい判断ができなかったと書きました。 それなら、同じような文章を学習データに仕込んでおけば正解できるはずです。そして、TexAIntelligenceに搭載しているISID-BERTは日本語の コーパス を学習させているので、完全に同じ言葉ではなくても似た意味を持つ単語が含まれていれば文脈の意味を理解できます。 ということで、文章:「予測の正確性が高水準になっている」ラベル:肯定的というデータを学習データに追加しました。 これで、間違えてしまった「日本語の認識精度が高くて驚いた」も正しく文意を捉えられるはずです。 結果は・・・ 素晴らしいですね。スッキリしました。これで今日もよく眠れそうです。 まとめ WRIMEデー タセット はめっちゃ イカ したデー タセット でした。 今回はサクッと使わせていただきましたが、それだけでも十分な結果が得られました。 豊富なデータ数と複数のラベルが存在しているので他にもいろんな応用の仕方ができると思います。 研究目的で作成されたデー タセット ということでビジネス利用は難しいかもしれませんが、 NLP 技術の研究にはかなり有効なデー タセット ですね。 これだけのデー タセット を作成するのはとても大変だったかと思います。構築に関わった方々に感謝です。 それでは。 執筆: @tokuhara.hikaru 、レビュー: @sato.taichi ( Shodo で執筆されました )
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。 CDKで Amazon Aurora データベース クラスタ を作成し、Secrets Managerで管理しているパスワードをローテーションしてみました。 ローテーションはSecrets Managerのマネジメントコンソールからでも設定できますが、CDKでも非常に簡単に書けました。やり方は 公式ドキュメント には書かれているものの、日本語の情報があまり見当たらなかったため書き残しておきます。 ※この記事のサンプルコードではAurora Serverlessを作成していますが、プロビジョンド版でも同じ方法でパスワードローテーションを実現できます。 公式ドキュメント マスターユーザーのローテーション(シングルユーザーローテーション) Secrets Managerにアクセスできない場合のエラー シングルユーザーローテーションで作成されたリソースを見てみる ローテーションを実行するLambda関数 Lambda関数のセキュリティグループ Lambda関数の実行ロール シングルユーザーローテーションのオプション マスターユーザー以外のユーザーのパスワードローテーション(マルチユーザーローテーション/交代ユーザーローテーション) マルチユーザーローテーションで作成されたリソース マルチユーザーローテーションのオプション まとめ 公式ドキュメント CDKの aws_rds モジュールの Rotating credentials セクションにクレデンシャルのローテーションに関する記載があり、これを参考にしました。 https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_rds-readme.html#rotating-credentials マスターユーザーのローテーション(シングルユーザーローテーション) 以下のCDKコードでリソースを作成します。 import { Stack , StackProps } from "aws-cdk-lib" ; import * as ec2 from "aws-cdk-lib/aws-ec2" ; import * as rds from "aws-cdk-lib/aws-rds" ; import { Construct } from "constructs" ; export class MyStack extends Stack { constructor( scope: Construct , id: string , props?: StackProps ) { super( scope , id , props ); // プライベートサブネットを持つVPC const vpc = new ec2.Vpc ( this , "MyVpc" , { cidr: "10.0.0.0/16" , enableDnsHostnames: true , enableDnsSupport: true , subnetConfiguration: [ { name: "myPrivateSubnet" , subnetType: ec2.SubnetType.PRIVATE_ISOLATED , cidrMask: 20 , } , ] , } ); // VPCエンドポイント用セキュリティグループ const VpceSG = new ec2.SecurityGroup ( this , "MyVpceSg" , { vpc: vpc , allowAllOutbound: true , } ); // Secrets ManagerへのVPCエンドポイント vpc.addInterfaceEndpoint ( "SecretsManagerEndpoint" , { service: ec2.InterfaceVpcEndpointAwsService.SECRETS_MANAGER , subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED } , securityGroups: [ VpceSG ] , privateDnsEnabled: true , } ); // Aurora Serverlessクラスタ const auroraCluster = new rds.ServerlessCluster ( this , "MyAuroraCluster" , { engine: rds.DatabaseClusterEngine.AURORA_MYSQL , vpc: vpc , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED } , } ); // パスワードのローテーションを設定 auroraCluster.addRotationSingleUser (); } } Aurora Serverless クラスタ を以上のサンプルコードで作成すると、マスターユーザーの情報はSecrets Managerに保存されます。 マスターユーザーのパスワードをローテーション設定しているのは次の一行のみです。これだけでローテーションが有効化され、ローテーションを実行するLambda関数などのリソースが作成されます。非常に簡単ですね。 auroraCluster.addRotationSingleUser (); マネジメントコンソールでSecrets Managerのシークレットを確認すると、確かにローテーションが有効になっていることがわかります。 addRotationSingleUser() 関数で有効になるローテーションは 「シングルユーザーローテーション」 と呼ばれ、ユーザーのパスワードをそのまま更新するだけの単純なローテーションです。 Secrets Managerにアクセスできない場合のエラー デフォルトでは、ローテーションを実行するLambda関数はデータベース クラスタ と同じサブネットにデプロイされます。 Lambda関数がSecrets Managerにアクセスできるようにする必要があり、今回はそのための VPC エンドポイントを作成しています。 Lambda関数がSecrets Managerにアクセスできない場合、マネジメントコンソールから手動でローテーションを実行すると以下のエラーが表示されます。 シークレット「MyAuroraClusterSecretD92700-ozDfy6jZIGiv」をローテーションできませんでした。 A previous rotation isn't complete. That rotation will be reattempted. また、Lambda関数のCloudWatch Logsロググループには次のように タイムアウト が記録されます。 START RequestId: 3031c3a5-9624-49ed-994e-db8f0cb14d63 Version: $LATEST END RequestId: 3031c3a5-9624-49ed-994e-db8f0cb14d63 REPORT RequestId: 3031c3a5-9624-49ed-994e-db8f0cb14d63 Duration: 30035.14 ms Billed Duration: 30000 ms Memory Size: 128 MB Max Memory Used: 70 MB 2022-05-24T04:28:30.600Z 3031c3a5-9624-49ed-994e-db8f0cb14d63 Task timed out after 30.04 seconds シングルユーザーローテーションで作成されたリソースを見てみる auroraCluster.addRotationSingleUser (); この一行でどのようなリソースが作成されているのか見てみました。 ローテーションを実行するLambda関数 まず、 MyStackMyAuroraClusterRotationSingleUser~ という名前でLambda関数が作成されていました。 このLambda関数はデータベース クラスタ と同じサブネットに配置されています。 Lambda関数のセキュリティグループ Lambda関数のセキュリティグループも新規に作成されていました。インバウンドルールはなく、アウトバウンドルールは全ての通信を許可しています。 また、データベース クラスタ のセキュリティグループは、Lambda関数のセキュリティグループから3306ポートのインバウンド通信が許可されていました。 Lambda関数の実行ロール Lambda関数の実行ロールが作成され、4つのポリシーが付けられていました。 AWSLambdaBasicExecutionRole( AWS 管理) AWSLambdaVPCAccessExecutionRole( AWS 管理) SecretsManagerRDSMySQLRotationSingleUserRolePolicy0(カスタマーインライン) SecretsManagerRDSMySQLRotationSingleUserRolePolicy1(カスタマーインライン) インラインポリシー SecretsManagerRDSMySQLRotationSingleUserRolePolicy0 は次のようになっていました。(ネットワークインターフェースの操作を許可しているのですが、なぜここで必要なのか分かりません) { " Statement ": [ { " Action ": [ " ec2:CreateNetworkInterface ", " ec2:DeleteNetworkInterface ", " ec2:DescribeNetworkInterfaces ", " ec2:DetachNetworkInterface " ] , " Resource ": " * ", " Effect ": " Allow " } ] } インラインポリシー SecretsManagerRDSMySQLRotationSingleUserRolePolicy1 は次のようになっていました。Lambda関数からSecrets Managerへのアクセスを許可しています。 Resourceは該当リージョンの全てのSecrets Managerシークレットを指しており、広めの許可です。 { " Statement ": [ { " Condition ": { " StringEquals ": { " secretsmanager:resource/AllowRotationLambdaArn ": " arn:aws:lambda:ap-northeast-1:<アカウントID>:function:MyStackMyAuroraClusterRotationSingleUser4A86DF55 " } } , " Action ": [ " secretsmanager:DescribeSecret ", " secretsmanager:GetSecretValue ", " secretsmanager:PutSecretValue ", " secretsmanager:UpdateSecretVersionStage " ] , " Resource ": " arn:aws:secretsmanager:ap-northeast-1:<アカウントID>:secret:* ", " Effect ": " Allow " } , { " Action ": [ " secretsmanager:GetRandomPassword " ] , " Resource ": " * ", " Effect ": " Allow " } ] } 全体の構成は次の図のようになっています。 シングルユーザーローテーションのオプション auroraCluster.addRotationSingleUser (); シングルユーザーローテーションはこの一行で書けますが、いくつかオプションを渡すこともできます。 import { Duration } from "aws-cdk-lib" ; auroraCluster.addRotationSingleUser ( { automaticallyAfter: Duration.days ( 30 ), excludeCharacters: " %+~`#$&*()|[]{}:;<>?!'/@\"\\" , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED } , endpoint: endpoint , securityGroup: securityGroup , // 2022/12/9追記:CDK v2.54.0〜 } ); automaticallyAfter : ローテーション間隔(デフォルトは30日) excludeCharacters : パスワードから除外する文字。デフォルトは「 %+~`#$&*()|[]{}:;<>?!'/@\"\」 vpcSubnets : ローテーション用Lambda関数を配置する VPC サブネット(デフォルトはデータベース クラスタ と同じサブネット) endpoint : ローテーション用Lambda関数がSecrets Managerにアクセスするために使う VPC エンドポイント。プライベート DNS が VPC で有効なら特に指定不要 securityGroup : (2022/12/9追記:CDK v2.54.0〜)ローテーション用Lambda関数のセキュリティグループ。指定しない場合は新規に作成される。指定することにより、Secrets Managerにアクセスするために使う VPC エンドポイントのアクセス元を、このセキュリティグループに限定しやすくなる マスターユーザー以外のユーザーのパスワードローテーション(マルチユーザーローテーション/交代ユーザーローテーション) アプリケーションからデータベースにアクセスするときはマスターユーザーではなく、権限を制限したユーザーを使うのが望ましいです。 addRotationSingleUser() 関数はマスターユーザーのローテーションのみを行うため、マスターユーザー以外のユーザーのパスワードをローテーションする場合、少し書き方が異なります。 // 「user」というユーザー名でパスワードを自動生成する const userSecret = new rds.DatabaseSecret ( this , "MyUserSecret" , { username: "user" , secretName: "MyAuroraClusterUserSecret" , masterSecret: auroraCluster.secret , } ); // データベースの接続情報を追加する const secretAttached = userSecret.attach ( auroraCluster ); // ローテーションを設定 auroraCluster.addRotationMultiUser ( "MyUserRotation" , { secret: secretAttached , } ); ローテーションには addRotationMultiUser() 関数を使います。これは 「マルチユーザーローテーション」もしくは「交代ユーザーローテーション」 と呼ばれるローテーション方法です。 ローテーション実行時はユーザーのパスワードをすぐに上書きするのではなく、元のユーザーと同じ権限を持つユーザーを新たにデータベースに作成します。同時に2つのユーザーが有効になるため、データベースにアクセスするアプリケーションがクレデンシャル情報をキャッシュしている場合でも、ローテーションによって急に接続できなくなる事態を回避できます。そして2回目以降のローテーションでは新規にユーザーは作成せず、2つ前のユーザーのパスワード情報を上書きすることで、古いパスワードを利用できなくします。 マルチユーザーローテーションを行うには、ユーザーをクローンする権限が必要であるため、マスターユーザーのシークレットを渡しています。 masterSecret: auroraCluster.secret , 以上はあくまでもシークレットの作成とローテーションの設定であり、 別途データベースに接続し、同じユーザー名でユーザーを作成する必要があります。作成するユーザーにはSecrets Managerに登録された自動生成パスワードを設定します。 1度ローテーションを実行した後のデータベースユーザー一覧を見ると、 user という名前のユーザーに加え、 user_clone という名前のユーザーも存在することがわかります。これ以降、 user と user_clone のパスワードが交互に変更されていきます。 マルチユーザーローテーションで作成されたリソース マルチユーザーローテーションを設定すると、シングルユーザーローテーションと同じく以下のリソースが作成されます ローテーション用Lambda関数 Lambda関数のセキュリティグループ Lambda関数の実行ロール Lambda関数の実行ロールは、シングルユーザーローテーションの時と若干異なり、以下のポリシーが付いていました。 AmazonRDSReadOnlyAccess ( AWS 管理) AWSLambdaBasicExecutionRole( AWS 管理) AWSLambdaVPCAccessExecutionRole( AWS 管理) SecretsManagerRDSMySQLRotationMultiUserRolePolicy1(カスタマーインライン) SecretsManagerRDSMySQLRotationMultiUserRolePolicy2(カスタマーインライン) SecretsManagerRDSMySQLRotationMultiUserRolePolicy3 (カスタマーインライン) インラインポリシー SecretsManagerRDSMySQLRotationMultiUserRolePolicy1 と SecretsManagerRDSMySQLRotationMultiUserRolePolicy2 は、シングルユーザーローテーションの時のインラインポリシーと同じ内容でした。 インラインポリシー SecretsManagerRDSMySQLRotationMultiUserRolePolicy3 はシングルユーザーローテーションにはなかったポリシーで、マスターユーザーのシークレットへのアクセスを許可しています。( ~UserRolePolicy2 で該当リージョンの全シークレットへの GetSecretValue を既に許可しているため、冗長であるように思えます) { " Statement ": [ { " Action ": [ " secretsmanager:GetSecretValue " ] , " Resource ": " arn:aws:secretsmanager:ap-northeast-1:<アカウントID>:secret:MyAuroraClusterSecretD92700-ozDfy6jZIGiv-iVeG0u ", " Effect ": " Allow " } ] } マルチユーザーローテーションのオプション マルチユーザーローテーションではパラメーター secret にローテーション対象のアタッチ済みシークレットを指定する必要があります。 auroraCluster.addRotationMultiUser ( "MyUserRotation" , { secret: secretAttached , } ); その他のオプションはシングルユーザーローテーションと同じものを指定できます。 automaticallyAfter excludeCharacters vpcSubnets endpoint securityGroup (2022/12/9追記:CDK v2.54.0〜) まとめ CDKでAurora クラスタ のパスワードをローテーションする設定を非常に簡単に書けました。マスターユーザーはシングルユーザーローテーション、それ以外のユーザーはマルチユーザーローテーションとなるのが個人的に面白かったです。 今回は試していませんが、 公式ドキュメント によるとAurora以外のRDSデータベースでも、同じような方法でパスワードのローテーションを実現できそうです。 執筆: @kou.kinyo2 、レビュー: @sato.taichi ( Shodo で執筆されました )
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。 CDKで Amazon Aurora データベース クラスタ を作成し、Secrets Managerで管理しているパスワードをローテーションしてみました。 ローテーションはSecrets Managerのマネジメントコンソールからでも設定できますが、CDKでも非常に簡単に書けました。やり方は 公式ドキュメント には書かれているものの、日本語の情報があまり見当たらなかったため書き残しておきます。 ※この記事のサンプルコードではAurora Serverlessを作成していますが、プロビジョンド版でも同じ方法でパスワードローテーションを実現できます。 公式ドキュメント マスターユーザーのローテーション(シングルユーザーローテーション) Secrets Managerにアクセスできない場合のエラー シングルユーザーローテーションで作成されたリソースを見てみる ローテーションを実行するLambda関数 Lambda関数のセキュリティグループ Lambda関数の実行ロール シングルユーザーローテーションのオプション マスターユーザー以外のユーザーのパスワードローテーション(マルチユーザーローテーション/交代ユーザーローテーション) マルチユーザーローテーションで作成されたリソース マルチユーザーローテーションのオプション まとめ 公式ドキュメント CDKの aws_rds モジュールの Rotating credentials セクションにクレデンシャルのローテーションに関する記載があり、これを参考にしました。 https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_rds-readme.html#rotating-credentials マスターユーザーのローテーション(シングルユーザーローテーション) 以下のCDKコードでリソースを作成します。 import { Stack , StackProps } from "aws-cdk-lib" ; import * as ec2 from "aws-cdk-lib/aws-ec2" ; import * as rds from "aws-cdk-lib/aws-rds" ; import { Construct } from "constructs" ; export class MyStack extends Stack { constructor( scope: Construct , id: string , props?: StackProps ) { super( scope , id , props ); // プライベートサブネットを持つVPC const vpc = new ec2.Vpc ( this , "MyVpc" , { cidr: "10.0.0.0/16" , enableDnsHostnames: true , enableDnsSupport: true , subnetConfiguration: [ { name: "myPrivateSubnet" , subnetType: ec2.SubnetType.PRIVATE_ISOLATED , cidrMask: 20 , } , ] , } ); // VPCエンドポイント用セキュリティグループ const VpceSG = new ec2.SecurityGroup ( this , "MyVpceSg" , { vpc: vpc , allowAllOutbound: true , } ); // Secrets ManagerへのVPCエンドポイント vpc.addInterfaceEndpoint ( "SecretsManagerEndpoint" , { service: ec2.InterfaceVpcEndpointAwsService.SECRETS_MANAGER , subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED } , securityGroups: [ VpceSG ] , privateDnsEnabled: true , } ); // Aurora Serverlessクラスタ const auroraCluster = new rds.ServerlessCluster ( this , "MyAuroraCluster" , { engine: rds.DatabaseClusterEngine.AURORA_MYSQL , vpc: vpc , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED } , } ); // パスワードのローテーションを設定 auroraCluster.addRotationSingleUser (); } } Aurora Serverless クラスタ を以上のサンプルコードで作成すると、マスターユーザーの情報はSecrets Managerに保存されます。 マスターユーザーのパスワードをローテーション設定しているのは次の一行のみです。これだけでローテーションが有効化され、ローテーションを実行するLambda関数などのリソースが作成されます。非常に簡単ですね。 auroraCluster.addRotationSingleUser (); マネジメントコンソールでSecrets Managerのシークレットを確認すると、確かにローテーションが有効になっていることがわかります。 addRotationSingleUser() 関数で有効になるローテーションは 「シングルユーザーローテーション」 と呼ばれ、ユーザーのパスワードをそのまま更新するだけの単純なローテーションです。 Secrets Managerにアクセスできない場合のエラー デフォルトでは、ローテーションを実行するLambda関数はデータベース クラスタ と同じサブネットにデプロイされます。 Lambda関数がSecrets Managerにアクセスできるようにする必要があり、今回はそのための VPC エンドポイントを作成しています。 Lambda関数がSecrets Managerにアクセスできない場合、マネジメントコンソールから手動でローテーションを実行すると以下のエラーが表示されます。 シークレット「MyAuroraClusterSecretD92700-ozDfy6jZIGiv」をローテーションできませんでした。 A previous rotation isn't complete. That rotation will be reattempted. また、Lambda関数のCloudWatch Logsロググループには次のように タイムアウト が記録されます。 START RequestId: 3031c3a5-9624-49ed-994e-db8f0cb14d63 Version: $LATEST END RequestId: 3031c3a5-9624-49ed-994e-db8f0cb14d63 REPORT RequestId: 3031c3a5-9624-49ed-994e-db8f0cb14d63 Duration: 30035.14 ms Billed Duration: 30000 ms Memory Size: 128 MB Max Memory Used: 70 MB 2022-05-24T04:28:30.600Z 3031c3a5-9624-49ed-994e-db8f0cb14d63 Task timed out after 30.04 seconds シングルユーザーローテーションで作成されたリソースを見てみる auroraCluster.addRotationSingleUser (); この一行でどのようなリソースが作成されているのか見てみました。 ローテーションを実行するLambda関数 まず、 MyStackMyAuroraClusterRotationSingleUser~ という名前でLambda関数が作成されていました。 このLambda関数はデータベース クラスタ と同じサブネットに配置されています。 Lambda関数のセキュリティグループ Lambda関数のセキュリティグループも新規に作成されていました。インバウンドルールはなく、アウトバウンドルールは全ての通信を許可しています。 また、データベース クラスタ のセキュリティグループは、Lambda関数のセキュリティグループから3306ポートのインバウンド通信が許可されていました。 Lambda関数の実行ロール Lambda関数の実行ロールが作成され、4つのポリシーが付けられていました。 AWSLambdaBasicExecutionRole( AWS 管理) AWSLambdaVPCAccessExecutionRole( AWS 管理) SecretsManagerRDSMySQLRotationSingleUserRolePolicy0(カスタマーインライン) SecretsManagerRDSMySQLRotationSingleUserRolePolicy1(カスタマーインライン) インラインポリシー SecretsManagerRDSMySQLRotationSingleUserRolePolicy0 は次のようになっていました。(ネットワークインターフェースの操作を許可しているのですが、なぜここで必要なのか分かりません) { " Statement ": [ { " Action ": [ " ec2:CreateNetworkInterface ", " ec2:DeleteNetworkInterface ", " ec2:DescribeNetworkInterfaces ", " ec2:DetachNetworkInterface " ] , " Resource ": " * ", " Effect ": " Allow " } ] } インラインポリシー SecretsManagerRDSMySQLRotationSingleUserRolePolicy1 は次のようになっていました。Lambda関数からSecrets Managerへのアクセスを許可しています。 Resourceは該当リージョンの全てのSecrets Managerシークレットを指しており、広めの許可です。 { " Statement ": [ { " Condition ": { " StringEquals ": { " secretsmanager:resource/AllowRotationLambdaArn ": " arn:aws:lambda:ap-northeast-1:<アカウントID>:function:MyStackMyAuroraClusterRotationSingleUser4A86DF55 " } } , " Action ": [ " secretsmanager:DescribeSecret ", " secretsmanager:GetSecretValue ", " secretsmanager:PutSecretValue ", " secretsmanager:UpdateSecretVersionStage " ] , " Resource ": " arn:aws:secretsmanager:ap-northeast-1:<アカウントID>:secret:* ", " Effect ": " Allow " } , { " Action ": [ " secretsmanager:GetRandomPassword " ] , " Resource ": " * ", " Effect ": " Allow " } ] } 全体の構成は次の図のようになっています。 シングルユーザーローテーションのオプション auroraCluster.addRotationSingleUser (); シングルユーザーローテーションはこの一行で書けますが、いくつかオプションを渡すこともできます。 import { Duration } from "aws-cdk-lib" ; auroraCluster.addRotationSingleUser ( { automaticallyAfter: Duration.days ( 30 ), excludeCharacters: " %+~`#$&*()|[]{}:;<>?!'/@\"\\" , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED } , endpoint: endpoint , securityGroup: securityGroup , // 2022/12/9追記:CDK v2.54.0〜 } ); automaticallyAfter : ローテーション間隔(デフォルトは30日) excludeCharacters : パスワードから除外する文字。デフォルトは「 %+~`#$&*()|[]{}:;<>?!'/@\"\」 vpcSubnets : ローテーション用Lambda関数を配置する VPC サブネット(デフォルトはデータベース クラスタ と同じサブネット) endpoint : ローテーション用Lambda関数がSecrets Managerにアクセスするために使う VPC エンドポイント。プライベート DNS が VPC で有効なら特に指定不要 securityGroup : (2022/12/9追記:CDK v2.54.0〜)ローテーション用Lambda関数のセキュリティグループ。指定しない場合は新規に作成される。指定することにより、Secrets Managerにアクセスするために使う VPC エンドポイントのアクセス元を、このセキュリティグループに限定しやすくなる マスターユーザー以外のユーザーのパスワードローテーション(マルチユーザーローテーション/交代ユーザーローテーション) アプリケーションからデータベースにアクセスするときはマスターユーザーではなく、権限を制限したユーザーを使うのが望ましいです。 addRotationSingleUser() 関数はマスターユーザーのローテーションのみを行うため、マスターユーザー以外のユーザーのパスワードをローテーションする場合、少し書き方が異なります。 // 「user」というユーザー名でパスワードを自動生成する const userSecret = new rds.DatabaseSecret ( this , "MyUserSecret" , { username: "user" , secretName: "MyAuroraClusterUserSecret" , masterSecret: auroraCluster.secret , } ); // データベースの接続情報を追加する const secretAttached = userSecret.attach ( auroraCluster ); // ローテーションを設定 auroraCluster.addRotationMultiUser ( "MyUserRotation" , { secret: secretAttached , } ); ローテーションには addRotationMultiUser() 関数を使います。これは 「マルチユーザーローテーション」もしくは「交代ユーザーローテーション」 と呼ばれるローテーション方法です。 ローテーション実行時はユーザーのパスワードをすぐに上書きするのではなく、元のユーザーと同じ権限を持つユーザーを新たにデータベースに作成します。同時に2つのユーザーが有効になるため、データベースにアクセスするアプリケーションがクレデンシャル情報をキャッシュしている場合でも、ローテーションによって急に接続できなくなる事態を回避できます。そして2回目以降のローテーションでは新規にユーザーは作成せず、2つ前のユーザーのパスワード情報を上書きすることで、古いパスワードを利用できなくします。 マルチユーザーローテーションを行うには、ユーザーをクローンする権限が必要であるため、マスターユーザーのシークレットを渡しています。 masterSecret: auroraCluster.secret , 以上はあくまでもシークレットの作成とローテーションの設定であり、 別途データベースに接続し、同じユーザー名でユーザーを作成する必要があります。作成するユーザーにはSecrets Managerに登録された自動生成パスワードを設定します。 1度ローテーションを実行した後のデータベースユーザー一覧を見ると、 user という名前のユーザーに加え、 user_clone という名前のユーザーも存在することがわかります。これ以降、 user と user_clone のパスワードが交互に変更されていきます。 マルチユーザーローテーションで作成されたリソース マルチユーザーローテーションを設定すると、シングルユーザーローテーションと同じく以下のリソースが作成されます ローテーション用Lambda関数 Lambda関数のセキュリティグループ Lambda関数の実行ロール Lambda関数の実行ロールは、シングルユーザーローテーションの時と若干異なり、以下のポリシーが付いていました。 AmazonRDSReadOnlyAccess ( AWS 管理) AWSLambdaBasicExecutionRole( AWS 管理) AWSLambdaVPCAccessExecutionRole( AWS 管理) SecretsManagerRDSMySQLRotationMultiUserRolePolicy1(カスタマーインライン) SecretsManagerRDSMySQLRotationMultiUserRolePolicy2(カスタマーインライン) SecretsManagerRDSMySQLRotationMultiUserRolePolicy3 (カスタマーインライン) インラインポリシー SecretsManagerRDSMySQLRotationMultiUserRolePolicy1 と SecretsManagerRDSMySQLRotationMultiUserRolePolicy2 は、シングルユーザーローテーションの時のインラインポリシーと同じ内容でした。 インラインポリシー SecretsManagerRDSMySQLRotationMultiUserRolePolicy3 はシングルユーザーローテーションにはなかったポリシーで、マスターユーザーのシークレットへのアクセスを許可しています。( ~UserRolePolicy2 で該当リージョンの全シークレットへの GetSecretValue を既に許可しているため、冗長であるように思えます) { " Statement ": [ { " Action ": [ " secretsmanager:GetSecretValue " ] , " Resource ": " arn:aws:secretsmanager:ap-northeast-1:<アカウントID>:secret:MyAuroraClusterSecretD92700-ozDfy6jZIGiv-iVeG0u ", " Effect ": " Allow " } ] } マルチユーザーローテーションのオプション マルチユーザーローテーションではパラメーター secret にローテーション対象のアタッチ済みシークレットを指定する必要があります。 auroraCluster.addRotationMultiUser ( "MyUserRotation" , { secret: secretAttached , } ); その他のオプションはシングルユーザーローテーションと同じものを指定できます。 automaticallyAfter excludeCharacters vpcSubnets endpoint securityGroup (2022/12/9追記:CDK v2.54.0〜) まとめ CDKでAurora クラスタ のパスワードをローテーションする設定を非常に簡単に書けました。マスターユーザーはシングルユーザーローテーション、それ以外のユーザーはマルチユーザーローテーションとなるのが個人的に面白かったです。 今回は試していませんが、 公式ドキュメント によるとAurora以外のRDSデータベースでも、同じような方法でパスワードのローテーションを実現できそうです。 執筆: @kou.kinyo2 、レビュー: @sato.taichi ( Shodo で執筆されました )
はいどーもー! X イノベーション 本部の宮澤響です! 本記事では、株式会社 電通国際情報サービス (以下、ISID)の新人研修に Factorio を導入した話を紹介します! そもそもFactorioって何? この研修を導入するに至った背景 Factorioの実行環境を巡る紆余曲折 迎えた研修当日 導入 操作説明・ハンズオン 実習ルール説明 実習 振り返り 解説とまとめ 実施してみてどうだったか まとめ そもそも Factorio って何? Factorio とは、自動化された工場を建設して様々なアイテムを生産していく、 サンドボックス 型の シミュレーションゲーム です。 資源の採掘、技術の研究、インフラスト ラク チャの構築、生産の自動化などを行い、最終的にはロケットで 人工衛星 を打ち上げ、プレイヤーが不時着した未知の星から脱出することが目的となります。 最初は手動での生産に始まり、そこから様々なアイテムを駆使して生産を自動化、効率化していく点が、このゲームの大きな特徴であり醍醐味となっています。 (画像は SteamのFactorioのページ より) この研修を導入するに至った背景 きっかけは、新入社員同士のアイスブレイクの場を内製で提供できないか、という人事部からの依頼でした。 もちろん、リモートでの研修が主体となる新入社員にとっては、対面でアイスブレイクができる場というだけでも十分価値があります。 しかし、新人研修の一環であるため、せっかくなら楽しむだけでなく学びを得てもらいたい(具体的には、論理思考力を強化してもらいたい)ということになり、この研修を企画することになりました。 そこで、何か良い題材がないか探していたところ、このISIDテックブログの発起人でもある佐藤太一さんに Factorio を紹介いただきました。 先述のとおり、 Factorio は自動化や効率化がキモであることから、 SIer の営みと関連させて論理思考力を強化できるのではないかと考え、 Factorio を題材とすることに決定しました。 ちなみに、研修担当者である私自身は Factorio 未経験であり、このようなジャンルのゲームのプレイ経験もほとんどありませんでした。 そのため、まずは Factorio を休日に触るところから始めました。 Factorio の実行環境を巡る紆余曲折 研修を導入するまでにはいくつかの紆余曲折がありましたが、その中でも最も大きかったものが、 Factorio をプレイするにあたり、 Factorio をどこで実行するか、というものでした。 最初に検討したのは、 Factorio を新入社員の社用PCにダウンロードさせ、ローカル環境で実行する形式です。 こちらは単純明快で技術的な問題も発生しない形式ではありますが、社用PCにゲームを入れるのはいかがなものか、という懸念もあり、代替手段がないか検証することになりました。 続いて検討したのは、新入社員69名分の 仮想マシン を社内に用意し、新入社員には社用PCからそこに接続してもらう、という形式です。 この形式であれば新入社員の社用PCに Factorio をダウンロードさせる必要がないため、先述の懸念は解消されます。 しかし、人数分の 仮想マシン を用意することはリソース的に難しいと担当者に断られてしまったため、別の代替手段を検討することになりました。 次に検討したのは、 クラウド サービスを利用する形式です。 社内の 仮想マシン の代わりに、 Amazon EC2 の インスタンス や Amazon WorkSpacesのデスクトップを用意し、それらに接続する形式の検証を行いました。 ですが、操作の遅延により快適にプレイできない、社内ネットワークの都合により Factorio に必要な UDP での通信ができない、などの問題点が発覚し、これらも現実的でないことが分かりました。 ここまでの検討の結果を踏まえ、一時は Factorio の導入自体を白紙に戻す案まで浮上しました。 しかし、人事部との相談の末、「そもそも遊び目的でなく研修のために実施するという大前提があるため、必要情報(今回が特別であること、社用PCはログを取られていること、など)をインプットすれば、大きな問題にはならないだろう」という判断をいただき、一周回って新入社員の社用PCにダウンロードさせる形式で研修を実施することとなりました。 迎えた研修当日 そんなこんなで迎えた研修当日です。 当日は、以下のような流れで研修を進めました。 導入 操作説明・ハンズオン 実習ルール説明 実習1 振り返り1 実習2 振り返り2 解説とまとめ 導入 自己紹介、 Factorio のダウンロード、研修の目的や内容の説明を行いました。 目的は、以下の力の基礎を身につけることとしました。 筋道立てて物事を考える力 自動化、効率化できる部分を考える力 ドキュメントを読んで仕様を理解する力 また、通常の研修や業務において、社用PCに不要なゲームやアプリをダウンロードする行為は禁止である旨の注意喚起も行いました。 操作説明・ハンズオン ハンズオン形式で基本操作を説明しました。 公式の チュートリアル は少し難易度が高く、今回の実習でプレイするチーム生産シナリオには不要な要素(研究、 蒸気機関 による電力の確保、バイターとの戦闘など)も含まれることから、今回は弊社独自のハンズオンを実施しました。 実習ルール説明 今回の実習でプレイするチーム生産シナリオのルールを説明しました。 このシナリオでは、プレイヤーはいくつかのチームに分かれて、共通のお題として指定されたアイテムを納品します。 それぞれのチームは同一の条件(生成されるフィールドや初期アイテムなど)の下でアイテムを製作していき、最終的に最も早く納品を完了させたチームの勝利です。 今回、このシナリオを選択した理由は以下です。 ゴールまでの道筋が明確で、難易度が初心者にちょうど良い チームで競い合える 以下の特徴により、自動化、効率化に専念できる 研究が進んだ状態で開始する 初期アイテムを豊富に所持している 最初から電力を利用できる バイターが出現しない ゲーム時間の概念がない(夜時間がないので暗くならない) 今回は、3台のヘッドレスサーバを用意し、それぞれのサーバに4チームずつ接続してもらう形式としました。 つまり、それぞれのサーバごと、4チームの中での勝負となります。 それぞれのサーバは同一のセーブデータから起動しているため、お題は全12チーム共通です。 実習 チーム生産シナリオでの実習を行いました。 納品完了までの時間の使い方は完全にチームに委ねたため、善は急げとすぐに資源を採掘し始めるチーム、 急がば回れ と全員で作戦会議をするチーム、間を取って戦略立案組と採掘組に分かれるチームなど、チームごとに様々な戦略で実習を進めていました。 運営側としては、このようにチームによって戦略がばらけているほど、振り返り内容の共有によって得られる気づきも大きいと考えていたため、目論見どおりといったところでした。 なお、実習1と実習2のお題は以下です。 実習1 駅:50 銅板:400 実習2 レーダー:50 自動車:10 想定ではどちらの所要時間も60分程度の見込みでしたが、それを上回るペースで納品を完了させるチームも散見されました。 振り返り 実習での良かった点、改善点などをチームで振り返ってもらい、その内容を簡単に発表してもらいました。 最終的に必要になる資源の数に応じてリソースの配分を意識すべきだった、初期アイテムに何があるかとその使い方を確認しておくべきだった、など、重要な気づきが多く生まれていました。 解説とまとめ 研修冒頭で提示した、以下の力の基礎を身につけるという目的に沿って、それぞれの力が今回の研修で必要だった場面と、実際の業務で必要になる場面を例に挙げて解説を行いました。 筋道立てて物事を考える力 自動化、効率化できる部分を考える力 ドキュメントを読んで仕様を理解する力 最後には、再度注意喚起を行った上で、新入社員のPCから Factorio を削除して終了となりました。 実施してみてどうだったか 率直な感想としては、無事に研修を実施できてホッとしているというのが正直なところです。 企画、技術的な検証、各種準備、当日の運営、振り返り、アウトプット(本記事)に至るまでの一連の業務を担当できたことは、私にとって非常に貴重で有意義な経験でした。 特に、検証の過程では、仮想サーバや AWS 、Dockerなどの知識を深めることができたため、私自身の技術的な学びにも繋がりました。 また、私自身、人前で何かを説明したり、ハンズオンを実施したりといったことが好きであるため、当日も楽しんで運営することができました。 新入社員からも、ただ楽しかったというだけでなく、 SIer に必要なスキルに関する学びを得られた、といったフィードバックをいただいており、この研修で伝えたかったことはしっかりと伝えられたのではないかと思います。 何から何まで初の試みでしたが、研修としては成功だったんじゃないかなと思います。 一方、ダウンロードに時間がかかる、回線が重く稀にサーバとの接続が切断される、1チームが納品を完了させてしまうと同じサーバに接続している他のチームは納品完了できずに途中で終了してしまう(これに関しては事前に承知の上で許容していたことではありましたが)など、改善すべき点も見つかりました。 今後は内定者研修などに応用したいという話にもなっているので、そのあたりの対応方法は引き続き検討していきたいと考えています。 まとめ 本記事では、ISIDの新人研修に Factorio を導入した話を紹介しました! 紆余曲折はあったものの、研修としては成功裏に終わり、新入社員からも高評価をいただけました。 皆さんもぜひ、所属企業の研修に Factorio を取り入れてみませんか? ということで、今回も最後までお読みいただき、本当にありがとうございました! 執筆: @miyazawa.hibiki 、レビュー: @sato.taichi ( Shodo で執筆されました )
はいどーもー! X イノベーション 本部の宮澤響です! 本記事では、株式会社 電通国際情報サービス (以下、ISID)の新人研修に Factorio を導入した話を紹介します! そもそもFactorioって何? この研修を導入するに至った背景 Factorioの実行環境を巡る紆余曲折 迎えた研修当日 導入 操作説明・ハンズオン 実習ルール説明 実習 振り返り 解説とまとめ 実施してみてどうだったか おわりに そもそも Factorio って何? Factorio とは、自動化された工場を建設して様々なアイテムを生産していく、 サンドボックス 型の シミュレーションゲーム です。 資源の採掘、技術の研究、インフラスト ラク チャの構築、生産の自動化などを行い、最終的にはロケットで 人工衛星 を打ち上げ、プレイヤーが不時着した未知の星から脱出することが目的となります。 最初は手動での生産に始まり、そこから様々なアイテムを駆使して生産を自動化、効率化していく点が、このゲームの大きな特徴であり醍醐味となっています。 (画像は SteamのFactorioのページ より) この研修を導入するに至った背景 きっかけは、新入社員同士のアイスブレイクの場を内製で提供できないか、という人事部からの依頼でした。 もちろん、リモートでの研修が主体となる新入社員にとっては、対面でアイスブレイクができる場というだけでも十分価値があります。 しかし、新人研修の一環であるため、せっかくなら楽しむだけでなく学びを得てもらいたい(具体的には、論理思考力を強化してもらいたい)ということになり、この研修を企画することになりました。 そこで、何か良い題材がないか探していたところ、このISIDテックブログの発起人でもある佐藤太一さんに Factorio を紹介いただきました。 先述のとおり、 Factorio は自動化や効率化がキモであることから、 SIer の営みと関連させて論理思考力を強化できるのではないかと考え、 Factorio を題材とすることに決定しました。 ちなみに、研修担当者である私自身は Factorio 未経験であり、このようなジャンルのゲームのプレイ経験もほとんどありませんでした。 そのため、まずは Factorio を休日に触るところから始めました。 Factorio の実行環境を巡る紆余曲折 研修を導入するまでにはいくつかの紆余曲折がありましたが、その中でも最も大きかったものが、 Factorio をプレイするにあたり、 Factorio をどこで実行するか、というものでした。 最初に検討したのは、 Factorio を新入社員の社用PCにダウンロードさせ、ローカル環境で実行する形式です。 こちらは単純明快で技術的な問題も発生しない形式ではありますが、社用PCにゲームを入れるのはいかがなものか、という懸念もあり、代替手段がないか検証することになりました。 続いて検討したのは、新入社員69名分の 仮想マシン を社内に用意し、新入社員には社用PCからそこに接続してもらう、という形式です。 この形式であれば新入社員の社用PCに Factorio をダウンロードさせる必要がないため、先述の懸念は解消されます。 しかし、人数分の 仮想マシン を用意することはリソース的に難しいと担当者に断られてしまったため、別の代替手段を検討することになりました。 次に検討したのは、 クラウド サービスを利用する形式です。 社内の 仮想マシン の代わりに、 Amazon EC2 の インスタンス や Amazon WorkSpacesのデスクトップを用意し、それらに接続する形式の検証を行いました。 ですが、操作の遅延により快適にプレイできない、社内ネットワークの都合により Factorio に必要な UDP での通信ができない、などの問題点が発覚し、これらも現実的でないことが分かりました。 ここまでの検討の結果を踏まえ、一時は Factorio の導入自体を白紙に戻す案まで浮上しました。 しかし、人事部との相談の末、「そもそも遊び目的でなく研修のために実施するという大前提があるため、必要情報(今回が特別であること、社用PCはログを取られていること、など)をインプットすれば、大きな問題にはならないだろう」という判断をいただき、一周回って新入社員の社用PCにダウンロードさせる形式で研修を実施することとなりました。 迎えた研修当日 そんなこんなで迎えた研修当日です。 当日は、以下のような流れで研修を進めました。 導入 操作説明・ハンズオン 実習ルール説明 実習1 振り返り1 実習2 振り返り2 解説とまとめ 導入 自己紹介、 Factorio のダウンロード、研修の目的や内容の説明を行いました。 目的は、以下の力の基礎を身につけることとしました。 筋道立てて物事を考える力 自動化、効率化できる部分を考える力 ドキュメントを読んで仕様を理解する力 また、通常の研修や業務において、社用PCに不要なゲームやアプリをダウンロードする行為は禁止である旨の注意喚起も行いました。 操作説明・ハンズオン ハンズオン形式で基本操作を説明しました。 公式の チュートリアル は少し難易度が高く、今回の実習でプレイするチーム生産シナリオには不要な要素(研究、 蒸気機関 による電力の確保、バイターとの戦闘など)も含まれることから、今回は弊社独自のハンズオンを実施しました。 実習ルール説明 今回の実習でプレイするチーム生産シナリオのルールを説明しました。 このシナリオでは、プレイヤーはいくつかのチームに分かれて、共通のお題として指定されたアイテムを納品します。 それぞれのチームは同一の条件(生成されるフィールドや初期アイテムなど)の下でアイテムを製作していき、最終的に最も早く納品を完了させたチームの勝利です。 今回、このシナリオを選択した理由は以下です。 ゴールまでの道筋が明確で、難易度が初心者にちょうど良い チームで競い合える 以下の特徴により、自動化、効率化に専念できる 研究が進んだ状態で開始する 初期アイテムを豊富に所持している 最初から電力を利用できる バイターが出現しない ゲーム時間の概念がない(夜時間がないので暗くならない) 今回は、3台のヘッドレスサーバを用意し、それぞれのサーバに4チームずつ接続してもらう形式としました。 つまり、それぞれのサーバごと、4チームの中での勝負となります。 それぞれのサーバは同一のセーブデータから起動しているため、お題は全12チーム共通です。 実習 チーム生産シナリオでの実習を行いました。 納品完了までの時間の使い方は完全にチームに委ねたため、善は急げとすぐに資源を採掘し始めるチーム、 急がば回れ と全員で作戦会議をするチーム、間を取って戦略立案組と採掘組に分かれるチームなど、チームごとに様々な戦略で実習を進めていました。 運営側としては、このようにチームによって戦略がばらけているほど、振り返り内容の共有によって得られる気づきも大きいと考えていたため、目論見どおりといったところでした。 なお、実習1と実習2のお題は以下です。 実習1 駅:50 銅板:400 実習2 レーダー:50 自動車:10 想定ではどちらの所要時間も60分程度の見込みでしたが、それを上回るペースで納品を完了させるチームも散見されました。 振り返り 実習での良かった点、改善点などをチームで振り返ってもらい、その内容を簡単に発表してもらいました。 最終的に必要になる資源の数に応じてリソースの配分を意識すべきだった、初期アイテムに何があるかとその使い方を確認しておくべきだった、など、重要な気づきが多く生まれていました。 解説とまとめ 研修冒頭で提示した、以下の力の基礎を身につけるという目的に沿って、それぞれの力が今回の研修で必要だった場面と、実際の業務で必要になる場面を例に挙げて解説を行いました。 筋道立てて物事を考える力 自動化、効率化できる部分を考える力 ドキュメントを読んで仕様を理解する力 最後には、再度注意喚起を行った上で、新入社員のPCから Factorio を削除して終了となりました。 実施してみてどうだったか 率直な感想としては、無事に研修を実施できてホッとしているというのが正直なところです。 企画、技術的な検証、各種準備、当日の運営、振り返り、アウトプット(本記事)に至るまでの一連の業務を担当できたことは、私にとって非常に貴重で有意義な経験でした。 特に、検証の過程では、仮想サーバや AWS 、Dockerなどの知識を深めることができたため、私自身の技術的な学びにも繋がりました。 また、私自身、人前で何かを説明したり、ハンズオンを実施したりといったことが好きであるため、当日も楽しんで運営することができました。 新入社員からも、ただ楽しかったというだけでなく、 SIer に必要なスキルに関する学びを得られた、といったフィードバックをいただいており、この研修で伝えたかったことはしっかりと伝えられたのではないかと思います。 何から何まで初の試みでしたが、研修としては成功だったんじゃないかなと思います。 一方、ダウンロードに時間がかかる、回線が重く稀にサーバとの接続が切断される、1チームが納品を完了させてしまうと同じサーバに接続している他のチームは納品完了できずに途中で終了してしまう(これに関しては事前に承知の上で許容していたことではありましたが)など、改善すべき点も見つかりました。 今後は内定者研修などに応用したいという話にもなっているので、そのあたりの対応方法は引き続き検討していきたいと考えています。 おわりに 本記事では、ISIDの新人研修に Factorio を導入した話を紹介しました! 紆余曲折はあったものの、研修としては成功裏に終わり、新入社員からも高評価をいただけました。 皆さんもぜひ、所属企業の研修に Factorio を取り入れてみませんか? ということで、今回も最後までお読みいただき、本当にありがとうございました! 私たちは同じ事業部で共に働いていただける仲間を募集しています! みなさまのご応募、お待ちしています! フルサイクルエンジニア 執筆: @miyazawa.hibiki 、レビュー: @sato.taichi ( Shodo で執筆されました )
みなさん、こんにちは。コーポレート本部コーポレートHRユニット人事部の今村と申します。 私自身、人事部ではここ10年ほどは人材開発、組織開発にどっぷり関わってきたのですが、今年から「ピープルアナリティクス」というテーマに取り組んでいます。 「HRアナリティクス」とか「データドリブン人事」とか表現はいろいろありますが、要は 「人」に関する取り組みの判断においてこれまで重視されがちだった「勘と経験」だけではなく、「人」のデータを収集/可視化/分析して様々な意思決定の確度を向上させよう ということをねらいとしたものです。 マーケティング を始め、日常のビジネスプロセスではごくごく当たり前の取り組みが、昨今、ようやく人事の領域でも本格的に注目されてきました。 個人的にこの領域には以前から興味があり、少なからず業務の中で取り組んできたこともあったのですが、ここに来て改めて新たな領域へ本格的にチャレンジなので、まずは体系的に学ばねば、ということで、今年に入ってからから本格的にピープルアナリティクスの勉強を始め、先日、 Academy to Innovate HR(略称AIHR)が認定している「People Analytics Specialist」のcertificationを取得することが出来ました ので、その内容について紹介いたします。 AIHRという学習機関 この「Academy to Innovate HR」は2016年に設立されたオランダの学習機関で、HR(人事)プロフェッショナルとして必要なスキルをオンラインで学べる学習プラットフォームです。 ※AIと略しているので一瞬あのAIと勘違いしがちですがもちろん別物です。 https://www.aihr.com/ その名の通り、HR全般を学べる学習機関で、People AnalyticsやDigital HR、OD(組織開発)等11のcertificationに加え、Hiring & Recruitment Strategy、Employee Experience and Design Thinking等の学習コースがあり、中にはBlockchain and HRと言った、日本ではなかなかお目にかかれないコースもあります。 そもそも日本ではなかなか「ピープルアナリティクス」という領域にフォーカスして体系的に学べる場が見つからなかったのですが、私が社外活動として理事も務めている人材育成のグローバルな会員組織である「ATD(The Associaton for Talent Development)」日本 支部 ( https://www.atdj.jp/atd-imnj )の方から紹介され、ここに来て業務上の必要性にも迫られたことあり、覚悟を決め本格的に学び始めることにしました。日本ではまだ全くと言っていいほど馴染みがないので、ちょっとレア感もあるのが自分好みだったということもありチャレンジしてみましたが、予想以上に価値のある学びの多い内容でした。 もしかすると、日本人でこのcertification取得したのはまだほとんどいなさそうなので、そういう意味でも心地よい達成感があったりします。 AIHRの特徴 なお、このAIHRは、 ・すべて英語(但し、字幕付き) ・すべてオンライン ・費用は、こんな感じ。 いくつかコースのオプションがあり、個々人の学習スタイルに応じて選択できる点も学習しやすい点だと感じました。 People Analytics certificationのカリキュラム このPeople Analytics certificationで学べる内容は、以下のとおりです。 「Statistics in HR」のパートがいわゆる分析手法をやや深めに学ぶパートです。深めと言っても、数学に全く明るくない私にも無理なく理解できる内容で、実際にデータを自分でいじりながら学ぶこともできるので、実務で活用するイメージも湧きやすくできています。(そもそも統計で使われている専門用語って「英語だとこう言うんだー」という素朴な発見もありました) なお、このパートについては、日本語で統計を解説している一般のサイトも並行して使いながら学ぶと、より効率的に学べると思います。 認定取得に要した学習時間 ちなみに、今回certificationを取得するまでに要した時間ですが、 おおよそ毎日30分~1時間の勉強で、約3か月 かかりました。一つのLessonの動画がおおよそ15-20分程度(+ボーナスレッスンや推奨動画/記事等もあり)なので、比較的無理なく学習できるペースでした。(もちろん期間中は何度でも視聴可能です) この学習コースから学んだこと 前述したように、カリキュラムとしては、 1.HR Analytics Leader 2.Statistics in HR 3.HR Data Analyst 4.Capstone Project という4つのモジュールに分かれていて、People Analyticsの基礎的な考え方や、分析プロセス、 フレームワーク 、そして具体的な分析手法等を学びました。「People Analytics」という名前の印象から、「Analytics」の手法を掘り下げて学ぶイメージがあるかもしれませんが、 全体を通して、再三、強調されている(と私が感じている)点は、「ビジネス課題」へのアプローチの重要性とビジネス インパク トを重視する、 ということです。 こう書くととても当たり前の話なのですが、単に人事関連のデータを分析する、そして インサイト を出す、予測をする、ということはもちろんPeople Analyticsの大事な要素であり、プロセスではあるものの、そもそもの目的はビジネスゴール(組織目標)を達成することである、というメッセージが何度も出てきます。 さらに言えば、 ビジネスゴールを達成するためには、いくつかの課題があり、その課題と人のパフォーマンスの関連をしっかりと紐づけた上で、その課題が生まれた背景やコンテクストも正しく理解することが重要 ということです。要は「 チェンジマ ネジメント」のプロセスそのものだよ、ということもメッセージの一つでした。 また、 Agile で進める、small-winを積み重ねる 、という点もキーメッセージの一つだと感じました。 なお、「どこから手を付けていいかわからない」という人のために、実務上の推進プロセスの整理の方法として、 「The HR Value Chain」 という フレームワーク が紹介されていました。 とてもシンプルではありますが、今後、People Analyticsを進めていく上では実践的で活用しやすそうです。 https://www.aihr.com/blog/hr-value-chain-essential-tool-for-adding-value-to-hr/ 今後実践していきたいこと 今回のcertificationの取得によって、私自身もこれから「ピープルアナリティクス」の実践スキルを高めていく上での前準備ができたという段階なので、これからさらに実践していきながらこのスキルを磨いていき、少しでも早くビジネス成果につなげていきたいと考えてます。 とはいえ、この取り組み自体はスタートしたばかりなので、まずは一つ目のsmall-winに向けて社内外での仲間を少しずつ増やしていければと思っています。 <参考>こんなデジタル証明書がもらえます。 執筆: @masayuki 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
みなさん、こんにちは。コーポレート本部コーポレートHRユニット人事部の今村と申します。 私自身、人事部ではここ10年ほどは人材開発、組織開発にどっぷり関わってきたのですが、今年から「ピープルアナリティクス」というテーマに取り組んでいます。 「HRアナリティクス」とか「データドリブン人事」とか表現はいろいろありますが、要は 「人」に関する取り組みの判断においてこれまで重視されがちだった「勘と経験」だけではなく、「人」のデータを収集/可視化/分析して様々な意思決定の確度を向上させよう ということをねらいとしたものです。 マーケティング を始め、日常のビジネスプロセスではごくごく当たり前の取り組みが、昨今、ようやく人事の領域でも本格的に注目されてきました。 個人的にこの領域には以前から興味があり、少なからず業務の中で取り組んできたこともあったのですが、ここに来て改めて新たな領域へ本格的にチャレンジなので、まずは体系的に学ばねば、ということで、今年に入ってからから本格的にピープルアナリティクスの勉強を始め、先日、 Academy to Innovate HR(略称AIHR)が認定している「People Analytics Specialist」のcertificationを取得することが出来ました ので、その内容について紹介いたします。 AIHRという学習機関 この「Academy to Innovate HR」は2016年に設立されたオランダの学習機関で、HR(人事)プロフェッショナルとして必要なスキルをオンラインで学べる学習プラットフォームです。 ※AIと略しているので一瞬あのAIと勘違いしがちですがもちろん別物です。 https://www.aihr.com/ その名の通り、HR全般を学べる学習機関で、People AnalyticsやDigital HR、OD(組織開発)等11のcertificationに加え、Hiring & Recruitment Strategy、Employee Experience and Design Thinking等の学習コースがあり、中にはBlockchain and HRと言った、日本ではなかなかお目にかかれないコースもあります。 そもそも日本ではなかなか「ピープルアナリティクス」という領域にフォーカスして体系的に学べる場が見つからなかったのですが、私が社外活動として理事も務めている人材育成のグローバルな会員組織である「ATD(The Associaton for Talent Development)」日本 支部 ( https://www.atdj.jp/atd-imnj )の方から紹介され、ここに来て業務上の必要性にも迫られたことあり、覚悟を決め本格的に学び始めることにしました。日本ではまだ全くと言っていいほど馴染みがないので、ちょっとレア感もあるのが自分好みだったということもありチャレンジしてみましたが、予想以上に価値のある学びの多い内容でした。 もしかすると、日本人でこのcertification取得したのはまだほとんどいなさそうなので、そういう意味でも心地よい達成感があったりします。 AIHRの特徴 なお、このAIHRは、 ・すべて英語(但し、字幕付き) ・すべてオンライン ・費用は、こんな感じ。 いくつかコースのオプションがあり、個々人の学習スタイルに応じて選択できる点も学習しやすい点だと感じました。 People Analytics certificationのカリキュラム このPeople Analytics certificationで学べる内容は、以下のとおりです。 「Statistics in HR」のパートがいわゆる分析手法をやや深めに学ぶパートです。深めと言っても、数学に全く明るくない私にも無理なく理解できる内容で、実際にデータを自分でいじりながら学ぶこともできるので、実務で活用するイメージも湧きやすくできています。(そもそも統計で使われている専門用語って「英語だとこう言うんだー」という素朴な発見もありました) なお、このパートについては、日本語で統計を解説している一般のサイトも並行して使いながら学ぶと、より効率的に学べると思います。 認定取得に要した学習時間 ちなみに、今回certificationを取得するまでに要した時間ですが、 おおよそ毎日30分~1時間の勉強で、約3か月 かかりました。一つのLessonの動画がおおよそ15-20分程度(+ボーナスレッスンや推奨動画/記事等もあり)なので、比較的無理なく学習できるペースでした。(もちろん期間中は何度でも視聴可能です) この学習コースから学んだこと 前述したように、カリキュラムとしては、 1.HR Analytics Leader 2.Statistics in HR 3.HR Data Analyst 4.Capstone Project という4つのモジュールに分かれていて、People Analyticsの基礎的な考え方や、分析プロセス、 フレームワーク 、そして具体的な分析手法等を学びました。「People Analytics」という名前の印象から、「Analytics」の手法を掘り下げて学ぶイメージがあるかもしれませんが、 全体を通して、再三、強調されている(と私が感じている)点は、「ビジネス課題」へのアプローチの重要性とビジネス インパク トを重視する、 ということです。 こう書くととても当たり前の話なのですが、単に人事関連のデータを分析する、そして インサイト を出す、予測をする、ということはもちろんPeople Analyticsの大事な要素であり、プロセスではあるものの、そもそもの目的はビジネスゴール(組織目標)を達成することである、というメッセージが何度も出てきます。 さらに言えば、 ビジネスゴールを達成するためには、いくつかの課題があり、その課題と人のパフォーマンスの関連をしっかりと紐づけた上で、その課題が生まれた背景やコンテクストも正しく理解することが重要 ということです。要は「 チェンジマ ネジメント」のプロセスそのものだよ、ということもメッセージの一つでした。 また、 Agile で進める、small-winを積み重ねる 、という点もキーメッセージの一つだと感じました。 なお、「どこから手を付けていいかわからない」という人のために、実務上の推進プロセスの整理の方法として、 「The HR Value Chain」 という フレームワーク が紹介されていました。 とてもシンプルではありますが、今後、People Analyticsを進めていく上では実践的で活用しやすそうです。 https://www.aihr.com/blog/hr-value-chain-essential-tool-for-adding-value-to-hr/ 今後実践していきたいこと 今回のcertificationの取得によって、私自身もこれから「ピープルアナリティクス」の実践スキルを高めていく上での前準備ができたという段階なので、これからさらに実践していきながらこのスキルを磨いていき、少しでも早くビジネス成果につなげていきたいと考えてます。 とはいえ、この取り組み自体はスタートしたばかりなので、まずは一つ目のsmall-winに向けて社内外での仲間を少しずつ増やしていければと思っています。 <参考>こんなデジタル証明書がもらえます。 執筆: @masayuki 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
みなさん、こんにちは。ISID CIT事業部の石際です。 コンタクトセンターの クラウド 化が進んでいますが、 Salesforce Service Cloud(以下「Service Cloud」)のような顧客管理( CRM )アプリケーションと連携することでのカスタマーエクス ペリエ ンス(CX)の向上も重要視されています。 Service Cloudで CTI (Computer Telephony Integration)機能を具備したコンタクトセンターを構築する場合、 Salesforce が提供しているOpen CTI というライブラリを利用して各テレフォニーベンダーが作成した CTI とService Cloudを連携することで実現できます。 コールセンター構築と聞くと複雑で構築に時間が掛かる印象ですが、Twilioが提供している クラウド 型コンタクトセンターのTwilio Flex であればクイックスタートが可能です。 今回はService CloudにTwilio Flex を連携させることで、 CTI 機能を具備したコンタクトセンターを構築してみました。 1. Twilio Flexとは 2. Service CloudとTwilio Flexを連携してみる 2-1. セットアップ Twilio Flexの設定 1. 設定を有効にする 2. パラメータを設定する 3. コールセンター定義ファイルをダウンロードする Salesforceの設定 1. コールセンター定義ファイルをインポートする 2. 着信時のアクションを設定する 3. ソフトフォンを追加する 2-2. 連携すると何ができるか 着信時の動作を確認してみる 1. 着信がポップアップする 2. 着信を受けると顧客情報ページを表示する/新規登録ページを表示する 3. タスクにログを記録する 3. 簡単なコールフローを作ってみました 4. 感想 1. Twilio Flex とは Twilioは、電話やSMS・ビデオ・チャット・ SNS など世の中にある様々なコミュニケーションチャネルをWeb・モバイルアプリケーションとつなぐ クラウド コミュニケーション API サービスです。そのTwilioの各種サービスを組み合わせた プログラマブル な クラウド 型コンタクトセンタープラットフォームがTwilio Flex になります。マルチチャンネルに対応し、オペレータの画面のUIはもちろんIVR 1 やACD 2 などのフルカスタマイズが可能となっています。 2. Service CloudとTwilio Flex を連携してみる 今回は Integrate Twilio Flex with Salesforce を参考に設定を行いました。 Service Cloudに電話を連携する場合、一番メジャーなのは Amazon Connect CTI Adapterだと思います。 Amazon Connectは Salesforce のAppExchangeからパッケージのインストールが必要です。 一方で、Twilio Flex との連携ではパッケージのインストールが不要です。Twilio Flex の設定とTwilioで用意されているコールセンター定義ファイルを Salesforce にインポートし Salesforce の設定を行うだけで完了します。10分程度あれば完了してしまうという驚きの簡単さです。 では、さっそくセットアップをしてみましょう。 (事前にTwilioで電話番号を取得しておきます。電話番号の取得方法は Twilioコンソールから電話番号を購入する方法 を参考にしてください。) 2-1. セットアップ Twilio Flex の設定 まずは、Twilio Flex の設定を行います。 Flex 管理画面から [INTEGRATIONS] をクリックし CRM 連携設定の画面に遷移します。 CRM 連携設定の画面で [ Salesforce ] を選択し、 Salesforce 連携の設定を行っていきます。 1. 設定を有効にする [STATUS] のセクションでトグルを [Enabled] にして、連携の設定を有効化します。 (こちらは公式ドキュメントに書いていないのでご注意ください) 2. パラメータを設定する [CONFIGURATION] のセクションで下記の項目を設定します。 Workflow SID (任意):エージェントのルーティングルール(Workflow)を指定します。デフォルトの場合は空欄にしておきます。 Task Channel SID (任意):音声チャネルとは異なるチャネルを使用したい場合にチャネルを指定します。 Agent Caller ID (必須): Salesforce からClick to Dialで発信するために使用する発信者IDを指定します。(上記の画像ではこの項目が表示されていませんが、初回の設定でのみ項目が表示されます。設定後はTwilioコンソールの [ Flex ] > [Manage] > [Voice] 画面の [ Flex Dialpad] にて設定が可能です) Salesforce Base URL (必須): Salesforce ドメイン を登録します。(初回の設定後はTwilioコンソールの [ Flex Settings] 画面で設定を行います) SSO : Salesforce がIdPとしてSSOの設定が可能です。(今回は設定していませんが、利用する際は Configure Salesforce SSO With Twilio Flex などを参照して必要な設定を行ってください) LOG :ログを Salesforce に記録したい場合はチェックを付けます。 それぞれの項目は設定後変更が可能です。 3. コールセンター定義ファイルをダウンロードする 最後に [FILES] のセクションの [DOWNLOAD] からコールセンター定義ファイルをダウンロードします。 Salesforce の設定 次に Salesforce の [Setup] にて設定を行います。 1. コールセンター定義ファイルをインポートする [Call Centers] の設定画面から [import] ボタンをクリックし、Twilio Flex からダウンロードしたコールセンター定義ファイルをインポートします。 インポート後、 [Call Center Users] のセクションにある [Manage Call Center Users] ボタンをクリックし、ユーザーを追加します。 2. 着信時のアクションを設定する [Softphone Layouts] の設定画面から着信時の挙動を必要に応じて設定します。 3. ソフトフォンを追加する [App Manager] の設定画面からTwilio Flex を表示させたいアプリを選択します。今回は [Service Console] にTwilio Flex のソフトフォンを追加します。 [App Settings] から [Utility Items] を選択します。 [Utility Items] のリストに [ Open CTI Softphone] を追加し、下記の内容で項目を設定します。 はい、これで完了です!すべて GUI ベースでクイックに連携ができました。 Service Consoleを見てみると、Twilio Flex のソフトフォンが表示されるようになっています。 2-2. 連携すると何ができるか さて、Service CloudとTwilio Flex を連携することで何ができるでしょうか。 着信時の動作を確認してみる Twilio Flex はコールフローをStudioで設定できます。動作確認では着信があるとすぐにオペレーターにつなぐフローを使用します。 早速、Twilioで取得した電話番号に電話をしてみます。 1. 着信がポップアップする まず、着信があると Flex のソフトフォンをポップアップします。 2. 着信を受けると顧客情報ページを表示する/新規登録ページを表示する 着信している電話番号をクリックすると電話番号からオブジェクトを検索し、画面に表示します。 電話番号がヒットしない場合は、新規登録ページが表示されます。この時、電話番号がフィルされます。 3. タスクにログを記録する Twilio Flex の Salesforce Integrationの設定でログを有効にした場合は、タスクにログが記録されます。 このように、デフォルトの設定で必要最低限の機能が実装されています。 カスタマイズが必要な場合はTwilio Studioや Salesforce の開発が必要になってきます。 3. 簡単なコールフローを作ってみました Studioを使って少しコールセンターっぽいコールフローを作ってみました。 フローの流れは上記のようになります。 "sfdcSearchString": "{{widgets.getInput.Digits}}" をセットすることで、グローバル検索に値を渡すことができます。 オペレータが見ている Salesforce の画面では、 会員番号がある顧客は会員番号でグローバル検索される 会員番号がない顧客は電話番号で検索され、なければ新規登録画面が表示される という動きになります。 このように、Studioをカスタマイズすることでオペレータにとっては効率的な、顧客にとっては便利で親切なコンタクトセンターの構築が可能です。 4. 感想 想像以上に簡単にService Cloudとの連携ができました! Amazon Connect CTI Adapterを使った連携よりもシンプルな構成のためクイックにスタートできる点が良いところだと感じました。 また、Twilio Flex を利用するメリットとしては、 対応チャネルが豊富 API や開発用のライブラリなどが充実 コンタクトセンターの総合的な改善が可能 などが挙げられます。 機能の拡張性も優れているため、クイックにはじめた後、業務に応じて開発を柔軟に行っていくことも可能です。Service Cloudでコンタクトセンターを構築する際、 Amazon ConnectだけでなくTwilio Flex も検討してみてはいかがでしょうか? 最後までお読みいただきありがとうございました。 執筆: @ishigiwa.yumi 、レビュー: @higa ( Shodo で執筆されました ) IVR (Interactive Voice Response) 自動音声応答:コールセンターなど企業の電話窓口で、音声による自動応答を行うコンピューターシステム。発信者のダイヤル操作に合わせて、あらかじめ録音してある音声を発信者側に自動的に再生する。 音声認識 機能を備え、相手の発話に応じて再生内容を決める製品もある。 ↩ ACD (Automatic Call Distribution) 自動着信呼分配機能:着信したコールを自動的に管理、コン トロール する装置。次々に入る着信コールを、その時点で空いている、あるいは次の応答を最も長時間待っている適切なスキルを持ったテ レコミュニ ケーターから順次均等に配分できる機能を備える。 ↩
みなさん、こんにちは。ISID CIT事業部の石際です。 コンタクトセンターの クラウド 化が進んでいますが、 Salesforce Service Cloud(以下「Service Cloud」)のような顧客管理( CRM )アプリケーションと連携することでのカスタマーエクス ペリエ ンス(CX)の向上も重要視されています。 Service Cloudで CTI (Computer Telephony Integration)機能を具備したコンタクトセンターを構築する場合、 Salesforce が提供しているOpen CTI というライブラリを利用して各テレフォニーベンダーが作成した CTI とService Cloudを連携することで実現できます。 コールセンター構築と聞くと複雑で構築に時間が掛かる印象ですが、Twilioが提供している クラウド 型コンタクトセンターのTwilio Flex であればクイックスタートが可能です。 今回はService CloudにTwilio Flex を連携させることで、 CTI 機能を具備したコンタクトセンターを構築してみました。 1. Twilio Flexとは 2. Service CloudとTwilio Flexを連携してみる 2-1. セットアップ Twilio Flexの設定 1. 設定を有効にする 2. パラメータを設定する 3. コールセンター定義ファイルをダウンロードする Salesforceの設定 1. コールセンター定義ファイルをインポートする 2. 着信時のアクションを設定する 3. ソフトフォンを追加する 2-2. 連携すると何ができるか 着信時の動作を確認してみる 1. 着信がポップアップする 2. 着信を受けると顧客情報ページを表示する/新規登録ページを表示する 3. タスクにログを記録する 3. 簡単なコールフローを作ってみました 4. 感想 1. Twilio Flex とは Twilioは、電話やSMS・ビデオ・チャット・ SNS など世の中にある様々なコミュニケーションチャネルをWeb・モバイルアプリケーションとつなぐ クラウド コミュニケーション API サービスです。そのTwilioの各種サービスを組み合わせた プログラマブル な クラウド 型コンタクトセンタープラットフォームがTwilio Flex になります。マルチチャンネルに対応し、オペレータの画面のUIはもちろんIVR 1 やACD 2 などのフルカスタマイズが可能となっています。 2. Service CloudとTwilio Flex を連携してみる 今回は Integrate Twilio Flex with Salesforce を参考に設定を行いました。 Service Cloudに電話を連携する場合、一番メジャーなのは Amazon Connect CTI Adapterだと思います。 Amazon Connectは Salesforce のAppExchangeからパッケージのインストールが必要です。 一方で、Twilio Flex との連携ではパッケージのインストールが不要です。Twilio Flex の設定とTwilioで用意されているコールセンター定義ファイルを Salesforce にインポートし Salesforce の設定を行うだけで完了します。10分程度あれば完了してしまうという驚きの簡単さです。 では、さっそくセットアップをしてみましょう。 (事前にTwilioで電話番号を取得しておきます。電話番号の取得方法は Twilioコンソールから電話番号を購入する方法 を参考にしてください。) 2-1. セットアップ Twilio Flex の設定 まずは、Twilio Flex の設定を行います。 Flex 管理画面から [INTEGRATIONS] をクリックし CRM 連携設定の画面に遷移します。 CRM 連携設定の画面で [ Salesforce ] を選択し、 Salesforce 連携の設定を行っていきます。 1. 設定を有効にする [STATUS] のセクションでトグルを [Enabled] にして、連携の設定を有効化します。 (こちらは公式ドキュメントに書いていないのでご注意ください) 2. パラメータを設定する [CONFIGURATION] のセクションで下記の項目を設定します。 Workflow SID (任意):エージェントのルーティングルール(Workflow)を指定します。デフォルトの場合は空欄にしておきます。 Task Channel SID (任意):音声チャネルとは異なるチャネルを使用したい場合にチャネルを指定します。 Agent Caller ID (必須): Salesforce からClick to Dialで発信するために使用する発信者IDを指定します。(上記の画像ではこの項目が表示されていませんが、初回の設定でのみ項目が表示されます。設定後はTwilioコンソールの [ Flex ] > [Manage] > [Voice] 画面の [ Flex Dialpad] にて設定が可能です) Salesforce Base URL (必須): Salesforce ドメイン を登録します。(初回の設定後はTwilioコンソールの [ Flex Settings] 画面で設定を行います) SSO : Salesforce がIdPとしてSSOの設定が可能です。(今回は設定していませんが、利用する際は Configure Salesforce SSO With Twilio Flex などを参照して必要な設定を行ってください) LOG :ログを Salesforce に記録したい場合はチェックを付けます。 それぞれの項目は設定後変更が可能です。 3. コールセンター定義ファイルをダウンロードする 最後に [FILES] のセクションの [DOWNLOAD] からコールセンター定義ファイルをダウンロードします。 Salesforce の設定 次に Salesforce の [Setup] にて設定を行います。 1. コールセンター定義ファイルをインポートする [Call Centers] の設定画面から [import] ボタンをクリックし、Twilio Flex からダウンロードしたコールセンター定義ファイルをインポートします。 インポート後、 [Call Center Users] のセクションにある [Manage Call Center Users] ボタンをクリックし、ユーザーを追加します。 2. 着信時のアクションを設定する [Softphone Layouts] の設定画面から着信時の挙動を必要に応じて設定します。 3. ソフトフォンを追加する [App Manager] の設定画面からTwilio Flex を表示させたいアプリを選択します。今回は [Service Console] にTwilio Flex のソフトフォンを追加します。 [App Settings] から [Utility Items] を選択します。 [Utility Items] のリストに [ Open CTI Softphone] を追加し、下記の内容で項目を設定します。 はい、これで完了です!すべて GUI ベースでクイックに連携ができました。 Service Consoleを見てみると、Twilio Flex のソフトフォンが表示されるようになっています。 2-2. 連携すると何ができるか さて、Service CloudとTwilio Flex を連携することで何ができるでしょうか。 着信時の動作を確認してみる Twilio Flex はコールフローをStudioで設定できます。動作確認では着信があるとすぐにオペレーターにつなぐフローを使用します。 早速、Twilioで取得した電話番号に電話をしてみます。 1. 着信がポップアップする まず、着信があると Flex のソフトフォンをポップアップします。 2. 着信を受けると顧客情報ページを表示する/新規登録ページを表示する 着信している電話番号をクリックすると電話番号からオブジェクトを検索し、画面に表示します。 電話番号がヒットしない場合は、新規登録ページが表示されます。この時、電話番号がフィルされます。 3. タスクにログを記録する Twilio Flex の Salesforce Integrationの設定でログを有効にした場合は、タスクにログが記録されます。 このように、デフォルトの設定で必要最低限の機能が実装されています。 カスタマイズが必要な場合はTwilio Studioや Salesforce の開発が必要になってきます。 3. 簡単なコールフローを作ってみました Studioを使って少しコールセンターっぽいコールフローを作ってみました。 フローの流れは上記のようになります。 "sfdcSearchString": "{{widgets.getInput.Digits}}" をセットすることで、グローバル検索に値を渡すことができます。 オペレータが見ている Salesforce の画面では、 会員番号がある顧客は会員番号でグローバル検索される 会員番号がない顧客は電話番号で検索され、なければ新規登録画面が表示される という動きになります。 このように、Studioをカスタマイズすることでオペレータにとっては効率的な、顧客にとっては便利で親切なコンタクトセンターの構築が可能です。 4. 感想 想像以上に簡単にService Cloudとの連携ができました! Amazon Connect CTI Adapterを使った連携よりもシンプルな構成のためクイックにスタートできる点が良いところだと感じました。 また、Twilio Flex を利用するメリットとしては、 対応チャネルが豊富 API や開発用のライブラリなどが充実 コンタクトセンターの総合的な改善が可能 などが挙げられます。 機能の拡張性も優れているため、クイックにはじめた後、業務に応じて開発を柔軟に行っていくことも可能です。Service Cloudでコンタクトセンターを構築する際、 Amazon ConnectだけでなくTwilio Flex も検討してみてはいかがでしょうか? 最後までお読みいただきありがとうございました。 執筆: @ishigiwa.yumi 、レビュー: @higa ( Shodo で執筆されました ) IVR (Interactive Voice Response) 自動音声応答:コールセンターなど企業の電話窓口で、音声による自動応答を行うコンピューターシステム。発信者のダイヤル操作に合わせて、あらかじめ録音してある音声を発信者側に自動的に再生する。 音声認識 機能を備え、相手の発話に応じて再生内容を決める製品もある。 ↩ ACD (Automatic Call Distribution) 自動着信呼分配機能:着信したコールを自動的に管理、コン トロール する装置。次々に入る着信コールを、その時点で空いている、あるいは次の応答を最も長時間待っている適切なスキルを持ったテ レコミュニ ケーターから順次均等に配分できる機能を備える。 ↩
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンターの耿です。 Amazon Aurora Serverlessは、コンピューティングとメモリのキャパシティ(Aurora 容量ユニット = ACU)をリク エス ト数に応じて自動で変化させることができるデータベースサービスです。事前のスケーリング計画が不要になるほか、実際のワークロードに合わせてキャパシティを増減させるため、費用の最適化に向いています。 Aurora Serverlessは v1 と v2 の2つのバージョンが一般利用可能ですが、v1 の方はしばらくアクセスがないと 0 ACU まで落として一時停止する機能があり、コンピューティングとメモリの料金が全くかからなくなります。本番環境であれば利用されることはあまりないと思いますが、リク エス ト数が限定的な開発環境ではこの機能をうまく利用することで、費用をさらに節約することができます。 しかし、 0 ACU で一時停止している状態のデータベースにアクセスしようとすると、キャパシティがないため初回接続が失敗してしまいます。本記事はシンプルにこの問題を解消し、費用を抑える方法を記載します。 Aurora Serverless の ACU 設定 Aurora Serverless のバージョンの違い 開発で遭遇した問題点 実現したいこと 実現方法 他の選択肢 CDKコード 実際の料金 Aurora Serverless の ACU 設定 Aurora Serverless は Aurora 容量ユニット (ACU) の最大値と最小値を指定することで、その間で負荷に応じてオートスケーリングします。v1に限って一時停止設定が可能で、リク エス トが全くない時に 0 ACU までスケールダウンできます。 Aurora Serverless v1の一時停止設定 Aurora Serverless のバージョンの違い 2022年5月時点において、Aurora Serverless v1にできてv2にできないことがあります。 v2は Data API を利用できない CloudFormationはまだv2をサポートしていない v2は 0 ACU(一時停止)にできず、最小ACUは 0.5 である ACUに関する補足として、2022年5月時点でv2のACU費用はv1の2倍に設定されています。すなわちv2を最小キャパシティ0.5 ACUで常時稼働した場合の費用は、v1を1 ACUで常時稼働した場合の費用と同等になります。v1は一時停止が可能なため、一時停止をした時間の分だけv2より費用を節約できます。 ※その他のAurora Serverless v2の特徴は、以下の動画で詳しく解説されています。 JAWS-UG横浜 #44 Aurora Serverless v2 開発で遭遇した問題点 Data API とCDKを利用したかったため、Aurora Serverless v1を利用して開発している環境があります。費用を抑えるために一時停止機能を有効にしていますが、0 ACUのときはコンピューティングとメモリの動作が完全に停止するため、 初回接続ではデータベースへの接続が失敗する という問題に遭遇しました。 Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.; SQLState: 08S01 しばらく(体感30秒〜1分程度)するとデータベースが起動し、問題なく接続できるようになるのですが、費用を抑えつつ初回接続でも失敗しないようにしたかったため、その仕組みを検討しました。 実現したいこと Aurora Serverlessに アクセスする可能性のある時間帯は一時停止をさせずに最低でも1 ACUで稼働させ、それ以外の時間帯は0 ACUへのスケールダウンを許容 すれば、余分な費用を削減し、初回接続でエラーになる問題も解消できます。今回はアクセスする可能性のある時間帯は余裕を持って 7:00 ~ 22:00 と広めに定義しています。 整理すると、実現したいことは次のようになります。 平日の7:00 ~ 22:00 は、Aurora Serverlessが 0 ACUにならないようしに、DBへの接続が常に成功するようにしたい それ以外の時間(平日深夜と土日)は 0 ACUにスケールダウンしても良い 実現方法 Aurora クラスタ が一時停止しない場合の最小 ACU を 1 とする Aurora クラスタ へ 2時間 アクセスがなかった場合、一時停止するよう(0 ACU になるよう)に設定する Aurora クラスタ へ参照系のクエリを発行するLambda関数を作成し、 平日の7:00 ~ 20:00 の間は1時間ごとに定期実行 する こうすることで、平日は20:00に最後のLambda関数が実行され、22:00まではAurora クラスタ が0 ACUにならないことが保証されます。夜間や土日はAurora クラスタ への接続がないと一時停止し、次の平日の朝7:00に最初のLambda関数が実行され、Aurora クラスタ が起動します。 他の選択肢 シビアに費用を抑える必要がない場合 、一時停止設定を無効にし、0 ACUにスケールダウンしないようにすれば、データベースへのアクセスがなくても停止しなくなり、本記事で述べるような ワークアラウンド は必要ありません。 あるいは 0 ACUにスケールダウンした後の初回接続が失敗しても、 起動を待ってからクエリを再実行することが許容できる場合 も、本記事の ワークアラウンド は必要ありません。 CDKコード 以下のCDKコードで環境を作成します。 import { Duration , Stack , StackProps } from "aws-cdk-lib" ; import * as ec2 from "aws-cdk-lib/aws-ec2" ; import * as events from "aws-cdk-lib/aws-events" ; import * as eventTargets from "aws-cdk-lib/aws-events-targets" ; import * as iam from "aws-cdk-lib/aws-iam" ; import * as lambda from "aws-cdk-lib/aws-lambda" ; import * as lambdaNodejs from "aws-cdk-lib/aws-lambda-nodejs" ; import * as rds from "aws-cdk-lib/aws-rds" ; import { Construct } from "constructs" ; export class MyStack extends Stack { constructor( scope: Construct , id: string , props?: StackProps ) { super( scope , id , props ); const privateSubnetName = "myPrivateSubnet" ; // VPCを作成 const vpc = new ec2.Vpc ( this , "MyVpc" , { cidr: "10.0.0.0/16" , enableDnsHostnames: true , enableDnsSupport: true , subnetConfiguration: [ { name: privateSubnetName , subnetType: ec2.SubnetType.PRIVATE_ISOLATED , cidrMask: 20 , } , ] , } ); // Aurora Serverless v1 クラスタを作成 const auroraCluseter = new rds.ServerlessCluster ( this , "MyAuroraCluster" , { engine: rds.DatabaseClusterEngine.AURORA_MYSQL , vpc: vpc , vpcSubnets: { subnetGroupName: privateSubnetName } , // 最小ACUを1、最大ACUを2、一時停止までに必要な非アクティブ時間を2時間に指定 scaling: { minCapacity: 1 , maxCapacity: 2 , autoPause: Duration.hours ( 2 ) } , // Data APIを有効化 enableDataApi: true , } ); // Lambda関数 const awakeAuroraFunction = new lambdaNodejs.NodejsFunction ( this , "MyFunction" , { // Lambda関数へのファイルパス entry: "functions/awake-aurora-serverless.ts" , runtime: lambda.Runtime.NODEJS_14_X , // Data APIを利用するため、AuroraクラスタARNとシークレットのARNを環境変数で渡す environment: { CLUSTER_ARN: auroraCluseter.clusterArn , SECRET_ARN: auroraCluseter.secret?.secretArn ?? "" , } , } ); // Lambda関数の実行ロールにData APIへのアクセスを許可するポリシーを追加 if ( auroraCluseter.secret?.secretArn ) { const auroraDataApiPolicy = new iam.ManagedPolicy ( this , "MyAuroraDataApiPolicy" , { statements: [ new iam.PolicyStatement ( { resources: [ ` ${ auroraCluseter.secret.secretArn } *` ] , actions: [ "secretsmanager:GetSecretValue" ] , effect: iam.Effect.ALLOW , } ), new iam.PolicyStatement ( { resources: [ auroraCluseter.clusterArn ] , actions: [ "rds-data:ExecuteStatement" ] , effect: iam.Effect.ALLOW , } ), ] , } ); awakeAuroraFunction.role?.addManagedPolicy ( auroraDataApiPolicy ); } // 日本時間 平日の 7:00 ~ 20:00 の間に1時間ごとにLambda関数を定期起動する // cron式は UTC で記載するため、「日曜 ~ 木曜の22:00 ~ 23:00」と「月曜 ~ 金曜の 0:00 ~ 11:00」の2つに分ける new events.Rule ( this , "MyEventRule1" , { schedule: events.Schedule.cron ( { minute: "0" , hour: "22-23" , weekDay: "SUN-THU" } ), targets: [ new eventTargets.LambdaFunction ( awakeAuroraFunction , { retryAttempts: 3 } ) ] , } ); new events.Rule ( this , "MyEventRule2" , { schedule: events.Schedule.cron ( { minute: "0" , hour: "0-11" , weekDay: "MON-FRI" } ), targets: [ new eventTargets.LambdaFunction ( awakeAuroraFunction , { retryAttempts: 3 } ) ] , } ); } } Lambda関数の部分では、 NodejsFunction コンストラクト を利用することで、TypeScript で記述した Lambda 関数の JavaScript への コンパイル からデプロイまでをCDKがやってくれます。 Aurora クラスタ へクエリを発行するLambda関数は、 functions/awake-aurora-serverless.ts に以下のように実装します。Data API を利用してクエリを発行します。 import * as RDS from "@aws-sdk/client-rds-data" ; import { Handler } from "aws-lambda" ; const client = new RDS.RDSDataClient ( { region: "ap-northeast-1" } ); export const handler: Handler = async () => { const input = { // Data APIを利用するための、AuroraクラスタのリソースARNとシークレットのARNを環境変数から取得する resourceArn: process .env.CLUSTER_ARN , secretArn: process .env.SECRET_ARN , // 発行するSQL文 sql: "SHOW databases;" , } ; const command = new RDS.ExecuteStatementCommand ( input ); await client.send ( command ); } ; 発行する SQL 文は更新系でなければ何でも良いですが、シンプルに SHOW databases; としています。 実際の料金 以上の構成でしばらく稼働した場合の料金を確認しました。 土日はAurora クラスタ が停止し、料金がかかっていないことがわかります。平日も24時間のうち15時間しか稼働していません。 今回の条件では一週間 24h * 7日 = 168h のうち、 15h * 5日 = 75h 稼働しているため、常時稼働に比べて 75h / 168h = 45% の費用に抑えることができています。 一方で平日の業務時間中は常に稼働状態のため、接続が失敗することがなくなり、今回の要件を満たすことができました。 執筆: @kou.kinyo2 、レビュー: @higa ( Shodo で執筆されました )
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンターの耿です。 Amazon Aurora Serverlessは、コンピューティングとメモリのキャパシティ(Aurora 容量ユニット = ACU)をリク エス ト数に応じて自動で変化させることができるデータベースサービスです。事前のスケーリング計画が不要になるほか、実際のワークロードに合わせてキャパシティを増減させるため、費用の最適化に向いています。 Aurora Serverlessは v1 と v2 の2つのバージョンが一般利用可能ですが、v1 の方はしばらくアクセスがないと 0 ACU まで落として一時停止する機能があり、コンピューティングとメモリの料金が全くかからなくなります。本番環境であれば利用されることはあまりないと思いますが、リク エス ト数が限定的な開発環境ではこの機能をうまく利用することで、費用をさらに節約することができます。 しかし、 0 ACU で一時停止している状態のデータベースにアクセスしようとすると、キャパシティがないため初回接続が失敗してしまいます。本記事はシンプルにこの問題を解消し、費用を抑える方法を記載します。 Aurora Serverless の ACU 設定 Aurora Serverless のバージョンの違い 開発で遭遇した問題点 実現したいこと 実現方法 他の選択肢 CDKコード 実際の料金 Aurora Serverless の ACU 設定 Aurora Serverless は Aurora 容量ユニット (ACU) の最大値と最小値を指定することで、その間で負荷に応じてオートスケーリングします。v1に限って一時停止設定が可能で、リク エス トが全くない時に 0 ACU までスケールダウンできます。 Aurora Serverless v1の一時停止設定 Aurora Serverless のバージョンの違い 2022年5月時点において、Aurora Serverless v1にできてv2にできないことがあります。 v2は Data API を利用できない CloudFormationはまだv2をサポートしていない v2は 0 ACU(一時停止)にできず、最小ACUは 0.5 である ACUに関する補足として、2022年5月時点でv2のACU費用はv1の2倍に設定されています。すなわちv2を最小キャパシティ0.5 ACUで常時稼働した場合の費用は、v1を1 ACUで常時稼働した場合の費用と同等になります。v1は一時停止が可能なため、一時停止をした時間の分だけv2より費用を節約できます。 ※その他のAurora Serverless v2の特徴は、以下の動画で詳しく解説されています。 JAWS-UG横浜 #44 Aurora Serverless v2 開発で遭遇した問題点 Data API とCDKを利用したかったため、Aurora Serverless v1を利用して開発している環境があります。費用を抑えるために一時停止機能を有効にしていますが、0 ACUのときはコンピューティングとメモリの動作が完全に停止するため、 初回接続ではデータベースへの接続が失敗する という問題に遭遇しました。 Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.; SQLState: 08S01 しばらく(体感30秒〜1分程度)するとデータベースが起動し、問題なく接続できるようになるのですが、費用を抑えつつ初回接続でも失敗しないようにしたかったため、その仕組みを検討しました。 実現したいこと Aurora Serverlessに アクセスする可能性のある時間帯は一時停止をさせずに最低でも1 ACUで稼働させ、それ以外の時間帯は0 ACUへのスケールダウンを許容 すれば、余分な費用を削減し、初回接続でエラーになる問題も解消できます。今回はアクセスする可能性のある時間帯は余裕を持って 7:00 ~ 22:00 と広めに定義しています。 整理すると、実現したいことは次のようになります。 平日の7:00 ~ 22:00 は、Aurora Serverlessが 0 ACUにならないようしに、DBへの接続が常に成功するようにしたい それ以外の時間(平日深夜と土日)は 0 ACUにスケールダウンしても良い 実現方法 Aurora クラスタ が一時停止しない場合の最小 ACU を 1 とする Aurora クラスタ へ 2時間 アクセスがなかった場合、一時停止するよう(0 ACU になるよう)に設定する Aurora クラスタ へ参照系のクエリを発行するLambda関数を作成し、 平日の7:00 ~ 20:00 の間は1時間ごとに定期実行 する こうすることで、平日は20:00に最後のLambda関数が実行され、22:00まではAurora クラスタ が0 ACUにならないことが保証されます。夜間や土日はAurora クラスタ への接続がないと一時停止し、次の平日の朝7:00に最初のLambda関数が実行され、Aurora クラスタ が起動します。 他の選択肢 シビアに費用を抑える必要がない場合 、一時停止設定を無効にし、0 ACUにスケールダウンしないようにすれば、データベースへのアクセスがなくても停止しなくなり、本記事で述べるような ワークアラウンド は必要ありません。 あるいは 0 ACUにスケールダウンした後の初回接続が失敗しても、 起動を待ってからクエリを再実行することが許容できる場合 も、本記事の ワークアラウンド は必要ありません。 CDKコード 以下のCDKコードで環境を作成します。 import { Duration , Stack , StackProps } from "aws-cdk-lib" ; import * as ec2 from "aws-cdk-lib/aws-ec2" ; import * as events from "aws-cdk-lib/aws-events" ; import * as eventTargets from "aws-cdk-lib/aws-events-targets" ; import * as iam from "aws-cdk-lib/aws-iam" ; import * as lambda from "aws-cdk-lib/aws-lambda" ; import * as lambdaNodejs from "aws-cdk-lib/aws-lambda-nodejs" ; import * as rds from "aws-cdk-lib/aws-rds" ; import { Construct } from "constructs" ; export class MyStack extends Stack { constructor( scope: Construct , id: string , props?: StackProps ) { super( scope , id , props ); const privateSubnetName = "myPrivateSubnet" ; // VPCを作成 const vpc = new ec2.Vpc ( this , "MyVpc" , { cidr: "10.0.0.0/16" , enableDnsHostnames: true , enableDnsSupport: true , subnetConfiguration: [ { name: privateSubnetName , subnetType: ec2.SubnetType.PRIVATE_ISOLATED , cidrMask: 20 , } , ] , } ); // Aurora Serverless v1 クラスタを作成 const auroraCluseter = new rds.ServerlessCluster ( this , "MyAuroraCluster" , { engine: rds.DatabaseClusterEngine.AURORA_MYSQL , vpc: vpc , vpcSubnets: { subnetGroupName: privateSubnetName } , // 最小ACUを1、最大ACUを2、一時停止までに必要な非アクティブ時間を2時間に指定 scaling: { minCapacity: 1 , maxCapacity: 2 , autoPause: Duration.hours ( 2 ) } , // Data APIを有効化 enableDataApi: true , } ); // Lambda関数 const awakeAuroraFunction = new lambdaNodejs.NodejsFunction ( this , "MyFunction" , { // Lambda関数へのファイルパス entry: "functions/awake-aurora-serverless.ts" , runtime: lambda.Runtime.NODEJS_14_X , // Data APIを利用するため、AuroraクラスタARNとシークレットのARNを環境変数で渡す environment: { CLUSTER_ARN: auroraCluseter.clusterArn , SECRET_ARN: auroraCluseter.secret?.secretArn ?? "" , } , } ); // Lambda関数の実行ロールにData APIへのアクセスを許可するポリシーを追加 if ( auroraCluseter.secret?.secretArn ) { const auroraDataApiPolicy = new iam.ManagedPolicy ( this , "MyAuroraDataApiPolicy" , { statements: [ new iam.PolicyStatement ( { resources: [ ` ${ auroraCluseter.secret.secretArn } *` ] , actions: [ "secretsmanager:GetSecretValue" ] , effect: iam.Effect.ALLOW , } ), new iam.PolicyStatement ( { resources: [ auroraCluseter.clusterArn ] , actions: [ "rds-data:ExecuteStatement" ] , effect: iam.Effect.ALLOW , } ), ] , } ); awakeAuroraFunction.role?.addManagedPolicy ( auroraDataApiPolicy ); } // 日本時間 平日の 7:00 ~ 20:00 の間に1時間ごとにLambda関数を定期起動する // cron式は UTC で記載するため、「日曜 ~ 木曜の22:00 ~ 23:00」と「月曜 ~ 金曜の 0:00 ~ 11:00」の2つに分ける new events.Rule ( this , "MyEventRule1" , { schedule: events.Schedule.cron ( { minute: "0" , hour: "22-23" , weekDay: "SUN-THU" } ), targets: [ new eventTargets.LambdaFunction ( awakeAuroraFunction , { retryAttempts: 3 } ) ] , } ); new events.Rule ( this , "MyEventRule2" , { schedule: events.Schedule.cron ( { minute: "0" , hour: "0-11" , weekDay: "MON-FRI" } ), targets: [ new eventTargets.LambdaFunction ( awakeAuroraFunction , { retryAttempts: 3 } ) ] , } ); } } Lambda関数の部分では、 NodejsFunction コンストラクト を利用することで、TypeScript で記述した Lambda 関数の JavaScript への コンパイル からデプロイまでをCDKがやってくれます。 Aurora クラスタ へクエリを発行するLambda関数は、 functions/awake-aurora-serverless.ts に以下のように実装します。Data API を利用してクエリを発行します。 import * as RDS from "@aws-sdk/client-rds-data" ; import { Handler } from "aws-lambda" ; const client = new RDS.RDSDataClient ( { region: "ap-northeast-1" } ); export const handler: Handler = async () => { const input = { // Data APIを利用するための、AuroraクラスタのリソースARNとシークレットのARNを環境変数から取得する resourceArn: process .env.CLUSTER_ARN , secretArn: process .env.SECRET_ARN , // 発行するSQL文 sql: "SHOW databases;" , } ; const command = new RDS.ExecuteStatementCommand ( input ); await client.send ( command ); } ; 発行する SQL 文は更新系でなければ何でも良いですが、シンプルに SHOW databases; としています。 実際の料金 以上の構成でしばらく稼働した場合の料金を確認しました。 土日はAurora クラスタ が停止し、料金がかかっていないことがわかります。平日も24時間のうち15時間しか稼働していません。 今回の条件では一週間 24h * 7日 = 168h のうち、 15h * 5日 = 75h 稼働しているため、常時稼働に比べて 75h / 168h = 45% の費用に抑えることができています。 一方で平日の業務時間中は常に稼働状態のため、接続が失敗することがなくなり、今回の要件を満たすことができました。 執筆: @kou.kinyo2 、レビュー: @higa ( Shodo で執筆されました )
こんにちは、 電通国際情報サービス デジタル イノベーション 1部の加世です。 今回は「FluentBitを利用したログルーティング」を進める際に、「FluentBitについて理解する」ことを目的とした記事となっております。 具体的なFluentBitの使い所や設計を考える前段階として、本記事を参考にしていただければと思います。 Fluent Bitについて Fluent Bitの特徴 検証環境と処理フローについて Fluent Bit設計前の準備 データパイプラインの理解 データの構造化について まとめ Fluent Bitについて FluentBitは、データ(メトリクス、ログ、それ以外の生情報など)をInput情報として収集し、加工処理したうえで任意の転送先に転送します。 クラウド サービスプロバイダを利用するうえでは、既に「システム」から「サービス」に転送する仕組みを用意していることが多いため、ログルーティングについて考慮しなくても問題ないケースが多いです。 そのため、FluentBitの利用は「複数のシステム(サーバ/コンテナ)」から「様々なデータ」を「複数の宛先」に「加工」して「集約」する場合が有効であると考えています。 FluentdとFluent Bitの違いについて ■Fluentd&Fluent Bit https://docs.fluentbit.io/manual/about/fluentd-and-fluent-bit FluentBitは、Fluentd傘下で開発された軽量なログルータであり、Fluentdの アーキテクチャ を踏まえて構築されています。 Fluent Bitの特徴 FluentBitは、大きく6種類「Input」->「Parse」->「Filter」->「Buffer」->「Router」->「Output」のPluginで構成されています。 また、「Output」 プラグイン は、主要な クラウド サービスプロバイダ( AWS , Azure, GCP , Datadog...etc)に対応しています。 そのため、データ転送先は アーキテクチャ ・データ分析方法を踏まえて、 プラグイン の対応範囲はありますがさまざまなサービスを選択できます。 FluentBitは、次の点で優れていると考えています。 優れていると考えられる点 Input/Output プラグイン でさまざまなソースと出力先を選択できる。 生データをParseして構造化して出力できる。 同じデータを複数出力先に対して、同時にルーティングできる。 一般的に必要とされる機能を備えた プラグイン が提供されている。 Fluent Bit ■ GitHub : Fluent Bit https://github.com/fluent/fluent-bit ■Fluent Bit : Official Manual https://docs.fluentbit.io/manual ■Release Notes https://fluentbit.io/announcements/ FluentBitに関する情報は、こちらを参照してください。 検証環境と処理フローについて 検証環境は、「 AWS Fargate」で「テストアプリケーションコンテナ (Firelensログドライバ付き)」「FluentBitコンテナ」を稼働しています。 また、FluentBitは、ログルーティング先として複数の転送先「CloudWatch」「S3」を指定します。 ※FluentBitコンテナを使用できる環境であれば、FluentBitの基礎的な機能は検証できます。 ※検証環境のホストOS カーネル パラメータ設定によっては、挙動が変わる場合はあります。 ※FireLensログドライバは、Fargate標準出力(stdout/stderr)をFluentBitにログルーティングするためだけに使用します。 AWS FargateでFirelensログドライバを利用して、標準出力をFluentBitに送信する方式について Firelensログドライバは、仕様を細かく確認していませんが「td-agent」の仕組みでFluentBitのInput プラグイン 「Forward」を利用して標準出力を転送していると思われます。 そのため、タグは「<コンテナ名>-firelens」となるため、必要に応じて「 rewrite _tags」などでタグを変更することで、Output プラグイン でのタグ条件指定がしやすくなります。 処理フロー アプリケーション(stdout/stderr) -> Firelensログドライバ -> (forward:24224) -> サイドカー コンテナ(FluentBit) -> CloudWatch/S3 アプリケーション(ローカルファイル) -> (tail:Volume共有マウント) -> サイドカー コンテナ(FluentBit) -> CloudWatch/S3 AWS 専用のFluentBitコンテナ https://docs.fluentbit.io/manual/installation/getting-started-with-fluent-bit AWS に最適化されたFluentBitコンテナが提供されています。 マニュアルにしたがって、 サイドカー コンテナとして起動します。 aws -for-fluent-bit AWS Fargateの場合は、「Firelens」ログドライバと連携して「 aws -for-fluent-bit」が一部設定を自動生成します。 また、オプション設定をすることで追加のFluentBit設定ファイルを読み込むことも可能です。 GitHub https://github.com/aws/aws-for-fluent-bit https://github.com/aws/amazon-cloudwatch-logs-for-fluent-bit Release Notes https://github.com/aws/aws-for-fluent-bit/releases IAMロール設定について 「 aws -for-fluent-bit」コンテナは出力先となる「CloudWatch」「S3」などに対して操作権限が必要になります。 そのため、Fargateコンテナを前提とした場合は「ECSタスクロール」に設定しておく必要があります。 なお、 AWS 以外から「CloudWatch」「S3」に転送する場合は、FluentBit向けのIAMロールを用意して「cloudwatch」「S3」 プラグイン でIAMロールを指定して使用できます。 Fluent Bit設計前の準備 データパイプラインの理解 FluentBitを設計するうえで、データパイプライン「Input」->「Parse」->「Filter」->「Buffer」->「Router」->「Output」を理解する必要があります。 Input https://docs.fluentbit.io/manual/pipeline/inputs 「Forward( TCP リスナポート経由のメッセージ受信)」「tail(ローカルファイスシステム上のログファイルなどのtail)」などで「生データ」の入力を受け付けます。 他にもメトリクスデータを取得する プラグイン も多数用意されています。 Parse https://docs.fluentbit.io/manual/pipeline/parsers Input プラグイン で受け取ったデータを「Parser」で処理することにより、「データ構造化」や「 マルチライン 処理」を行います。 「Input」「Filter」 プラグイン で使用できます。 データ構造化 「生データ(log)」を「時間(time)」「レベル(level)」「メッセージ(message)」などのフィールドに分割します。 事前に用意されているParser https://docs.fluentbit.io/manual/pipeline/parsers/configuring-parser 「 Apache 」「Docker」などは構造化を目的として、すでにParserが用意されています。 マルチライン 処理 複数行データ(たとえば、 Java スタックトレース の「at」など)を1つのデータとして扱います。 ※なお、「\n」「\t」が エス ケープされずにファイル出力されますが、回避方法は執筆時点で未調査です。 処理前 { "hostname": "ip-172-24-136-132.ap-northeast-1.compute.internal", "level": "EROROR", "message": "org.apache.catalina.startup.Catalina.start Server startup in 135176 ms", "thread": "main", "time": "02-Mar-2022 15:33:32.000" } { "hostname": "ip-172-24-136-132.ap-northeast-1.compute.internal", "level": "EROROR", "message": "\tat com.myproject.module.MyProject.badMethod(MyProject.java:22)", "thread": "main", "time": "02-Mar-2022 15:33:32.000" } { "hostname": "ip-172-24-136-132.ap-northeast-1.compute.internal", "level": "EROROR", "message": "\tat com.myproject.module.MyProject.oneMoreMethod(MyProject.java:18)", "thread": "main", "time": "02-Mar-2022 15:33:32.000" } 処理後 { "hostname": "ip-172-24-136-132.ap-northeast-1.compute.internal", "level": "EROROR", "message": "org.apache.catalina.startup.Catalina.start Server startup in 135176 ms\n\tat com.myproject.module.MyProject.badMethod(MyProject.java:22)\n\tat com.myproject.module.MyProject.oneMoreMethod(MyProject.java:18)", "thread": "main", "time": "02-Mar-2022 15:33:32.000" } Filter https://docs.fluentbit.io/manual/pipeline/filters 入力された「生データ」を「Filter」で加工(追加・変更・整形・削除 etc)します。 「Parser」「Multiline(Parser)」「Record Modifier」「 Rewrite Tag」「 Lua 」「 Kubernetes 」などがあります。 ※「 AWS Metadata」はEC2向けであり、Fargate向けのものではありません。(Fargate自体は、 メタデータ を参照するURLは提供されています) Buffer https://docs.fluentbit.io/manual/concepts/buffering 生データを保管する領域として、「メモリ」または「 ファイルシステム (永続領域)」を選択できます。 「Service」「Input」「Output」 プラグイン などで定義します。 なお、「処理間隔(メモリリフレッシュ、データ出力などのタイミング)」「各種バッファサイズ(ファイル初期読み込みサイズなど)」はチューニング要素となります。 補足 通常は、「メモリ」のみを選択する方針で問題ありません。 生データの過去分までの情報(オフセットなど)を持っておきたい場合は、「 ファイルシステム 」を選択します。 Fargateなどを前提とした エフェメラ ルストレージを利用する場合は、コンテナ内のメトリクス・ログデータなどは更新時に初期化されるため「メモリ」を採用する点は問題ありません。 一方で、データ分析などで永続領域にあるデータを漏れなく・重複なく読み込む必要がある場合は、EFSと連携するなどの永続領域のデータを参照する構成が必要になります。 Router https://docs.fluentbit.io/manual/concepts/data-pipeline/router 出力対象となるデータは、Input時点でデータとひもづけられたTag(または、Filterで書き換えられたTag)をもとに「識別」できるようにします。 そのうえで、正しく条件を指定することで適切な出力先に出力します。 ルーティング条件は、Output プラグイン の「Match( ワイルドカード 指定のみ)」と「Match_ regex 」により一致条件を設定します。 Output https://docs.fluentbit.io/manual/pipeline/outputs 「 クラウド サービスプロバイダ向けのストレージサービス」「ローカルログファイル」「FluentBitコンテナの標準出力」などに対して「データ」を出力します。 データの構造化について Inputデータは、「データフィールド名の追加・加工」「データ値の追加・加工」が可能です。 Inputデータが JSON 形式であり、すでに構造化されているデータの場合は、そのまま「フィールド名(キー名)」「値」を利用することが多いと考えられます。 ※ただし、どのようなデータでも「Filter」 プラグイン により追加の加工処理は可能です。 フィールドの追加・加工 Inputデータは、「Filter」 プラグイン でデータフィールド名を追加・加工できます。 Firelensログドライバ経由でInputした標準出力・ 標準エラー出力 は、「container_id」「container_name」「log」「source」フィールドをInputします。 これは既に構造化されたInputデータですが、例えば「log」「source」に対して「キ名ー(フィールド名)」を統一する目的で「message」「file_path」に変換できます。 また、追加の加工処理としてコンテナ内の 環境変数 「$HOSTNAME」の情報をもとに、「hostname」フィールドを追加できます。 Inputデータ { "container_id": "3885a532543547978adf8d6e9bdf729b-2449111020", "container_name": "test-container", "log": "test message.", "source": "stdout" } { "container_id": "625a41f4c1a241f49e7308b9g62911cb-1475094415", "container_name": "test-container", "log": "java.io.IOException: listener timeout after waiting for [60000] ms", "source": "stderr" } 加工済みデータ { "container_id": "3885a532543547978adf8d6e9bdf729b-2449111020", "container_name": "test-container", "file_path": "stdout", "hostname": "ip-172-24-100-100.ap-northeast-1.compute.internal", "message": "test message.", } { "container_id": "625a41f4c1a241f49e7308b9g62911cb-1475094415", "container_name": "test-container", "file_path": "stderr" "hostname": "ip-172-24-100-100.ap-northeast-1.compute.internal", "message": "java.io.IOException: listener timeout after waiting for [60000] ms", } データ値の追加・加工 Inputデータは、「Filter」 プラグイン でデータ値を追加・加工できます。 Docker標準出力などであれば、すでに「Parser」 プラグイン として用意されているパーサ「docker」を利用できます。 事前に用意されているParserで構造化が難しい場合は、独自にParserを定義できます。 たとえば、以下に示す独自の「Parser」 プラグイン 定義は、 Tomcat の標準出力ログを加工します。 これは、Inputデータのログを Regex に指定した 正規表現 でパースして、「time」「level」「thread」「message」などのフィールド名に マッピング します。 「Parser」 プラグイン 定義 [PARSER] Name tomcat Format regex Regex /^(?<time>\d{1,2}-\D{3}-\d{4} \d{1,2}:\d{1,2}:\d{1,2}.\d{3}) (?<level>[^\s]+) \[(?<thread>[^\]]*)\] (?<message>.*)/ Time_Key time Time_Format %d-%b-%Y %H:%M:%S.%L Time_Offset +0900 Time_Keep On # Command | Decoder | Field | Optional Action | # ==============|==============|=========|===================| Decode_Field_As escaped message インプットデータ 04-Mar-2022 12:34:39.072 ERROR [main] org.apache.catalina.startup.Catalina.start Server startup in 123094 ms 加工済みデータ { "file_path": "/usr/local/tomcat/logs/catalina.test.log", "hostname": "ip-172-24-136-164.ap-northeast-1.compute.internal", "level": "EROROR", "message": "org.apache.catalina.startup.Catalina.start Server startup in 135176 ms\n\tat com.myproject.module.MyProject.badMethod(MyProject.java:22)\n\tat com.myproject.module.MyProject.oneMoreMethod(MyProject.java:18)\n\tat com.myproject.module.MyProject.anotherMethod(MyProject.java:14)\n\tat com.myproject.module.MyProject.someMethod(MyProject.java:10)\n\tat com.myproject.module.MyProject.main(MyProject.java:6)", "thread": "main", "time": "04-Mar-2022 12:42:28.000" } まとめ 本記事では、「FluentBitについて理解する」ことを目的として記事を作成しました。 次回の記事では、「FluentBitを実際に動かしたうえで確認した設計・設定ポイント」をお話できればと考えています。 執筆: @kase.teruyoshi 、レビュー: @sato.taichi ( Shodo で執筆されました )
こんにちは、 電通国際情報サービス デジタル イノベーション 1部の加世です。 今回は「FluentBitを利用したログルーティング」を進める際に、「FluentBitについて理解する」ことを目的とした記事となっております。 具体的なFluentBitの使い所や設計を考える前段階として、本記事を参考にしていただければと思います。 Fluent Bitについて Fluent Bitの特徴 検証環境と処理フローについて Fluent Bit設計前の準備 データパイプラインの理解 データの構造化について まとめ Fluent Bitについて FluentBitは、データ(メトリクス、ログ、それ以外の生情報など)をInput情報として収集し、加工処理したうえで任意の転送先に転送します。 クラウド サービスプロバイダを利用するうえでは、既に「システム」から「サービス」に転送する仕組みを用意していることが多いため、ログルーティングについて考慮しなくても問題ないケースが多いです。 そのため、FluentBitの利用は「複数のシステム(サーバ/コンテナ)」から「様々なデータ」を「複数の宛先」に「加工」して「集約」する場合が有効であると考えています。 FluentdとFluent Bitの違いについて ■Fluentd&Fluent Bit https://docs.fluentbit.io/manual/about/fluentd-and-fluent-bit FluentBitは、Fluentd傘下で開発された軽量なログルータであり、Fluentdの アーキテクチャ を踏まえて構築されています。 Fluent Bitの特徴 FluentBitは、大きく6種類「Input」->「Parse」->「Filter」->「Buffer」->「Router」->「Output」のPluginで構成されています。 また、「Output」 プラグイン は、主要な クラウド サービスプロバイダ( AWS , Azure, GCP , Datadog...etc)に対応しています。 そのため、データ転送先は アーキテクチャ ・データ分析方法を踏まえて、 プラグイン の対応範囲はありますがさまざまなサービスを選択できます。 FluentBitは、次の点で優れていると考えています。 優れていると考えられる点 Input/Output プラグイン でさまざまなソースと出力先を選択できる。 生データをParseして構造化して出力できる。 同じデータを複数出力先に対して、同時にルーティングできる。 一般的に必要とされる機能を備えた プラグイン が提供されている。 Fluent Bit ■ GitHub : Fluent Bit https://github.com/fluent/fluent-bit ■Fluent Bit : Official Manual https://docs.fluentbit.io/manual ■Release Notes https://fluentbit.io/announcements/ FluentBitに関する情報は、こちらを参照してください。 検証環境と処理フローについて 検証環境は、「 AWS Fargate」で「テストアプリケーションコンテナ (Firelensログドライバ付き)」「FluentBitコンテナ」を稼働しています。 また、FluentBitは、ログルーティング先として複数の転送先「CloudWatch」「S3」を指定します。 ※FluentBitコンテナを使用できる環境であれば、FluentBitの基礎的な機能は検証できます。 ※検証環境のホストOS カーネル パラメータ設定によっては、挙動が変わる場合はあります。 ※FireLensログドライバは、Fargate標準出力(stdout/stderr)をFluentBitにログルーティングするためだけに使用します。 AWS FargateでFirelensログドライバを利用して、標準出力をFluentBitに送信する方式について Firelensログドライバは、仕様を細かく確認していませんが「td-agent」の仕組みでFluentBitのInput プラグイン 「Forward」を利用して標準出力を転送していると思われます。 そのため、タグは「<コンテナ名>-firelens」となるため、必要に応じて「 rewrite _tags」などでタグを変更することで、Output プラグイン でのタグ条件指定がしやすくなります。 処理フロー アプリケーション(stdout/stderr) -> Firelensログドライバ -> (forward:24224) -> サイドカー コンテナ(FluentBit) -> CloudWatch/S3 アプリケーション(ローカルファイル) -> (tail:Volume共有マウント) -> サイドカー コンテナ(FluentBit) -> CloudWatch/S3 AWS 専用のFluentBitコンテナ https://docs.fluentbit.io/manual/installation/getting-started-with-fluent-bit AWS に最適化されたFluentBitコンテナが提供されています。 マニュアルにしたがって、 サイドカー コンテナとして起動します。 aws -for-fluent-bit AWS Fargateの場合は、「Firelens」ログドライバと連携して「 aws -for-fluent-bit」が一部設定を自動生成します。 また、オプション設定をすることで追加のFluentBit設定ファイルを読み込むことも可能です。 GitHub https://github.com/aws/aws-for-fluent-bit https://github.com/aws/amazon-cloudwatch-logs-for-fluent-bit Release Notes https://github.com/aws/aws-for-fluent-bit/releases IAMロール設定について 「 aws -for-fluent-bit」コンテナは出力先となる「CloudWatch」「S3」などに対して操作権限が必要になります。 そのため、Fargateコンテナを前提とした場合は「ECSタスクロール」に設定しておく必要があります。 なお、 AWS 以外から「CloudWatch」「S3」に転送する場合は、FluentBit向けのIAMロールを用意して「cloudwatch」「S3」 プラグイン でIAMロールを指定して使用できます。 Fluent Bit設計前の準備 データパイプラインの理解 FluentBitを設計するうえで、データパイプライン「Input」->「Parse」->「Filter」->「Buffer」->「Router」->「Output」を理解する必要があります。 Input https://docs.fluentbit.io/manual/pipeline/inputs 「Forward( TCP リスナポート経由のメッセージ受信)」「tail(ローカルファイスシステム上のログファイルなどのtail)」などで「生データ」の入力を受け付けます。 他にもメトリクスデータを取得する プラグイン も多数用意されています。 Parse https://docs.fluentbit.io/manual/pipeline/parsers Input プラグイン で受け取ったデータを「Parser」で処理することにより、「データ構造化」や「 マルチライン 処理」を行います。 「Input」「Filter」 プラグイン で使用できます。 データ構造化 「生データ(log)」を「時間(time)」「レベル(level)」「メッセージ(message)」などのフィールドに分割します。 事前に用意されているParser https://docs.fluentbit.io/manual/pipeline/parsers/configuring-parser 「 Apache 」「Docker」などは構造化を目的として、すでにParserが用意されています。 マルチライン 処理 複数行データ(たとえば、 Java スタックトレース の「at」など)を1つのデータとして扱います。 ※なお、「\n」「\t」が エス ケープされずにファイル出力されますが、回避方法は執筆時点で未調査です。 処理前 { "hostname": "ip-172-24-136-132.ap-northeast-1.compute.internal", "level": "EROROR", "message": "org.apache.catalina.startup.Catalina.start Server startup in 135176 ms", "thread": "main", "time": "02-Mar-2022 15:33:32.000" } { "hostname": "ip-172-24-136-132.ap-northeast-1.compute.internal", "level": "EROROR", "message": "\tat com.myproject.module.MyProject.badMethod(MyProject.java:22)", "thread": "main", "time": "02-Mar-2022 15:33:32.000" } { "hostname": "ip-172-24-136-132.ap-northeast-1.compute.internal", "level": "EROROR", "message": "\tat com.myproject.module.MyProject.oneMoreMethod(MyProject.java:18)", "thread": "main", "time": "02-Mar-2022 15:33:32.000" } 処理後 { "hostname": "ip-172-24-136-132.ap-northeast-1.compute.internal", "level": "EROROR", "message": "org.apache.catalina.startup.Catalina.start Server startup in 135176 ms\n\tat com.myproject.module.MyProject.badMethod(MyProject.java:22)\n\tat com.myproject.module.MyProject.oneMoreMethod(MyProject.java:18)", "thread": "main", "time": "02-Mar-2022 15:33:32.000" } Filter https://docs.fluentbit.io/manual/pipeline/filters 入力された「生データ」を「Filter」で加工(追加・変更・整形・削除 etc)します。 「Parser」「Multiline(Parser)」「Record Modifier」「 Rewrite Tag」「 Lua 」「 Kubernetes 」などがあります。 ※「 AWS Metadata」はEC2向けであり、Fargate向けのものではありません。(Fargate自体は、 メタデータ を参照するURLは提供されています) Buffer https://docs.fluentbit.io/manual/concepts/buffering 生データを保管する領域として、「メモリ」または「 ファイルシステム (永続領域)」を選択できます。 「Service」「Input」「Output」 プラグイン などで定義します。 なお、「処理間隔(メモリリフレッシュ、データ出力などのタイミング)」「各種バッファサイズ(ファイル初期読み込みサイズなど)」はチューニング要素となります。 補足 通常は、「メモリ」のみを選択する方針で問題ありません。 生データの過去分までの情報(オフセットなど)を持っておきたい場合は、「 ファイルシステム 」を選択します。 Fargateなどを前提とした エフェメラ ルストレージを利用する場合は、コンテナ内のメトリクス・ログデータなどは更新時に初期化されるため「メモリ」を採用する点は問題ありません。 一方で、データ分析などで永続領域にあるデータを漏れなく・重複なく読み込む必要がある場合は、EFSと連携するなどの永続領域のデータを参照する構成が必要になります。 Router https://docs.fluentbit.io/manual/concepts/data-pipeline/router 出力対象となるデータは、Input時点でデータとひもづけられたTag(または、Filterで書き換えられたTag)をもとに「識別」できるようにします。 そのうえで、正しく条件を指定することで適切な出力先に出力します。 ルーティング条件は、Output プラグイン の「Match( ワイルドカード 指定のみ)」と「Match_ regex 」により一致条件を設定します。 Output https://docs.fluentbit.io/manual/pipeline/outputs 「 クラウド サービスプロバイダ向けのストレージサービス」「ローカルログファイル」「FluentBitコンテナの標準出力」などに対して「データ」を出力します。 データの構造化について Inputデータは、「データフィールド名の追加・加工」「データ値の追加・加工」が可能です。 Inputデータが JSON 形式であり、すでに構造化されているデータの場合は、そのまま「フィールド名(キー名)」「値」を利用することが多いと考えられます。 ※ただし、どのようなデータでも「Filter」 プラグイン により追加の加工処理は可能です。 フィールドの追加・加工 Inputデータは、「Filter」 プラグイン でデータフィールド名を追加・加工できます。 Firelensログドライバ経由でInputした標準出力・ 標準エラー出力 は、「container_id」「container_name」「log」「source」フィールドをInputします。 これは既に構造化されたInputデータですが、例えば「log」「source」に対して「キ名ー(フィールド名)」を統一する目的で「message」「file_path」に変換できます。 また、追加の加工処理としてコンテナ内の 環境変数 「$HOSTNAME」の情報をもとに、「hostname」フィールドを追加できます。 Inputデータ { "container_id": "3885a532543547978adf8d6e9bdf729b-2449111020", "container_name": "test-container", "log": "test message.", "source": "stdout" } { "container_id": "625a41f4c1a241f49e7308b9g62911cb-1475094415", "container_name": "test-container", "log": "java.io.IOException: listener timeout after waiting for [60000] ms", "source": "stderr" } 加工済みデータ { "container_id": "3885a532543547978adf8d6e9bdf729b-2449111020", "container_name": "test-container", "file_path": "stdout", "hostname": "ip-172-24-100-100.ap-northeast-1.compute.internal", "message": "test message.", } { "container_id": "625a41f4c1a241f49e7308b9g62911cb-1475094415", "container_name": "test-container", "file_path": "stderr" "hostname": "ip-172-24-100-100.ap-northeast-1.compute.internal", "message": "java.io.IOException: listener timeout after waiting for [60000] ms", } データ値の追加・加工 Inputデータは、「Filter」 プラグイン でデータ値を追加・加工できます。 Docker標準出力などであれば、すでに「Parser」 プラグイン として用意されているパーサ「docker」を利用できます。 事前に用意されているParserで構造化が難しい場合は、独自にParserを定義できます。 たとえば、以下に示す独自の「Parser」 プラグイン 定義は、 Tomcat の標準出力ログを加工します。 これは、Inputデータのログを Regex に指定した 正規表現 でパースして、「time」「level」「thread」「message」などのフィールド名に マッピング します。 「Parser」 プラグイン 定義 [PARSER] Name tomcat Format regex Regex /^(?<time>\d{1,2}-\D{3}-\d{4} \d{1,2}:\d{1,2}:\d{1,2}.\d{3}) (?<level>[^\s]+) \[(?<thread>[^\]]*)\] (?<message>.*)/ Time_Key time Time_Format %d-%b-%Y %H:%M:%S.%L Time_Offset +0900 Time_Keep On # Command | Decoder | Field | Optional Action | # ==============|==============|=========|===================| Decode_Field_As escaped message インプットデータ 04-Mar-2022 12:34:39.072 ERROR [main] org.apache.catalina.startup.Catalina.start Server startup in 123094 ms 加工済みデータ { "file_path": "/usr/local/tomcat/logs/catalina.test.log", "hostname": "ip-172-24-136-164.ap-northeast-1.compute.internal", "level": "EROROR", "message": "org.apache.catalina.startup.Catalina.start Server startup in 135176 ms\n\tat com.myproject.module.MyProject.badMethod(MyProject.java:22)\n\tat com.myproject.module.MyProject.oneMoreMethod(MyProject.java:18)\n\tat com.myproject.module.MyProject.anotherMethod(MyProject.java:14)\n\tat com.myproject.module.MyProject.someMethod(MyProject.java:10)\n\tat com.myproject.module.MyProject.main(MyProject.java:6)", "thread": "main", "time": "04-Mar-2022 12:42:28.000" } まとめ 本記事では、「FluentBitについて理解する」ことを目的として記事を作成しました。 次回の記事では、「FluentBitを実際に動かしたうえで確認した設計・設定ポイント」をお話できればと考えています。 執筆: @kase.teruyoshi 、レビュー: @sato.taichi ( Shodo で執筆されました )
皆さんこんにちは!金融ソリューション事業部 市場系ソリューション1部の寺山です。 かなり温かく、というか暑くなってきましたね。私は、今の時期から冷房に頼ると本場の夏の暑さに耐えられないぞ!という戦略で冷房を使うのを我慢しています。 これまではインフラ/ クラウド 関連の記事を投稿してきた私ですが、今回は打って変わってローコード関連の内容となります。背景を踏まえてローコードツール:Power Appsを用いて実現した内容をご紹介したいと思います! 背景 Power Appsを作成 アプリの作成とコネクタの追加 初期化 カレンダーの描画 表示する年/月のセレクタ あとはカレンダーらしさが出る修飾 ローコードをはじめてちゃんと触ってみた感想 参考文献/記事 背景 私は、昨年度の弊社 アドベントカレンダー で記事を投稿した以降に、当テックブログの運営チームに参加しました。 テックブログの運営において、誰がいつ投稿する予定なのか?/投稿の途切れてしまう期間があるか?といった観点で、 執筆状況をカレンダー形式で可視化したいよね という意見が生まれました。 結論として、 Microsoft Plannerで執筆タスクを管理することにより上記の目的を達成しようとなりました。理由は以下のとおりです。 Plannerにはカレンダー機能がある。 機能がシンプルであり、厳密なタスク管理ルールを策定しないことにより執筆者・運営側の双方の負荷にならないよう、執筆管理を運用可能と考えた。 1. でカレンダー形式で可視化するという当初の目的は達成しました。加えて、弊社内でテックブログの活動や執筆ガイドを共有するための SharePoint ポータルサイト を構築していたため、そこにカレンダー形式として埋め込むことで、 活動状況を執筆メンバー以外にも共有したいよね! という考えに発展しました。 そこで、プレビュー版ではあるもののWebパーツが提供されているPower Appsを用いてカレンダーを作成し、 SharePoint に埋め込んでみようと思い立ったのが背景となります。 実際に埋め込んだ PowreAppsは以下のように表示されます! Power Appsを作成 前述のPower Appsアプリをどのように作成したのかを簡単にご紹介します。 作業はすべてPower AppsのWebコンソールにて行いました。 私はPower Appsについて無知な状態からスタートしたため、Power Appsの各機能や コンポーネント (Power Apps用語ではコン トロール )の説明は割愛し、全体的な流れの説明に比重を置かせていただきます。 アプリの作成とコネクタの追加 まずはアプリを作成します。Power Appsのサブメニューより、 作成 > 空のキャンバスアプリ > 作成 と選択し、アプリ名を設定して空のキャンバスアプリを作成します。 私は利用していませんが、PowreAppsではアプリのテンプレートも提供されています。 形式 ですが、 SharePoint の ポータルサイト は弊社の社員が業務中にPCから参照するケースの方が多いと考え、 タブレット を選択しました。 次はコネクタの追加です。Power Apps で表示/加工するデータは、Office365の他のアプリケーションや サードパーティ ツール( DBMS やDWHなど)を データソース として コネクタ で接続して取得します。 今回利用したコネクタは以下のとおりです。 Planner:カレンダーに表示するPlannerタスクや バケット の取得に利用 O365Group:タスクの担当者名の取得に利用 コネクタの追加は、サブメニューの データ > データの追加 より行います。データソースに対する認証情報に自身のOffice365アカウントを指定します。 初期化 キャンバスアプリのトップエンティティはスクリーンです。空のキャンバスアプリを作成すると執筆時点のデフォルトではスクリーンのみが作成された状態となります。 私の作成した Power Apps ではスクリーンの OnVisible プロパティに以下の関数を設定することで、Power Appsの描画時に初期化がされるようにしました。 // 共通して使用する変数の宣言 UpdateContext ( { planId : "<PlannerのPlanID>" , groupId : "<PlannerのGroupID>" , officeGroupId : "<PlannerのGroupID>" , weekDay :[ "Sun." , "Mon." , "Tue." , "Wed." , "Thu." , "Fri." , "Sat." ] } ); // カレンダーとして表示対象の月の1日と月末の日付を設定 UpdateContext ( { startOfMonth : Date (TextInputYear_1.Text,DropdownMonth_1.Selected.Value, 1 ), endOfMonth : Date (TextInputYear_1.Text,DropdownMonth_1.Selected.Value + 1 , 1 )- 1 } ); // カレンダーに表示する開始日と終了日を計算 UpdateContext ( { fromDate :startOfMonth-( Weekday (startOfMonth, 1 )- 1 ), toDate :endOfMonth+( 7 - Weekday (endOfMonth, 1 )) } ); // PlannerとOffice365Groupデータソースから、Plannerタスク一覧、Plannerのバケット一覧、Office365Groupのメンバー一覧を取得してテーブルに格納 UpdateContext ( { tasks :Planner. ListTasksV3 (planId,groupId).value, buckets :Planner. ListBucketsV3 (planId,groupId).value, members :O365Group. ListGroupMembers (officeGroupId).value } ); // カレンダーに表示する開始日から終了日までの全日付をテーブルに格納 UpdateContext ( { days : ForAll ( Sequence (toDate-fromDate+ 1 ), DateAdd (fromDate- 1 ,Value,Days)) } ) UpdateContext はスクリーンがスコープとなる変数を宣言/更新する関数です。 以下は各UpdateContextブロックに対する補足です。 1つ目のブロックで変数の値に設定している PlannerのPlanID と PlannerのGroupID はPlannerのURLから確認可能です。 2つ目のブロックでは、後述する TextInputYear_1 という テキスト入力 コン トロール の初期値と、 DropdownMonth_1 という ドロップダウン コン トロール の初期値から取得しています。 5つ目のブロックの ForAll は、第一引数のテーブルに対して第二引数の操作を繰り返す関数です。 Sequence 関数を使用してカレンダーに表示する開始日から終了日までのインデックスのテーブルを作成して、カレンダーの開始日からインデックスを相対距離として日付を計算することで、カレンダーの開始から終了日までに含まれる全日付のテーブルを作成しています。 Power Apps上での作業は以下のようになります。 カレンダーの描画 カレンダー風に描画するために、2つの ギャラリー コン トロール を作成しています。 ギャラリーとは、指定したデータに対し、他のコン トロール をテンプレートとして展開可能なコンテナ型のコン トロール です。 1つ目のギャラリーは、カレンダーの曜日を表示するための水平ギャラリーです。 前のセクションで初期化した weekday テーブルをギャラリーの Items プロパティに指定し、ギャラリー内には テキストラベル コン トロール を配置しています。 テキストラベルに表示する Text プロパティで以下の関数を指定することで、曜日の表す列のように描画しています。 ThisItem にはギャラリーの Items プロパティに指定したテーブルの要素が格納されます。 ThisItem.Value 2つ目はカレンダーの各日のボックスを表現する水平ギャラリーです。 Items プロパティには前のセクションで初期化した days テーブルを指定しています。 水平ギャラリーには、まず垂直コンテナを配置し、内部に配置する2つのコン トロール の位置関係と描画範囲を調整しています。 コンテナ内に配置する1つ目のコン トロール は テキストラベル で、以下の関数を設定することでカレンダーの「日付」を表示しています。 Text (ThisItem.Value, "dd" ) Plannerのタスクを表示する領域は垂直ギャラリーを使用しました。ギャラリーに表示するデータは、 Items プロパティに以下の関数を設定し、前のセクションで取得したPlannerタスク一覧から抽出しています。 Sort ( Filter (tasks, And (dueDateTime>=ThisItem.Value,dueDateTime<ThisItem.Value+ 1 )),title) これにより、「各日のボックスを表現する水平ギャラリー」の ThisItem に格納されている各日がPlannerの 期日 に一致するタスクのテーブルが、垂直ギャラリーのデータに設定されます。 垂直ギャラリーのテンプレートに以下のコン トロール を配置することでタスクを表示しています。 テキストラベル :Plannerタスクのタイトル ThisItem.title テキストラベル と楕円の図形:Plannerタスクの バケット 本件では、Planner タスクのステータスではなく、タスクが属する バケット をタスクのステータス情報として採用しました。 LookUp は、 Excel のVLOOKUPと同じイメージで、第一引数のテーブルから第二引数の条件でデータを抽出する関数です。 buckets には前のセクションで初期化したPlannerの バケット 一覧が格納されています。 LookUp (buckets,id=ThisItem.bucketId).name テキストラベル :Plannerタスクのオーナー members には前のセクションで初期化したOffice365Groupのグループメンバー一覧が格納されています。 LookUp (members,id= First (ThisItem._assignments).userId).displayName ポイントとしては、「カレンダーの各日のボックスを表現する水平ギャラリー」の WrapCount(折り返しの数) プロパティに 7 を指定している点です。 水平方向に7アイテムが表示される毎に折り返されるので、カレンダーのように描画されます。 また、描画範囲を調整するため、上記の2つの水平ギャラリーは コンテナ コン トロール に配置しています。 表示する年/月の セレクタ 前述までのセクションでカレンダーは表示されます。 初期化の年/月以外のカレンダーを表示可能なよう、 セレクタ を作成しました。 年は テキスト入力 コン トロール で利用者に入力してもらう仕様としました。入力された値は、 <コントロール名>.Text で参照できます。 初期値として、 Default プロパティに以下の関数を設定しています。「初期化」セクションで startOfMonth と endOfMonth 変数の入力の一方が、この値です。 Text ( Today (), "yyyy" ) 月は、 ドロップダウン コン トロール から選択する仕様です。プルダウンに表示するリストは、 Items プロパティに01~12のテーブルとして設定しました。選択された値は、 <コントロール名>.Selected.Value で参照可能です。 初期値として、 Default プロパティに以下の関数を設定しています。「初期化」セクションで startOfMonth と endOfMonth 変数の入力の他方が、この値です。 Text ( Today (), "mm" ) 上記2つのコン トロール の入力をカレンダーに反映する ボタン コン トロール を追加します。 OnSelect プロパティに以下の関数を設定することでカレンダーを更新します。内容は初期化セクションとほぼ同じです。 UpdateContext ( { startOfMonth : Date (TextInputYear_1.Text,DropdownMonth_1.Selected.Value, 1 ), endOfMonth : Date (TextInputYear_1.Text,DropdownMonth_1.Selected.Value + 1 , 1 )- 1 } ); UpdateContext ( { fromDate :startOfMonth-( Weekday (startOfMonth, 1 )- 1 ), toDate :endOfMonth+( 7 - Weekday (endOfMonth, 1 )) } ); UpdateContext ( { days : ForAll ( Sequence (toDate-fromDate+ 1 ), DateAdd (fromDate- 1 ,Value,Days)) } ) おまけで、利用者の入力を Default に戻すリセットボタンも配置しました。 あとはカレンダーらしさが出る修飾 見た目の修飾として以下を行っています。 当日のボックスの日付を強調 土日の背景をグレー表示 年/月 セレクタ で選択された月以外の日付をグレー表示 例えば、2022年04月が選択された場合、2022/04は4/1~4/30ですが、カレンダー上には3/27~3/31も表示されるため、これらの日付文字の色はグレーになるようにしています。 タスクのステータス(Plannerの バケット )毎に表示色を変更 公開済みステータス(Plannerの バケット )の場合はクラッカーの画像を表示 これらは、各コン トロール のプロパティに If 関数を使用して実現しています。すべての紹介は割愛しますが、代表として当日日付の強調をご紹介します。 当日日付は テキストラベル コン トロール で、 Color プロパティに以下の関数を設定することで、当日日付のテキストラベルの背景色を変更しています。 If ( Text ( Today (), "yyyy/mm/dd" )= Text (ThisItem.Value, "yyyy/mm/dd" ), RGBA ( 20 , 165 , 255 , 1 ), RGBA ( 255 , 255 , 255 , 1 )) ローコードをはじめてちゃんと触ってみた感想 ご参考までに利用したコン トロール の一覧は下図のとおりです。 私はこれまで、Power Appsに限らずローコードツール/プラットフォームというものはほとんど触ったことがありませんでした。 本件で確りと触ってみて、専門的な知識がなくても、それっぽいものを比較的簡単に作れるという便利さが印象的でした。 Microsoft 製品だけでも、Power Appsの他にPower Automateなども提供されています。また、弊社のようなベンダーだけでなくエンドユーザー様でも利用しやすい点から、業務効率化やDXの一環として活用できる強力なツールであると実感しました。 最後までご覧いただきありがとうございました。弊社にはローコード開発やお客様の業務効率化/DX推進のご支援も行っている組織もございます。この記事の内容が参考になるか、弊社に興味を持つ機会になれば幸いです。また次の記事でお会いしましょう! 参考文献/記事 キャンバス アプリでのコントロールの追加と設定 Microsoft Planner との統合 Power Apps で Planner の機能を強化してみる(後編) Power Apps プランナー(Planner)のタスクをギャラリー(Gallery)で一覧表示する! 執筆: 寺山 輝 (@terayama.akira) 、レビュー: @sato.taichi ( Shodo で執筆されました )
皆さんこんにちは!金融ソリューション事業部 市場系ソリューション1部の寺山です。 かなり温かく、というか暑くなってきましたね。私は、今の時期から冷房に頼ると本場の夏の暑さに耐えられないぞ!という戦略で冷房を使うのを我慢しています。 これまではインフラ/ クラウド 関連の記事を投稿してきた私ですが、今回は打って変わってローコード関連の内容となります。背景を踏まえてローコードツール:Power Appsを用いて実現した内容をご紹介したいと思います! 背景 Power Appsを作成 アプリの作成とコネクタの追加 初期化 カレンダーの描画 表示する年/月のセレクタ あとはカレンダーらしさが出る修飾 ローコードをはじめてちゃんと触ってみた感想 参考文献/記事 背景 私は、昨年度の弊社 アドベントカレンダー で記事を投稿した以降に、当テックブログの運営チームに参加しました。 テックブログの運営において、誰がいつ投稿する予定なのか?/投稿の途切れてしまう期間があるか?といった観点で、 執筆状況をカレンダー形式で可視化したいよね という意見が生まれました。 結論として、 Microsoft Plannerで執筆タスクを管理することにより上記の目的を達成しようとなりました。理由は以下のとおりです。 Plannerにはカレンダー機能がある。 機能がシンプルであり、厳密なタスク管理ルールを策定しないことにより執筆者・運営側の双方の負荷にならないよう、執筆管理を運用可能と考えた。 1. でカレンダー形式で可視化するという当初の目的は達成しました。加えて、弊社内でテックブログの活動や執筆ガイドを共有するための SharePoint ポータルサイト を構築していたため、そこにカレンダー形式として埋め込むことで、 活動状況を執筆メンバー以外にも共有したいよね! という考えに発展しました。 そこで、プレビュー版ではあるもののWebパーツが提供されているPower Appsを用いてカレンダーを作成し、 SharePoint に埋め込んでみようと思い立ったのが背景となります。 実際に埋め込んだ PowreAppsは以下のように表示されます! Power Appsを作成 前述のPower Appsアプリをどのように作成したのかを簡単にご紹介します。 作業はすべてPower AppsのWebコンソールにて行いました。 私はPower Appsについて無知な状態からスタートしたため、Power Appsの各機能や コンポーネント (Power Apps用語ではコン トロール )の説明は割愛し、全体的な流れの説明に比重を置かせていただきます。 アプリの作成とコネクタの追加 まずはアプリを作成します。Power Appsのサブメニューより、 作成 > 空のキャンバスアプリ > 作成 と選択し、アプリ名を設定して空のキャンバスアプリを作成します。 私は利用していませんが、PowreAppsではアプリのテンプレートも提供されています。 形式 ですが、 SharePoint の ポータルサイト は弊社の社員が業務中にPCから参照するケースの方が多いと考え、 タブレット を選択しました。 次はコネクタの追加です。Power Apps で表示/加工するデータは、Office365の他のアプリケーションや サードパーティ ツール( DBMS やDWHなど)を データソース として コネクタ で接続して取得します。 今回利用したコネクタは以下のとおりです。 Planner:カレンダーに表示するPlannerタスクや バケット の取得に利用 O365Group:タスクの担当者名の取得に利用 コネクタの追加は、サブメニューの データ > データの追加 より行います。データソースに対する認証情報に自身のOffice365アカウントを指定します。 初期化 キャンバスアプリのトップエンティティはスクリーンです。空のキャンバスアプリを作成すると執筆時点のデフォルトではスクリーンのみが作成された状態となります。 私の作成した Power Apps ではスクリーンの OnVisible プロパティに以下の関数を設定することで、Power Appsの描画時に初期化がされるようにしました。 // 共通して使用する変数の宣言 UpdateContext ( { planId : "<PlannerのPlanID>" , groupId : "<PlannerのGroupID>" , officeGroupId : "<PlannerのGroupID>" , weekDay :[ "Sun." , "Mon." , "Tue." , "Wed." , "Thu." , "Fri." , "Sat." ] } ); // カレンダーとして表示対象の月の1日と月末の日付を設定 UpdateContext ( { startOfMonth : Date (TextInputYear_1.Text,DropdownMonth_1.Selected.Value, 1 ), endOfMonth : Date (TextInputYear_1.Text,DropdownMonth_1.Selected.Value + 1 , 1 )- 1 } ); // カレンダーに表示する開始日と終了日を計算 UpdateContext ( { fromDate :startOfMonth-( Weekday (startOfMonth, 1 )- 1 ), toDate :endOfMonth+( 7 - Weekday (endOfMonth, 1 )) } ); // PlannerとOffice365Groupデータソースから、Plannerタスク一覧、Plannerのバケット一覧、Office365Groupのメンバー一覧を取得してテーブルに格納 UpdateContext ( { tasks :Planner. ListTasksV3 (planId,groupId).value, buckets :Planner. ListBucketsV3 (planId,groupId).value, members :O365Group. ListGroupMembers (officeGroupId).value } ); // カレンダーに表示する開始日から終了日までの全日付をテーブルに格納 UpdateContext ( { days : ForAll ( Sequence (toDate-fromDate+ 1 ), DateAdd (fromDate- 1 ,Value,Days)) } ) UpdateContext はスクリーンがスコープとなる変数を宣言/更新する関数です。 以下は各UpdateContextブロックに対する補足です。 1つ目のブロックで変数の値に設定している PlannerのPlanID と PlannerのGroupID はPlannerのURLから確認可能です。 2つ目のブロックでは、後述する TextInputYear_1 という テキスト入力 コン トロール の初期値と、 DropdownMonth_1 という ドロップダウン コン トロール の初期値から取得しています。 5つ目のブロックの ForAll は、第一引数のテーブルに対して第二引数の操作を繰り返す関数です。 Sequence 関数を使用してカレンダーに表示する開始日から終了日までのインデックスのテーブルを作成して、カレンダーの開始日からインデックスを相対距離として日付を計算することで、カレンダーの開始から終了日までに含まれる全日付のテーブルを作成しています。 Power Apps上での作業は以下のようになります。 カレンダーの描画 カレンダー風に描画するために、2つの ギャラリー コン トロール を作成しています。 ギャラリーとは、指定したデータに対し、他のコン トロール をテンプレートとして展開可能なコンテナ型のコン トロール です。 1つ目のギャラリーは、カレンダーの曜日を表示するための水平ギャラリーです。 前のセクションで初期化した weekday テーブルをギャラリーの Items プロパティに指定し、ギャラリー内には テキストラベル コン トロール を配置しています。 テキストラベルに表示する Text プロパティで以下の関数を指定することで、曜日の表す列のように描画しています。 ThisItem にはギャラリーの Items プロパティに指定したテーブルの要素が格納されます。 ThisItem.Value 2つ目はカレンダーの各日のボックスを表現する水平ギャラリーです。 Items プロパティには前のセクションで初期化した days テーブルを指定しています。 水平ギャラリーには、まず垂直コンテナを配置し、内部に配置する2つのコン トロール の位置関係と描画範囲を調整しています。 コンテナ内に配置する1つ目のコン トロール は テキストラベル で、以下の関数を設定することでカレンダーの「日付」を表示しています。 Text (ThisItem.Value, "dd" ) Plannerのタスクを表示する領域は垂直ギャラリーを使用しました。ギャラリーに表示するデータは、 Items プロパティに以下の関数を設定し、前のセクションで取得したPlannerタスク一覧から抽出しています。 Sort ( Filter (tasks, And (dueDateTime>=ThisItem.Value,dueDateTime<ThisItem.Value+ 1 )),title) これにより、「各日のボックスを表現する水平ギャラリー」の ThisItem に格納されている各日がPlannerの 期日 に一致するタスクのテーブルが、垂直ギャラリーのデータに設定されます。 垂直ギャラリーのテンプレートに以下のコン トロール を配置することでタスクを表示しています。 テキストラベル :Plannerタスクのタイトル ThisItem.title テキストラベル と楕円の図形:Plannerタスクの バケット 本件では、Planner タスクのステータスではなく、タスクが属する バケット をタスクのステータス情報として採用しました。 LookUp は、 Excel のVLOOKUPと同じイメージで、第一引数のテーブルから第二引数の条件でデータを抽出する関数です。 buckets には前のセクションで初期化したPlannerの バケット 一覧が格納されています。 LookUp (buckets,id=ThisItem.bucketId).name テキストラベル :Plannerタスクのオーナー members には前のセクションで初期化したOffice365Groupのグループメンバー一覧が格納されています。 LookUp (members,id= First (ThisItem._assignments).userId).displayName ポイントとしては、「カレンダーの各日のボックスを表現する水平ギャラリー」の WrapCount(折り返しの数) プロパティに 7 を指定している点です。 水平方向に7アイテムが表示される毎に折り返されるので、カレンダーのように描画されます。 また、描画範囲を調整するため、上記の2つの水平ギャラリーは コンテナ コン トロール に配置しています。 表示する年/月の セレクタ 前述までのセクションでカレンダーは表示されます。 初期化の年/月以外のカレンダーを表示可能なよう、 セレクタ を作成しました。 年は テキスト入力 コン トロール で利用者に入力してもらう仕様としました。入力された値は、 <コントロール名>.Text で参照できます。 初期値として、 Default プロパティに以下の関数を設定しています。「初期化」セクションで startOfMonth と endOfMonth 変数の入力の一方が、この値です。 Text ( Today (), "yyyy" ) 月は、 ドロップダウン コン トロール から選択する仕様です。プルダウンに表示するリストは、 Items プロパティに01~12のテーブルとして設定しました。選択された値は、 <コントロール名>.Selected.Value で参照可能です。 初期値として、 Default プロパティに以下の関数を設定しています。「初期化」セクションで startOfMonth と endOfMonth 変数の入力の他方が、この値です。 Text ( Today (), "mm" ) 上記2つのコン トロール の入力をカレンダーに反映する ボタン コン トロール を追加します。 OnSelect プロパティに以下の関数を設定することでカレンダーを更新します。内容は初期化セクションとほぼ同じです。 UpdateContext ( { startOfMonth : Date (TextInputYear_1.Text,DropdownMonth_1.Selected.Value, 1 ), endOfMonth : Date (TextInputYear_1.Text,DropdownMonth_1.Selected.Value + 1 , 1 )- 1 } ); UpdateContext ( { fromDate :startOfMonth-( Weekday (startOfMonth, 1 )- 1 ), toDate :endOfMonth+( 7 - Weekday (endOfMonth, 1 )) } ); UpdateContext ( { days : ForAll ( Sequence (toDate-fromDate+ 1 ), DateAdd (fromDate- 1 ,Value,Days)) } ) おまけで、利用者の入力を Default に戻すリセットボタンも配置しました。 あとはカレンダーらしさが出る修飾 見た目の修飾として以下を行っています。 当日のボックスの日付を強調 土日の背景をグレー表示 年/月 セレクタ で選択された月以外の日付をグレー表示 例えば、2022年04月が選択された場合、2022/04は4/1~4/30ですが、カレンダー上には3/27~3/31も表示されるため、これらの日付文字の色はグレーになるようにしています。 タスクのステータス(Plannerの バケット )毎に表示色を変更 公開済みステータス(Plannerの バケット )の場合はクラッカーの画像を表示 これらは、各コン トロール のプロパティに If 関数を使用して実現しています。すべての紹介は割愛しますが、代表として当日日付の強調をご紹介します。 当日日付は テキストラベル コン トロール で、 Color プロパティに以下の関数を設定することで、当日日付のテキストラベルの背景色を変更しています。 If ( Text ( Today (), "yyyy/mm/dd" )= Text (ThisItem.Value, "yyyy/mm/dd" ), RGBA ( 20 , 165 , 255 , 1 ), RGBA ( 255 , 255 , 255 , 1 )) ローコードをはじめてちゃんと触ってみた感想 ご参考までに利用したコン トロール の一覧は下図のとおりです。 私はこれまで、Power Appsに限らずローコードツール/プラットフォームというものはほとんど触ったことがありませんでした。 本件で確りと触ってみて、専門的な知識がなくても、それっぽいものを比較的簡単に作れるという便利さが印象的でした。 Microsoft 製品だけでも、Power Appsの他にPower Automateなども提供されています。また、弊社のようなベンダーだけでなくエンドユーザー様でも利用しやすい点から、業務効率化やDXの一環として活用できる強力なツールであると実感しました。 最後までご覧いただきありがとうございました。弊社にはローコード開発やお客様の業務効率化/DX推進のご支援も行っている組織もございます。この記事の内容が参考になるか、弊社に興味を持つ機会になれば幸いです。また次の記事でお会いしましょう! 参考文献/記事 キャンバス アプリでのコントロールの追加と設定 Microsoft Planner との統合 Power Apps で Planner の機能を強化してみる(後編) Power Apps プランナー(Planner)のタスクをギャラリー(Gallery)で一覧表示する! 執筆: 寺山 輝 (@terayama.akira) 、レビュー: @sato.taichi ( Shodo で執筆されました )
こんにちは。 電通国際情報サービス (ISID) グループ経営ソリューション事業部の高崎です。 私が担当しているプロダクトの開発・運用中に発生した各種インシデントについて、解決後に再発防止を目的とした振り返りを実施しています。振り返りの方法として、ポストモーテムを導入してみました。 導入して3ヵ月が経過し、導入してよかったと思うことや今後の課題などが見えてきたので、紹介したいと思います。 後述するポストモーテムの内容は下記の書籍を参考にしています。 SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム (O'Reilly Japan) ポストモーテムとは インシデントが発生したことによる影響、解決のために行ったアクション、発生した原因、再発防止策などを記録したドキュメントを指します。 ポストモーテムを作成する上で個人を非難してはいけません。ポストモーテムの目的は、誰がインシデントを引き起こしたのかを明らかにすることではなく、なぜインシデントが発生してしまったのかを組織としてはっきりとさせることです。 焦点は人ではなくプロセスと技術にあてられなければなりません。 また、完成したポストモーテムは記載されている教訓が役立つよう、可能な限り広い範囲に共有することが重要です。 ポストモーテムを導入したきっかけ 開発プロジェクトの体制は以下のようになっています。 PM配下に業務領域ごとの開発チーム、その開発チームを横断的に見ているTech Leadがいます。 ※私のポジションはTech Leadです これまでインシデントが発生した場合、原因となった機能を担当している各開発チームごとに振り返りを実施し、再発防止策を作成していました。そうすると同じチーム内では再発しないのですが、振り返りの内容や再発防止策が他チームに浸透しておらず、同様の原因によるインシデントが他チームで発生するという課題がありました。 上記を解決するための方法を検討していた中で、ポストモーテムを導入してみようと思ったことがきっかけです。 どのようにしてポストモーテムを作成しているか 以下のフォーマットに沿って、関係者が各項目について対面で会話しながら作成しています。 ファシリテーター はTech Leadが担当しています。 # インシデント名 ## インシデント発生日 ## 作成日 ## 作者 ## ステータス → インシデントの現在のステータス ## サマリ → インシデントの概要 ## インパクト → インシデントによってどんな影響があったか ## 検出 → インシデントを検出した方法 ## 対応 → インシデントを収束させるために実施したこと ## タイムライン → インシデント発生から復旧までのタイムラインを書く ## 教訓 ### うまくいったこと ### うまくいかなかったこと ## 根本原因 → インシデントが発生した根本原因 ## 発生要因 → 根本原因が発生した要因 ## 再発防止策 特に重要な根本原因・発生要因・再発防止策については、 マインドマップ を使って深掘りを行っています。 まず根本原因(Where)が何かを突き止めます。次に根本原因となった事象がなぜ発生したのか(Why)を突き止め、最後に再発させないために何をするべきか(How)を決定します。 上記手順を踏まないと、根本原因や発生要因を明らかにしないまま、再発防止策ありきで話が進んでしまい、効果的な対策を打てない可能性があるため、注意が必要です。 問題解決の手段は下記の書籍を参考にしました。 問題解決(英治出版) ポストモーテムが作成できたら、可能な限り広い範囲に共有したいため、各開発チームのメンバー全員が集まっているデイリー スクラム の中で内容の説明を行います。 導入してよかったこと ポストモーテムを導入した目的である、同じ原因によるインシデントが他チームで発生するということは今のところ発生していません。また、しっかりと時間をかけて振り返りを行うことで、効果的な再発防止策を作成することができていると感じています。 今後の課題 実際にポストモーテムを作成してみて難しいなと思ったことなのですが、インシデントが発生した原因を突き止めるために、結局は特定のメンバーに当時の様子を細かく ヒアリ ングする必要があります。 ヒアリ ングするメンバーに 心理的 負担をかけてしまうと、本音を包み隠さず話すことができなくなってしまいます。 いかにメンバーに 心理的 負担をかけずに振り返りを実施できるかは、 ファシリテーター である私にかかっているため、改善していきたいと思っています。 まとめ まだ導入して3ヵ月しか経っていないため、今後もポストモーテムを実施する上で課題が出てくるかと思いますが、プロダクトを改善するためにどうすればよいかを軸に、改善を進めていきたいと思います。 最後までお読みいただき、ありがとうございました。 執筆: @takasaki.keisuke 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
こんにちは。 電通国際情報サービス (ISID) グループ経営ソリューション事業部の高崎です。 私が担当しているプロダクトの開発・運用中に発生した各種インシデントについて、解決後に再発防止を目的とした振り返りを実施しています。振り返りの方法として、ポストモーテムを導入してみました。 導入して3ヵ月が経過し、導入してよかったと思うことや今後の課題などが見えてきたので、紹介したいと思います。 後述するポストモーテムの内容は下記の書籍を参考にしています。 SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム (O'Reilly Japan) ポストモーテムとは インシデントが発生したことによる影響、解決のために行ったアクション、発生した原因、再発防止策などを記録したドキュメントを指します。 ポストモーテムを作成する上で個人を非難してはいけません。ポストモーテムの目的は、誰がインシデントを引き起こしたのかを明らかにすることではなく、なぜインシデントが発生してしまったのかを組織としてはっきりとさせることです。 焦点は人ではなくプロセスと技術にあてられなければなりません。 また、完成したポストモーテムは記載されている教訓が役立つよう、可能な限り広い範囲に共有することが重要です。 ポストモーテムを導入したきっかけ 開発プロジェクトの体制は以下のようになっています。 PM配下に業務領域ごとの開発チーム、その開発チームを横断的に見ているTech Leadがいます。 ※私のポジションはTech Leadです これまでインシデントが発生した場合、原因となった機能を担当している各開発チームごとに振り返りを実施し、再発防止策を作成していました。そうすると同じチーム内では再発しないのですが、振り返りの内容や再発防止策が他チームに浸透しておらず、同様の原因によるインシデントが他チームで発生するという課題がありました。 上記を解決するための方法を検討していた中で、ポストモーテムを導入してみようと思ったことがきっかけです。 どのようにしてポストモーテムを作成しているか 以下のフォーマットに沿って、関係者が各項目について対面で会話しながら作成しています。 ファシリテーター はTech Leadが担当しています。 # インシデント名 ## インシデント発生日 ## 作成日 ## 作者 ## ステータス → インシデントの現在のステータス ## サマリ → インシデントの概要 ## インパクト → インシデントによってどんな影響があったか ## 検出 → インシデントを検出した方法 ## 対応 → インシデントを収束させるために実施したこと ## タイムライン → インシデント発生から復旧までのタイムラインを書く ## 教訓 ### うまくいったこと ### うまくいかなかったこと ## 根本原因 → インシデントが発生した根本原因 ## 発生要因 → 根本原因が発生した要因 ## 再発防止策 特に重要な根本原因・発生要因・再発防止策については、 マインドマップ を使って深掘りを行っています。 まず根本原因(Where)が何かを突き止めます。次に根本原因となった事象がなぜ発生したのか(Why)を突き止め、最後に再発させないために何をするべきか(How)を決定します。 上記手順を踏まないと、根本原因や発生要因を明らかにしないまま、再発防止策ありきで話が進んでしまい、効果的な対策を打てない可能性があるため、注意が必要です。 問題解決の手段は下記の書籍を参考にしました。 問題解決(英治出版) ポストモーテムが作成できたら、可能な限り広い範囲に共有したいため、各開発チームのメンバー全員が集まっているデイリー スクラム の中で内容の説明を行います。 導入してよかったこと ポストモーテムを導入した目的である、同じ原因によるインシデントが他チームで発生するということは今のところ発生していません。また、しっかりと時間をかけて振り返りを行うことで、効果的な再発防止策を作成することができていると感じています。 今後の課題 実際にポストモーテムを作成してみて難しいなと思ったことなのですが、インシデントが発生した原因を突き止めるために、結局は特定のメンバーに当時の様子を細かく ヒアリ ングする必要があります。 ヒアリ ングするメンバーに 心理的 負担をかけてしまうと、本音を包み隠さず話すことができなくなってしまいます。 いかにメンバーに 心理的 負担をかけずに振り返りを実施できるかは、 ファシリテーター である私にかかっているため、改善していきたいと思っています。 まとめ まだ導入して3ヵ月しか経っていないため、今後もポストモーテムを実施する上で課題が出てくるかと思いますが、プロダクトを改善するためにどうすればよいかを軸に、改善を進めていきたいと思います。 最後までお読みいただき、ありがとうございました。 執筆: @takasaki.keisuke 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。 以前の記事 では、 AWS Security Hubを検証した際に気付いたことを山口さんよりご紹介しました。今回はその続編として、Security Hubの実用に向けた取り組みをお話しします。 社内プロジェクトへのSecurity Hub導入 検出結果の集約 検出結果を通知する仕組みの構築 構築上のTips 一度に取得できる検出結果は100件まで 一度にフィルタリングできるアカウントIDは20件まで 今後に向けて 社内プロジェクトへのSecurity Hub導入 普段ならつい見過ごしてしまいがちな、不十分なセキュリティ設定をきっちり警告してくれるため、ISIDでは AWS を使用している全てのプロジェクトにSecurity Hubを導入することを目指しています。 Security Hubは導入するだけなら非常に簡単です。しかし本当に重要なのはその検出結果を確認し、確実に改善に繋げることです。そのためには少なくとも以下のことが必要になります。 定期的にSecurity Hubの検出結果を確認する運用手順や仕組み 検出結果の内容の理解 修正すべきポイントと、修正することによる影響の理解 セキュリティリスクと修正コストを総合的に判断し、対応方針を決定すること ISIDには数多くのプロジェクトがあり、担当メンバーも異なるため、1~4をプロジェクト内で個別に対応するのは望ましい姿とはいえません。そこで組織横断的な支援を行う体制により、1~4の実施を各プロジェクトに対してサポートしています。 定期的にSecurity Hubの検出結果を確認する運用手順や仕組み → 各プロジェクトの検出結果を集約し、定期的に通知する仕組みの導入(のちに詳述) 検出結果の内容の理解 → Security Hubのセキュリティ基準 をさらに詳細化したノウハウ集の作成と展開 修正すべきポイントと、修正することによる影響の理解 → 2.と同じ セキュリティリスクと修正コストを総合的に判断し、対応方針を決定すること → 対応方針の相談窓口の設置 2.と3.については検証用の AWS アカウントを利用して、各検出項目の発火の条件と改善方法を調査してきました。Security Hubのセキュリティ基準の項目は 不定 期に追加されますので、今後も継続的に調査を行っていくことになります。 4.については Microsoft Teamsに専用のチームを作成し、プロジェクトからの相談を随時受け付ける体制にしています。検出結果に対応するにあたって、各プロジェクトに共通する課題なども見えてくるのではないかと期待しています。 ここからは 1. の「検出結果を集約し、通知する仕組み」について、詳細をお話しします。 検出結果の集約 ※注:以下の記述は AWS Organizationsと統合されていない場合です。 Security Hubには 複数のメンバーアカウントの検出結果を管理者アカウントに集約する機能 がありますので、これを利用します。 いわゆる管理者アカウントから各プロジェクトのメンバーアカウントに招待を送り、メンバーアカウントから承認することで、Security Hubの検出項目を管理者アカウントからも確認できるようになります。この際、メンバーアカウントにてSecurity HubとConfigの有効化が必要になります。 注意が必要なのは、Security Hubはリージョナルサービスであるため、メンバーアカウントの複数リージョンから結果を集約したい場合は リージョンごとに招待・承認 しなければなりません。 複数のメンバーアカウントを取り扱うため、 管理者アカウントの方は当然、全リージョンでSecurity Hubを有効 にしておきます。 管理者アカウントに集約された結果を、リージョンを切り替えながら確認するのは手間がかかるので、 結果をリージョン間で集約する機能 を利用します。 これにより、 複数のメンバーアカウントの複数リージョンの検出結果を、1つの管理者アカウントの1リージョンから取得できる ようになります。 検出結果を通知する仕組みの構築 1箇所に集約された検出結果を、定期的に取得してプロジェクトに通知する仕組みを構築しました。 AWS SDK for JavaScript を利用し、ECSタスクからSecurity Hub検出結果の取得、レポートの生成と保存、配信までを行います。 ①ECSタスクを定期実行します ②プロジェクトと AWS アカウントID、および結果配信先を関連付ける情報を取得します。今回はS3 バケット に CSV ファイルとして配置することにしました ③プロジェクトごとに、Security Hubの検出結果を取得します ④⑤プロジェクトごとに検出結果を見やすい形でまとめた Excel レポートを作成し、S3 バケット に保存します ⑥レポートにプロジェクトの担当者がアクセスできるように、署名付きURLを生成します ⑦レポートへの署名付きURLをプロジェクト担当者に通知します。今回はメールで配信することにしました ⑧将来的にプロジェクトの対応状況を分析できるように、検出履歴をDynamoDBに保存しておきます ⑨プロジェクト担当者は署名付きURLからレポートをダウンロードします。万が一署名付きURLが漏れても社外の第 三者 がレポートを取得できないように、 バケット ポリシーを設定しsource IPをISID社内からのアクセスに限定しておきます この仕組みにより、以下のようなメリットが発生します プロジェクトが個別にSecurity Hubを確認する負荷を軽減できる 複数アカウント を利用しているプロジェクトの場合、1つのレポートに検出結果がまとまる Excel のレポートを生成するため、検出結果をフィルターしやすい 組織横断的に検出結果への対応状況を集計、分析できる(今後の期待) 構築上のTips AWS SDK for JavaScript から Security Hub の検出結果を取得する際のTipsを2つ記します。 一度に取得できる検出結果は100件まで @aws-sdk/client-securityhub モジュールの GetFindingsCommand から受け取る結果の最大数を MaxResults として指定できるのですが、最大100件までという制約があります。 const command = new GetFindingsCommand ( { MaxResults: 100 , // 最大100まで NextToken: nextToken , Filters: filters , } ); 100件を超える検出結果を取得したい場合は、結果に NextToken というプロパティに値が入った状態で返ってきます。これを GetFindingsCommand の入力に追加してもう一度送ることで、続きの検出結果を取得できます。 const data = await client.send ( command ); if ( data.NextToken === undefined ) { // 結果が100件以内 } else { // 結果が100件を超えている } すなわち、 再帰 的に GetFindingsCommand を送信することで、全ての検出結果を取得できます。 import { SecurityHubClient , GetFindingsCommand , AwsSecurityFinding , AwsSecurityFindingFilters , StringFilter , } from "@aws-sdk/client-securityhub" ; const client = new SecurityHubClient ( { region: "ap-northeast-1" } ); export async function getNextFindings ( awsAccountIds: string [] , nextToken?: string ) : Promise < AwsSecurityFinding [] > { const accountsFilter: StringFilter [] = awsAccountIds.map (( id ) => { return { Value: id , Comparison: "EQUALS" } ; } ); // AWSアカウントID、レコードの状態、ワークフローステータスでフィルタリング const filters: AwsSecurityFindingFilters = { AwsAccountId: accountsFilter , RecordState: [{ Value: "ACTIVE" , Comparison: "EQUALS" }] , WorkflowStatus: [ { Value: "NEW" , Comparison: "EQUALS" } , { Value: "NOTIFIED" , Comparison: "EQUALS" } , ] , } ; const command = new GetFindingsCommand ( { MaxResults: 100 , NextToken: nextToken , Filters: filters , } ); // コマンド送信 const data = await client.send ( command ); const findings: AwsSecurityFinding [] = data.Findings ?? [] ; if ( data.NextToken === undefined ) { return findings ; } else { // 100件を超える場合は再帰的に呼び出す return findings.concat (await getNextFindings ( awsAccountIds , data.NextToken )); } } 一度にフィルタリングできるアカウントIDは20件まで プロジェクトごとに検出結果をSecurity Hubから取得したいので、 AWS アカウントIDで検出結果をフィルタリングしてクエリしていますが、アカウントIDの数が多いと以下のようなエラーになりました。 UnhandledPromiseRejectionWarning: InvalidInputException: Invalid parameter 'Filters'. data.AwsAccountId should NOT have more than 20 items アカウントIDは一度に20件までしかフィルタリングに利用できないとのことなので、20件を超えるアカウントIDの検出結果を取得したい場合は、20件以下に分割してから複数回クエリする必要があります。 今後に向けて 今回お話しした仕組みの運用はまだ始まったばかりで、今後新たな課題が発生するかもしれません。ISIDでは引き続き、組織横断的に AWS 環境をセキュアにするための取り組みを実施していきます。 執筆: @kou.kinyo2 、レビュー: @higa ( Shodo で執筆されました )