電通総研のブログ - TECH PLAY

TECH PLAY

電通総研

電通総研 の技術ブログ

856

X イノベーション 本部デジタルエンゲージメントセンターの橋詰です。普段は Salesforce (Financial Services Cloud)を利用した システム開発 を金融機関のお客様向けに行っています。2022年12月に業務の一環でScrum Allienceの認定 スクラム プロダクトオーナー研修を受講してきたので簡単なレポートをお届けします。 受講の動機 何を受講したの? 印象的だったのはプロダクトオーナーの振る舞い方 もっと勉強したいのはトヨタ生産方式のこと おわりに 受講の動機 ここ数年金融ソリューション事業部において アジャイル 開発を普及するお仕事をしていました。主に開発事例を収集したり、 ガイドライン を作成したり、新人さん向けに アジャイル 開発に関する研修(これは後日記事にするつもりです)を実施したりしています。 現在は CRM / SFA システムを構築するプロジェクトを担当しており、システム全体を構築するミッションに加えて、お客様側の開発チームを支援するミッション(Scrumで開発しているチームの内製化支援を実施)も持っています。絵にすると下記のようなイメージで、私は左側の本体開発チームのPMを担当しています。 またこれ以外にもサイドワークとして新規事業でプロダクトを開発中であり、プロダクトオーナーチームの一員として活動しています。これまではどちらかというと開発者よりの立場が多かったため スクラム マスターとしての知識を主に身につけようとしていました。ただ最近はプロダクトオーナー側の知識が必要になりつつあり、研修で補完しようと思ったことが受講の動機です。 何を受講したの? 以前にScrum Allienceの認定資格を取得していることから、今回もScrum Allienceのコース(オンライン セミ ナー:認定 スクラム プロダクトオーナー)を選択しました。 アギレルゴコンサルティング 社が主催するト レーニン グを受講しました。アギレルゴさんは継続的かつ定期的に スクラム マスター・ デベロッパ ー・プロダクトオーナー等の研修コースを提供してくださるので、比較的研修計画を立てやすくいつも助かっています。 講師は「組織パターン」や「A Scrum Book」で有名なJames Coplienさんです。Zoomによる研修で、1日4時間(14-18時)×4日間の講義を受けます。英語での講義になりますが、同時通訳がつくため日本語での参加も問題ないです。 なお研修の費用は22万円でしたが、全額会社の教育費で受講しました。私は自部署の教育費で受講しましたが、これ以外にも、年に1度全社的に受講者の募集もあります。そのほかの資格で セミ ナー等の受講が必要な場合も同様の仕組みで受講できるため、エンジニアの育成に力を入れてくれているなとよく思います。 印象的だったのはプロダクトオーナーの振る舞い方 合計16時間の講義があるため内容は盛りだくさんです。わたしが特にこの研修で刷り込まれたのは、プロダクトオーナーの振る舞い方です。 プロダクトオーナーのもっとも重要なことは、顧客へ届けたい価値(作りたいもの)を開発者のみなさんの脳みそに刻み込むこと。そのために(プロダクト担当の)ミニCEOとしてあらゆる手段と ステークホルダー の力を駆使して準備を密度濃く実施すること。 これに尽きます。個人的にはこの説明でとても霧が晴れたと感じました。以前まではどちらかというと、プロダクト バックログ アイテムを分かりやすく表現するにはどういう手法やツールがあるのだろうか…と悩むことが多かったのですが意識する方向性が間違ってました。あまりにしっくりきたため、研修の翌日にプロダクトオーナー向けのちょっとした社内研修をしたのですが、この気持ちをくどくどと説明していました😅 もっと勉強したいのは トヨタ生産方式 のこと コプリエンさんが担当する研修の特徴の一つかもしれませんが、 トヨタ や製造業に関する考え方がたくさん出てきます。私の担当するお客様の業種は金融機関が多いため、仕事で製造業の知識に触れる機会は少ないです。 アジャイル やLeanの文脈で自習的に学ぶことはありましたが、コプリエンさんの説明を聞いていると脇が甘かったなと反省しました。今後自分としても継続的に学んでいく対象としたいなと思いました。例えば下記のような言葉や考え方です。 - プロダクトの主査 - 5ゲン主義(現場・現物・現実・原理・原則という5つの視点) - 3つのM(ムリ・ムダ・ムラ)などのLeanの考え方 - スウォーミング(モブ)、あんどん、1個流しなどの TOC (制約理論)につながる話 特に5ゲン主義は図らずも自分が大切にしている考え方なので、2023年はより深堀したいです。 おわりに 研修を受けた結果いつもとは違うまなざしを得られたことはとてもためになりました。学んだことを実業でも活かしていきたいです。 さて、私が所属するデジタルエンゲージメントセンターではたくさんの 中途採用 を行っています。さまざまなプロジェクトがあり、 アジャイル 開発に関する認定資格は必須ではありませんがお持ちの方も大歓迎です。下記に採用リンクも貼っておりますので、ぜひご参考にしてください。 一緒に働いてくれる仲間を募集しています!下記以外にも多くの募集を行っていますので、ぜひ採用サイトもご覧ください。 【全社集約】CRMソリューションコンサルタント 執筆: @hashizume.hideki 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
X イノベーション 本部デジタルエンゲージメントセンターの橋詰です。普段は Salesforce (Financial Services Cloud)を利用した システム開発 を金融機関のお客様向けに行っています。2022年12月に業務の一環でScrum Allienceの認定 スクラム プロダクトオーナー研修を受講してきたので簡単なレポートをお届けします。 受講の動機 何を受講したの? 印象的だったのはプロダクトオーナーの振る舞い方 もっと勉強したいのはトヨタ生産方式のこと おわりに 受講の動機 ここ数年金融ソリューション事業部において アジャイル 開発を普及するお仕事をしていました。主に開発事例を収集したり、 ガイドライン を作成したり、新人さん向けに アジャイル 開発に関する研修(これは後日記事にするつもりです)を実施したりしています。 現在は CRM / SFA システムを構築するプロジェクトを担当しており、システム全体を構築するミッションに加えて、お客様側の開発チームを支援するミッション(Scrumで開発しているチームの内製化支援を実施)も持っています。絵にすると下記のようなイメージで、私は左側の本体開発チームのPMを担当しています。 またこれ以外にもサイドワークとして新規事業でプロダクトを開発中であり、プロダクトオーナーチームの一員として活動しています。これまではどちらかというと開発者よりの立場が多かったため スクラム マスターとしての知識を主に身につけようとしていました。ただ最近はプロダクトオーナー側の知識が必要になりつつあり、研修で補完しようと思ったことが受講の動機です。 何を受講したの? 以前にScrum Allienceの認定資格を取得していることから、今回もScrum Allienceのコース(オンライン セミ ナー:認定 スクラム プロダクトオーナー)を選択しました。 アギレルゴコンサルティング 社が主催するト レーニン グを受講しました。アギレルゴさんは継続的かつ定期的に スクラム マスター・ デベロッパ ー・プロダクトオーナー等の研修コースを提供してくださるので、比較的研修計画を立てやすくいつも助かっています。 講師は「組織パターン」や「A Scrum Book」で有名なJames Coplienさんです。Zoomによる研修で、1日4時間(14-18時)×4日間の講義を受けます。英語での講義になりますが、同時通訳がつくため日本語での参加も問題ないです。 なお研修の費用は22万円でしたが、全額会社の教育費で受講しました。私は自部署の教育費で受講しましたが、これ以外にも、年に1度全社的に受講者の募集もあります。そのほかの資格で セミ ナー等の受講が必要な場合も同様の仕組みで受講できるため、エンジニアの育成に力を入れてくれているなとよく思います。 印象的だったのはプロダクトオーナーの振る舞い方 合計16時間の講義があるため内容は盛りだくさんです。わたしが特にこの研修で刷り込まれたのは、プロダクトオーナーの振る舞い方です。 プロダクトオーナーのもっとも重要なことは、顧客へ届けたい価値(作りたいもの)を開発者のみなさんの脳みそに刻み込むこと。そのために(プロダクト担当の)ミニCEOとしてあらゆる手段と ステークホルダー の力を駆使して準備を密度濃く実施すること。 これに尽きます。個人的にはこの説明でとても霧が晴れたと感じました。以前まではどちらかというと、プロダクト バックログ アイテムを分かりやすく表現するにはどういう手法やツールがあるのだろうか…と悩むことが多かったのですが意識する方向性が間違ってました。あまりにしっくりきたため、研修の翌日にプロダクトオーナー向けのちょっとした社内研修をしたのですが、この気持ちをくどくどと説明していました😅 もっと勉強したいのは トヨタ生産方式 のこと コプリエンさんが担当する研修の特徴の一つかもしれませんが、 トヨタ や製造業に関する考え方がたくさん出てきます。私の担当するお客様の業種は金融機関が多いため、仕事で製造業の知識に触れる機会は少ないです。 アジャイル やLeanの文脈で自習的に学ぶことはありましたが、コプリエンさんの説明を聞いていると脇が甘かったなと反省しました。今後自分としても継続的に学んでいく対象としたいなと思いました。例えば下記のような言葉や考え方です。 - プロダクトの主査 - 5ゲン主義(現場・現物・現実・原理・原則という5つの視点) - 3つのM(ムリ・ムダ・ムラ)などのLeanの考え方 - スウォーミング(モブ)、あんどん、1個流しなどの TOC (制約理論)につながる話 特に5ゲン主義は図らずも自分が大切にしている考え方なので、2023年はより深堀したいです。 おわりに 研修を受けた結果いつもとは違うまなざしを得られたことはとてもためになりました。学んだことを実業でも活かしていきたいです。 さて、私が所属するデジタルエンゲージメントセンターではたくさんの 中途採用 を行っています。さまざまなプロジェクトがあり、 アジャイル 開発に関する認定資格は必須ではありませんがお持ちの方も大歓迎です。下記に採用リンクも貼っておりますので、ぜひご参考にしてください。 一緒に働いてくれる仲間を募集しています!下記以外にも多くの募集を行っていますので、ぜひ採用サイトもご覧ください。 【全社集約】CRMソリューションコンサルタント 執筆: @hashizume.hideki 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
こんにちは!金融ソリューション事業部の孫です。 ゲームが好きなみなさま、クライアント・サーバーモデルの マルチプレイ ゲームの制作に興味を持っていますか? 本記事では、熱意を持っていますが「難しそう・・・どうやって始めたらいいんだろうか、ゲームサーバーの構築はどうすればいいのか」という状況の読者向けに開発を体験するのハンズオンを紹介します。 皆さまの熱い気持ちを早く形にするため、 AWS が提供する マルチプレイ ーゲーム用の クラウド サーバー管理サービスである Amazon GameLiftと ゲームエンジン であるUnreal Engines5を使用し、オンライン マルチプレイ 環境を構築する最低限の手順でご紹介します。 注意事項 本記事では以下の操作が行えることと、環境が整っていることを前提としています。 AWS のマネジメントコンソールの使用 対話型シェルの使用 Unreal Engine の利用とプロジェクトのビルド また、本検証を行う場合、使用する AWS の利用料金が発生する点に注意してください。 Amazon GameLiftとは 冒頭でも紹介した通り、 Amazon GameLift (以下 GameLift ) は、 マルチプレイ 環境に必要なサーバー側のゲームアプリケーションならびにその実行環境を管理するサービスです。 本来、 マルチプレイ 用ゲームサーバーの構築にあたり、プレイヤーアカウントの作成、プレイヤー認証、プレイヤーマッチング、プレイヤーのスコアなど様々な要素を同時に検討する必要がありますが、GameLiftの採用によってそれらの手間が要らなくなって以前より実装するハードルが下がってきています。 GameLiftを利用した開発の流れは、以下図のように4stepがあります。とてもシンプルにゲームの開発ができます。 更にクライアント側で専用の SDK を使用することで接続管理やメッセージの送受信を手軽に実装することが可能となっています。本記事では、GameLiftSDKの組込みでオンライン マルチプレイ 環境を実現しました。 Unreal Engine5 とは Unreal Engine は、 Epic Games によって開発されている ゲームエンジン です。 そもそも、 ゲームエンジン が何かというと簡単に言うとゲームを作るためのソフトです。 ゲームエンジン を使用することで、ゲームを作るためのツールや環境が準備された状態でゲーム制作をすることができます。いわゆる、0からプログラミングをしなくて済みます。 Unreal Engine の特徴として、下記のようなものが挙げられます。 無料で使用できる ソースコード が公開されている プログラミングなしでもコンテンツ制作ができる グラフィックスが断トツで高品質 高品質なアセットが無料、有料ともに豊富 更に近年 メタバース による変革がリアルタイムの 3D技術が強く求められています。 Unreal Engine によって高品質な VR コンテンツの制作が可能になります。 Unreal Engine5(以下 UE5 )は Unreal Engine の最新バージョンです。 実施手順 手順は、以下の通りです。 UE5 ソースコード のビルド UE5テンプレートからゲームサーバーを作成する GameLiftSDKをビルドし プラグイン を生成する ゲームサーバーにGameLift プラグイン の組込み ローカルでゲームのテスト及びGameLiftへのアップロード AWS CLI コマンドによるゲームセッション作成と接続 AWS アーキテクチャ 本記事では、 マルチプレイ ゲーム開発を体験することのみに注力し、以下の通りほぼGameLiftのみを利用して構築します。 ※Lambda、 API Gateway 、Cognitoに構築については別記事でご紹介します。 使用環境/ツール Unreal Engine 5.1.0 windows10 21H2 x64 RAM 16GM, SSD 1TB NVIDIA GeForce GTX 980M Gamelift SDK GameLift Cpp ServerSDK 3.4.2 GameLift Unreal plugin 3.4.0 Visual Studio 2019 version 16.11.21(以下VS2019) JavaSDK 1.8.0 手順1. UE5 ソースコード のビルド Unreal Engine の公式 GitHub リポジトリ より、 Unreal Engine ソースをクローンして コンパイル します。 クローン: git clone https://github.com/EpicGames/UnrealEngine.git コンパイル : UnrealEngineフォルダに移動 Setup.batをダブルクリックして実行 GenerateProjectFiles.batをダブルクリックして実行 UE5.slnをクリックしてVS2019で開いて以下の図の通りにビルド実行 ※ Unreal Engine の リポジトリ へのアクセスは、権限が必要なので、済ではない方は、 SignUp の手順に従ってアクセス権限を設定してください。 ※ビルド時間はマシンのスペックによるが、参考までに、 Epicの推奨スペック の情報があります(ビルド時間を短縮するため、最低限は500GB SSD 、16GB RAMをおすすめします)。 手順2.UE5テンプレートからゲームサーバーを作成する 手順1で無事にUE5のビルドが完了後、「Local Windows Debugger」をクリックして Unreal Editorを立ち上げます。 ※Configure情報は以下であることを確認して Unreal Editorを立ち上げてください。 Unreal Editorの画面から「 ゲーム 」⇒ 「 サードパーソン 」⇒「 C++ 」⇒「 新プロジェクト名入力 」(今回は、プロジェクト名を「Gamelift_UE5」としました)でゲームサーバーのプロジェクトを作成します。 プロジェクト作成完了後、vs2019と Unreal Editorをクロースしてプロジェクトフォルダに移動します。 SourceフォルダのGamelift_UE5Editor.Target.csファイルを複製して、ゲームサーバー用の Gamelift_UE5Server.Target.cs ビルドファイルを作成します。 任意の テキストエディタ でGamelift_UE5Server.Target.csを開いて、「Editor」⇒「Server」を書き換えます プロジェクトフォルダに戻して、プロジェクトファイルを右クリックし「Generate Visual Studio project files」でプロジェクトを再生成します プロジェクトフォルダの Gamelift_UE5.sln ファイルをクリックし、VS2019を立ち上げます、そこで先ほど新規追加したゲームサーバー用のプロジェクトファイルが見えることを確認します プロジェクトをビルドします プロジェクトを再ビルドして後、 Gamelift_UE5.uproject をクリックして Unreal Editorを立ち上げます クライアントがゲームサーバーとの接続に成功したかを判別するため、"ゲームサーバー接続前の「オフラインマップ」"と"接続後の「オンラインマップ」"を別々に作成します(既存のマップの複製で作成) プロジェクトの「マップ&モード」でマップの利用ルールを設定します(「サーバーのデフォルトマップ」を、先ほど複製して作成したレベルに変更します) パッケージ化の時に、作成したマップを含まれるように、「パッケージ化」で「マップのパス」を設定します。 Windows 向けにプロジェクトをパッケージ化します バイナリコンフィグレーション:開発 ビルドターゲット: Gamelift_UE5Server ※パッケージ化の所要時間はマシンのスペックによります。 手順3.GameLiftSDKをビルドし プラグイン を生成する ※GameLiftSDK開発ドキュメントのセットアップ要件で、現在 UE4 .25のみの対応となっておりますが、筆者の検証によってUE5も利用可能です!ただし、ビルド用 Visual studio はVS2019を推奨します(筆者はVS2022のビルドでエラーだらけになった)。 GameLiftサーバーSDK から、GameLift Managed Servers SDK をダウンロードします。 CMDでダウンロード先のフォルダに移動して、以下のコマンドでビルドを実施します。 mkdir out cd out cmake -G "Visual Studio 16 2019" -A x64 -DBUILD_FOR_UNREAL=1 .. msbuild ALL_BUILD.vcxproj /p:Configuration=Release ※ビルドにあたり、VS2019のmsvc C++ ツールのバージョンがVS2017と違うのが原因で、以下のエラーが発生します。 msvc initialization: parameter version inconsistent 本エラーは、GameLift-Cpp-ServerSDK-3.4.2\out\thirdparty\boost配下のproject-config.jamにmsvcのバージョンを指定することで解決できます。 using msvc : 14.0 ; 無事にビルドが終わりましたら、生成したDLLとLibファイル out\prefix\bin\aws-cpp-sdk-gamelift-server.dll out\prefix\lib\aws-cpp-sdk-gamelift-server.lib を、 プラグイン のフォルダ(以下はパス)に複製して、セットアップが完了となります。 GameLift-SDK-Release-4.0.2\GameLift-Unreal-plugin-3.4.0\GameLiftServerSDK\ThirdParty\GameLiftServerSDK\Win64 手順4.ゲームサーバーにGameLift プラグイン の組込み UE5のプロジェクトルートフォルダの配下に「 Plugins 」フォルダを新規作成し、手順3でセットアップ完了した プラグイン をそこに移動します プロジェクトフォルダの Gamelift_UE5.sln ァイルをクリックし、VS2019を立ち上げて、 プラグイン をインポートします 以下の プラグイン 定義をゲームの Gamelift_UE5.uproject ファイルに追加します { "Name": "GameLiftServerSDK", "Enabled": true } b. Gamelift_UE5.Build.csファイルに プラグイン 名「 GameLiftServerSDK 」をゲームリストに依存関係として追加します c. 以下のGameLift を使用して Unreal Engine ゲームサーバーを初期化するコードを「 Gamelift_UE5GameMode.cpp 」に追加します #if WITH_GAMELIFT //Getting the module first. FGameLiftServerSDKModule* gameLiftSdkModule = &FModuleManager::LoadModuleChecked<FGameLiftServerSDKModule>(FName("GameLiftServerSDK")); //InitSDK establishes a local connection with GameLift's agent to enable communication. gameLiftSdkModule->InitSDK(); //Respond to new game session activation request. GameLift sends activation request //to the game server along with a game session object containing game properties //and other settings. Once the game server is ready to receive player connections, //invoke GameLiftServerAPI.ActivateGameSession() auto onGameSession = [=](Aws::GameLift::Server::Model::GameSession gameSession) { gameLiftSdkModule->ActivateGameSession(); }; FProcessParameters* params = new FProcessParameters(); params->OnStartGameSession.BindLambda(onGameSession); //OnProcessTerminate callback. GameLift invokes this before shutting down the instance //that is hosting this game server to give it time to gracefully shut down on its own. //In this example, we simply tell GameLift we are indeed going to shut down. params->OnTerminate.BindLambda([=](){gameLiftSdkModule->ProcessEnding();}); //HealthCheck callback. GameLift invokes this callback about every 60 seconds. By default, //GameLift API automatically responds 'true'. A game can optionally perform checks on //dependencies and such and report status based on this info. If no response is received //within 60 seconds, health status is recorded as 'false'. //In this example, we're always healthy! params->OnHealthCheck.BindLambda([](){return true; }); //Here, the game server tells GameLift what port it is listening on for incoming player //connections. In this example, the port is hardcoded for simplicity. Since active game //that are on the same instance must have unique ports, you may want to assign port values //from a range, such as: //const int32 port = FURL::UrlConfig.DefaultPort; //params->port; params->port = 7777; //Here, the game server tells GameLift what set of files to upload when the game session //ends. GameLift uploads everything specified here for the developers to fetch later. TArray<FString> logfiles; logfiles.Add(TEXT("aLogFile.txt")); params->logParameters = logfiles; //Call ProcessReady to tell GameLift this game server is ready to receive game sessions! gameLiftSdkModule->ProcessReady(*params); #endif d.GameLiftServerSDKのヘッドフォルダ(Plugins\GameLiftServerSDK\Source\GameLiftServerSDK\Public)をビルドのincludeパスに追加します。 e. UE5プロジェクトをビルドします 3. UE5プロジェクトのルートフォルダに戻して Gamelift_UE5.uproject をクリックして Unreal Editorを立ち上げます、「Edit」⇒「Plugins」をクリックして、GameLiftSDK プラグイン にチェックが入っていることを確認します 手順5.ローカルでゲームのテスト及びGameLiftへのアップロード ここまでは、UE5ゲームサーバーの開発とGameLiftSDKの組込みは全部完了しました。 GameLiftへゲームサーバーをプッシュする前に、一応ローカルで次の点を確認します。 ゲームサーバーが Server SDK と正常に統合されるか ゲームクライアントは新しいゲームセッションのスタート、プレイヤーのゲームへの参加、ゲームセッションへのConnectができるか 確認完了後に、以下の手順でGameLiftへアップロードを実施する CMDでGameLiftローカルのセットアップ cd {gameliftSDKダウンロード先}\GameLiftLocal-1.0.5 java -jar GameLiftLocal.jar -p 9080 ゲームサーバーを起動します 手順2でパッケージ化したゲームサーバーフォルダに移動します ゲームサーバーのログを出力したいため、起動exeのショットカットを作成して、 リンク先の後ろに「-log」を追加します ショットカットをクリックして、ゲームサーバーを起動します UE5プロジェクトのルートフォルダに戻して、 Gamelift_UE5.uproject をクリックして Unreal Editorを立ち上げます、 をクリックして、出た画面でプレイヤー数を2に設定して でクライアントを起動します CMDでゲームセッションを作成します AWS gamelift describe-game-sessions --endpoint-url http://localhost:9080 --fleet-id fleet-123 AWS gamelift create-game-session --endpoint-url http://localhost:9080 --maximum-player-session-count 2 --fleet-id fleet-1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d クライアントからゲームサーバーに接続してみます。 クライアントで **~** キーを押して、 コマンドライン が表示されます、そこにローカルホストIP( 127.0.0.1 )を入力すれば、上記作成したゲームルームに入ります ※下記の図ではメモリ不足に関するエラーが発生していますが、検証に影響はないため無視して進めます。 接続確認します ローカルの検証はできたので、ここから AWS 側で必要なリソースを作成します。 GameLift側で起動用 スクリプト 作成 手順2でパッケージ化したゲームサーバーフォルダに移動します その配下にinstall.batを配置します、以下は中身です。 Engine\Extras\Redist\en-us\UEPrereqSetup_x64.exe /install /quiet /norestart /log c:\game\UE5PrereqSetup.log 以下の aws コマンドでゲームサーバーをGameLiftへアップロードします ※ AWS の基本的な知識(IAMアカウント作成、 aws cli セットアップなど)の説明は割愛いたします。 operating-system: ゲームサーバーの稼働OS(筆者はwindows2012を採用します) build-root: 手順2で作ったパッケージのパス name: GameLiftでの表示名 build-version: バージョン定義 region: AWS のリージョン名 aws gamelift upload-build \ --operating-system WINDOWS_2012 \ --build-root "E:\UnrealBuilds\WindowsServer" \ --name "gamelift-Unreal-engine" \ --build-version "0.01" \ --region ap-northeast-1 aws consoleにログインして、GameLiftに開いてアップロードしたゲームサーバーを確認します。 ビルド数の隣に「 フリートを作成する 」をクリックしてGameLiftのFleetを作成します。 名前: Fleet名 フリートタイプ: オンデマンド 証明書タイプ: 無効 バイナリ型: ビルド ビルド: 上記2でアップロードしたゲームサーバーを選択する インスタンス タイプ: 無料のタイプでより ロケーション管理: 日本のリージョン プロセス管理 起動パス: Gamelift_UE5\Binaries\ Win64 \Gamelift_UE5Server.exe 同時プロセス: 1 EC2ポート設定 ポート範囲: 7777 プロトコル : UDP IPアドレス 範囲: 0.0.0.0/0 その他デフォルト値でよい 数十分ほど待つとフリートが完成します。こちらは以下マネジメントコンソールのページからも確認することができます。 ここまでで、GameLift側の構築は完了となります。 手順6. AWS CLI コマンドによるゲームセッション作成と接続 まず マルチプレイ を始めるにあたって、プレイヤーが集合するためのルーム、つまりGameLiftのゲームセッションを作成する必要があります(以降、ゲームセッションとして記載します)。次に、ゲームに接続するプレイヤーは、ゲームルームの「 IPアドレス 」を指定し、ゲームに参加することができます。 本来であれば、冒頭の AWS アーキテクチャ 図のように別途APIGatewayとlambdaを用意し、ユーザー認証を実施した上でGameLiftへ接続するなどセキュリ ティー を考慮する必要がありますが、今回は検証のため AWS CLI を用いたコマンドベースで接続します。 ゲームセッション作成 以下のコマンドを、手順5で作成したフリートのIDを取得し変数として設定してください(マネジメントコンソールのフリートの一覧ページから作成したフリート ID の確認が可能) aws gamelift create-game-session --fleet-id fleet-5f14fed2-30d6-4314-9220-47a261a9e6ee --maximum-player-session-count 2 aのコマンドを実行しフリートにゲームセッションを作成します。 ゲームクライアントの起動とゲームサーバーへの接続 ローカル検証する時と同様に、 Unreal Editorで をクリックして、出た画面でプレイヤー数を2に設定して でクライアントを起動します。 クライアントで **~** キーを押して、 コマンドライン が表示されます、そこに「open IPアドレス 」と入力することでゲームサーバーへ接続できます。 うまく接続できない場合、まずは以下の点を確認してみてください。 クライアント側OSやプロキシなどのネットワークの経路上で接続をブロックしている設定がないか確認する GameLiftのフリートではEC2 ポート設定が反映できたか確認する 終わりに 今回、UE5とGameLiftを利用し、オンライン マルチプレイ ゲームの構築する方法をご紹介しました。 冒頭で記載した通り、 メタバース においてよりよい没入感を実現するため、高精細なリアルタイム レンダリング が必要でこの辺はUnrealEngineの強みだと思います。 また、 メタバース 上でユーザーは「 SecondLife 」として生活していく上、運営側は大規模大人数同時オンライン可能のサーバーサイドの構築は不可欠で、今後ゲームサーバー技術の活用は増えていくと思われます。 そのため、引き続きゲーム領域のサーバーサイド技術をウォッチしていきたいと思います。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ(Web3/メタバース/AI) 参考 Amazon GameLift Developer Guider Unreal Engine5.1 Documentation GitHub aws-gamelift-samples 執筆: @chen.sun 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
こんにちは!金融ソリューション事業部の孫です。 ゲームが好きなみなさま、クライアント・サーバーモデルの マルチプレイ ゲームの制作に興味を持っていますか? 本記事では、熱意を持っていますが「難しそう・・・どうやって始めたらいいんだろうか、ゲームサーバーの構築はどうすればいいのか」という状況の読者向けに開発を体験するのハンズオンを紹介します。 皆さまの熱い気持ちを早く形にするため、 AWS が提供する マルチプレイ ーゲーム用の クラウド サーバー管理サービスである Amazon GameLiftと ゲームエンジン であるUnreal Engines5を使用し、オンライン マルチプレイ 環境を構築する最低限の手順でご紹介します。 注意事項 本記事では以下の操作が行えることと、環境が整っていることを前提としています。 AWS のマネジメントコンソールの使用 対話型シェルの使用 Unreal Engine の利用とプロジェクトのビルド また、本検証を行う場合、使用する AWS の利用料金が発生する点に注意してください。 Amazon GameLiftとは 冒頭でも紹介した通り、 Amazon GameLift (以下 GameLift ) は、 マルチプレイ 環境に必要なサーバー側のゲームアプリケーションならびにその実行環境を管理するサービスです。 本来、 マルチプレイ 用ゲームサーバーの構築にあたり、プレイヤーアカウントの作成、プレイヤー認証、プレイヤーマッチング、プレイヤーのスコアなど様々な要素を同時に検討する必要がありますが、GameLiftの採用によってそれらの手間が要らなくなって以前より実装するハードルが下がってきています。 GameLiftを利用した開発の流れは、以下図のように4stepがあります。とてもシンプルにゲームの開発ができます。 更にクライアント側で専用の SDK を使用することで接続管理やメッセージの送受信を手軽に実装することが可能となっています。本記事では、GameLiftSDKの組込みでオンライン マルチプレイ 環境を実現しました。 Unreal Engine5 とは Unreal Engine は、 Epic Games によって開発されている ゲームエンジン です。 そもそも、 ゲームエンジン が何かというと簡単に言うとゲームを作るためのソフトです。 ゲームエンジン を使用することで、ゲームを作るためのツールや環境が準備された状態でゲーム制作をすることができます。いわゆる、0からプログラミングをしなくて済みます。 Unreal Engine の特徴として、下記のようなものが挙げられます。 無料で使用できる ソースコード が公開されている プログラミングなしでもコンテンツ制作ができる グラフィックスが断トツで高品質 高品質なアセットが無料、有料ともに豊富 更に近年 メタバース による変革がリアルタイムの 3D技術が強く求められています。 Unreal Engine によって高品質な VR コンテンツの制作が可能になります。 Unreal Engine5(以下 UE5 )は Unreal Engine の最新バージョンです。 実施手順 手順は、以下の通りです。 UE5 ソースコード のビルド UE5テンプレートからゲームサーバーを作成する GameLiftSDKをビルドし プラグイン を生成する ゲームサーバーにGameLift プラグイン の組込み ローカルでゲームのテスト及びGameLiftへのアップロード AWS CLI コマンドによるゲームセッション作成と接続 AWS アーキテクチャ 本記事では、 マルチプレイ ゲーム開発を体験することのみに注力し、以下の通りほぼGameLiftのみを利用して構築します。 ※Lambda、 API Gateway 、Cognitoに構築については別記事でご紹介します。 使用環境/ツール Unreal Engine 5.1.0 windows10 21H2 x64 RAM 16GM, SSD 1TB NVIDIA GeForce GTX 980M Gamelift SDK GameLift Cpp ServerSDK 3.4.2 GameLift Unreal plugin 3.4.0 Visual Studio 2019 version 16.11.21(以下VS2019) JavaSDK 1.8.0 手順1. UE5 ソースコード のビルド Unreal Engine の公式 GitHub リポジトリ より、 Unreal Engine ソースをクローンして コンパイル します。 クローン: git clone https://github.com/EpicGames/UnrealEngine.git コンパイル : UnrealEngineフォルダに移動 Setup.batをダブルクリックして実行 GenerateProjectFiles.batをダブルクリックして実行 UE5.slnをクリックしてVS2019で開いて以下の図の通りにビルド実行 ※ Unreal Engine の リポジトリ へのアクセスは、権限が必要なので、済ではない方は、 SignUp の手順に従ってアクセス権限を設定してください。 ※ビルド時間はマシンのスペックによるが、参考までに、 Epicの推奨スペック の情報があります(ビルド時間を短縮するため、最低限は500GB SSD 、16GB RAMをおすすめします)。 手順2.UE5テンプレートからゲームサーバーを作成する 手順1で無事にUE5のビルドが完了後、「Local Windows Debugger」をクリックして Unreal Editorを立ち上げます。 ※Configure情報は以下であることを確認して Unreal Editorを立ち上げてください。 Unreal Editorの画面から「 ゲーム 」⇒ 「 サードパーソン 」⇒「 C++ 」⇒「 新プロジェクト名入力 」(今回は、プロジェクト名を「Gamelift_UE5」としました)でゲームサーバーのプロジェクトを作成します。 プロジェクト作成完了後、vs2019と Unreal Editorをクロースしてプロジェクトフォルダに移動します。 SourceフォルダのGamelift_UE5Editor.Target.csファイルを複製して、ゲームサーバー用の Gamelift_UE5Server.Target.cs ビルドファイルを作成します。 任意の テキストエディタ でGamelift_UE5Server.Target.csを開いて、「Editor」⇒「Server」を書き換えます プロジェクトフォルダに戻して、プロジェクトファイルを右クリックし「Generate Visual Studio project files」でプロジェクトを再生成します プロジェクトフォルダの Gamelift_UE5.sln ファイルをクリックし、VS2019を立ち上げます、そこで先ほど新規追加したゲームサーバー用のプロジェクトファイルが見えることを確認します プロジェクトをビルドします プロジェクトを再ビルドして後、 Gamelift_UE5.uproject をクリックして Unreal Editorを立ち上げます クライアントがゲームサーバーとの接続に成功したかを判別するため、"ゲームサーバー接続前の「オフラインマップ」"と"接続後の「オンラインマップ」"を別々に作成します(既存のマップの複製で作成) プロジェクトの「マップ&モード」でマップの利用ルールを設定します(「サーバーのデフォルトマップ」を、先ほど複製して作成したレベルに変更します) パッケージ化の時に、作成したマップを含まれるように、「パッケージ化」で「マップのパス」を設定します。 Windows 向けにプロジェクトをパッケージ化します バイナリコンフィグレーション:開発 ビルドターゲット: Gamelift_UE5Server ※パッケージ化の所要時間はマシンのスペックによります。 手順3.GameLiftSDKをビルドし プラグイン を生成する ※GameLiftSDK開発ドキュメントのセットアップ要件で、現在 UE4 .25のみの対応となっておりますが、筆者の検証によってUE5も利用可能です!ただし、ビルド用 Visual studio はVS2019を推奨します(筆者はVS2022のビルドでエラーだらけになった)。 GameLiftサーバーSDK から、GameLift Managed Servers SDK をダウンロードします。 CMDでダウンロード先のフォルダに移動して、以下のコマンドでビルドを実施します。 mkdir out cd out cmake -G "Visual Studio 16 2019" -A x64 -DBUILD_FOR_UNREAL=1 .. msbuild ALL_BUILD.vcxproj /p:Configuration=Release ※ビルドにあたり、VS2019のmsvc C++ ツールのバージョンがVS2017と違うのが原因で、以下のエラーが発生します。 msvc initialization: parameter version inconsistent 本エラーは、GameLift-Cpp-ServerSDK-3.4.2\out\thirdparty\boost配下のproject-config.jamにmsvcのバージョンを指定することで解決できます。 using msvc : 14.0 ; 無事にビルドが終わりましたら、生成したDLLとLibファイル out\prefix\bin\aws-cpp-sdk-gamelift-server.dll out\prefix\lib\aws-cpp-sdk-gamelift-server.lib を、 プラグイン のフォルダ(以下はパス)に複製して、セットアップが完了となります。 GameLift-SDK-Release-4.0.2\GameLift-Unreal-plugin-3.4.0\GameLiftServerSDK\ThirdParty\GameLiftServerSDK\Win64 手順4.ゲームサーバーにGameLift プラグイン の組込み UE5のプロジェクトルートフォルダの配下に「 Plugins 」フォルダを新規作成し、手順3でセットアップ完了した プラグイン をそこに移動します プロジェクトフォルダの Gamelift_UE5.sln ァイルをクリックし、VS2019を立ち上げて、 プラグイン をインポートします 以下の プラグイン 定義をゲームの Gamelift_UE5.uproject ファイルに追加します { "Name": "GameLiftServerSDK", "Enabled": true } b. Gamelift_UE5.Build.csファイルに プラグイン 名「 GameLiftServerSDK 」をゲームリストに依存関係として追加します c. 以下のGameLift を使用して Unreal Engine ゲームサーバーを初期化するコードを「 Gamelift_UE5GameMode.cpp 」に追加します #if WITH_GAMELIFT //Getting the module first. FGameLiftServerSDKModule* gameLiftSdkModule = &FModuleManager::LoadModuleChecked<FGameLiftServerSDKModule>(FName("GameLiftServerSDK")); //InitSDK establishes a local connection with GameLift's agent to enable communication. gameLiftSdkModule->InitSDK(); //Respond to new game session activation request. GameLift sends activation request //to the game server along with a game session object containing game properties //and other settings. Once the game server is ready to receive player connections, //invoke GameLiftServerAPI.ActivateGameSession() auto onGameSession = [=](Aws::GameLift::Server::Model::GameSession gameSession) { gameLiftSdkModule->ActivateGameSession(); }; FProcessParameters* params = new FProcessParameters(); params->OnStartGameSession.BindLambda(onGameSession); //OnProcessTerminate callback. GameLift invokes this before shutting down the instance //that is hosting this game server to give it time to gracefully shut down on its own. //In this example, we simply tell GameLift we are indeed going to shut down. params->OnTerminate.BindLambda([=](){gameLiftSdkModule->ProcessEnding();}); //HealthCheck callback. GameLift invokes this callback about every 60 seconds. By default, //GameLift API automatically responds 'true'. A game can optionally perform checks on //dependencies and such and report status based on this info. If no response is received //within 60 seconds, health status is recorded as 'false'. //In this example, we're always healthy! params->OnHealthCheck.BindLambda([](){return true; }); //Here, the game server tells GameLift what port it is listening on for incoming player //connections. In this example, the port is hardcoded for simplicity. Since active game //that are on the same instance must have unique ports, you may want to assign port values //from a range, such as: //const int32 port = FURL::UrlConfig.DefaultPort; //params->port; params->port = 7777; //Here, the game server tells GameLift what set of files to upload when the game session //ends. GameLift uploads everything specified here for the developers to fetch later. TArray<FString> logfiles; logfiles.Add(TEXT("aLogFile.txt")); params->logParameters = logfiles; //Call ProcessReady to tell GameLift this game server is ready to receive game sessions! gameLiftSdkModule->ProcessReady(*params); #endif d.GameLiftServerSDKのヘッドフォルダ(Plugins\GameLiftServerSDK\Source\GameLiftServerSDK\Public)をビルドのincludeパスに追加します。 e. UE5プロジェクトをビルドします 3. UE5プロジェクトのルートフォルダに戻して Gamelift_UE5.uproject をクリックして Unreal Editorを立ち上げます、「Edit」⇒「Plugins」をクリックして、GameLiftSDK プラグイン にチェックが入っていることを確認します 手順5.ローカルでゲームのテスト及びGameLiftへのアップロード ここまでは、UE5ゲームサーバーの開発とGameLiftSDKの組込みは全部完了しました。 GameLiftへゲームサーバーをプッシュする前に、一応ローカルで次の点を確認します。 ゲームサーバーが Server SDK と正常に統合されるか ゲームクライアントは新しいゲームセッションのスタート、プレイヤーのゲームへの参加、ゲームセッションへのConnectができるか 確認完了後に、以下の手順でGameLiftへアップロードを実施する CMDでGameLiftローカルのセットアップ cd {gameliftSDKダウンロード先}\GameLiftLocal-1.0.5 java -jar GameLiftLocal.jar -p 9080 ゲームサーバーを起動します 手順2でパッケージ化したゲームサーバーフォルダに移動します ゲームサーバーのログを出力したいため、起動exeのショットカットを作成して、 リンク先の後ろに「-log」を追加します ショットカットをクリックして、ゲームサーバーを起動します UE5プロジェクトのルートフォルダに戻して、 Gamelift_UE5.uproject をクリックして Unreal Editorを立ち上げます、 をクリックして、出た画面でプレイヤー数を2に設定して でクライアントを起動します CMDでゲームセッションを作成します AWS gamelift describe-game-sessions --endpoint-url http://localhost:9080 --fleet-id fleet-123 AWS gamelift create-game-session --endpoint-url http://localhost:9080 --maximum-player-session-count 2 --fleet-id fleet-1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d クライアントからゲームサーバーに接続してみます。 クライアントで **~** キーを押して、 コマンドライン が表示されます、そこにローカルホストIP( 127.0.0.1 )を入力すれば、上記作成したゲームルームに入ります ※下記の図ではメモリ不足に関するエラーが発生していますが、検証に影響はないため無視して進めます。 接続確認します ローカルの検証はできたので、ここから AWS 側で必要なリソースを作成します。 GameLift側で起動用 スクリプト 作成 手順2でパッケージ化したゲームサーバーフォルダに移動します その配下にinstall.batを配置します、以下は中身です。 Engine\Extras\Redist\en-us\UEPrereqSetup_x64.exe /install /quiet /norestart /log c:\game\UE5PrereqSetup.log 以下の aws コマンドでゲームサーバーをGameLiftへアップロードします ※ AWS の基本的な知識(IAMアカウント作成、 aws cli セットアップなど)の説明は割愛いたします。 operating-system: ゲームサーバーの稼働OS(筆者はwindows2012を採用します) build-root: 手順2で作ったパッケージのパス name: GameLiftでの表示名 build-version: バージョン定義 region: AWS のリージョン名 aws gamelift upload-build \ --operating-system WINDOWS_2012 \ --build-root "E:\UnrealBuilds\WindowsServer" \ --name "gamelift-Unreal-engine" \ --build-version "0.01" \ --region ap-northeast-1 aws consoleにログインして、GameLiftに開いてアップロードしたゲームサーバーを確認します。 ビルド数の隣に「 フリートを作成する 」をクリックしてGameLiftのFleetを作成します。 名前: Fleet名 フリートタイプ: オンデマンド 証明書タイプ: 無効 バイナリ型: ビルド ビルド: 上記2でアップロードしたゲームサーバーを選択する インスタンス タイプ: 無料のタイプでより ロケーション管理: 日本のリージョン プロセス管理 起動パス: Gamelift_UE5\Binaries\ Win64 \Gamelift_UE5Server.exe 同時プロセス: 1 EC2ポート設定 ポート範囲: 7777 プロトコル : UDP IPアドレス 範囲: 0.0.0.0/0 その他デフォルト値でよい 数十分ほど待つとフリートが完成します。こちらは以下マネジメントコンソールのページからも確認することができます。 ここまでで、GameLift側の構築は完了となります。 手順6. AWS CLI コマンドによるゲームセッション作成と接続 まず マルチプレイ を始めるにあたって、プレイヤーが集合するためのルーム、つまりGameLiftのゲームセッションを作成する必要があります(以降、ゲームセッションとして記載します)。次に、ゲームに接続するプレイヤーは、ゲームルームの「 IPアドレス 」を指定し、ゲームに参加することができます。 本来であれば、冒頭の AWS アーキテクチャ 図のように別途APIGatewayとlambdaを用意し、ユーザー認証を実施した上でGameLiftへ接続するなどセキュリ ティー を考慮する必要がありますが、今回は検証のため AWS CLI を用いたコマンドベースで接続します。 ゲームセッション作成 以下のコマンドを、手順5で作成したフリートのIDを取得し変数として設定してください(マネジメントコンソールのフリートの一覧ページから作成したフリート ID の確認が可能) aws gamelift create-game-session --fleet-id fleet-5f14fed2-30d6-4314-9220-47a261a9e6ee --maximum-player-session-count 2 aのコマンドを実行しフリートにゲームセッションを作成します。 ゲームクライアントの起動とゲームサーバーへの接続 ローカル検証する時と同様に、 Unreal Editorで をクリックして、出た画面でプレイヤー数を2に設定して でクライアントを起動します。 クライアントで **~** キーを押して、 コマンドライン が表示されます、そこに「open IPアドレス 」と入力することでゲームサーバーへ接続できます。 うまく接続できない場合、まずは以下の点を確認してみてください。 クライアント側OSやプロキシなどのネットワークの経路上で接続をブロックしている設定がないか確認する GameLiftのフリートではEC2 ポート設定が反映できたか確認する 終わりに 今回、UE5とGameLiftを利用し、オンライン マルチプレイ ゲームの構築する方法をご紹介しました。 冒頭で記載した通り、 メタバース においてよりよい没入感を実現するため、高精細なリアルタイム レンダリング が必要でこの辺はUnrealEngineの強みだと思います。 また、 メタバース 上でユーザーは「 SecondLife 」として生活していく上、運営側は大規模大人数同時オンライン可能のサーバーサイドの構築は不可欠で、今後ゲームサーバー技術の活用は増えていくと思われます。 そのため、引き続きゲーム領域のサーバーサイド技術をウォッチしていきたいと思います。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ(Web3/メタバース/AI) 参考 Amazon GameLift Developer Guider Unreal Engine5.1 Documentation GitHub aws-gamelift-samples 執筆: @chen.sun 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
みなさんこんにちは、 電通国際情報サービス (ISID)X イノベーション 本部ソフトウェアデザインセンターの佐藤太一です。 最近は少しずつRustにさわっているので、 コンパイラ などのツールチェインを更新する方法と、それを元に戻す方法を併せて紹介します。 構築済みの開発環境 Rustツールチェインを更新する方法 バージョンの確認 Rustツールチェインを元に戻す方法 バージョンの確認 まとめ 構築済みの開発環境 私の開発環境は Microsoft が提供するセットアップ手順にそって構築してあります。 Windows で Rust 用の開発環境を設定する 記事執筆時点でインストールしてあるrustupは 1.24.3 です。 Rustツールチェインを更新する方法 まずは、ツールチェインを最新の安定版に更新するコマンドを紹介しましょう。 rustup update stable このコマンドを実行すると以下のようにログが出力されます。 Rust標準のタ スクラン ナーであるcargoや コンパイラ であるrustc、標準ライブラリであるrust-stdがアップデートされています。 この実行では、記事執筆時における最新の安定版である 1.59.0 がインストールされていますね。 バージョンの確認 rustcのバージョンを確認してみましょう。 rustc --version rustcのバージョンが 1.59.0 になっています。バージョンアップは成功です。 Rustツールチェインを元に戻す方法 次は、ツールチェンを元に戻す方法を紹介しましょう。 まず、以下のコマンドを実行してインストール済みのツールチェインの一覧を確認します。 rustup toolchain list 筆者の環境では、一つ前のバージョンと最新の安定版をインストールしてあるので以下のように出力されます。 stable-x86_64-pc-windows-msvc の後ろに (default) と表示されていることから、現在利用中のツールチェインが最新の安定版を使っていることが分かります。 それでは、インストール済みの古いバージョンにツールチェインを戻してみましょう。 rustup default 1.58.1- x86 _64-pc- windows -msvc rustup default コマンドの引数として、先ほどのツールチェイン一覧から読み取れる古いバージョンを指定します。 古いバージョンが使われるように切り替わりましたね。最後にインストール済みのツールチェインをもう一度一覧してみましょう。 古いバージョンのツールチェインを使うようになりましたね。 バージョンの確認 本当に古いバージョンへ戻せているか、rustcのバージョンを確認してみましょう。 rustc --version rustcのバージョンが 1.58.1 になっていますので、古いものへ戻せています。 まとめ 今回は、ツールチェインを更新する方法とそれを元に戻す方法を説明しました。 rustupコマンドの詳細情報が知りたいなら The rustup book を確認してください。 執筆: @sato.taichi 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
みなさんこんにちは、 電通国際情報サービス (ISID)X イノベーション 本部ソフトウェアデザインセンターの佐藤太一です。 最近は少しずつRustにさわっているので、 コンパイラ などのツールチェインを更新する方法と、それを元に戻す方法を併せて紹介します。 構築済みの開発環境 Rustツールチェインを更新する方法 バージョンの確認 Rustツールチェインを元に戻す方法 バージョンの確認 まとめ 構築済みの開発環境 私の開発環境は Microsoft が提供するセットアップ手順にそって構築してあります。 Windows で Rust 用の開発環境を設定する 記事執筆時点でインストールしてあるrustupは 1.24.3 です。 Rustツールチェインを更新する方法 まずは、ツールチェインを最新の安定版に更新するコマンドを紹介しましょう。 rustup update stable このコマンドを実行すると以下のようにログが出力されます。 Rust標準のタ スクラン ナーであるcargoや コンパイラ であるrustc、標準ライブラリであるrust-stdがアップデートされています。 この実行では、記事執筆時における最新の安定版である 1.59.0 がインストールされていますね。 バージョンの確認 rustcのバージョンを確認してみましょう。 rustc --version rustcのバージョンが 1.59.0 になっています。バージョンアップは成功です。 Rustツールチェインを元に戻す方法 次は、ツールチェンを元に戻す方法を紹介しましょう。 まず、以下のコマンドを実行してインストール済みのツールチェインの一覧を確認します。 rustup toolchain list 筆者の環境では、一つ前のバージョンと最新の安定版をインストールしてあるので以下のように出力されます。 stable-x86_64-pc-windows-msvc の後ろに (default) と表示されていることから、現在利用中のツールチェインが最新の安定版を使っていることが分かります。 それでは、インストール済みの古いバージョンにツールチェインを戻してみましょう。 rustup default 1.58.1- x86 _64-pc- windows -msvc rustup default コマンドの引数として、先ほどのツールチェイン一覧から読み取れる古いバージョンを指定します。 古いバージョンが使われるように切り替わりましたね。最後にインストール済みのツールチェインをもう一度一覧してみましょう。 古いバージョンのツールチェインを使うようになりましたね。 バージョンの確認 本当に古いバージョンへ戻せているか、rustcのバージョンを確認してみましょう。 rustc --version rustcのバージョンが 1.58.1 になっていますので、古いものへ戻せています。 まとめ 今回は、ツールチェインを更新する方法とそれを元に戻す方法を説明しました。 rustupコマンドの詳細情報が知りたいなら The rustup book を確認してください。 執筆: @sato.taichi 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
X イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの福山です。 先日、米政府(米サイバーセキュリティインフラスト ラク チャセキュリティ庁( CISA )や米 連邦捜査局 (FBI)、 MS-ISAC(Multi-State ISAC)の共同)から、 DDoS攻撃 に対するガイダンス「 Understanding and Responding to Distributed Denial-of-Service Attacks 」が公開されました。 業務で AWS に触れる機会が多いので、この機会に AWS における DDoS攻撃 対策を調査したいと思いました。 そこで今回は、 AWS WAF、GuardDutyを有効活用できていない AWS 上のWebアプリケーションに対して DDoS攻撃 を受けた際に、対策となるリソースを追加するためのCloudFormationテンプレートや後続作業を調査しましたので、紹介したいと思います。 前提 初動対応 ①隔離用のネットワークACLを関連付け(主にL3の防御) 【概要】 【目的】 【構成図】 【注意点】 【手順】 【ポイント解説】 ②AWS WAFの関連付け(主にL7の防御) 【概要】 【目的】 【構成図】 【注意点】 【手順】 【ポイント解説】 ③GuardDutyの全リージョン有効化 保全 事後調査 事後対策 まとめ 前提 AWS における DDoS攻撃 とその対策について知るため、以下の資料を確認しました。 こちらをベースに対策を考えました。 参考: AWS BlackBelt AWS上でのDDoS対策 上記P9によると、 AWS ではインフラ層(L3/L4)とアプリ層(L6/L7)について対策する必要があるようです。 上図(P12引用)のL3( ネットワーク層 )を狙った DDoS攻撃 として、 UDP 反射攻撃などの処理能力を超えた トラフィック を送りつける攻撃が一般的です。これらの対策としては、セキュリティグループやネットワーク ACL などの境界防御が挙げられます。 また、L7(アプリケーション層)に対してはHTTP GET、 DNS クエリフラッドなど悪意のある要求を使用して、アプリケーションリソースを使用する攻撃が挙げられます。これらの対策サービスとして、 AWS WAFなどがあります。 上記2点が標的となるWebアプリケーション構成として、EC2を利用しているケースは多いかと思います。そこで今回はEC2を利用しているケースで考えたいと思います。 攻撃者が AWS 外から DDoS攻撃 を行っているケースを想定しています。 本執筆では主に初動対応に焦点を当てており、いかに素早く対処できるかを重視した内容となっています。 対応の自動化にあたりCloudFormationを利用します。CloudFormationはインフラをコードで管理できるサービスとなっています。なお、 AWS CDKの利用が広がってきている中ではありますが、環境準備の手間が不要で、開発経験がない方でも手軽に作業ができる点を考慮し、CloudFormationを採用しました。 AWS Shield Advancedと呼ばれるDDoS対策を提供する AWS の有償サービス(月額3,000USD)がありますが、 今回は契約していない状態を想定しています。 初動対応 ①隔離用のネットワーク ACL を関連付け(主にL3の防御) 【概要】  攻撃対象のリソースが設置されているサブネットに、自動で新規ネットワーク ACL が適用されます。 【目的】  悪用可能性のあるポート、 プロトコル からの通信を遮断します。 【構成図】  作成されるリソースは下図の赤枠部分となります。 【注意点】  以下の手順でCloudFormationスタックを作成すると、元々アタッチされていたネットワーク ACL は  デタッチされます。その後、CloudFormationスタックを削除すると、defaultのネットワーク ACL が  アタッチされますのでご注意ください(元々default以外のネットワーク ACL をアタッチしていた場合も、  defaultのネットワーク ACL に切り替わります)。 【手順】  CloudFormationでリソースのあるリージョンを選択し、スタックの作成、テンプレートファイルのアップロード  から下記コードをyml形式でアップロードし実行します。詳細な手順を確認したい場合は以下をご参考ください。  参考: AWS CloudFormation コンソールでのスタックの作成  コードを表示 AWSTemplateFormatVersion : '2010-09-09' Metadata : AWS::CloudFormation::Interface : ParameterGroups : - Label : default : NACL Configuration Parameters : - Prefix - VpcId - SubnetId - VpcCidr Parameters : Prefix : Type : String Default : ddos VpcId : Type : AWS::EC2::VPC::Id SubnetId : Type : AWS::EC2::Subnet::Id Description : "Select the subnet to which you want to attach the NACL" ### VPC Cidrは手動で入力する VpcCidr : Type : String Default : xx.xx.xx.xx/xx Description : "Set the VPCCidrBlok to allow inbound traffic within the VPC" Resources : Nacl : Type : AWS::EC2::NetworkAcl Properties : VpcId : !Ref VpcId Tags : - Key : Name Value : !Sub ${Prefix}-nacl NaclAssoc : Type : AWS::EC2::SubnetNetworkAclAssociation Properties : NetworkAclId : !Ref Nacl SubnetId : !Ref SubnetId ### ここからインバウンドルール #### VPC内通信を許可 NaclEntryInbound001 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 1 RuleAction : allow Protocol : -1 CidrBlock : !Ref VpcCidr NetworkAclId : !Ref Nacl #### MemcachedのUDP通信をブロック NaclEntryInbound005 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 5 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 11211 To : 11211 NetworkAclId : !Ref Nacl #### NTPのUDP通信を許可 NaclEntryInbound010 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 10 RuleAction : allow Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 123 To : 123 NetworkAclId : !Ref Nacl #### CharGENのUDP通信をブロック NaclEntryInbound015 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 15 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 19 To : 19 NetworkAclId : !Ref Nacl #### QOTDのUDP通信をブロック NaclEntryInbound020 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 20 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 17 To : 17 NetworkAclId : !Ref Nacl #### RIPv1のUDP通信をブロック NaclEntryInbound025 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 25 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 520 To : 520 NetworkAclId : !Ref Nacl #### RIPv1のUDP通信をブロック NaclEntryInbound030 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 30 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 389 To : 389 NetworkAclId : !Ref Nacl #### CLDAPのUDP通信をブロック NaclEntryInbound035 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 35 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 389 To : 389 NetworkAclId : !Ref Nacl #### DNSのUDP通信を許可 NaclEntryInbound040 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 40 RuleAction : allow Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 53 To : 53 NetworkAclId : !Ref Nacl #### Quake Network ProtocolのUDP通信をブロック NaclEntryInbound045 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 45 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 27960 To : 27960 NetworkAclId : !Ref Nacl #### TFTPのUDP通信をブロック NaclEntryInbound050 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 50 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 69 To : 69 NetworkAclId : !Ref Nacl #### SSDPのUDP通信をブロック NaclEntryInbound055 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 55 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 1900 To : 1900 NetworkAclId : !Ref Nacl #### MSSQLのUDP通信をブロック NaclEntryInbound060 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 60 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 1434 To : 1434 NetworkAclId : !Ref Nacl #### Kad (P2P)のUDP通信をブロック NaclEntryInbound065 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 65 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 751 To : 751 NetworkAclId : !Ref Nacl #### Portmap (RPCbind)のUDP通信をブロック NaclEntryInbound070 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 70 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 111 To : 111 NetworkAclId : !Ref Nacl #### Multicast DNSのUDP通信をブロック NaclEntryInbound075 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 75 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 5353 To : 5353 NetworkAclId : !Ref Nacl #### ICMPのエコー応答をブロック NaclEntryInbound080 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 80 RuleAction : deny Protocol : 1 CidrBlock : 0.0.0.0/0 Icmp : Type : 0 Code : -1 NetworkAclId : !Ref Nacl #### ICMPのエコー要求をブロック NaclEntryInbound085 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 85 RuleAction : deny Protocol : 1 CidrBlock : 0.0.0.0/0 Icmp : Type : 8 Code : -1 NetworkAclId : !Ref Nacl #### デフォルトの許可ルール NaclEntryInbound100 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 100 RuleAction : allow Protocol : -1 CidrBlock : 0.0.0.0/0 NetworkAclId : !Ref Nacl ### ここからアウトバウンドルール #### デフォルトの許可ルール NaclEntryOutbound100 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : true RuleNumber : 100 RuleAction : allow Protocol : -1 CidrBlock : 0.0.0.0/0 NetworkAclId : !Ref Nacl   【ポイント解説】 ネットワーク ACL を選んだ理由   ホワイトリスト により少ない定義量で書けるセキュリティグループも検討しましたが、以下の理由から  ネットワーク ACL を採用しました。  ・明示的に拒否ルールが書ける  ・今後EC2が増えても追加設定なしで境界防御を実現できる  ・NLBのようなセキュリティグループをサポートしないリソースも保護できる  ・汎用性を重視したい ルール全般について  全ての通信を遮断するわけではなく、悪用実績のある UDP サービスを増幅率の高い順でルール設定しています。  (念のためICMPも拒否ルールを設定しています)  参考: UDP-Based Amplification Attacks  ただし、 VPC 内通信、53/ udp 、123/ udp については、システムへの影響を考慮して許可しています。 VPC Cidrについて  対象 VPC 内の通信を許可するため、ParametersのVpcCidrには IPアドレス レンジを入力します。  こちらは最優先で適用されるルールとなるため、誤って0.0.0.0/0と入力してしまうと通信が全て許可されて  しまいますので、ご注意ください。 ② AWS WAFの関連付け(主にL7の防御)  攻撃者がレイヤーを変えてくる可能性があるため、①に続いて下記を速やかに実施します。 【概要】   AWS WAFを作成し、適用します。 【目的】   Bot からの攻撃の遮断や地域制限を行うことができ、アプリケーションリソースを保護します。 【構成図】  作成されるリソースは、下図A、Bの場合赤枠部分となります。  CのケースはEC2が丸裸の構成です。  (A)最前段がCloudFront構成 (B)最前段がALBで、CloudFrontなしの構成 (C)CloudFront、ALBが両方ともない構成 【注意点】  以下の手順でCloudFormationスタックを作成すると、元々 ディストリビューション またはALBに関連付け  されていたWeb ACL はデタッチされます。その後、CloudFormationスタックを削除しても、  元のWeb ACL は変わらずデタッチされた状態となりますのでご注意ください。 【手順】  以下A、B、Cの構成において、該当する作業を実施します。   (A)最前段がCloudFront構成   1. CloudFormationでus-east-1( バージニア 北部)リージョンを選択し、スタックの作成、テンプレート    ファイルのアップロードから、下記コードをyml形式でアップロードし実行します。  コードを表示 AWSTemplateFormatVersion : 2010-09-09 Metadata : AWS::CloudFormation::Interface : ParameterGroups : - Label : default : WAF Configuration Parameters : - Prefix - WhiteListIP - RateLimit - SwitchGeoRestriction - WhiteListGeoRestriction Parameters : Prefix : Type : String Default : ddos ### 社内のIP等、許可するIPを設定する WhiteListIP : Type : CommaDelimitedList Default : xx.xx.xx.xx/xx Description : Set IPs to Whitelist. Commas allow multiple sets(e.g. xx.xx.0.0/16, xx.xx.xx.xx/32). RateLimit : Type : Number Default : 100 Description : Set value of WAF Rate Limit ### 地理的一致ルールを有効化したい場合はONにする SwitchGeoRestriction : Type : String AllowedValues : [ "ON" , "OFF" ] Description : Select "ON" to block access except in designated countries, or "OFF" to not configure. ### アクセス許可したい国のコードを入力する(SwitchGeoRestrictionがOFFの場合はデフォルトのまま変更不要) WhiteListGeoRestriction : Type : CommaDelimitedList Default : JP Description : Set CountryCodes to which access is allowed. Commas allow multiple sets(e.g. JP, US). - https://docs.aws.amazon.com/ja_jp/waf/latest/APIReference/API_GeoMatchStatement.html Conditions : GeoRestriction : !Equals [ "ON" , !Ref SwitchGeoRestriction ] Resources : WebACL : Type : AWS::WAFv2::WebACL Properties : Name : !Ref Prefix DefaultAction : Allow : {} Scope : CLOUDFRONT VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : !Ref Prefix SampledRequestsEnabled : true Rules : - Name : Custom-WhiteListIPSet Action : Allow : {} Priority : 0 Statement : IPSetReferenceStatement : Arn : !GetAtt WhiteListIPSet.Arn VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : Custom-WhiteListIPSet SampledRequestsEnabled : true - Name : AWS-AWSManagedRulesCommonRuleSet Priority : 1 Statement : ManagedRuleGroupStatement : VendorName : AWS Name : AWSManagedRulesCommonRuleSet OverrideAction : None : {} VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : AWSManagedRulesCommonRuleSet SampledRequestsEnabled : true - Name : AWS-AWSManagedRulesKnownBadInputsRuleSet Priority : 2 Statement : ManagedRuleGroupStatement : VendorName : AWS Name : AWSManagedRulesKnownBadInputsRuleSet OverrideAction : None : {} VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : AWSManagedRulesKnownBadInputsRuleSet SampledRequestsEnabled : true - Name : AWS-AWSManagedRulesAmazonIpReputationList Priority : 3 Statement : ManagedRuleGroupStatement : VendorName : AWS Name : AWSManagedRulesAmazonIpReputationList OverrideAction : None : {} VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : AWSManagedRulesAmazonIpReputationList SampledRequestsEnabled : true - Name : Custom-Ratebased Action : Block : {} Priority : 4 Statement : RateBasedStatement : AggregateKeyType : IP Limit : !Ref RateLimit ScopeDownStatement : NotStatement : Statement : IPSetReferenceStatement : Arn : !GetAtt WhiteListIPSet.Arn VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : Custom-Ratebased SampledRequestsEnabled : true - !If - GeoRestriction - Name : Custom-GeoRestriction Action : Block : {} Priority : 5 Statement : NotStatement : Statement : GeoMatchStatement : CountryCodes : !Ref WhiteListGeoRestriction VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : Custom-GeoRestriction SampledRequestsEnabled : true - Ref : AWS::NoValue WhiteListIPSet : Type : "AWS::WAFv2::IPSet" Properties : Name : Custom-ipaddress-whitelist Scope : CLOUDFRONT IPAddressVersion : IPV4 Addresses : !Ref WhiteListIP   2. 作成されたWeb ACL を、対象のCloudFront ディストリビューション に手動でアタッチします。    詳細な手順を確認したい場合は下記をご参考ください。    参考: Web ACLとCloudFrontディストリビューションとの関連付け   (B)最前段がALBで、CloudFrontなしの構成   CloudFormationでリソースがあるリージョンを選択し、スタックの作成、テンプレートファイルの   アップロードから下記コードをyml形式でアップロードし実行します。   ※作成されるWeb ACL は、対象のALBに自動でアタッチされます。  コードを表示 AWSTemplateFormatVersion : 2010-09-09 Metadata : AWS::CloudFormation::Interface : ParameterGroups : - Label : default : WAF Configuration Parameters : - Prefix - WebAclAssociationResourceArn - WhiteListIP - RateLimit - SwitchGeoRestriction - WhiteListGeoRestriction Parameters : Prefix : Type : String Default : ddos ### ALBのARNを入力する WebAclAssociationResourceArn : Type : String Default : "arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:loadbalancer/app/XXXXXXXXXXXX" Description : Enter RegionalResource(ALB) ARN to associate with WEBACL. ### 社内のIP等、許可するIPを設定する WhiteListIP : Type : CommaDelimitedList Default : xx.xx.xx.xx/xx Description : Set IPs to Whitelist. Commas allow multiple sets(e.g. xx.xx.0.0/16, xx.xx.xx.xx/32). RateLimit : Type : Number Default : 100 Description : Set value of WAF Rate Limit ### 地理的一致ルールを有効化したい場合はONにする SwitchGeoRestriction : Type : String AllowedValues : [ "ON" , "OFF" ] Description : Select "ON" to block access except in designated countries, or "OFF" to not configure. ### アクセス許可したい国のコードを入力する(SwitchGeoRestrictionがOFFの場合はデフォルトの値で変更不要) WhiteListGeoRestriction : Type : CommaDelimitedList Default : JP Description : Set CountryCodes to which access is allowed. Commas allow multiple sets(e.g. JP, US). - https://docs.aws.amazon.com/ja_jp/waf/latest/APIReference/API_GeoMatchStatement.html Conditions : GeoRestriction : !Equals [ "ON" , !Ref SwitchGeoRestriction ] Resources : WebACL : Type : AWS::WAFv2::WebACL Properties : Name : !Ref Prefix DefaultAction : Allow : {} Scope : REGIONAL VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : !Ref Prefix SampledRequestsEnabled : true Rules : - Name : Custom-WhiteListIPSet Action : Allow : {} Priority : 0 Statement : IPSetReferenceStatement : Arn : !GetAtt WhiteListIPSet.Arn VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : Custom-WhiteListIPSet SampledRequestsEnabled : true - Name : AWS-AWSManagedRulesCommonRuleSet Priority : 1 Statement : ManagedRuleGroupStatement : VendorName : AWS Name : AWSManagedRulesCommonRuleSet OverrideAction : None : {} VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : AWSManagedRulesCommonRuleSet SampledRequestsEnabled : true - Name : AWS-AWSManagedRulesKnownBadInputsRuleSet Priority : 2 Statement : ManagedRuleGroupStatement : VendorName : AWS Name : AWSManagedRulesKnownBadInputsRuleSet OverrideAction : None : {} VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : AWSManagedRulesKnownBadInputsRuleSet SampledRequestsEnabled : true - Name : AWS-AWSManagedRulesAmazonIpReputationList Priority : 3 Statement : ManagedRuleGroupStatement : VendorName : AWS Name : AWSManagedRulesAmazonIpReputationList OverrideAction : None : {} VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : AWSManagedRulesAmazonIpReputationList SampledRequestsEnabled : true - Name : Custom-Ratebased Action : Block : {} Priority : 4 Statement : RateBasedStatement : AggregateKeyType : IP Limit : !Ref RateLimit ScopeDownStatement : NotStatement : Statement : IPSetReferenceStatement : Arn : !GetAtt WhiteListIPSet.Arn VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : Custom-Ratebased SampledRequestsEnabled : true - !If - GeoRestriction - Name : Custom-GeoRestriction Action : Block : {} Priority : 5 Statement : NotStatement : Statement : GeoMatchStatement : CountryCodes : !Ref WhiteListGeoRestriction VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : Custom-GeoRestriction SampledRequestsEnabled : true - Ref : AWS::NoValue WhiteListIPSet : Type : "AWS::WAFv2::IPSet" Properties : Name : Custom-ipaddress-whitelist Scope : REGIONAL IPAddressVersion : IPV4 Addresses : !Ref WhiteListIP WebACLAssociation : Type : AWS::WAFv2::WebACLAssociation Properties : ResourceArn : !Ref WebAclAssociationResourceArn WebACLArn : !GetAtt WebACL.Arn   (C)CloudFront、ALBが両方ともない構成(A、Bで解消しない場合もこちら)   この場合、 AWS WAFはアタッチできないため、他の手を打つ必要があります。   なお、上段A、Bで解消しない場合も最終手段として下記の作業を行うことになると考えます。   以下α、βいずれかを判断の上、対応してください。   (α)コストが掛かってもシステム稼働を優先したい    ・複数 インスタンス 構成かつAuto Scaling Groupで稼働している場合      Auto Scalingの インスタンス 最大台数を増やします。    ・単一 インスタンス 等、Auto Scaling Groupを利用せずに稼働している場合       インスタンス タイプのスケールアップを実施します。   (β)システム稼働よりもDDoS被害(コスト)軽減を優先したい     対象EC2を停止します。 【ポイント解説】 Aに関して、CloudFormationでは既存のCloudFrontに AWS WAFをアタッチすることができません。 スタック作成後、手動でCloudFrontにアタッチする必要があります。 A、B共通して以下のルールが作成されます。優先度順に記載します。 ホワイトリスト IP(許可) ・ParametersのWhiteListIPに社内のIP等、許可するIPを入力(複数可) AWS マネージドルール(拒否) ・AWSManagedRulesCommonRuleSet ・AWSManagedRulesKnownBadInputsRuleSet ・AWSManagedRulesAmazonIpReputationList レートベースのルール(アクセス制限) ・ParametersのRateLimitにレート制限値を入力 ・ParametersのWhiteListIPで設定したIPは対象外 地理的一致ルール(許可) ・ParametersのSwitchGeoRestrictionをONにすることで有効化 ・ParametersのWhiteListGeoRestrictionにアクセス許可する国のコードを入力(複数可)  参考: CountryCodes ・ParametersのSwitchGeoRestrictionをOFFにする場合、デフォルトの値から変更不要 ③GuardDutyの全リージョン有効化   ガイダンス によると、より悪意のある攻撃から注意を反らすために DDoS攻撃 が使用されることもある  との記載がありました(P4)。 AWS の脅威検知サービスであるGuardDutyを全リージョン有効化  していない場合は、このタイミングで有効にすることをお勧めします。  以下のサイトでは、全リージョン一括で有効化して通知設定する方法が紹介されていました。  参考: https://dev.classmethod.jp/articles/set-guardduty-all-region/ 保全 ・CloudWatch Logs等、関連するログのエクスポート(ログローテーションによる消失を回避するため)。 事後調査 ・ログの分析、原因調査。 事後対策 ・今回適用したネットワーク ACL と AWS WAFについて、アタッチを継続するか、設定変更するか等を判断。  今回作成したリソースは、CloudFormationスタックを削除することで消すことができる。 ・ アーキテクチャ の見直し( インスタンス をプライベートサブネットに設置、CloudFrontの導入、Route53への移行等)。 ・Auto Scalingの最大台数、 インスタンス タイプの見直し。 ・セキュリティグループの設定見直し。 まとめ DDoS攻撃 を受けた時の初動対応をできるだけ自動化してみました。 本記事が皆様のお役に立てれば幸いです。 〜最後に〜 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募お待ちしています。 - セキュリティエンジニア(セキュリティ設計) 執筆: @fuku.dancho 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
X イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの福山です。 先日、米政府(米サイバーセキュリティインフラスト ラク チャセキュリティ庁( CISA )や米 連邦捜査局 (FBI)、 MS-ISAC(Multi-State ISAC)の共同)から、 DDoS攻撃 に対するガイダンス「 Understanding and Responding to Distributed Denial-of-Service Attacks 」が公開されました。 業務で AWS に触れる機会が多いので、この機会に AWS における DDoS攻撃 対策を調査したいと思いました。 そこで今回は、 AWS WAF、GuardDutyを有効活用できていない AWS 上のWebアプリケーションに対して DDoS攻撃 を受けた際に、対策となるリソースを追加するためのCloudFormationテンプレートや後続作業を調査しましたので、紹介したいと思います。 前提 初動対応 ①隔離用のネットワークACLを関連付け(主にL3の防御) 【概要】 【目的】 【構成図】 【注意点】 【手順】 【ポイント解説】 ②AWS WAFの関連付け(主にL7の防御) 【概要】 【目的】 【構成図】 【注意点】 【手順】 【ポイント解説】 ③GuardDutyの全リージョン有効化 保全 事後調査 事後対策 まとめ 前提 AWS における DDoS攻撃 とその対策について知るため、以下の資料を確認しました。 こちらをベースに対策を考えました。 参考: AWS BlackBelt AWS上でのDDoS対策 上記P9によると、 AWS ではインフラ層(L3/L4)とアプリ層(L6/L7)について対策する必要があるようです。 上図(P12引用)のL3( ネットワーク層 )を狙った DDoS攻撃 として、 UDP 反射攻撃などの処理能力を超えた トラフィック を送りつける攻撃が一般的です。これらの対策としては、セキュリティグループやネットワーク ACL などの境界防御が挙げられます。 また、L7(アプリケーション層)に対してはHTTP GET、 DNS クエリフラッドなど悪意のある要求を使用して、アプリケーションリソースを使用する攻撃が挙げられます。これらの対策サービスとして、 AWS WAFなどがあります。 上記2点が標的となるWebアプリケーション構成として、EC2を利用しているケースは多いかと思います。そこで今回はEC2を利用しているケースで考えたいと思います。 攻撃者が AWS 外から DDoS攻撃 を行っているケースを想定しています。 本執筆では主に初動対応に焦点を当てており、いかに素早く対処できるかを重視した内容となっています。 対応の自動化にあたりCloudFormationを利用します。CloudFormationはインフラをコードで管理できるサービスとなっています。なお、 AWS CDKの利用が広がってきている中ではありますが、環境準備の手間が不要で、開発経験がない方でも手軽に作業ができる点を考慮し、CloudFormationを採用しました。 AWS Shield Advancedと呼ばれるDDoS対策を提供する AWS の有償サービス(月額3,000USD)がありますが、 今回は契約していない状態を想定しています。 初動対応 ①隔離用のネットワーク ACL を関連付け(主にL3の防御) 【概要】  攻撃対象のリソースが設置されているサブネットに、自動で新規ネットワーク ACL が適用されます。 【目的】  悪用可能性のあるポート、 プロトコル からの通信を遮断します。 【構成図】  作成されるリソースは下図の赤枠部分となります。 【注意点】  以下の手順でCloudFormationスタックを作成すると、元々アタッチされていたネットワーク ACL は  デタッチされます。その後、CloudFormationスタックを削除すると、defaultのネットワーク ACL が  アタッチされますのでご注意ください(元々default以外のネットワーク ACL をアタッチしていた場合も、  defaultのネットワーク ACL に切り替わります)。 【手順】  CloudFormationでリソースのあるリージョンを選択し、スタックの作成、テンプレートファイルのアップロード  から下記コードをyml形式でアップロードし実行します。詳細な手順を確認したい場合は以下をご参考ください。  参考: AWS CloudFormation コンソールでのスタックの作成  コードを表示 AWSTemplateFormatVersion : '2010-09-09' Metadata : AWS::CloudFormation::Interface : ParameterGroups : - Label : default : NACL Configuration Parameters : - Prefix - VpcId - SubnetId - VpcCidr Parameters : Prefix : Type : String Default : ddos VpcId : Type : AWS::EC2::VPC::Id SubnetId : Type : AWS::EC2::Subnet::Id Description : "Select the subnet to which you want to attach the NACL" ### VPC Cidrは手動で入力する VpcCidr : Type : String Default : xx.xx.xx.xx/xx Description : "Set the VPCCidrBlok to allow inbound traffic within the VPC" Resources : Nacl : Type : AWS::EC2::NetworkAcl Properties : VpcId : !Ref VpcId Tags : - Key : Name Value : !Sub ${Prefix}-nacl NaclAssoc : Type : AWS::EC2::SubnetNetworkAclAssociation Properties : NetworkAclId : !Ref Nacl SubnetId : !Ref SubnetId ### ここからインバウンドルール #### VPC内通信を許可 NaclEntryInbound001 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 1 RuleAction : allow Protocol : -1 CidrBlock : !Ref VpcCidr NetworkAclId : !Ref Nacl #### MemcachedのUDP通信をブロック NaclEntryInbound005 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 5 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 11211 To : 11211 NetworkAclId : !Ref Nacl #### NTPのUDP通信を許可 NaclEntryInbound010 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 10 RuleAction : allow Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 123 To : 123 NetworkAclId : !Ref Nacl #### CharGENのUDP通信をブロック NaclEntryInbound015 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 15 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 19 To : 19 NetworkAclId : !Ref Nacl #### QOTDのUDP通信をブロック NaclEntryInbound020 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 20 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 17 To : 17 NetworkAclId : !Ref Nacl #### RIPv1のUDP通信をブロック NaclEntryInbound025 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 25 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 520 To : 520 NetworkAclId : !Ref Nacl #### RIPv1のUDP通信をブロック NaclEntryInbound030 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 30 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 389 To : 389 NetworkAclId : !Ref Nacl #### CLDAPのUDP通信をブロック NaclEntryInbound035 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 35 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 389 To : 389 NetworkAclId : !Ref Nacl #### DNSのUDP通信を許可 NaclEntryInbound040 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 40 RuleAction : allow Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 53 To : 53 NetworkAclId : !Ref Nacl #### Quake Network ProtocolのUDP通信をブロック NaclEntryInbound045 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 45 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 27960 To : 27960 NetworkAclId : !Ref Nacl #### TFTPのUDP通信をブロック NaclEntryInbound050 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 50 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 69 To : 69 NetworkAclId : !Ref Nacl #### SSDPのUDP通信をブロック NaclEntryInbound055 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 55 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 1900 To : 1900 NetworkAclId : !Ref Nacl #### MSSQLのUDP通信をブロック NaclEntryInbound060 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 60 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 1434 To : 1434 NetworkAclId : !Ref Nacl #### Kad (P2P)のUDP通信をブロック NaclEntryInbound065 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 65 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 751 To : 751 NetworkAclId : !Ref Nacl #### Portmap (RPCbind)のUDP通信をブロック NaclEntryInbound070 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 70 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 111 To : 111 NetworkAclId : !Ref Nacl #### Multicast DNSのUDP通信をブロック NaclEntryInbound075 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 75 RuleAction : deny Protocol : 17 CidrBlock : 0.0.0.0/0 PortRange : From : 5353 To : 5353 NetworkAclId : !Ref Nacl #### ICMPのエコー応答をブロック NaclEntryInbound080 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 80 RuleAction : deny Protocol : 1 CidrBlock : 0.0.0.0/0 Icmp : Type : 0 Code : -1 NetworkAclId : !Ref Nacl #### ICMPのエコー要求をブロック NaclEntryInbound085 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 85 RuleAction : deny Protocol : 1 CidrBlock : 0.0.0.0/0 Icmp : Type : 8 Code : -1 NetworkAclId : !Ref Nacl #### デフォルトの許可ルール NaclEntryInbound100 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : false RuleNumber : 100 RuleAction : allow Protocol : -1 CidrBlock : 0.0.0.0/0 NetworkAclId : !Ref Nacl ### ここからアウトバウンドルール #### デフォルトの許可ルール NaclEntryOutbound100 : Type : AWS::EC2::NetworkAclEntry Properties : Egress : true RuleNumber : 100 RuleAction : allow Protocol : -1 CidrBlock : 0.0.0.0/0 NetworkAclId : !Ref Nacl   【ポイント解説】 ネットワーク ACL を選んだ理由   ホワイトリスト により少ない定義量で書けるセキュリティグループも検討しましたが、以下の理由から  ネットワーク ACL を採用しました。  ・明示的に拒否ルールが書ける  ・今後EC2が増えても追加設定なしで境界防御を実現できる  ・NLBのようなセキュリティグループをサポートしないリソースも保護できる  ・汎用性を重視したい ルール全般について  全ての通信を遮断するわけではなく、悪用実績のある UDP サービスを増幅率の高い順でルール設定しています。  (念のためICMPも拒否ルールを設定しています)  参考: UDP-Based Amplification Attacks  ただし、 VPC 内通信、53/ udp 、123/ udp については、システムへの影響を考慮して許可しています。 VPC Cidrについて  対象 VPC 内の通信を許可するため、ParametersのVpcCidrには IPアドレス レンジを入力します。  こちらは最優先で適用されるルールとなるため、誤って0.0.0.0/0と入力してしまうと通信が全て許可されて  しまいますので、ご注意ください。 ② AWS WAFの関連付け(主にL7の防御)  攻撃者がレイヤーを変えてくる可能性があるため、①に続いて下記を速やかに実施します。 【概要】   AWS WAFを作成し、適用します。 【目的】   Bot からの攻撃の遮断や地域制限を行うことができ、アプリケーションリソースを保護します。 【構成図】  作成されるリソースは、下図A、Bの場合赤枠部分となります。  CのケースはEC2が丸裸の構成です。  (A)最前段がCloudFront構成 (B)最前段がALBで、CloudFrontなしの構成 (C)CloudFront、ALBが両方ともない構成 【注意点】  以下の手順でCloudFormationスタックを作成すると、元々 ディストリビューション またはALBに関連付け  されていたWeb ACL はデタッチされます。その後、CloudFormationスタックを削除しても、  元のWeb ACL は変わらずデタッチされた状態となりますのでご注意ください。 【手順】  以下A、B、Cの構成において、該当する作業を実施します。   (A)最前段がCloudFront構成   1. CloudFormationでus-east-1( バージニア 北部)リージョンを選択し、スタックの作成、テンプレート    ファイルのアップロードから、下記コードをyml形式でアップロードし実行します。  コードを表示 AWSTemplateFormatVersion : 2010-09-09 Metadata : AWS::CloudFormation::Interface : ParameterGroups : - Label : default : WAF Configuration Parameters : - Prefix - WhiteListIP - RateLimit - SwitchGeoRestriction - WhiteListGeoRestriction Parameters : Prefix : Type : String Default : ddos ### 社内のIP等、許可するIPを設定する WhiteListIP : Type : CommaDelimitedList Default : xx.xx.xx.xx/xx Description : Set IPs to Whitelist. Commas allow multiple sets(e.g. xx.xx.0.0/16, xx.xx.xx.xx/32). RateLimit : Type : Number Default : 100 Description : Set value of WAF Rate Limit ### 地理的一致ルールを有効化したい場合はONにする SwitchGeoRestriction : Type : String AllowedValues : [ "ON" , "OFF" ] Description : Select "ON" to block access except in designated countries, or "OFF" to not configure. ### アクセス許可したい国のコードを入力する(SwitchGeoRestrictionがOFFの場合はデフォルトのまま変更不要) WhiteListGeoRestriction : Type : CommaDelimitedList Default : JP Description : Set CountryCodes to which access is allowed. Commas allow multiple sets(e.g. JP, US). - https://docs.aws.amazon.com/ja_jp/waf/latest/APIReference/API_GeoMatchStatement.html Conditions : GeoRestriction : !Equals [ "ON" , !Ref SwitchGeoRestriction ] Resources : WebACL : Type : AWS::WAFv2::WebACL Properties : Name : !Ref Prefix DefaultAction : Allow : {} Scope : CLOUDFRONT VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : !Ref Prefix SampledRequestsEnabled : true Rules : - Name : Custom-WhiteListIPSet Action : Allow : {} Priority : 0 Statement : IPSetReferenceStatement : Arn : !GetAtt WhiteListIPSet.Arn VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : Custom-WhiteListIPSet SampledRequestsEnabled : true - Name : AWS-AWSManagedRulesCommonRuleSet Priority : 1 Statement : ManagedRuleGroupStatement : VendorName : AWS Name : AWSManagedRulesCommonRuleSet OverrideAction : None : {} VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : AWSManagedRulesCommonRuleSet SampledRequestsEnabled : true - Name : AWS-AWSManagedRulesKnownBadInputsRuleSet Priority : 2 Statement : ManagedRuleGroupStatement : VendorName : AWS Name : AWSManagedRulesKnownBadInputsRuleSet OverrideAction : None : {} VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : AWSManagedRulesKnownBadInputsRuleSet SampledRequestsEnabled : true - Name : AWS-AWSManagedRulesAmazonIpReputationList Priority : 3 Statement : ManagedRuleGroupStatement : VendorName : AWS Name : AWSManagedRulesAmazonIpReputationList OverrideAction : None : {} VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : AWSManagedRulesAmazonIpReputationList SampledRequestsEnabled : true - Name : Custom-Ratebased Action : Block : {} Priority : 4 Statement : RateBasedStatement : AggregateKeyType : IP Limit : !Ref RateLimit ScopeDownStatement : NotStatement : Statement : IPSetReferenceStatement : Arn : !GetAtt WhiteListIPSet.Arn VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : Custom-Ratebased SampledRequestsEnabled : true - !If - GeoRestriction - Name : Custom-GeoRestriction Action : Block : {} Priority : 5 Statement : NotStatement : Statement : GeoMatchStatement : CountryCodes : !Ref WhiteListGeoRestriction VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : Custom-GeoRestriction SampledRequestsEnabled : true - Ref : AWS::NoValue WhiteListIPSet : Type : "AWS::WAFv2::IPSet" Properties : Name : Custom-ipaddress-whitelist Scope : CLOUDFRONT IPAddressVersion : IPV4 Addresses : !Ref WhiteListIP   2. 作成されたWeb ACL を、対象のCloudFront ディストリビューション に手動でアタッチします。    詳細な手順を確認したい場合は下記をご参考ください。    参考: Web ACLとCloudFrontディストリビューションとの関連付け   (B)最前段がALBで、CloudFrontなしの構成   CloudFormationでリソースがあるリージョンを選択し、スタックの作成、テンプレートファイルの   アップロードから下記コードをyml形式でアップロードし実行します。   ※作成されるWeb ACL は、対象のALBに自動でアタッチされます。  コードを表示 AWSTemplateFormatVersion : 2010-09-09 Metadata : AWS::CloudFormation::Interface : ParameterGroups : - Label : default : WAF Configuration Parameters : - Prefix - WebAclAssociationResourceArn - WhiteListIP - RateLimit - SwitchGeoRestriction - WhiteListGeoRestriction Parameters : Prefix : Type : String Default : ddos ### ALBのARNを入力する WebAclAssociationResourceArn : Type : String Default : "arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:loadbalancer/app/XXXXXXXXXXXX" Description : Enter RegionalResource(ALB) ARN to associate with WEBACL. ### 社内のIP等、許可するIPを設定する WhiteListIP : Type : CommaDelimitedList Default : xx.xx.xx.xx/xx Description : Set IPs to Whitelist. Commas allow multiple sets(e.g. xx.xx.0.0/16, xx.xx.xx.xx/32). RateLimit : Type : Number Default : 100 Description : Set value of WAF Rate Limit ### 地理的一致ルールを有効化したい場合はONにする SwitchGeoRestriction : Type : String AllowedValues : [ "ON" , "OFF" ] Description : Select "ON" to block access except in designated countries, or "OFF" to not configure. ### アクセス許可したい国のコードを入力する(SwitchGeoRestrictionがOFFの場合はデフォルトの値で変更不要) WhiteListGeoRestriction : Type : CommaDelimitedList Default : JP Description : Set CountryCodes to which access is allowed. Commas allow multiple sets(e.g. JP, US). - https://docs.aws.amazon.com/ja_jp/waf/latest/APIReference/API_GeoMatchStatement.html Conditions : GeoRestriction : !Equals [ "ON" , !Ref SwitchGeoRestriction ] Resources : WebACL : Type : AWS::WAFv2::WebACL Properties : Name : !Ref Prefix DefaultAction : Allow : {} Scope : REGIONAL VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : !Ref Prefix SampledRequestsEnabled : true Rules : - Name : Custom-WhiteListIPSet Action : Allow : {} Priority : 0 Statement : IPSetReferenceStatement : Arn : !GetAtt WhiteListIPSet.Arn VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : Custom-WhiteListIPSet SampledRequestsEnabled : true - Name : AWS-AWSManagedRulesCommonRuleSet Priority : 1 Statement : ManagedRuleGroupStatement : VendorName : AWS Name : AWSManagedRulesCommonRuleSet OverrideAction : None : {} VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : AWSManagedRulesCommonRuleSet SampledRequestsEnabled : true - Name : AWS-AWSManagedRulesKnownBadInputsRuleSet Priority : 2 Statement : ManagedRuleGroupStatement : VendorName : AWS Name : AWSManagedRulesKnownBadInputsRuleSet OverrideAction : None : {} VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : AWSManagedRulesKnownBadInputsRuleSet SampledRequestsEnabled : true - Name : AWS-AWSManagedRulesAmazonIpReputationList Priority : 3 Statement : ManagedRuleGroupStatement : VendorName : AWS Name : AWSManagedRulesAmazonIpReputationList OverrideAction : None : {} VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : AWSManagedRulesAmazonIpReputationList SampledRequestsEnabled : true - Name : Custom-Ratebased Action : Block : {} Priority : 4 Statement : RateBasedStatement : AggregateKeyType : IP Limit : !Ref RateLimit ScopeDownStatement : NotStatement : Statement : IPSetReferenceStatement : Arn : !GetAtt WhiteListIPSet.Arn VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : Custom-Ratebased SampledRequestsEnabled : true - !If - GeoRestriction - Name : Custom-GeoRestriction Action : Block : {} Priority : 5 Statement : NotStatement : Statement : GeoMatchStatement : CountryCodes : !Ref WhiteListGeoRestriction VisibilityConfig : CloudWatchMetricsEnabled : true MetricName : Custom-GeoRestriction SampledRequestsEnabled : true - Ref : AWS::NoValue WhiteListIPSet : Type : "AWS::WAFv2::IPSet" Properties : Name : Custom-ipaddress-whitelist Scope : REGIONAL IPAddressVersion : IPV4 Addresses : !Ref WhiteListIP WebACLAssociation : Type : AWS::WAFv2::WebACLAssociation Properties : ResourceArn : !Ref WebAclAssociationResourceArn WebACLArn : !GetAtt WebACL.Arn   (C)CloudFront、ALBが両方ともない構成(A、Bで解消しない場合もこちら)   この場合、 AWS WAFはアタッチできないため、他の手を打つ必要があります。   なお、上段A、Bで解消しない場合も最終手段として下記の作業を行うことになると考えます。   以下α、βいずれかを判断の上、対応してください。   (α)コストが掛かってもシステム稼働を優先したい    ・複数 インスタンス 構成かつAuto Scaling Groupで稼働している場合      Auto Scalingの インスタンス 最大台数を増やします。    ・単一 インスタンス 等、Auto Scaling Groupを利用せずに稼働している場合       インスタンス タイプのスケールアップを実施します。   (β)システム稼働よりもDDoS被害(コスト)軽減を優先したい     対象EC2を停止します。 【ポイント解説】 Aに関して、CloudFormationでは既存のCloudFrontに AWS WAFをアタッチすることができません。 スタック作成後、手動でCloudFrontにアタッチする必要があります。 A、B共通して以下のルールが作成されます。優先度順に記載します。 ホワイトリスト IP(許可) ・ParametersのWhiteListIPに社内のIP等、許可するIPを入力(複数可) AWS マネージドルール(拒否) ・AWSManagedRulesCommonRuleSet ・AWSManagedRulesKnownBadInputsRuleSet ・AWSManagedRulesAmazonIpReputationList レートベースのルール(アクセス制限) ・ParametersのRateLimitにレート制限値を入力 ・ParametersのWhiteListIPで設定したIPは対象外 地理的一致ルール(許可) ・ParametersのSwitchGeoRestrictionをONにすることで有効化 ・ParametersのWhiteListGeoRestrictionにアクセス許可する国のコードを入力(複数可)  参考: CountryCodes ・ParametersのSwitchGeoRestrictionをOFFにする場合、デフォルトの値から変更不要 ③GuardDutyの全リージョン有効化   ガイダンス によると、より悪意のある攻撃から注意を反らすために DDoS攻撃 が使用されることもある  との記載がありました(P4)。 AWS の脅威検知サービスであるGuardDutyを全リージョン有効化  していない場合は、このタイミングで有効にすることをお勧めします。  以下のサイトでは、全リージョン一括で有効化して通知設定する方法が紹介されていました。  参考: https://dev.classmethod.jp/articles/set-guardduty-all-region/ 保全 ・CloudWatch Logs等、関連するログのエクスポート(ログローテーションによる消失を回避するため)。 事後調査 ・ログの分析、原因調査。 事後対策 ・今回適用したネットワーク ACL と AWS WAFについて、アタッチを継続するか、設定変更するか等を判断。  今回作成したリソースは、CloudFormationスタックを削除することで消すことができる。 ・ アーキテクチャ の見直し( インスタンス をプライベートサブネットに設置、CloudFrontの導入、Route53への移行等)。 ・Auto Scalingの最大台数、 インスタンス タイプの見直し。 ・セキュリティグループの設定見直し。 まとめ DDoS攻撃 を受けた時の初動対応をできるだけ自動化してみました。 本記事が皆様のお役に立てれば幸いです。 〜最後に〜 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募お待ちしています。 - セキュリティエンジニア(セキュリティ設計) 執筆: @fuku.dancho 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
おはようございます!こんにちは!こんばんは! 電通国際情報サービス 、X(クロス) イノベーション 本部 デジタルエンゲージメントセンターの根本康平です。 先日、 Salesforce 資格の 1 つ「 Salesforce 認定 アドミニストレーター 」を受験し合格しました。どのような対策をしたのか・試験がどのような感じで行われたのかを共有します。 他のブログで書かれていた情報とはかなりイメージが違いました!  その点についても共有します。あくまでも個人的な見解ですので、信用しすぎないようにしてください。また、リンク先のURLが変更され情報が閲覧できなくなる場合もあります。ご了承ください。 そもそもどんな試験? 試験概要・私の試験結果 試験当日の流れ 試験申し込み 事前準備 試験開始 勉強方法 試験を終えて 一言アドバイス 参考 10 月に取り組んだ Trailhead そもそもどんな試験? 公式サイトには「管理者、 コンサルタント 、アーキテクトにおすすめのファーストステップ」と書いてあります。 つまり、 Salesforce 初学者が最初に受けるべき試験かと思います。 試験概要・私の試験結果 内容:多肢選択/複数選択方式で 60 問 試験時間:105 分 合格ライン:65% 受験方法:オンライン(自宅やオフィス) or テストセンター 前提資格や条件:なし 次に出題範囲とその割合についてです。(括弧内に私の試験での正答率を示します) 範囲 出題割合 私の正答率 組織の設定 3% 50% ユーザの設定 7% 66% セキュリティとアクセス 13% 37% 標準オブジェクトとカスタムオブジェクト 14% 88% 営業アプリケーションと マーケティング アプリケーション 14% 75% サービスアプリケーションとサポートアプリケーション 13% 75% 活動の管理 3% 100% データの管理 10% 83% 分析 - レポートと ダッシュ ボード 10% 83% ワークフロー / プロセスの自動化 8% 100% デスクトップとモバイルの管理 3% 0% APPEXCHANGE 2% 100% なお、試験を受ける時期によって出題範囲と割合は大きく変わります!ここに記載しているのは Summer'22 の情報です。 Winter'23では出題割合は大きく変化しています。必ず公式ドキュメントを確認して出題範囲と割合を確認しましょう! 試験当日の流れ 受験方法は 2 種類 オンラインで自宅やオフィスから受験 → 今回私はこちらを選択 テストセンターで受験 試験申し込み オンライン試験は 24 時間、いつでも受験可能です。 申し込み可能な日程は随時更新されます。数分前には予約できなかった日程もページを更新すると申し込み可能になっていたりします! オンライン試験は、試験予定時間の 24 時間より前であれば無料でキャンセル・日程変更が可能です。 事前準備 試験前までに 2 つの作業をする必要があります。この事前準備は数分で完了しますが、試験直前に慌てないよう早めに準備しておくべきです。 顔認証システムへの登録(PCカメラに自分の顔を映すだけ。数十秒でOK!) 試験用のソフトをダウンロード(数分で完了します) 試験開始 オンライン試験は予約時間の 10 分前から受験用サイトを開くことができます。 試験開始サイトを開くとまずは顔認証です。事前準備で登録した顔と受験者の顔が一致するかシステムで判断されます。 顔認証が終われば実際に問題を解いていきます。試験中カメラとマイク機能は常にオンですが、自分の顔や試験官の顔が表示されるようなことはなく、集中して試験を受けることができました。 とあるブログには「カメラで机の上を映し本や携帯がないことを試験官に見せなければならない」と書いてありましたが、そのような場面はありませんでした! (せっかく机の上をきれいにしたのでせっかくなら見ていただきたかった・・) また「試験中のトラブルが多発」とも書いてありましたが、私はとてもスムーズに受験することができました! (記事で書かれていたのが 1・2 年前の話だったのでだいぶ改善されたのだと思います) 試験の文章は日本語ですが、所々翻訳が微妙な部分があります。ただ、問題を解くのに支障があるレベルではないので心配しなくて大丈夫だと思います。 全て解き終わったら試験時間をカットして回答を提出できます。回答を提出すると、次の画面に試験結果が即表示されます。合格の場合、【合格】と表示されて得点分布を確認できます。(後ほどメールにも送られてくるのでメモする必要はないです) 勉強方法 私は 10/1 にデジタルエンゲージメントセンターに配属となり、そこから Salesforce の学習を始めました。10/1 から試験を受けた 11/20 までの過程を書いていきます。 10月 Salesforce には E ラーニングのようなサイトがあります。「Trailhead」です。10 月は Trailhead を通して学習をしました。Trailhead で学習したコースについては本投稿の下部「参考」に書いています。10 月は試験に受かることよりも Salesforce を知るという目的が強かったです。 11月 大きく分けて 3 つのことに取り組みました。試験 2 週間前くらいから「試験に受かる」を目的に勉強しました。 Trailhead Trailmix 【Salesforce公式】認定アドミニストレーター資格 対策 Salesforce Certification Days 認定 アドミニストレーター 試験対策 セミ ナー ネットにある模擬問題演習 1 つ目の Trailmix については、非常に量が多く、2 週間前からでは終わりませんでした( 64% 分実施してやめました)。もし、この Trailmix を完全に終えてから試験に挑みたい場合は 2 週間以上前から取り組んだ方が良いと思います。ちなみに、1 日あたりの勉強に充てた時間は平均 5~6 時間程度です。 2 つ目の「 Salesforce Certification Days」とは Salesforce 社が実施している無料の資格対策 セミ ナーです( 詳細はこちら )。非常にわかりやすく、試験に出るポイントも教えてくれるのでぜひ参加することをお勧めします!さらに、私が受けたときには本試験 70% 引きクーポンコードも貰えました! 3 つ目の模擬問題演習は、ネットで「 アドミニストレーター 試験 模擬問題」と検索して表示されたサイトに書かれている問題をひたすらに解くということをやりました。そのサイトの解答が必ずしも正しいかはわかりませんが、自分なりに理解して回答できるまで 3 周くらい繰り返し取り組みました。 試験を終えて 試験で問題を解いていた感覚としては「8 割は確実に取れているな」と思っていたものの、出題割合を考慮して総合正答率を計算すると 73% でした。思っていた以上に低い結果だったなというのが感想です。特に、「セキュリティとアクセス」の正答率が低く衝撃を受けています。今後、セキュリティとアクセスの分野の知識をさらに吸収していきたいと思います! 一言アド バイス 試験勉強や無料試験対策 セミ ナー等を通して「これは覚えてた方がいい!」と思ったポイントを書いてみます! アクセスを制限するのがプロファイル 制限されたアクセスを緩和・開放するのが権限セット ログイン可否はプロファイルのIP制限とプロファイルの時間のみに依存する!(組織の信頼した IPアドレス 範囲内でも外でもログインはできる!範囲内なら即ログイン、範囲外なら追加の処理を通してログイン可) インポートウィザードは、ケース・商談オブジェクトのインポートできない! これを覚えるだけで 60 問中 4~5 問は解けると思います!ぜひ覚えてみてください! 参考 10 月に取り組んだ Trailhead Trailhead を使用した Salesforce の学習 Salesforce の概要 システム管理者初級 開発者初級 【Salesforce公式】認定Platformアプリケーションビルダー資格 対策 これから アドミニストレーター 試験を受ける方々にとって、何か1つでもプラスになれば嬉しいです。 私たちは同じチームで働いてくれる仲間を探しています。今回のエントリで紹介したような仕事に興味のある方、ご応募をお待ちしています。 CRMソリューションコンサルタント 【新卒採用】ISID 採用ページ 執筆: @nemoto.kouhei 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
おはようございます!こんにちは!こんばんは! 電通国際情報サービス 、X(クロス) イノベーション 本部 デジタルエンゲージメントセンターの根本康平です。 先日、 Salesforce 資格の 1 つ「 Salesforce 認定 アドミニストレーター 」を受験し合格しました。どのような対策をしたのか・試験がどのような感じで行われたのかを共有します。 他のブログで書かれていた情報とはかなりイメージが違いました!  その点についても共有します。あくまでも個人的な見解ですので、信用しすぎないようにしてください。また、リンク先のURLが変更され情報が閲覧できなくなる場合もあります。ご了承ください。 そもそもどんな試験? 試験概要・私の試験結果 試験当日の流れ 試験申し込み 事前準備 試験開始 勉強方法 試験を終えて 一言アドバイス 参考 10 月に取り組んだ Trailhead そもそもどんな試験? 公式サイトには「管理者、 コンサルタント 、アーキテクトにおすすめのファーストステップ」と書いてあります。 つまり、 Salesforce 初学者が最初に受けるべき試験かと思います。 試験概要・私の試験結果 内容:多肢選択/複数選択方式で 60 問 試験時間:105 分 合格ライン:65% 受験方法:オンライン(自宅やオフィス) or テストセンター 前提資格や条件:なし 次に出題範囲とその割合についてです。(括弧内に私の試験での正答率を示します) 範囲 出題割合 私の正答率 組織の設定 3% 50% ユーザの設定 7% 66% セキュリティとアクセス 13% 37% 標準オブジェクトとカスタムオブジェクト 14% 88% 営業アプリケーションと マーケティング アプリケーション 14% 75% サービスアプリケーションとサポートアプリケーション 13% 75% 活動の管理 3% 100% データの管理 10% 83% 分析 - レポートと ダッシュ ボード 10% 83% ワークフロー / プロセスの自動化 8% 100% デスクトップとモバイルの管理 3% 0% APPEXCHANGE 2% 100% なお、試験を受ける時期によって出題範囲と割合は大きく変わります!ここに記載しているのは Summer'22 の情報です。 Winter'23では出題割合は大きく変化しています。必ず公式ドキュメントを確認して出題範囲と割合を確認しましょう! 試験当日の流れ 受験方法は 2 種類 オンラインで自宅やオフィスから受験 → 今回私はこちらを選択 テストセンターで受験 試験申し込み オンライン試験は 24 時間、いつでも受験可能です。 申し込み可能な日程は随時更新されます。数分前には予約できなかった日程もページを更新すると申し込み可能になっていたりします! オンライン試験は、試験予定時間の 24 時間より前であれば無料でキャンセル・日程変更が可能です。 事前準備 試験前までに 2 つの作業をする必要があります。この事前準備は数分で完了しますが、試験直前に慌てないよう早めに準備しておくべきです。 顔認証システムへの登録(PCカメラに自分の顔を映すだけ。数十秒でOK!) 試験用のソフトをダウンロード(数分で完了します) 試験開始 オンライン試験は予約時間の 10 分前から受験用サイトを開くことができます。 試験開始サイトを開くとまずは顔認証です。事前準備で登録した顔と受験者の顔が一致するかシステムで判断されます。 顔認証が終われば実際に問題を解いていきます。試験中カメラとマイク機能は常にオンですが、自分の顔や試験官の顔が表示されるようなことはなく、集中して試験を受けることができました。 とあるブログには「カメラで机の上を映し本や携帯がないことを試験官に見せなければならない」と書いてありましたが、そのような場面はありませんでした! (せっかく机の上をきれいにしたのでせっかくなら見ていただきたかった・・) また「試験中のトラブルが多発」とも書いてありましたが、私はとてもスムーズに受験することができました! (記事で書かれていたのが 1・2 年前の話だったのでだいぶ改善されたのだと思います) 試験の文章は日本語ですが、所々翻訳が微妙な部分があります。ただ、問題を解くのに支障があるレベルではないので心配しなくて大丈夫だと思います。 全て解き終わったら試験時間をカットして回答を提出できます。回答を提出すると、次の画面に試験結果が即表示されます。合格の場合、【合格】と表示されて得点分布を確認できます。(後ほどメールにも送られてくるのでメモする必要はないです) 勉強方法 私は 10/1 にデジタルエンゲージメントセンターに配属となり、そこから Salesforce の学習を始めました。10/1 から試験を受けた 11/20 までの過程を書いていきます。 10月 Salesforce には E ラーニングのようなサイトがあります。「Trailhead」です。10 月は Trailhead を通して学習をしました。Trailhead で学習したコースについては本投稿の下部「参考」に書いています。10 月は試験に受かることよりも Salesforce を知るという目的が強かったです。 11月 大きく分けて 3 つのことに取り組みました。試験 2 週間前くらいから「試験に受かる」を目的に勉強しました。 Trailhead Trailmix 【Salesforce公式】認定アドミニストレーター資格 対策 Salesforce Certification Days 認定 アドミニストレーター 試験対策 セミ ナー ネットにある模擬問題演習 1 つ目の Trailmix については、非常に量が多く、2 週間前からでは終わりませんでした( 64% 分実施してやめました)。もし、この Trailmix を完全に終えてから試験に挑みたい場合は 2 週間以上前から取り組んだ方が良いと思います。ちなみに、1 日あたりの勉強に充てた時間は平均 5~6 時間程度です。 2 つ目の「 Salesforce Certification Days」とは Salesforce 社が実施している無料の資格対策 セミ ナーです( 詳細はこちら )。非常にわかりやすく、試験に出るポイントも教えてくれるのでぜひ参加することをお勧めします!さらに、私が受けたときには本試験 70% 引きクーポンコードも貰えました! 3 つ目の模擬問題演習は、ネットで「 アドミニストレーター 試験 模擬問題」と検索して表示されたサイトに書かれている問題をひたすらに解くということをやりました。そのサイトの解答が必ずしも正しいかはわかりませんが、自分なりに理解して回答できるまで 3 周くらい繰り返し取り組みました。 試験を終えて 試験で問題を解いていた感覚としては「8 割は確実に取れているな」と思っていたものの、出題割合を考慮して総合正答率を計算すると 73% でした。思っていた以上に低い結果だったなというのが感想です。特に、「セキュリティとアクセス」の正答率が低く衝撃を受けています。今後、セキュリティとアクセスの分野の知識をさらに吸収していきたいと思います! 一言アド バイス 試験勉強や無料試験対策 セミ ナー等を通して「これは覚えてた方がいい!」と思ったポイントを書いてみます! アクセスを制限するのがプロファイル 制限されたアクセスを緩和・開放するのが権限セット ログイン可否はプロファイルのIP制限とプロファイルの時間のみに依存する!(組織の信頼した IPアドレス 範囲内でも外でもログインはできる!範囲内なら即ログイン、範囲外なら追加の処理を通してログイン可) インポートウィザードは、ケース・商談オブジェクトのインポートできない! これを覚えるだけで 60 問中 4~5 問は解けると思います!ぜひ覚えてみてください! 参考 10 月に取り組んだ Trailhead Trailhead を使用した Salesforce の学習 Salesforce の概要 システム管理者初級 開発者初級 【Salesforce公式】認定Platformアプリケーションビルダー資格 対策 これから アドミニストレーター 試験を受ける方々にとって、何か1つでもプラスになれば嬉しいです。 私たちは同じチームで働いてくれる仲間を探しています。今回のエントリで紹介したような仕事に興味のある方、ご応募をお待ちしています。 CRMソリューションコンサルタント 【新卒採用】ISID 採用ページ 執筆: @nemoto.kouhei 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
電通国際情報サービス 、オープン イノベーション ラボの 比嘉康雄 です。 Stable Diffusion シリーズ、今回のテーマは、 Waifu Diffusion 1.3.5_80000 です。 Waifu Diffusion というのは、 Stable Diffusion から派生していて、 美少女アニメ 画に強いという特徴を持っています。 80000 というのは、学習の度合いを表していて、「まだ完成してないけど、みんなの反応を見たい」ということで、プレビューとしてリリースされたんだと思います。 Hugging Face 上のページは、 こちら 。 バージョンが1.4になっているので、学習が進んで完成すると、 1.3.5 が 1.4 になるんでしょうね。 Stable Diffusionのおすすめコンテンツはこちら。 Waifu Diffusion 1.3.5_80000 v2.1 金髪美女写真 v2.1 美少女アニメ画 v2.1 AUTOMATIC1111 v2.0 美少女イラスト v1.5 美少女画検証 美少女アニメ画改善版 美少女を高確率で出す呪文編 美少女アニメ画編 美少女写真編 女性イラスト編 長い呪文は切り捨てられる編 AUTOMATIC1111に対応したColabノートブック VAEの比較 仲間募集 Stable Diffusionの全コンテンツ AUTOMATIC1111に対応したColabノートブック 今回の Waifu Diffusion 1.3.5_80000 には、2つのVAEが存在します。 kl-f8-anime.ckpt と kl-f8-anime2.ckpt です。 kl-f8-anime.ckpt は、元のVAEをファインチューニングしたものです。ファインチューニングとは、元のVAEに追加で、いくつか画像を学習させたという意味です。 kl-f8-anime2.ckpt は、元のVAEを 刈り込んだ(pruned) ものです。 刈り込んだ の意味は、たぶん、元のVAEの学習に使った画像のうち、イマイチなものを取り除いて学習させたという意味なんじゃないかと思います。 kl-f8-anime.ckpt を使ったAUTOMATIC1111に対応したColabノートブックは、 こちら 。 kl-f8-anime2.ckpt を使ったAUTOMATIC1111に対応したColabノートブックは、 こちら 。 VAEの比較 SeedをふくめたすべてのパラメータをVAE以外は同じにして比べてみました。 kl-f8-anime.ckpt その一 kl-f8-anime2.ckpt その一 kl-f8-anime.ckpt その二 kl-f8-anime2.ckpt その二 kl-f8-anime.ckpt その三 kl-f8-anime2.ckpt その三 ぼくの感想としては、 kl-f8-anime.ckpt の方が、全体的に明るいが、ちょっとチープ感があるなぁという感じです。 表現が難しいんですが、もう少し垢抜けた感じがほしいところです。同じ呪文で、 Cool Japan Diffusion 2.0で出すとこんな感じです。 垢抜けたという感じが伝わるでしょうか。 今回使った通常呪文 masterpiece high quality highly detailed kawaii princess white glowing skin kawaii face with blush blue eyes with eyelashes long waved hair (cleavage breasts:0.7) open shoulders gothic lolita glossy dress with ruffles gorgeous jewelry accessories anime gorgeous background centered composition lim lighting intense shadows 通常呪文の改行版 masterpiece high quality highly detailed kawaii princess white glowing skin kawaii face with blush blue eyes with eyelashes long waved hair (cleavage breasts:0.7) open shoulders gothic lolita glossy dress with ruffles gorgeous jewelry accessories anime gorgeous background centered composition lim lighting intense shadows 今回使ったネガティブ呪文 blender deformed mutated disfigured lowres blurred repetitive double mutated hands bad hands missing hands extra hands liquid hands poorly drawn hands mutated fingers bad fingers missing fingers extra fingers liquid fingers poorly drawn fingers partial head bad face small face partial face bad eyes missing eyes too big eyes bad eyebrows bad eyelashes bad nose missing nose bad mouth missing mouth open mouth bad ears thick lips chest pad bad legs missing legs extra legs bad arms missing arms extra arms low quality normal quality crown black and white 今回使ったネガティブ呪文の改行版 blender deformed mutated disfigured lowres blurred repetitive double mutated hands bad hands missing hands extra hands liquid hands poorly drawn hands mutated fingers bad fingers missing fingers extra fingers liquid fingers poorly drawn fingers partial head bad face small face partial face bad eyes missing eyes too big eyes bad eyebrows bad eyelashes bad nose missing nose bad mouth missing mouth open mouth bad ears thick lips bad legs missing legs extra legs bad arms missing arms extra arms low quality normal quality crown black and white 仲間募集 私たちは一緒に働いてくれる仲間を募集しています! ソリューションアーキテクト Stable Diffusionの全コンテンツ 人物写真編 レンズ編 画像タイプ編 美少女アニメ画編 美少女写真編 女性イラスト編 美しい夜空を見渡す男編 魅惑的な女アニメ画(トゥーンレンダリング)編 美少女を高確率で出す呪文編 長い呪文は切り捨てられる編 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 A as Bの呪文による画像合成編 かわいい動物の擬人化編 バベルの塔のイラスト編 TPU版の使い方 美少女アニメ画改善版 v1.5 美少女画検証 東京タワーの写真 折り紙合体変形ロボ v2.0 美少女イラスト v2.1 AUTOMATIC1111 v2.1 美少女アニメ画 v2.1 金髪美女写真 Waifu Diffusion 1.3.5_80000 執筆: @higa 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
電通国際情報サービス 、オープン イノベーション ラボの 比嘉康雄 です。 Stable Diffusion シリーズ、今回のテーマは、 Waifu Diffusion 1.3.5_80000 です。 Waifu Diffusion というのは、 Stable Diffusion から派生していて、 美少女アニメ 画に強いという特徴を持っています。 80000 というのは、学習の度合いを表していて、「まだ完成してないけど、みんなの反応を見たい」ということで、プレビューとしてリリースされたんだと思います。 Hugging Face 上のページは、 こちら 。 バージョンが1.4になっているので、学習が進んで完成すると、 1.3.5 が 1.4 になるんでしょうね。 Stable Diffusionのおすすめコンテンツはこちら。 Waifu Diffusion 1.3.5_80000 v2.1 金髪美女写真 v2.1 美少女アニメ画 v2.1 AUTOMATIC1111 v2.0 美少女イラスト v1.5 美少女画検証 美少女アニメ画改善版 美少女を高確率で出す呪文編 美少女アニメ画編 美少女写真編 女性イラスト編 長い呪文は切り捨てられる編 AUTOMATIC1111に対応したColabノートブック VAEの比較 仲間募集 Stable Diffusionの全コンテンツ AUTOMATIC1111に対応したColabノートブック 今回の Waifu Diffusion 1.3.5_80000 には、2つのVAEが存在します。 kl-f8-anime.ckpt と kl-f8-anime2.ckpt です。 kl-f8-anime.ckpt は、元のVAEをファインチューニングしたものです。ファインチューニングとは、元のVAEに追加で、いくつか画像を学習させたという意味です。 kl-f8-anime2.ckpt は、元のVAEを 刈り込んだ(pruned) ものです。 刈り込んだ の意味は、たぶん、元のVAEの学習に使った画像のうち、イマイチなものを取り除いて学習させたという意味なんじゃないかと思います。 kl-f8-anime.ckpt を使ったAUTOMATIC1111に対応したColabノートブックは、 こちら 。 kl-f8-anime2.ckpt を使ったAUTOMATIC1111に対応したColabノートブックは、 こちら 。 VAEの比較 SeedをふくめたすべてのパラメータをVAE以外は同じにして比べてみました。 kl-f8-anime.ckpt その一 kl-f8-anime2.ckpt その一 kl-f8-anime.ckpt その二 kl-f8-anime2.ckpt その二 kl-f8-anime.ckpt その三 kl-f8-anime2.ckpt その三 ぼくの感想としては、 kl-f8-anime.ckpt の方が、全体的に明るいが、ちょっとチープ感があるなぁという感じです。 表現が難しいんですが、もう少し垢抜けた感じがほしいところです。同じ呪文で、 Cool Japan Diffusion 2.0で出すとこんな感じです。 垢抜けたという感じが伝わるでしょうか。 今回使った通常呪文 masterpiece high quality highly detailed kawaii princess white glowing skin kawaii face with blush blue eyes with eyelashes long waved hair (cleavage breasts:0.7) open shoulders gothic lolita glossy dress with ruffles gorgeous jewelry accessories anime gorgeous background centered composition lim lighting intense shadows 通常呪文の改行版 masterpiece high quality highly detailed kawaii princess white glowing skin kawaii face with blush blue eyes with eyelashes long waved hair (cleavage breasts:0.7) open shoulders gothic lolita glossy dress with ruffles gorgeous jewelry accessories anime gorgeous background centered composition lim lighting intense shadows 今回使ったネガティブ呪文 blender deformed mutated disfigured lowres blurred repetitive double mutated hands bad hands missing hands extra hands liquid hands poorly drawn hands mutated fingers bad fingers missing fingers extra fingers liquid fingers poorly drawn fingers partial head bad face small face partial face bad eyes missing eyes too big eyes bad eyebrows bad eyelashes bad nose missing nose bad mouth missing mouth open mouth bad ears thick lips chest pad bad legs missing legs extra legs bad arms missing arms extra arms low quality normal quality crown black and white 今回使ったネガティブ呪文の改行版 blender deformed mutated disfigured lowres blurred repetitive double mutated hands bad hands missing hands extra hands liquid hands poorly drawn hands mutated fingers bad fingers missing fingers extra fingers liquid fingers poorly drawn fingers partial head bad face small face partial face bad eyes missing eyes too big eyes bad eyebrows bad eyelashes bad nose missing nose bad mouth missing mouth open mouth bad ears thick lips bad legs missing legs extra legs bad arms missing arms extra arms low quality normal quality crown black and white 仲間募集 私たちは一緒に働いてくれる仲間を募集しています! ソリューションアーキテクト Stable Diffusionの全コンテンツ 人物写真編 レンズ編 画像タイプ編 美少女アニメ画編 美少女写真編 女性イラスト編 美しい夜空を見渡す男編 魅惑的な女アニメ画(トゥーンレンダリング)編 美少女を高確率で出す呪文編 長い呪文は切り捨てられる編 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 A as Bの呪文による画像合成編 かわいい動物の擬人化編 バベルの塔のイラスト編 TPU版の使い方 美少女アニメ画改善版 v1.5 美少女画検証 東京タワーの写真 折り紙合体変形ロボ v2.0 美少女イラスト v2.1 AUTOMATIC1111 v2.1 美少女アニメ画 v2.1 金髪美女写真 Waifu Diffusion 1.3.5_80000 執筆: @higa 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
皆様こんにちは。 XI本部 AIトランスフォーメーションセンター AI製品開発グループの福竹と申します。 本記事は ISID Techblogの2022年アドベントカレンダー 12/23の記事となります。しかしクリスマスどころか2022年の営業日も残りわずかですね。皆様の2022年はいかがでしたか? もう残り少ないですが、ここらで2022年を「ふりかえって」おきたいところですね?(強引なアイスブレイク) という訳で本記事のテーマは「ふりかえり」です。 今年一年、執筆者はオンラインホワイトボードツールのmiroを使って、開発チームで「ふりかえり」を行うことがよくありました。この試行錯誤の中で、特に企画側として意識するようになったTipsや課題意識について、本記事では共有したいと思います。あくまで私個人のTipsであり、チーム状況や志向性によって適用できる/できないはあるかと思いますが、このテーマに関心のあるかたへのア イデア や考察につながれば幸いです。 はじめに:ふりかえりとは はじめに:miroとは 事前:ふりかえりのアジェンダを設計する 目的を明確に決めて、スコープを想起できるよう工夫する バッファを見込んだアジェンダを組む miroのテンプレートを活かして、ホワイトボードを設計する 事中:ふりかえりをファシリテートする Bring everyone to meを要所で使う(乱用しない) 意識して非同期コミュニケーションの時間を作る(コメント機能を活用する) タイマーを意識的に使う(無実にしない) 事後:ふりかえりを、やりっぱなしにしない 折に触れて使う(コンテキストを呼びだすショートカットにする) 収束の段階で出てきたアイデアの種は、無理に皆でまとめない おわりに 参考文献:ふりかえりのアジェンダを組む はじめに:ふりかえりとは チームの活動をより良くするために、チームで企画・実施するプ ラク ティスです。特に「 KPT 」「FUN/DONE/LEARN」など、 アジャイル レトロスペクティブに端を発するアクティビティを、本記事では想定しています。 アジャイル の文脈で生まれたプ ラク ティスですが、チーム活動であれば何にでも汎用的に使えます。入門編については、 昨年の拙記事 をご参考にどうぞ。 はじめに:miroとは オンラインホワイトボードツールの一つです。 https://miro.com/ 同様のツールには Google Jamboard、 Microsoft Whiteboard 、MURAL、 Apple フリーボード、あたりが挙がります。本記事の主眼ではないので細かく触れませんが、個人的に「2022年ベストバイ」の一つに挙げたいくらい気に入っているツールです。本記事の内容はmiroなしでも実践できるものを含みますが、お手元にmiroがあると、より実践が近付くと思います。 前置きはこのくらいにしましょう。ここからは実際のTipsや課題意識について、実際にふりかえりを企画〜実施する時にステップに沿いながら書いていきます。基本的なプロセスは、昨年の記事でも引用した ふりかえりガイドブック が下敷きにありますので、お持ちの方はご参考にしてください。 事前:ふりかえりの アジェンダ を設計する チームの状況にもよりますが「大きめのリリースも終わるし、ここらで次に向けて改善できる所がないか考えたいな」のようなシチュエーションは多いと思います。となると関係者に MTG を設定して、 アジェンダ を決めておく所から始まるでしょう。かっこよく言えば『ふりかえりの設計』です。 目的を明確に決めて、スコープを想起できるよう工夫する アジェンダ を設計するにあたり、最初に 「なぜ、ふりかえりをやるんだっけ?」という目的は 言語化 しておきましょう 。そして目的から逆算した時の 「意識してほしいスコープ」を決めておきましょう 。例を挙げます。 (目的)製品Aの大きめのリリースが完了した。メンバの功績を 言語化 するとともに、次のスプリントで活かせそうなア イデア を考えておく。 (スコープ)前回のふりかえり実施後から、リリース当日までの製品Aに関するアクティビティ こうしてスコープが明瞭になっていれば、例えばこういった工夫ができます。 期間中に取り組んだ製品Aの バックログ 、バーンダウンチャート、前回のふりかえり完了時のmiroボードを用意しておこう。 アジェンダ の最初に、これらを見てもらえる時間も追加しておこう。 メンバの状況にもよりますが、事前ワークのない「ふりかえり」であれば特に効果的だと思います。 バッファを見込んだ アジェンダ を組む 次に アジェンダ を組みます。ワークの選び方は割愛しますが、慣れた フレームワーク や、後述の参考資料からピックアップしていくことになるでしょう。やりたいワークが決まったら、当日の アジェンダ を組むことになります。 この時、 アジェンダ には必ずバッファを入れましょう 。Keep/Problem/Tryで例を挙げます。 Keepをmiroに書く:5分 書かれたKeepを読む:10分 Problemをmiroに書く:5 書かれたProblemを読む:10分 Tryをmiroに書く:5分 書かれたTryを読む:10分 よし!45分!と考えそうになりますが、少なくとも私の場合、この通りになったことがありません。参加者の状況にもよりますが「Problemを読むのに時間がかかる」「Tryを書くのに時間がかかる」なんてことはよくあると思います。なので合計45分でも、思い切って60分取ります。あとは、重要な議論の時間が広がりやすいProblemやTryの時間を先に増やしておくのもいいでしょう。ここで作った余裕を、当日うまく使います(後述)。 miroのテンプレートを活かして、ホワイトボードを設計する アジェンダ が決まったら、事前にmiroのホワイトボードに、当日使うボードを作る必要があります。この時、 なるべくイチからは作らず、miroのテンプレートを利用しましょう 。自作してもいいのですが、ボードの自作は結構楽しく、時間泥棒です。暇な時以外はやめておきましょう。 コミュニティのテンプレートであるMiroverseも有用です。Miroverseは長年英語のボードしかありませんでしたが、ここ最近は日本語のテンプレートも出始めています。ふりかえりガイドブック著者の森さんが KPT のテンプレートを公開してくれています。 Miroverse:KPTふりかえり(日本語) 余談ですが、miroverseには面白いボードも多く、これまた時間泥棒です。ついでなので、私がいつか、訓練されたマグルの集まりで使ってみたいと思っているボードの例を紹介します。 Miroverse:Harry Potter Retrospective 最後に、ここで用意したテンプレートは、編集をロックしておきましょう。ロックしておくことで、メンバが誤って背景のアイテムを消したり、変更してしまったりを防ぐことが出来ます。 事中:ふりかえりをファシリテートする さて、当日です。企画者が ファシリテーター も兼任するケースは多いでしょう。皆がmiroにやってきます。事前に作った アジェンダ を手元に、ふりかえりを開始します。 Bring everyone to meを要所で使う(乱用しない) miroには、参加者全員の画面を強制的に自分の見ている範囲に移動させる Bring everyone to me という機能があります。 アジェンダ の説明やBoard内の誘導には、こちらを 有効に使いましょう 。ただ「最初の説明」「議論の導入」の時など限られたタイミングだけで使うのがおすすめめです。 『メンバーが迷子になることを防ぐ』目的にとどめて使う ほうが、参加側には負荷がかからないように思います。 意識して非同期コミュニケーションの時間を作る(コメント機能を活用する) チームの慣れ具合にもよるのですが、miroボードを前にワークしている時は 「喋らない時間」を意図的に設けたほうが総コミュニケーション量を増やせます 。全てを発話で済ませるのではなく、 miroのコメント機能を有効に使いましょう 。 KPT の例であれば、次のようなイメージです。 Keepをmiroに書く 他のメンバのKeepを読み、コメントを入れる時間を作る Keepをピックアップして発話に入る。どうしても時間がない時はコメントを見ながらピックアップ対象を絞る。 付箋の内容をあえて発話してもらう事で参加を促したいケースは、この限りではありません。ただ、チームメンバーがワークに慣れている等の状況では、このステップを踏んだほうが時間単位でできる議論の量は増えます。 タイマーを意識的に使う(無実にしない) miroには タイマー機能 があります。これも 是非活用しましょう 。タイマーが0になると、アラームでボードを見ている人全員に時間を知らせることができます。 ただタイマーの設定については、 アジェンダ の時間枠を杓子定規に設定するよりは、 議論の様子を見て柔軟に設定時間を変えたほうが効果的 です。どういうことかというと、「この議論はまだ続きそうだな」と思ったら、いたずらに終了のタイマーを鳴らさず、タイマーの時間をそっと追加してしまうのです(ここで最初に作ったバッファを使います)。 この方法がベストであるかは残り時間などの状況にもよります。いっぽうで、頻繁にアラームの音が鳴ってしまうと、それはそれで参加者がアラームの音を気にしなくなる(無実になる)傾向にあります。全体を時間内にきれいに収めるためにも、タイマーは意識的に アジェンダ が切り替わってほしいタイミングでのみ鳴るようにしましょう。 事後:ふりかえりを、やりっぱなしにしない 無事ふりかえりの時間が終わりました。miroボードにメンバーの色々な思いが書き出され、議論も白熱し、良い感じの達成感が残ります。ちょっと消化不良に終わった? そんな時もあります。また挫けずやってみましょう。 折に触れて使う(コンテキストを呼びだすショートカットにする) 使ったホワイトボードは 実施日が分かるようにしておき 、折に触れて「この時こんな議論があったと思うんだけど」と 思い出す時に使いましょう 。ホワイトボードツールの良い所は、議論の過程が、直感的に理解しやすいホワイトボードの形で残ることです。特に定期的なふりかえりの場合、前回のふりかえりボードが同じホワイトボード上にあると非常に便利です。ボードを見ただけで当時のコンテキストをある程度呼び出せるので「前回はこう考えてたけど、結局こうなったな」といった仮説検証的な思考を自然とメンバに想起できます。 また、こういった状態を作るためにも、付箋へのコメント機能は有効活用しておきたい所です。意識してコメント機能を使っていれば、おそらくパッと見て気になった付箋には、コメントが残っているでしょう。議論の過程も残っているとなおよいです。 収束の段階で出てきたア イデア の種は、無理に皆でまとめない 発散→収束の収束のプロセスで、ふと単純なToDoにはなっていない、 ア イデア めいた付箋 が生まれることがあります。こうしたアイテムは 無闇にToDoに落としこまず 、議論の過程をコメントに書くに留めて、 そのまま残してよい と思います。例が出しづらいですが、例えば「AをBと組み合わせてみる」みたいな、まだ妥当性がわからない、実験めいた記述のものが該当するかもしれません。 なぜそうするかというと、こうした ア イデア めいた内容をグループワークの限られた時間内で無理にToDoに落とし込もうとすると、工夫の余地を削った平均値的なものに収束してしまう事が多い からです。なので焦って 言語化 するよりは、挙がった議論の過程だけ残しア イデア の種に留めておきたいのです。実際のところ本当に面白いア イデア は、書いた当人が後日、おもむろにやりはじめたりします(これは弊チームの場合かもしれません)。 (ふりかえりとは少し異なりますが)このあたりは最近読んだ 妄想する頭 思考する手 想像を超えるアイデアのつくり方 という書籍でも、ア イデア づくりの文脈で近い考え方が示されており、非常に共感できました( 第3章2節「ブレストはワークしない」 )。ご興味が有れば、是非。 おわりに いかがでしたか?(定型文) ワークの文脈はチームの数だけありますし、どこまで一般的に適用できるノウハウとなっているかはチームそれぞれかもしれません。ただ私達の試行錯誤が、少しでも同好の士のご参考となっていれば幸いです。 そのまま宣伝ですが、こういった試行錯誤を日々重ねながら、AI技術の社会実装をAIトランスフォーメーションセンターでは進めています。新卒、中途問わず一緒に働いてくださる方を募集しており、ご興味が湧いた方は AITC採用サイト も是非御覧ください。カジュアル面談の申込みもお受付しています。 さらに宣伝ですが、私個人も スクラム マスターとして日々修行しており、今年はチームメンバーと共に アジャイルとスクラムによる開発手法 という書籍の翻訳出版をしました。鈍器一歩手前の分量ですが、とても良い本ですので、ご興味が有れば是非手にとってみてください。 では。メリー・クリスマス!🎅 参考文献:ふりかえりの アジェンダ を組む アジャイルなチームをつくる ふりかえりガイドブック 始め方・ふりかえりの型・手法・マインドセット :まずはここから。購入者特典の「ふりかえり チートシート 」も是非。 ふりかえりカタログ :同著者が無料公開している、ふりかえりのカタログです。 執筆: @fhiroaki 、レビュー: @hashizume.hideki ( Shodo で執筆されました )
皆様こんにちは。 XI本部 AIトランスフォーメーションセンター AI製品開発グループの福竹と申します。 本記事は ISID Techblogの2022年アドベントカレンダー 12/23の記事となります。しかしクリスマスどころか2022年の営業日も残りわずかですね。皆様の2022年はいかがでしたか? もう残り少ないですが、ここらで2022年を「ふりかえって」おきたいところですね?(強引なアイスブレイク) という訳で本記事のテーマは「ふりかえり」です。 今年一年、執筆者はオンラインホワイトボードツールのmiroを使って、開発チームで「ふりかえり」を行うことがよくありました。この試行錯誤の中で、特に企画側として意識するようになったTipsや課題意識について、本記事では共有したいと思います。あくまで私個人のTipsであり、チーム状況や志向性によって適用できる/できないはあるかと思いますが、このテーマに関心のあるかたへのア イデア や考察につながれば幸いです。 はじめに:ふりかえりとは はじめに:miroとは 事前:ふりかえりのアジェンダを設計する 目的を明確に決めて、スコープを想起できるよう工夫する バッファを見込んだアジェンダを組む miroのテンプレートを活かして、ホワイトボードを設計する 事中:ふりかえりをファシリテートする Bring everyone to meを要所で使う(乱用しない) 意識して非同期コミュニケーションの時間を作る(コメント機能を活用する) タイマーを意識的に使う(無実にしない) 事後:ふりかえりを、やりっぱなしにしない 折に触れて使う(コンテキストを呼びだすショートカットにする) 収束の段階で出てきたアイデアの種は、無理に皆でまとめない おわりに 参考文献:ふりかえりのアジェンダを組む はじめに:ふりかえりとは チームの活動をより良くするために、チームで企画・実施するプ ラク ティスです。特に「 KPT 」「FUN/DONE/LEARN」など、 アジャイル レトロスペクティブに端を発するアクティビティを、本記事では想定しています。 アジャイル の文脈で生まれたプ ラク ティスですが、チーム活動であれば何にでも汎用的に使えます。入門編については、 昨年の拙記事 をご参考にどうぞ。 はじめに:miroとは オンラインホワイトボードツールの一つです。 https://miro.com/ 同様のツールには Google Jamboard、 Microsoft Whiteboard 、MURAL、 Apple フリーボード、あたりが挙がります。本記事の主眼ではないので細かく触れませんが、個人的に「2022年ベストバイ」の一つに挙げたいくらい気に入っているツールです。本記事の内容はmiroなしでも実践できるものを含みますが、お手元にmiroがあると、より実践が近付くと思います。 前置きはこのくらいにしましょう。ここからは実際のTipsや課題意識について、実際にふりかえりを企画〜実施する時にステップに沿いながら書いていきます。基本的なプロセスは、昨年の記事でも引用した ふりかえりガイドブック が下敷きにありますので、お持ちの方はご参考にしてください。 事前:ふりかえりの アジェンダ を設計する チームの状況にもよりますが「大きめのリリースも終わるし、ここらで次に向けて改善できる所がないか考えたいな」のようなシチュエーションは多いと思います。となると関係者に MTG を設定して、 アジェンダ を決めておく所から始まるでしょう。かっこよく言えば『ふりかえりの設計』です。 目的を明確に決めて、スコープを想起できるよう工夫する アジェンダ を設計するにあたり、最初に 「なぜ、ふりかえりをやるんだっけ?」という目的は 言語化 しておきましょう 。そして目的から逆算した時の 「意識してほしいスコープ」を決めておきましょう 。例を挙げます。 (目的)製品Aの大きめのリリースが完了した。メンバの功績を 言語化 するとともに、次のスプリントで活かせそうなア イデア を考えておく。 (スコープ)前回のふりかえり実施後から、リリース当日までの製品Aに関するアクティビティ こうしてスコープが明瞭になっていれば、例えばこういった工夫ができます。 期間中に取り組んだ製品Aの バックログ 、バーンダウンチャート、前回のふりかえり完了時のmiroボードを用意しておこう。 アジェンダ の最初に、これらを見てもらえる時間も追加しておこう。 メンバの状況にもよりますが、事前ワークのない「ふりかえり」であれば特に効果的だと思います。 バッファを見込んだ アジェンダ を組む 次に アジェンダ を組みます。ワークの選び方は割愛しますが、慣れた フレームワーク や、後述の参考資料からピックアップしていくことになるでしょう。やりたいワークが決まったら、当日の アジェンダ を組むことになります。 この時、 アジェンダ には必ずバッファを入れましょう 。Keep/Problem/Tryで例を挙げます。 Keepをmiroに書く:5分 書かれたKeepを読む:10分 Problemをmiroに書く:5 書かれたProblemを読む:10分 Tryをmiroに書く:5分 書かれたTryを読む:10分 よし!45分!と考えそうになりますが、少なくとも私の場合、この通りになったことがありません。参加者の状況にもよりますが「Problemを読むのに時間がかかる」「Tryを書くのに時間がかかる」なんてことはよくあると思います。なので合計45分でも、思い切って60分取ります。あとは、重要な議論の時間が広がりやすいProblemやTryの時間を先に増やしておくのもいいでしょう。ここで作った余裕を、当日うまく使います(後述)。 miroのテンプレートを活かして、ホワイトボードを設計する アジェンダ が決まったら、事前にmiroのホワイトボードに、当日使うボードを作る必要があります。この時、 なるべくイチからは作らず、miroのテンプレートを利用しましょう 。自作してもいいのですが、ボードの自作は結構楽しく、時間泥棒です。暇な時以外はやめておきましょう。 コミュニティのテンプレートであるMiroverseも有用です。Miroverseは長年英語のボードしかありませんでしたが、ここ最近は日本語のテンプレートも出始めています。ふりかえりガイドブック著者の森さんが KPT のテンプレートを公開してくれています。 Miroverse:KPTふりかえり(日本語) 余談ですが、miroverseには面白いボードも多く、これまた時間泥棒です。ついでなので、私がいつか、訓練されたマグルの集まりで使ってみたいと思っているボードの例を紹介します。 Miroverse:Harry Potter Retrospective 最後に、ここで用意したテンプレートは、編集をロックしておきましょう。ロックしておくことで、メンバが誤って背景のアイテムを消したり、変更してしまったりを防ぐことが出来ます。 事中:ふりかえりをファシリテートする さて、当日です。企画者が ファシリテーター も兼任するケースは多いでしょう。皆がmiroにやってきます。事前に作った アジェンダ を手元に、ふりかえりを開始します。 Bring everyone to meを要所で使う(乱用しない) miroには、参加者全員の画面を強制的に自分の見ている範囲に移動させる Bring everyone to me という機能があります。 アジェンダ の説明やBoard内の誘導には、こちらを 有効に使いましょう 。ただ「最初の説明」「議論の導入」の時など限られたタイミングだけで使うのがおすすめめです。 『メンバーが迷子になることを防ぐ』目的にとどめて使う ほうが、参加側には負荷がかからないように思います。 意識して非同期コミュニケーションの時間を作る(コメント機能を活用する) チームの慣れ具合にもよるのですが、miroボードを前にワークしている時は 「喋らない時間」を意図的に設けたほうが総コミュニケーション量を増やせます 。全てを発話で済ませるのではなく、 miroのコメント機能を有効に使いましょう 。 KPT の例であれば、次のようなイメージです。 Keepをmiroに書く 他のメンバのKeepを読み、コメントを入れる時間を作る Keepをピックアップして発話に入る。どうしても時間がない時はコメントを見ながらピックアップ対象を絞る。 付箋の内容をあえて発話してもらう事で参加を促したいケースは、この限りではありません。ただ、チームメンバーがワークに慣れている等の状況では、このステップを踏んだほうが時間単位でできる議論の量は増えます。 タイマーを意識的に使う(無実にしない) miroには タイマー機能 があります。これも 是非活用しましょう 。タイマーが0になると、アラームでボードを見ている人全員に時間を知らせることができます。 ただタイマーの設定については、 アジェンダ の時間枠を杓子定規に設定するよりは、 議論の様子を見て柔軟に設定時間を変えたほうが効果的 です。どういうことかというと、「この議論はまだ続きそうだな」と思ったら、いたずらに終了のタイマーを鳴らさず、タイマーの時間をそっと追加してしまうのです(ここで最初に作ったバッファを使います)。 この方法がベストであるかは残り時間などの状況にもよります。いっぽうで、頻繁にアラームの音が鳴ってしまうと、それはそれで参加者がアラームの音を気にしなくなる(無実になる)傾向にあります。全体を時間内にきれいに収めるためにも、タイマーは意識的に アジェンダ が切り替わってほしいタイミングでのみ鳴るようにしましょう。 事後:ふりかえりを、やりっぱなしにしない 無事ふりかえりの時間が終わりました。miroボードにメンバーの色々な思いが書き出され、議論も白熱し、良い感じの達成感が残ります。ちょっと消化不良に終わった? そんな時もあります。また挫けずやってみましょう。 折に触れて使う(コンテキストを呼びだすショートカットにする) 使ったホワイトボードは 実施日が分かるようにしておき 、折に触れて「この時こんな議論があったと思うんだけど」と 思い出す時に使いましょう 。ホワイトボードツールの良い所は、議論の過程が、直感的に理解しやすいホワイトボードの形で残ることです。特に定期的なふりかえりの場合、前回のふりかえりボードが同じホワイトボード上にあると非常に便利です。ボードを見ただけで当時のコンテキストをある程度呼び出せるので「前回はこう考えてたけど、結局こうなったな」といった仮説検証的な思考を自然とメンバに想起できます。 また、こういった状態を作るためにも、付箋へのコメント機能は有効活用しておきたい所です。意識してコメント機能を使っていれば、おそらくパッと見て気になった付箋には、コメントが残っているでしょう。議論の過程も残っているとなおよいです。 収束の段階で出てきたア イデア の種は、無理に皆でまとめない 発散→収束の収束のプロセスで、ふと単純なToDoにはなっていない、 ア イデア めいた付箋 が生まれることがあります。こうしたアイテムは 無闇にToDoに落としこまず 、議論の過程をコメントに書くに留めて、 そのまま残してよい と思います。例が出しづらいですが、例えば「AをBと組み合わせてみる」みたいな、まだ妥当性がわからない、実験めいた記述のものが該当するかもしれません。 なぜそうするかというと、こうした ア イデア めいた内容をグループワークの限られた時間内で無理にToDoに落とし込もうとすると、工夫の余地を削った平均値的なものに収束してしまう事が多い からです。なので焦って 言語化 するよりは、挙がった議論の過程だけ残しア イデア の種に留めておきたいのです。実際のところ本当に面白いア イデア は、書いた当人が後日、おもむろにやりはじめたりします(これは弊チームの場合かもしれません)。 (ふりかえりとは少し異なりますが)このあたりは最近読んだ 妄想する頭 思考する手 想像を超えるアイデアのつくり方 という書籍でも、ア イデア づくりの文脈で近い考え方が示されており、非常に共感できました( 第3章2節「ブレストはワークしない」 )。ご興味が有れば、是非。 おわりに いかがでしたか?(定型文) ワークの文脈はチームの数だけありますし、どこまで一般的に適用できるノウハウとなっているかはチームそれぞれかもしれません。ただ私達の試行錯誤が、少しでも同好の士のご参考となっていれば幸いです。 そのまま宣伝ですが、こういった試行錯誤を日々重ねながら、AI技術の社会実装をAIトランスフォーメーションセンターでは進めています。新卒、中途問わず一緒に働いてくださる方を募集しており、ご興味が湧いた方は AITC採用サイト も是非御覧ください。カジュアル面談の申込みもお受付しています。 さらに宣伝ですが、私個人も スクラム マスターとして日々修行しており、今年はチームメンバーと共に アジャイルとスクラムによる開発手法 という書籍の翻訳出版をしました。鈍器一歩手前の分量ですが、とても良い本ですので、ご興味が有れば是非手にとってみてください。 では。メリー・クリスマス!🎅 参考文献:ふりかえりの アジェンダ を組む アジャイルなチームをつくる ふりかえりガイドブック 始め方・ふりかえりの型・手法・マインドセット :まずはここから。購入者特典の「ふりかえり チートシート 」も是非。 ふりかえりカタログ :同著者が無料公開している、ふりかえりのカタログです。 執筆: @fhiroaki 、レビュー: @hashizume.hideki ( Shodo で執筆されました )
みなさんこんにちは! 金融ソリューション事業部の市場系ソリューション1部の寺山です。12 月に入ってから一気に寒くなったように感じます。 本記事は 電通国際情報サービス Advent Calendar 2022 の 12 月 22 日の記事です。 昨年の アドベントカレンダー でテックブログに参加して以来、普段の業務においても「何か記事にできることはないかな?」と考えるようになり、一周り充実した1年でした! 今回は、 AWS Fargate で実行した Web アプリケーション(バックエンド API )のマルチスレッドが想定外の挙動となった点をインフラ視点で調査したので、発生した事象とその対応方法について紹介いたします! 発生した事象 概要 調査開始時の予想 原因 JavaのavailableProcessors cgroupのcpu.sharesパラメータ 対応 コンテナ定義のcpuパラメータの指定 XX:ActiveProcessorCountオプションの利用 非同期処理を検討する おわりに 発生した事象 概要 バックエンド API をホストする クラウド 構成は下図のとおりです。本件で触れないサービスは割愛しています。 バックエンド API はコンテナ化し、 AWS Fargate で ECS タスクとして起動します。 API リク エス トは Application Load Balancer が受け付け、ターゲットグループに登録した ECS サービスへルーティングする典型的な クラウド アーキテクチャ です。 バックエンド API は Java (11)で実装されています。 事象は、レスポンスの返却に時間を要するリク エス トの処理中に発生しました。 ALB のターゲットグループのヘルスチェックは、バックエンド API のヘルスチェック用エンドポイントを指定していました。このエンドポイントがヘルスチェックの タイムアウト 時間内に正常レスポンスを返却しないことを 閾値 の回数以上に繰り返したため、クライアントのリク エス ト処理中の Fargate タスクが Unhealthy と判定され、停止されてしまいました。 タスクの停止理由に、 Task failed ELB health checks in (target-group arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:targetgroup/m5infr-sandb-D87C6CX3M8FL/a5285befd3edc05d) と出力されています。 調査開始時の予想 私は事象の初回発生時、当該システム/プロジェクトには関与しておらず、後に調査を引き取った形になります。 この事象の話を聞いた当初は CPU リソースの不足が理由だろうからタスクサイズをチューニングすればよい(バックエンド API のタスクサイズは vCPU:1 でした)ものだと考えていました。 実際に検証したところ、私の予想とは異なる結果となりました。まずはその調査結果を紹介します。 事象が発生したアプリケーションとは別にアプリチームが調査用のアプリケーションを用意してくれたので、それを同じ構成で AWS にデプロイし検証しました。 4vCPU を割り当てた Fargate タスクで再現するか検証します。 API リク エス トは、コンテナイメージの手動ビルド用途として作成した EC2 インスタンス で行いました。 $ curl http://<ALBのDNS名>:8080/sandbox/greet ; echo everyone! hello!everyone! /sandbox/greet はリク エス トに対し、即座に hello! と返却する API です。上記のように正常時は curl コマンドでレスポンスを取得できます。 $ (curl http://<ALBのDNS名>:8080/sandbox/sleep ; echo done at `date`) & [1] 3087 $ curl http://<ALBのDNS名>:8080/sandbox/greet ; echo everyone! <html> <head><title>502 Bad Gateway</title></head> <body> <center><h1>502 Bad Gateway</h1></center> </body> </html> <html> <head><title>502 Bad Gateway</title></head> <body> <center><h1>502 Bad Gateway</h1></center> </body> </html> everyone! 次は、 /sandbox/sleep エンドポイントをバックグラウンドジョブとして実行し、ジョブが終了した日付を表示するようにしています。 /sandbox/sleep は TimeUnit.sleep を無期限に実行する API です。応答に時間を要する API というのを簡易的に表現しています。 バックグラウンドジョブの後に /sandbox/greet を curl していますが、今度はレスポンスを取得できずに API コンテナが終了したため 502 エラーとなっています。 実際にタスクも停止されており、事象が再現しています。 sleep でアイドル状態になっているので自明ではあるのですが、リソース使用率も低いことがメトリクスより確認できます。 つまり、タスクサイズのチューニングにより解消するという私の予想には反して、本件はタスクサイズに依らず発生する事象であることがわかりました。 原因 Java のavailableProcessors バックエンド API は Java のマイクロサービス軽量 フレームワーク である Helidon を使用しています。 この フレームワーク ではデフォルトの動作として、スレッドプール数を Runtime.getRuntime().availableProcessors() の戻り値に設定します。 1 ECS/Fargate では availableProcessors が vCPU のサイズに依らず 1 となるため、すでにスレッドを使用中の場合に、リク エス トを処理するためのスレッドを新たに取得できないことが原因です。 実際に確認してみます。 確認は、 ECS Exec を利用して Fargate 内で CLI 操作をすることにより行いました。 対象のタスクは先ほどと同じ 4vCPU を割り当てています。 $ aws ecs describe-tasks --cluster m5infrasurvey-poc-ecs-cluster --tasks 6218b4dd29c146a6ac120c5395a6e462 { "tasks": [ { # 省略 "cpu": "4096", # 省略 "memory": "8192", # 省略 } ], "failures": [] } ECS Exec よりコンテナのシェルにアクセスし、 JShell より availableProcessors を実行します。 $ aws ecs execute-command --cluster m5infrasurvey-poc-ecs-cluster --task 6218b4dd29c146a6ac120c5395a6e462 --container sandbox --interactive --command "sh" The Session Manager plugin was installed successfully. Use the AWS CLI to start a session. Starting session with SessionId: ecs-execute-command-0dc2b2f03561dd7b9 # # jshell Dec 19, 2022 5:33:04 PM java.util.prefs.FileSystemPreferences$1 run INFO: Created user preferences directory. | Welcome to JShell -- Version 11.0.16.1 | For an introduction type: /help intro jshell> Runtime.getRuntime().availableProcessors() $1 ==> 1 jshell> /exit | Goodbye 戻り値が 1 であることを確認しました。 比較として、EC2 インスタンス として起動している Amazon Linux2 に Docker Server をインストールし、同じ Docker イメージを起動して確認してみます。 docker exec コマンドでシェルにアクセスして、上記同様に JShell を実行します。 $ docker exec -it sandbox "sh" # # lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian Address sizes: 46 bits physical, 48 bits virtual CPU(s): 8 On-line CPU(s) list: 0-7 Thread(s) per core: 2 Core(s) per socket: 4 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 85 Model name: Intel(R) Xeon(R) Platinum 8124M CPU @ 3.00GHz Stepping: 4 CPU MHz: 3416.106 BogoMIPS: 5999.99 Hypervisor vendor: KVM Virtualization type: full L1d cache: 128 KiB L1i cache: 128 KiB L2 cache: 4 MiB L3 cache: 24.8 MiB NUMA node0 CPU(s): 0-7 Vulnerability Itlb multihit: KVM: Mitigation: VMX unsupported Vulnerability L1tf: Mitigation; PTE Inversion Vulnerability Mds: Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknown Vulnerability Meltdown: Mitigation; PTI Vulnerability Mmio stale data: Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknown Vulnerability Retbleed: Vulnerable Vulnerability Spec store bypass: Vulnerable Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Vulnerability Spectre v2: Mitigation; Retpolines, STIBP disabled, RSB filling Vulnerability Srbds: Not affected Vulnerability Tsx async abort: Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknown Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe 1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowpr efetch invpcid_single pti fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves ida arat pku ospke # # jshell Dec 20, 2022 9:07:44 AM java.util.prefs.FileSystemPreferences$1 run INFO: Created user preferences directory. | Welcome to JShell -- Version 11.0.16.1 | For an introduction type: /help intro jshell> Runtime.getRuntime().availableProcessors() $1 ==> 8 jshell> /exit | Goodbye インスタンス タイプは c5.2xlarge です。参考として上記では lscpu も実行しています。 コンテナ起動時に CPU オプションは指定していないため、ホストの CPU がそのまま見えています。 availableProcessors() は EC2 インスタンス の vCPU 数を返却しており、ECS/Fargate とは挙動が異なっています。 cgroupのcpu.sharesパラメータ コンテナ仮想化におけるリソース割り当てに利用されるcgroupのcpuサブシステムのsharesパラメータは、コンテナが 利用可能なCPUリソースのスケジューリングに利用されます。Dockerでは run コマンドの --cpu-shares パラメータで指定します。 割合は cpu.shares パラメータの値を 1024 で除算した値で計算されます。 Dockerの場合はこのパラメータにデフォルトで 1024 が適用されます。 https://docs.docker.jp/config/container/resource_constraints.html#cfs コンテナへの配分を定めるもので、デフォルト値は1024 です。 つまり、ホスト上で実行するコンテナが1台で他にリソース制限を付与するパラメータが指定されていない場合、割合は 1024/1024=1 となりホストの CPUリソースを全て利用可能となります。 一方、ECSではデフォルト値として cpu.shares に 2 が適用されます。 https://aws.amazon.com/jp/blogs/news/how-amazon-ecs-manages-cpu-and-memory-resources/ 注: コンテナに CPU ユニットを指定しない場合、ECS は内部的に cgroup に対して 2 ( Linux カーネル が許容する最小値) という値の Linux CPU 配分 (cpu.shares) を設定します。 Fargateタスクに対し、 Java の -Xlog:os+container=trace オプションを使用して JVM のリソース認識状況を出力したものが以下になります。 $ aws ecs execute-command --cluster m5infrasurvey-poc-ecs-cluster --task 83d8e044611d4d22bbeaf65d164af34f --container sandbox --interactive --command "/bin/sh" The Session Manager plugin was installed successfully. Use the AWS CLI to start a session. Starting session with SessionId: ecs-execute-command-0dc479f32fcd9891d # # java -Xlog:os+container=trace -version [0.000s][trace][os,container] OSContainer::init: Initializing Container Support [0.001s][debug][os,container] Detected cgroups hybrid or legacy hierarchy, using cgroups v1 controllers [0.001s][trace][os,container] Path to /memory.use_hierarchy is /sys/fs/cgroup/memory/memory.use_hierarchy [0.001s][trace][os,container] Use Hierarchy is: 1 [0.001s][trace][os,container] Path to /memory.limit_in_bytes is /sys/fs/cgroup/memory/memory.limit_in_bytes [0.001s][trace][os,container] Memory Limit is: 9223372036854771712 [0.001s][trace][os,container] Non-Hierarchical Memory Limit is: Unlimited [0.001s][trace][os,container] Path to /memory.stat is /sys/fs/cgroup/memory/memory.stat [0.001s][trace][os,container] Hierarchical Memory Limit is: 8589934592 [0.001s][info ][os,container] Memory Limit is: 8589934592 [0.001s][trace][os,container] Path to /cpu.cfs_quota_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us [0.001s][trace][os,container] CPU Quota is: -1 [0.001s][trace][os,container] Path to /cpu.cfs_period_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us [0.001s][trace][os,container] CPU Period is: 100000 [0.001s][trace][os,container] Path to /cpu.shares is /sys/fs/cgroup/cpu,cpuacct/cpu.shares [0.001s][trace][os,container] CPU Shares is: 2 [0.001s][trace][os,container] CPU Share count based on shares: 1 [0.001s][trace][os,container] OSContainer::active_processor_count: 1 [0.001s][trace][os,container] CgroupSubsystem::active_processor_count (cached): 1 [0.001s][trace][os,container] CgroupSubsystem::active_processor_count (cached): 1 # 省略 実際に CPU Share is: 2 と出力されていることが確認できました。 2/1024≒0.002 のためコンテナに割り当てられる CPUリソース数が極端に少なく、 JVM は利用可能な CPU 数の最小値である 1 を適用する挙動をしたと判明しました。ECS/FargateとDockerにて挙動の異なる点にも説明がつきます。 対応 コンテナ定義のcpuパラメータの指定 前のセクションで説明した通り、 cpu.shares がデフォルトでは 2 であることが、タスクサイズに依らず1スレッドしか利用できない事象の深層的な原因であるとわかりました。 ECSにおいて cpu.shares を指定するには、コンテナ定義の cpu パラメータを指定すれば良いです。タスク定義におけるタスクサイズの cpu とは別のパラメータであることに注意してください。 私の検証では環境構築に AWS CDK を利用したので、対応例として ソースコード の一部を紹介します。 利用しているバージョンは package.json の一部の紹介で代替いたします。 { //省略 " devDependencies ": { " @types/jest ": " ^29.2.3 ", " @types/node ": " ^18.11.9 ", " @typescript-eslint/eslint-plugin ": " ^5.20.0 ", " @typescript-eslint/parser ": " ^5.20.0 ", " aws-cdk ": " ^2.51.0 ", " eslint ": " ^8.13.0 ", " eslint-config-prettier ": " ^8.5.0 ", " jest ": " ^29.3.1 ", " prettier ": " ^2.6.2 ", " ts-jest ": " ^29.0.3 ", " ts-node ": " ^10.9.1 ", " typescript ": " ^4.9.3 " } , " dependencies ": { " aws-cdk-lib ": " ^2.51.0 ", " constructs ": " ^10.0.0 ", " source-map-support ": " ^0.5.16 " } } const sandboxTaskdef = new TaskDefinition ( this , 'sandboxTaskdef' , { compatibility: Compatibility.FARGATE , networkMode: NetworkMode.AWS_VPC , family: ` ${ SYSTEM_NAME } - ${ props.m5Props.m5Env } -ecs-taskdef-sandbox` , executionRole: sandboxTaskRole , taskRole: sandboxTaskRole , cpu: '4096' , memoryMiB: '8192' , } ); sandboxTaskdef.addContainer ( 'sandbox' , { image: ContainerImage.fromEcrRepository ( Repository.fromRepositoryArn ( this , 'sandbox' , 'arn:aws:ecr:ap-northeast-1:XXXXXXXXXXXX:repository/m5infrasurvey-poc-ecr-sandbox' ) ), containerName: 'sandbox' , cpu: 1024 , // cpu.sharesに設定される /*省略*/ } ); 宣言した TaskDefinition クラスの addContaier メソッドからコンテナ定義の cpu パラメータを指定しています。 上記のコードをデプロイして起動されたFargateタスクの cpu.shares を実際に確認してみます。 まずは起動されたタスクの情報です。 $ aws ecs describe-tasks --cluster m5infrasurvey-poc-ecs-cluster --tasks 46e1d6fd883c47419093ad0e84a41ad1 { "tasks": [ { # 省略 "containers": [ { "containerArn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:container/m5infrasurvey-poc-ecs-cluster/46e1d6fd883c4741 9093ad0e84a41ad1/342343c2-0d87-4cdf-b60a-4496307cfc33", "taskArn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task/m5infrasurvey-poc-ecs-cluster/46e1d6fd883c47419093ad0e84 a41ad1", "name": "sandbox", # 省略 "managedAgents": [ { "lastStartedAt": "2022-12-21T17:30:48.947000+09:00", "name": "ExecuteCommandAgent", "lastStatus": "RUNNING" } ], "cpu": "1024" } ], "cpu": "4096", # 省略 } ], "failures": [] } タスクサイズとは別にコンテナ定義として "cpu": "1024" が反映されていることを確認しました。 続いて、 JVM が認識するリソース情報と availableProcessors の戻り値を確認します。 $ aws ecs execute-command --cluster m5infrasurvey-poc-ecs-cluster --task 46e1d6fd883c47419093ad0e84a41ad1 --container sandbox --interactive --command "/bin/sh" The Session Manager plugin was installed successfully. Use the AWS CLI to start a session. Starting session with SessionId: ecs-execute-command-0d914bdaa48aec635 # # java -Xlog:os+container=trace -version [0.000s][trace][os,container] OSContainer::init: Initializing Container Support [0.001s][debug][os,container] Detected cgroups hybrid or legacy hierarchy, using cgroups v1 controllers [0.001s][trace][os,container] Path to /memory.use_hierarchy is /sys/fs/cgroup/memory/memory.use_hierarchy [0.001s][trace][os,container] Use Hierarchy is: 1 [0.001s][trace][os,container] Path to /memory.limit_in_bytes is /sys/fs/cgroup/memory/memory.limit_in_bytes [0.001s][trace][os,container] Memory Limit is: 9223372036854771712 [0.001s][trace][os,container] Non-Hierarchical Memory Limit is: Unlimited [0.001s][trace][os,container] Path to /memory.stat is /sys/fs/cgroup/memory/memory.stat [0.001s][trace][os,container] Hierarchical Memory Limit is: 8589934592 [0.001s][info ][os,container] Memory Limit is: 8589934592 [0.001s][trace][os,container] Path to /cpu.cfs_quota_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us [0.001s][trace][os,container] CPU Quota is: -1 [0.001s][trace][os,container] Path to /cpu.cfs_period_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us [0.001s][trace][os,container] CPU Period is: 100000 [0.001s][trace][os,container] Path to /cpu.shares is /sys/fs/cgroup/cpu,cpuacct/cpu.shares [0.001s][trace][os,container] CPU Shares is: 1024 [0.001s][trace][os,container] OSContainer::active_processor_count: 4 [0.001s][trace][os,container] CgroupSubsystem::active_processor_count (cached): 4 [0.001s][trace][os,container] CgroupSubsystem::active_processor_count (cached): 4 [0.037s][trace][os,container] Path to /cpu.cfs_quota_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us [0.038s][trace][os,container] CPU Quota is: -1 [0.038s][trace][os,container] Path to /cpu.cfs_period_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us [0.038s][trace][os,container] CPU Period is: 100000 [0.038s][trace][os,container] Path to /cpu.shares is /sys/fs/cgroup/cpu,cpuacct/cpu.shares [0.038s][trace][os,container] CPU Shares is: 1024 [0.038s][trace][os,container] OSContainer::active_processor_count: 4 # 省略 # # jshell Dec 21, 2022 5:55:00 PM java.util.prefs.FileSystemPreferences$1 run INFO: Created user preferences directory. | Welcome to JShell -- Version 11.0.16.1 | For an introduction type: /help intro jshell> Runtime.getRuntime().availableProcessors() $1 ==> 4 以下が確認できました。 CPU Shares is: 1024 と出力され、 cpu.shares が意図通りに設定されていること active_processor_count: 4 と出力され、タスクのvCPUと同値が認識されていること availableProcessors の戻り値が 4 と出力され、タスクのvCPUと同値であること 最後に、本件の事象が解消しているかを事象の再現方法と同じように確認します。 $ curl http://m5infrasurvey-poc-alb-sandbox-352400359.ap-northeast-1.elb.amazonaws.com:8080/sandbox/greet ; echo everyone! hello!everyone! $ $ (curl http://m5infrasurvey-poc-alb-sandbox-352400359.ap-northeast-1.elb.amazonaws.com:8080/sandbox/sleep ; echo done at `date`) & [1] 4454 $ (curl http://m5infrasurvey-poc-alb-sandbox-352400359.ap-northeast-1.elb.amazonaws.com:8080/sandbox/sleep ; echo done at `date`) & [2] 4457 $ (curl http://m5infrasurvey-poc-alb-sandbox-352400359.ap-northeast-1.elb.amazonaws.com:8080/sandbox/sleep ; echo done at `date`) & [3] 4460 $ $ curl http://m5infrasurvey-poc-alb-sandbox-352400359.ap-northeast-1.elb.amazonaws.com:8080/sandbox/greet ; echo everyone! hello!everyone! スレッドプール数は 4 になっているので、事象の再現に使用した /sandbox/sleep API を 3 リク エス ト受け付け後も、 /sandbox/greet API からレスポンスを取得できています。想定通りの結果を得ることができました。 XX:ActiveProcessorCountオプションの利用 前のセクションの対応で、 cpu.shares の設定方法がわかりました。 しかしながら、 18.0.2+ , 17.0.5+ , 11.0.17+ からOpenJDKにて cpu.shares を用いて利用可能なCPU数の制御を廃止する( 2 )ため、 Java のバージョン次第で前述した方法では事象が再現します。 そこで、 Java の拡張ランタイムオプションである -XX:ActiveProcessorCount=N を利用します。このパラメータを利用すると、 JVM が認識する CPU の数を上書きできます。 前述した対応ではコンテナのリソース量を環境に合わせて動的に割り当て可能ですが、こちらの場合は環境ごとにパラメータを変更する必要があります。 -XX:ActiveProcessorCount=N を利用するケースにおいても、対応例として AWS CDKの ソースコード の一部を紹介します。 const cpuNum = 4 ; const sandboxTaskdef = new TaskDefinition ( this , 'sandboxTaskdef' , { compatibility: Compatibility.FARGATE , networkMode: NetworkMode.AWS_VPC , family: ` ${ SYSTEM_NAME } - ${ props.m5Props.m5Env } -ecs-taskdef-sandbox` , executionRole: sandboxTaskRole , taskRole: sandboxTaskRole , cpu: String ( cpuNum * 1024 ), memoryMiB: '8192' , } ); sandboxTaskdef.addContainer ( 'sandbox' , { image: ContainerImage.fromEcrRepository ( Repository.fromRepositoryArn ( this , 'sandbox' , 'arn:aws:ecr:ap-northeast-1:XXXXXXXXXXXX:repository/m5infrasurvey-poc-ecr-sandbox' ) ), containerName: 'sandbox' , environment: { TZ: 'Asia/Tokyo' , JAVA_TOOL_OPTIONS: `-XX:ActiveProcessorCount= ${ cpuNum } ` , // 環境変数で-XX:ActiveProcessorCountを設定 } , } ); タスクに割り当てる vCPU の数をあらかじめ宣言しておき( cpuNum )、タスクサイズの cpu パラメータと -XX:ActiveProcessorCount= の値に使用します。 本番環境と開発環境間でタスクサイズは異なることが多いので、 -XX:ActiveProcessorCount= は JAVA_TOOL_OPTIONS 環境変数 を利用して外部から注入する形で付与するのがベターと考えました。 このように クラウド のサービスやリソースを宣言的に構築できる点や、値やオブジェクト等を再利用可能なところもIaCのメリットですね! 前のセクションと同じように反映されたか確認します。 $ aws ecs execute-command --cluster m5infrasurvey-poc-ecs-cluster --task e4696c0103574ad0a07a8eabc1360087 --container sandbox --interactive --command "/bin/sh" The Session Manager plugin was installed successfully. Use the AWS CLI to start a session. Starting session with SessionId: ecs-execute-command-0c5d73c5e08474f67 # # jshell Picked up JAVA_TOOL_OPTIONS: -XX:ActiveProcessorCount=4 Dec 20, 2022 6:58:07 PM java.util.prefs.FileSystemPreferences$1 run INFO: Created user preferences directory. | Welcome to JShell -- Version 11.0.16.1 | For an introduction type: /help intro jshell> Runtime.getRuntime().availableProcessors() $1 ==> 4 JAVA_TOOL_OPTIONS 環境変数 が適用されていること、および、 availableProcessors の戻り値も指定した値になっていることが確認できました。 実際に API にリク エス トを行う動作確認は前述と同じ結果になったため記載は割愛します。 非同期処理を検討する 前述までの対応は、タスクの vCPU を 2 以上に設定することが前提となっています。 常時多数のリク エス トを受けるつけるようなワークロードであればよいですが、それ以外の場合はリソースに余剰が発生しコスト最適化の設計原則に反しています。 理想は、必要最小限のタスクサイズとタスク数で ECS サービスを起動し、負荷に応じてスケールすることです。 今回の発端となったような応答まで時間を要するような処理は非同期で実行することで、スレッドを長時間占有することを回避するという案です。 AWS においては SQS と Lambda を利用してメッセージキューイングによる非同期処理をサーバレス アーキテクチャ で実現する方法が知られています。 上記の図の例では、バックエンド API は enqueue に成功した時点でレスポンスを返却するため、本件の事象を回避するという意図になります。 非同期化した場合は API クライアント側にポーリングやリフレッシュの仕組みが必要になるため、 API 仕様として許容可能かの調整も必要となる点には注意が必要です。 おわりに 今回は ECS/Fargate で発生した事象について紹介いたしました。 今後は他の クラウド プロバイダのコンテナ関連サービスにおける事象の発生有無についても調査したいと考えています。 最後までご覧いただきありがとうございました。皆さま良いお年を! 私たちは一緒に働いてくれる仲間を募集しています! 金融機関のようなお客様においても クラウド ファーストなアプローチやマイクロサービスのようなモダンな技術の採用が進みつつあります。ご自身のインフラ/ クラウド スキルを エンタープライズ 領域でも活用したい・挑戦したいという方がいらっしゃいましたら、ぜひご応募ください! 金融システム インフラ・アーキテクト 金融システム インフラエンジニア 執筆: 寺山 輝 (@terayama.akira) 、レビュー: @mizuno.kazuhiro ( Shodo で執筆されました ) https://github.com/helidon-io/helidon/blob/helidon-2.x/webserver/webserver/src/main/java/io/helidon/webserver/ServerConfiguration.java#L58-L65 , https://github.com/helidon-io/helidon/blob/helidon-3.x/common/configurable/src/main/java/io/helidon/common/configurable/ServerThreadPoolSupplier.java#L54-L68 ↩ https://bugs.openjdk.org/browse/JDK-8281181 ↩
本記事は Microsoft Azure Tech Advent Calendar 2022 の22日目の記事です X イノベーション 本部 AITC の後藤です。最近、Azureが提供する 機械学習 サービスであるAzure Machine Learning(Azure ML)の SDK v2が新たにGAになりました。 Azure MLは先日 TechPlayのイベント でもご紹介した、私たちのチームが背極的に活用している 機械学習 のさまざまな用途に活用可能なサービスです。 Azure ML SDK v2はv1と大きく使い方が変わりました。本記事ではまだまだ情報が少ないAzure ML SDK v2に関して公式ドキュメントをベースに使い方を紹介します。 そもそもAzure Machine Learning (Azure ML) とは Azure ML SDK v1とv2の比較 Azure ML SDK v2の基本的な使い方 準備 データセット登録 学習の実行 学習済みモデルの登録 デプロイ SDK v2の感想 おわりに そもそもAzure Machine Learning (Azure ML) とは Azure ML は、Azure の 機械学習 サービスです。一言で 機械学習 サービスといってもAzure ML は非常に多くの機能を提供しており、 機械学習 に関連する多くの ユースケース で活用可能です。 機械学習 を実際の業務で運用していくいわゆるMLOpsを実現するには多くの工程が必要です。モデルを学習させるまでも大変ですが、学習後に実際の業務で使用できるように運用していくのはさらに大変です。Azure MLではそういった 機械学習 をビジネスで活用しようとする際に遭遇する多くの問題を解決してくれます。 参考: https://learn.microsoft.com/ja-jp/azure/machine-learning/overview-what-is-azure-machine-learning Azure ML SDK v1とv2の比較 Azure ML SDK v2はv1から大きく変更が加えられ、使い方もほとんど原型がないレベルで変わっています。また、互換性に関してもv1とv2で維持されないものもあります。こういった理由から、v1とv2を同じコードベースで使用することは推奨されていません。 以下は SDK で使用されるクラスを念頭にv1とv2の概念の比較をした表です。 AzureML v1 AzureML v2 Workspace Workspace Datastore Datastore Compute Compute Webservice OnlineEndpoint、OnlineDeployment ParallelRunStep for Batch Scoring BatchEndpoint、BatchDeployment Experiment, Run, Pipeline Job Dataset FileDataset TabularDataset Data assets(v1との整合性が取れていない) URI _FILE URI _FOLDER MLTABLE Model Model Environment Environment 学習ジョブや推論まわりは名称含め大きく変わっていることがわかります。また、上記の表で名前が一緒でも、与える引数が異なるものなども存在します。 参考: https://learn.microsoft.com/ja-jp/azure/machine-learning/how-to-migrate-from-v1#using-v1-and-v2-code-together Azure ML SDK v2の基本的な使い方 それでは基本的な 機械学習 のフローとして以下の内容をAzure ML SDK v2で順番に実行し、使い方を紹介します。 環境準備 デー タセット 登録 学習の実行 学習済みモデルの登録 モデルのデプロイ 準備 Python パッケージの azure-ai-ml をインストールします(ちなみに SDK v1は azureml-core です)。次にAzure portal もしくは Azure CLI でAzure Machine Learning workspace(AML ワークスペース )を作成します。 ワークスペース を作成後、必要な情報をメモし、以下のように Python でMLClientを定義します。 from azure.ai.ml import MLClient from azure.identity import DefaultAzureCredential # AMLワークスペースの情報 subscription_id = "<subscription_id>" resource_group = "<リソースグループ名>" workspace = "<ワークスペース名>" ml_client = MLClient( DefaultAzureCredential(), subscription_id, resource_group, workspace ) SDK v2の主要な変更の一つとして、上記のMLClientが挙げられます。 SDK v1では、ExperimentやRunなど様々なクラスを用途に応じて使い分ける必要がありましたが、v2におけるAMLの操作は全てこのMLClientから実行します。 デー タセット 登録 Azure MLに学習に使用するデータを登録します。 ちなみに細かいですが、v1では データセット と呼称されていたものがv2では データ資産 という呼称に変更されています。本記事では一般的な 機械学習 用語として「デー タセット 」という言葉を使用しています。 参考: https://learn.microsoft.com/ja-jp/azure/machine-learning/how-to-migrate-from-v1#data-datasets-in-v1 Azure MLに登録する際のデータソースには以下の選択肢があります。 ローカルファイル Azure BLOB Storage Azure Blob Storage はAzure のオブジェクトストレージサービスです 参考: https://learn.microsoft.com/ja-jp/azure/storage/blobs/storage-blobs-overview Azure Data Lake Storage Gen2(ADLS gen2) ADLS gen2はAzure Blob Storage をベースに構築された、ビッグ データ分析用途のストレージサービスです Datastore Azure ML で指定するAzureのストレージサービスです 上記のBlobやADSK gen2を指定することで安全にAzure MLからデータにアクセスが可能になります 今回は単純にローカルファイルをAzure MLのデータ資産に登録します。デー タセット 登録は先ほどのMLClientを使用して以下のように書きます。 from azure.ai.ml.entities import Data from azure.ai.ml.constants import AssetTypes # データの場所によりpathの記述方法が異なる # local: './<path>' # blob: 'https://<account_name>.blob.core.windows.net/<container_name>/<path>' # ADLS gen2: 'abfss://<file_system>@<account_name>.dfs.core.windows.net/<path>/' # Datastore: 'azureml://datastores/<data_store_name>/paths/<path>' my_data = Data( path="./data/iris.csv", # ローカルファイルパス type=AssetTypes.URI_FILE, description="irisデータ", name="iris", version='1' # データセットのバージョン ) # AMLにデータセットを登録 ml_client.data.create_or_update(my_data) 参考: https://learn.microsoft.com/ja-jp/azure/machine-learning/how-to-create-data-assets?tabs=CLI#tabpanel_2_Python-SDK 正常に処理が終わるとブラウザでAML ワークスペース のアセット⇨データより以下のように確認できます。 学習の実行 デー タセット の登録が終わったので、次に学習を実行します。 Azure ML SDK v2における学習の実行場所はローカルかコンピュート クラスタ ーの2つです。コンピュート クラスタ ーはAMLにおける学習用の計算リソースです。コンピュート クラスタ ーは事前に作成しておく必要があります。作成は SDK や CLI 、AML ワークスペース からも可能です。 今回はAML ワークスペース からコンピュート クラスタ ーを作成します。AML ワークスペース より左のブレードメニューからコンピューティングを選択し、新規ボタンから作成できます。作成すると以下のようにコンピューティング クラスタ ータブに作成した クラスタ ーが表示されます。 コンピュート クラスタ ーはその名の通り設定した台数で VM が必要に応じてスケールしてくれます。最小の VM 台数を0に設定できるので、学習を実行する時だけ計算リソースを立ち上げることができます。逆に最大の台数を増やせばその分同時に実行できる学習も増やせます。 参考: https://learn.microsoft.com/ja-jp/azure/machine-learning/quickstart-create-resources 続いて、コンピュート クラスタ ー内で実行する学習 スクリプト を用意します。今回はMSのexampleのコードを拝借しました。(引用元: https://github.com/Azure/azureml-examples ) # imports import os import mlflow import argparse import pandas as pd import matplotlib.pyplot as plt from sklearn.svm import SVC from sklearn.model_selection import train_test_split # define functions def main(args): # enable auto logging mlflow.autolog() # setup parameters params = { "C": args.C, "kernel": args.kernel, "degree": args.degree, "gamma": args.gamma, "coef0": args.coef0, "shrinking": args.shrinking, "probability": args.probability, "tol": args.tol, "cache_size": args.cache_size, "class_weight": args.class_weight, "verbose": args.verbose, "max_iter": args.max_iter, "decision_function_shape": args.decision_function_shape, "break_ties": args.break_ties, "random_state": args.random_state, } # read in data df = pd.read_csv(args.iris_csv) # process data X_train, X_test, y_train, y_test = process_data(df, args.random_state) # train model model = train_model(params, X_train, X_test, y_train, y_test) def process_data(df, random_state): # split dataframe into X and y X = df.drop(["species"], axis=1) y = df["species"] # train/test split X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=random_state ) # return splits and encoder return X_train, X_test, y_train, y_test def train_model(params, X_train, X_test, y_train, y_test): # train model model = SVC(**params) model = model.fit(X_train, y_train) # return model return model def parse_args(): # setup arg parser parser = argparse.ArgumentParser() # add arguments parser.add_argument("--iris-csv", type=str) parser.add_argument("--C", type=float, default=1.0) parser.add_argument("--kernel", type=str, default="rbf") parser.add_argument("--degree", type=int, default=3) parser.add_argument("--gamma", type=str, default="scale") parser.add_argument("--coef0", type=float, default=0) parser.add_argument("--shrinking", type=bool, default=False) parser.add_argument("--probability", type=bool, default=False) parser.add_argument("--tol", type=float, default=1e-3) parser.add_argument("--cache_size", type=float, default=1024) parser.add_argument("--class_weight", type=dict, default=None) parser.add_argument("--verbose", type=bool, default=False) parser.add_argument("--max_iter", type=int, default=-1) parser.add_argument("--decision_function_shape", type=str, default="ovr") parser.add_argument("--break_ties", type=bool, default=False) parser.add_argument("--random_state", type=int, default=42) # parse args args = parser.parse_args() # return args return args # run script if __name__ == "__main__": # parse args args = parse_args() # run main function main(args) ポイントは mlflow.autolog です。 SDK v1の頃はAML独自の書き方でログを記録するのが主流でしたが、 SDK v2からはmlflowで記録を取ることが可能です。これによりAMLのコンピュート クラスタ ー以外でも動作する汎用的な 機械学習 スクリプト が利用可能です。 そして、 mlflow.autolog が有効に使えるコードであれば、この1行でAMLに学習済みモデルの記録や主要なメトリックの登録が行われます。ただし、後述しますがモデルをAMLに登録するには別途操作が必要です。 では、この スクリプト をコンピュート クラスタ ーで実行させましょう。 SDK v2から学習を実行するには先ほどのMLClientを利用し、以下のように書きます。 from azure.ai.ml import command, Input job = command( code="./src", # ローカルの学習スクリプトがあるディレクトリパス command="python train.py --iris-csv ${{inputs.iris}} --C ${{inputs.C}} --kernel ${{inputs.kernel}} --coef0 ${{inputs.coef0}}", inputs={ "iris": Input( type="uri_file", path=my_data.path, ), "C": 0.8, "kernel": "rbf", "coef0": 0.1, }, environment="AzureML-sklearn-1.0-ubuntu20.04-py38-cpu@latest", compute="cpu-cluster", # コンピュートクラスター名 display_name="sklearn-iris-example", experiment_name="iris-experiment", description="AML実験" ) returned_job = ml_client.jobs.create_or_update(job) returned_job ポイントは3つです。 1つ目は、学習に使用する入力デー タセット をInputオブジェクトとして定義することです。定義方法は簡単で、先ほど登録したDataオブジェクトのpathとtypeを引数に与えます。 2つ目は、学習環境となるenvironmentです。今回は学習 スクリプト に複雑な依存関係がなかったのでAMLで用意してくれている環境を指定し、使用しました。こちらは自作の環境も使用できます。 3つ目はcompute引数に先ほど作成したコンピュート クラスタ ー名を指定しているところです。これにより、コンピュート クラスタ ーで学習が実行されます。 このコードを実行するとiris-experimentという実験の配下にsklearn-iris-exampleという名前のジョブで実行情報が以下のように記録されます。 画像にあるように、学習済みモデル、タグ、メトリックなど学習 スクリプト やジョブ実行時に指定していない内容まで自動で記録してくれます。 学習済みモデルの登録 モデルをバージョン管理するために学習済みモデルを登録します。 先ほど実行した学習ジョブには学習済みモデルの情報が記録されています。記録したモデルはAML ワークスペース からも該当のジョブを参照すると確認できます。 SDK から登録するにはジョブ名をコピーして以下のpath引数に与えてModelオブジェクトを作成し、ml_clientからモデルの登録を行います。 from azure.ai.ml.entities import Model from azure.ai.ml.constants import AssetTypes model = Model( path="azureml://jobs/<job name>/outputs/artifacts/paths/model/", name="run-iris-example", description="Model created from run.", type=AssetTypes.CUSTOM_MODEL ) ml_client.models.create_or_update(model) Modelオブジェクトを作成する際のパスのフォーマットはいくつか存在します。このフォーマットは保存したモデルのtypeによって変わります。例えばtypeがmlflowであれば以下のような書き方になります。 model = Model( path="runs:/<job name>/model", name="run-iris-example", description="Model created from run.", type=AssetTypes.CUSTOM_MODEL ) 参考: https://learn.microsoft.com/en-us/azure/machine-learning/how-to-manage-models?tabs=use-job-output%2Ccli デプロイ SDK v2で導入されたマネージドオンライン推論を試してみます。今回はバッチ推論がmlflowモデルをまだサポートしていないので実施しませんが、バッチ推論用のエンドポイントを作成することも可能です。 SDK v2で導入されたマネージドオンライン推論は、その名の通りインフラ管理が不要なマネージドな環境でオンライン推論が実現できます。エンドポイントの細かい管理・運用は必要なく、スケーリングやブルーグリーンデプロイを用いたロールアウトなどの実際の運用時に欲しい設定が簡単にできます。(エンドポイントを作成後削除しない限り料金が発生し続けるので注意です) では早速マネージドオンライン推論の準備を行います。 まずはエンドポイントを作成します。 from azure.ai.ml.entities import ManagedOnlineEndpoint endpoint_name = "iris-test-online-endpoint" endpoint = ManagedOnlineEndpoint( name=endpoint_name, description="this is a sample online endpoint", auth_mode="key", ) ml_client.begin_create_or_update(endpoint).result() 次にデプロイの設定を作成します。推論時の依存関係などの環境や使用するモデル、推論 スクリプト はこのデプロイで設定します。今回デプロイするMLflowモデルの場合、推論用 スクリプト は自動生成されるためデプロイ時に指定する必要はありません。 from azure.ai.ml.entities import ManagedOnlineDeployment blue_deployment = ManagedOnlineDeployment( name="blue", endpoint_name=endpoint_name, # 作成したエンドポイント名 model=model, # モデルオブジェクト instance_type="Standard_DS2_v2", instance_count=1, ) ml_client.online_deployments.begin_create_or_update(blue_deployment).result() 参考: https://learn.microsoft.com/ja-jp/azure/machine-learning/how-to-mlflow-batch?tabs=sdk#using-mlflow-models-with-a-scoring-script 作成したデプロイに全ての トラフィック を割り当てるようエンドポイントを更新します。 endpoint.traffic = {"blue": 100} ml_client.begin_create_or_update(endpoint).result() これでリアルタイム推論用のエンドポイントの完成です。 推論は SDK から以下のようにできます。 ml_client.online_endpoints.invoke( endpoint_name=endpoint_name, deployment_name="blue", request_file="./data/request.json", ) この時、登録したモデルによってリク エス トの json スキーマ が異なるので注意です。今回はMLflowモデルを使用しているので、request. json の中身は以下のようになります。 input_data というキーに対して columns と data を入力します。 index はなくても大丈夫です。 { "input_data": { "columns": [ "sepal length (cm)", "sepal width (cm)", "petal length (cm)", "petal width (cm)" ], "index": [0, 1], "data": [ [2, 3, 4, 5], [6, 5, 4, 3] ] } } 個人的にエンドポイントのテストは SDK から実行するよりも、AML ワークスペース から実行できるのでそちらの方が楽です。 SDK v2の感想 SDK v1の頃に比べると、操作が直感的になり使いやすくなったと感じています。一方で、 SDK v1を使用していた身からすると、使い方が大きく変わりすぎて戸惑うことも多かったです。あとはGAになったばかりということで、ドキュメント通りに動かないものも一部あり、苦労しました。 おわりに 私たちは同じチームで働いてくれる仲間を探しています。今回のエントリで紹介したような仕事に興味のある方、ご応募をお待ちしています。 ISID AIトランスフォーメーションセンター 採用情報ページ 執筆: @goto.yuki 、レビュー: @yamada.y ( Shodo で執筆されました )
本記事は Microsoft Azure Tech Advent Calendar 2022 の22日目の記事です X イノベーション 本部 AITC の後藤です。最近、Azureが提供する 機械学習 サービスであるAzure Machine Learning(Azure ML)の SDK v2が新たにGAになりました。 Azure MLは先日 TechPlayのイベント でもご紹介した、私たちのチームが背極的に活用している 機械学習 のさまざまな用途に活用可能なサービスです。 Azure ML SDK v2はv1と大きく使い方が変わりました。本記事ではまだまだ情報が少ないAzure ML SDK v2に関して公式ドキュメントをベースに使い方を紹介します。 そもそもAzure Machine Learning (Azure ML) とは Azure ML SDK v1とv2の比較 Azure ML SDK v2の基本的な使い方 準備 データセット登録 学習の実行 学習済みモデルの登録 デプロイ SDK v2の感想 おわりに そもそもAzure Machine Learning (Azure ML) とは Azure ML は、Azure の 機械学習 サービスです。一言で 機械学習 サービスといってもAzure ML は非常に多くの機能を提供しており、 機械学習 に関連する多くの ユースケース で活用可能です。 機械学習 を実際の業務で運用していくいわゆるMLOpsを実現するには多くの工程が必要です。モデルを学習させるまでも大変ですが、学習後に実際の業務で使用できるように運用していくのはさらに大変です。Azure MLではそういった 機械学習 をビジネスで活用しようとする際に遭遇する多くの問題を解決してくれます。 参考: https://learn.microsoft.com/ja-jp/azure/machine-learning/overview-what-is-azure-machine-learning Azure ML SDK v1とv2の比較 Azure ML SDK v2はv1から大きく変更が加えられ、使い方もほとんど原型がないレベルで変わっています。また、互換性に関してもv1とv2で維持されないものもあります。こういった理由から、v1とv2を同じコードベースで使用することは推奨されていません。 以下は SDK で使用されるクラスを念頭にv1とv2の概念の比較をした表です。 AzureML v1 AzureML v2 Workspace Workspace Datastore Datastore Compute Compute Webservice OnlineEndpoint、OnlineDeployment ParallelRunStep for Batch Scoring BatchEndpoint、BatchDeployment Experiment, Run, Pipeline Job Dataset FileDataset TabularDataset Data assets(v1との整合性が取れていない) URI _FILE URI _FOLDER MLTABLE Model Model Environment Environment 学習ジョブや推論まわりは名称含め大きく変わっていることがわかります。また、上記の表で名前が一緒でも、与える引数が異なるものなども存在します。 参考: https://learn.microsoft.com/ja-jp/azure/machine-learning/how-to-migrate-from-v1#using-v1-and-v2-code-together Azure ML SDK v2の基本的な使い方 それでは基本的な 機械学習 のフローとして以下の内容をAzure ML SDK v2で順番に実行し、使い方を紹介します。 環境準備 デー タセット 登録 学習の実行 学習済みモデルの登録 モデルのデプロイ 準備 Python パッケージの azure-ai-ml をインストールします(ちなみに SDK v1は azureml-core です)。次にAzure portal もしくは Azure CLI でAzure Machine Learning workspace(AML ワークスペース )を作成します。 ワークスペース を作成後、必要な情報をメモし、以下のように Python でMLClientを定義します。 from azure.ai.ml import MLClient from azure.identity import DefaultAzureCredential # AMLワークスペースの情報 subscription_id = "<subscription_id>" resource_group = "<リソースグループ名>" workspace = "<ワークスペース名>" ml_client = MLClient( DefaultAzureCredential(), subscription_id, resource_group, workspace ) SDK v2の主要な変更の一つとして、上記のMLClientが挙げられます。 SDK v1では、ExperimentやRunなど様々なクラスを用途に応じて使い分ける必要がありましたが、v2におけるAMLの操作は全てこのMLClientから実行します。 デー タセット 登録 Azure MLに学習に使用するデータを登録します。 ちなみに細かいですが、v1では データセット と呼称されていたものがv2では データ資産 という呼称に変更されています。本記事では一般的な 機械学習 用語として「デー タセット 」という言葉を使用しています。 参考: https://learn.microsoft.com/ja-jp/azure/machine-learning/how-to-migrate-from-v1#data-datasets-in-v1 Azure MLに登録する際のデータソースには以下の選択肢があります。 ローカルファイル Azure BLOB Storage Azure Blob Storage はAzure のオブジェクトストレージサービスです 参考: https://learn.microsoft.com/ja-jp/azure/storage/blobs/storage-blobs-overview Azure Data Lake Storage Gen2(ADLS gen2) ADLS gen2はAzure Blob Storage をベースに構築された、ビッグ データ分析用途のストレージサービスです Datastore Azure ML で指定するAzureのストレージサービスです 上記のBlobやADSK gen2を指定することで安全にAzure MLからデータにアクセスが可能になります 今回は単純にローカルファイルをAzure MLのデータ資産に登録します。デー タセット 登録は先ほどのMLClientを使用して以下のように書きます。 from azure.ai.ml.entities import Data from azure.ai.ml.constants import AssetTypes # データの場所によりpathの記述方法が異なる # local: './<path>' # blob: 'https://<account_name>.blob.core.windows.net/<container_name>/<path>' # ADLS gen2: 'abfss://<file_system>@<account_name>.dfs.core.windows.net/<path>/' # Datastore: 'azureml://datastores/<data_store_name>/paths/<path>' my_data = Data( path="./data/iris.csv", # ローカルファイルパス type=AssetTypes.URI_FILE, description="irisデータ", name="iris", version='1' # データセットのバージョン ) # AMLにデータセットを登録 ml_client.data.create_or_update(my_data) 参考: https://learn.microsoft.com/ja-jp/azure/machine-learning/how-to-create-data-assets?tabs=CLI#tabpanel_2_Python-SDK 正常に処理が終わるとブラウザでAML ワークスペース のアセット⇨データより以下のように確認できます。 学習の実行 デー タセット の登録が終わったので、次に学習を実行します。 Azure ML SDK v2における学習の実行場所はローカルかコンピュート クラスタ ーの2つです。コンピュート クラスタ ーはAMLにおける学習用の計算リソースです。コンピュート クラスタ ーは事前に作成しておく必要があります。作成は SDK や CLI 、AML ワークスペース からも可能です。 今回はAML ワークスペース からコンピュート クラスタ ーを作成します。AML ワークスペース より左のブレードメニューからコンピューティングを選択し、新規ボタンから作成できます。作成すると以下のようにコンピューティング クラスタ ータブに作成した クラスタ ーが表示されます。 コンピュート クラスタ ーはその名の通り設定した台数で VM が必要に応じてスケールしてくれます。最小の VM 台数を0に設定できるので、学習を実行する時だけ計算リソースを立ち上げることができます。逆に最大の台数を増やせばその分同時に実行できる学習も増やせます。 参考: https://learn.microsoft.com/ja-jp/azure/machine-learning/quickstart-create-resources 続いて、コンピュート クラスタ ー内で実行する学習 スクリプト を用意します。今回はMSのexampleのコードを拝借しました。(引用元: https://github.com/Azure/azureml-examples ) # imports import os import mlflow import argparse import pandas as pd import matplotlib.pyplot as plt from sklearn.svm import SVC from sklearn.model_selection import train_test_split # define functions def main(args): # enable auto logging mlflow.autolog() # setup parameters params = { "C": args.C, "kernel": args.kernel, "degree": args.degree, "gamma": args.gamma, "coef0": args.coef0, "shrinking": args.shrinking, "probability": args.probability, "tol": args.tol, "cache_size": args.cache_size, "class_weight": args.class_weight, "verbose": args.verbose, "max_iter": args.max_iter, "decision_function_shape": args.decision_function_shape, "break_ties": args.break_ties, "random_state": args.random_state, } # read in data df = pd.read_csv(args.iris_csv) # process data X_train, X_test, y_train, y_test = process_data(df, args.random_state) # train model model = train_model(params, X_train, X_test, y_train, y_test) def process_data(df, random_state): # split dataframe into X and y X = df.drop(["species"], axis=1) y = df["species"] # train/test split X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=random_state ) # return splits and encoder return X_train, X_test, y_train, y_test def train_model(params, X_train, X_test, y_train, y_test): # train model model = SVC(**params) model = model.fit(X_train, y_train) # return model return model def parse_args(): # setup arg parser parser = argparse.ArgumentParser() # add arguments parser.add_argument("--iris-csv", type=str) parser.add_argument("--C", type=float, default=1.0) parser.add_argument("--kernel", type=str, default="rbf") parser.add_argument("--degree", type=int, default=3) parser.add_argument("--gamma", type=str, default="scale") parser.add_argument("--coef0", type=float, default=0) parser.add_argument("--shrinking", type=bool, default=False) parser.add_argument("--probability", type=bool, default=False) parser.add_argument("--tol", type=float, default=1e-3) parser.add_argument("--cache_size", type=float, default=1024) parser.add_argument("--class_weight", type=dict, default=None) parser.add_argument("--verbose", type=bool, default=False) parser.add_argument("--max_iter", type=int, default=-1) parser.add_argument("--decision_function_shape", type=str, default="ovr") parser.add_argument("--break_ties", type=bool, default=False) parser.add_argument("--random_state", type=int, default=42) # parse args args = parser.parse_args() # return args return args # run script if __name__ == "__main__": # parse args args = parse_args() # run main function main(args) ポイントは mlflow.autolog です。 SDK v1の頃はAML独自の書き方でログを記録するのが主流でしたが、 SDK v2からはmlflowで記録を取ることが可能です。これによりAMLのコンピュート クラスタ ー以外でも動作する汎用的な 機械学習 スクリプト が利用可能です。 そして、 mlflow.autolog が有効に使えるコードであれば、この1行でAMLに学習済みモデルの記録や主要なメトリックの登録が行われます。ただし、後述しますがモデルをAMLに登録するには別途操作が必要です。 では、この スクリプト をコンピュート クラスタ ーで実行させましょう。 SDK v2から学習を実行するには先ほどのMLClientを利用し、以下のように書きます。 from azure.ai.ml import command, Input job = command( code="./src", # ローカルの学習スクリプトがあるディレクトリパス command="python train.py --iris-csv ${{inputs.iris}} --C ${{inputs.C}} --kernel ${{inputs.kernel}} --coef0 ${{inputs.coef0}}", inputs={ "iris": Input( type="uri_file", path=my_data.path, ), "C": 0.8, "kernel": "rbf", "coef0": 0.1, }, environment="AzureML-sklearn-1.0-ubuntu20.04-py38-cpu@latest", compute="cpu-cluster", # コンピュートクラスター名 display_name="sklearn-iris-example", experiment_name="iris-experiment", description="AML実験" ) returned_job = ml_client.jobs.create_or_update(job) returned_job ポイントは3つです。 1つ目は、学習に使用する入力デー タセット をInputオブジェクトとして定義することです。定義方法は簡単で、先ほど登録したDataオブジェクトのpathとtypeを引数に与えます。 2つ目は、学習環境となるenvironmentです。今回は学習 スクリプト に複雑な依存関係がなかったのでAMLで用意してくれている環境を指定し、使用しました。こちらは自作の環境も使用できます。 3つ目はcompute引数に先ほど作成したコンピュート クラスタ ー名を指定しているところです。これにより、コンピュート クラスタ ーで学習が実行されます。 このコードを実行するとiris-experimentという実験の配下にsklearn-iris-exampleという名前のジョブで実行情報が以下のように記録されます。 画像にあるように、学習済みモデル、タグ、メトリックなど学習 スクリプト やジョブ実行時に指定していない内容まで自動で記録してくれます。 学習済みモデルの登録 モデルをバージョン管理するために学習済みモデルを登録します。 先ほど実行した学習ジョブには学習済みモデルの情報が記録されています。記録したモデルはAML ワークスペース からも該当のジョブを参照すると確認できます。 SDK から登録するにはジョブ名をコピーして以下のpath引数に与えてModelオブジェクトを作成し、ml_clientからモデルの登録を行います。 from azure.ai.ml.entities import Model from azure.ai.ml.constants import AssetTypes model = Model( path="azureml://jobs/<job name>/outputs/artifacts/paths/model/", name="run-iris-example", description="Model created from run.", type=AssetTypes.CUSTOM_MODEL ) ml_client.models.create_or_update(model) Modelオブジェクトを作成する際のパスのフォーマットはいくつか存在します。このフォーマットは保存したモデルのtypeによって変わります。例えばtypeがmlflowであれば以下のような書き方になります。 model = Model( path="runs:/<job name>/model", name="run-iris-example", description="Model created from run.", type=AssetTypes.CUSTOM_MODEL ) 参考: https://learn.microsoft.com/en-us/azure/machine-learning/how-to-manage-models?tabs=use-job-output%2Ccli デプロイ SDK v2で導入されたマネージドオンライン推論を試してみます。今回はバッチ推論がmlflowモデルをまだサポートしていないので実施しませんが、バッチ推論用のエンドポイントを作成することも可能です。 SDK v2で導入されたマネージドオンライン推論は、その名の通りインフラ管理が不要なマネージドな環境でオンライン推論が実現できます。エンドポイントの細かい管理・運用は必要なく、スケーリングやブルーグリーンデプロイを用いたロールアウトなどの実際の運用時に欲しい設定が簡単にできます。(エンドポイントを作成後削除しない限り料金が発生し続けるので注意です) では早速マネージドオンライン推論の準備を行います。 まずはエンドポイントを作成します。 from azure.ai.ml.entities import ManagedOnlineEndpoint endpoint_name = "iris-test-online-endpoint" endpoint = ManagedOnlineEndpoint( name=endpoint_name, description="this is a sample online endpoint", auth_mode="key", ) ml_client.begin_create_or_update(endpoint).result() 次にデプロイの設定を作成します。推論時の依存関係などの環境や使用するモデル、推論 スクリプト はこのデプロイで設定します。今回デプロイするMLflowモデルの場合、推論用 スクリプト は自動生成されるためデプロイ時に指定する必要はありません。 from azure.ai.ml.entities import ManagedOnlineDeployment blue_deployment = ManagedOnlineDeployment( name="blue", endpoint_name=endpoint_name, # 作成したエンドポイント名 model=model, # モデルオブジェクト instance_type="Standard_DS2_v2", instance_count=1, ) ml_client.online_deployments.begin_create_or_update(blue_deployment).result() 参考: https://learn.microsoft.com/ja-jp/azure/machine-learning/how-to-mlflow-batch?tabs=sdk#using-mlflow-models-with-a-scoring-script 作成したデプロイに全ての トラフィック を割り当てるようエンドポイントを更新します。 endpoint.traffic = {"blue": 100} ml_client.begin_create_or_update(endpoint).result() これでリアルタイム推論用のエンドポイントの完成です。 推論は SDK から以下のようにできます。 ml_client.online_endpoints.invoke( endpoint_name=endpoint_name, deployment_name="blue", request_file="./data/request.json", ) この時、登録したモデルによってリク エス トの json スキーマ が異なるので注意です。今回はMLflowモデルを使用しているので、request. json の中身は以下のようになります。 input_data というキーに対して columns と data を入力します。 index はなくても大丈夫です。 { "input_data": { "columns": [ "sepal length (cm)", "sepal width (cm)", "petal length (cm)", "petal width (cm)" ], "index": [0, 1], "data": [ [2, 3, 4, 5], [6, 5, 4, 3] ] } } 個人的にエンドポイントのテストは SDK から実行するよりも、AML ワークスペース から実行できるのでそちらの方が楽です。 SDK v2の感想 SDK v1の頃に比べると、操作が直感的になり使いやすくなったと感じています。一方で、 SDK v1を使用していた身からすると、使い方が大きく変わりすぎて戸惑うことも多かったです。あとはGAになったばかりということで、ドキュメント通りに動かないものも一部あり、苦労しました。 おわりに 私たちは同じチームで働いてくれる仲間を探しています。今回のエントリで紹介したような仕事に興味のある方、ご応募をお待ちしています。 ISID AIトランスフォーメーションセンター 採用情報ページ 執筆: @goto.yuki 、レビュー: @yamada.y ( Shodo で執筆されました )
みなさんこんにちは! 金融ソリューション事業部の市場系ソリューション1部の寺山です。12 月に入ってから一気に寒くなったように感じます。 本記事は 電通国際情報サービス Advent Calendar 2022 の 12 月 22 日の記事です。 昨年の アドベントカレンダー でテックブログに参加して以来、普段の業務においても「何か記事にできることはないかな?」と考えるようになり、一周り充実した1年でした! 今回は、 AWS Fargate で実行した Web アプリケーション(バックエンド API )のマルチスレッドが想定外の挙動となった点をインフラ視点で調査したので、発生した事象とその対応方法について紹介いたします! 発生した事象 概要 調査開始時の予想 原因 JavaのavailableProcessors cgroupのcpu.sharesパラメータ 対応 コンテナ定義のcpuパラメータの指定 XX:ActiveProcessorCountオプションの利用 非同期処理を検討する おわりに 発生した事象 概要 バックエンド API をホストする クラウド 構成は下図のとおりです。本件で触れないサービスは割愛しています。 バックエンド API はコンテナ化し、 AWS Fargate で ECS タスクとして起動します。 API リク エス トは Application Load Balancer が受け付け、ターゲットグループに登録した ECS サービスへルーティングする典型的な クラウド アーキテクチャ です。 バックエンド API は Java (11)で実装されています。 事象は、レスポンスの返却に時間を要するリク エス トの処理中に発生しました。 ALB のターゲットグループのヘルスチェックは、バックエンド API のヘルスチェック用エンドポイントを指定していました。このエンドポイントがヘルスチェックの タイムアウト 時間内に正常レスポンスを返却しないことを 閾値 の回数以上に繰り返したため、クライアントのリク エス ト処理中の Fargate タスクが Unhealthy と判定され、停止されてしまいました。 タスクの停止理由に、 Task failed ELB health checks in (target-group arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:targetgroup/m5infr-sandb-D87C6CX3M8FL/a5285befd3edc05d) と出力されています。 調査開始時の予想 私は事象の初回発生時、当該システム/プロジェクトには関与しておらず、後に調査を引き取った形になります。 この事象の話を聞いた当初は CPU リソースの不足が理由だろうからタスクサイズをチューニングすればよい(バックエンド API のタスクサイズは vCPU:1 でした)ものだと考えていました。 実際に検証したところ、私の予想とは異なる結果となりました。まずはその調査結果を紹介します。 事象が発生したアプリケーションとは別にアプリチームが調査用のアプリケーションを用意してくれたので、それを同じ構成で AWS にデプロイし検証しました。 4vCPU を割り当てた Fargate タスクで再現するか検証します。 API リク エス トは、コンテナイメージの手動ビルド用途として作成した EC2 インスタンス で行いました。 $ curl http://<ALBのDNS名>:8080/sandbox/greet ; echo everyone! hello!everyone! /sandbox/greet はリク エス トに対し、即座に hello! と返却する API です。上記のように正常時は curl コマンドでレスポンスを取得できます。 $ (curl http://<ALBのDNS名>:8080/sandbox/sleep ; echo done at `date`) & [1] 3087 $ curl http://<ALBのDNS名>:8080/sandbox/greet ; echo everyone! <html> <head><title>502 Bad Gateway</title></head> <body> <center><h1>502 Bad Gateway</h1></center> </body> </html> <html> <head><title>502 Bad Gateway</title></head> <body> <center><h1>502 Bad Gateway</h1></center> </body> </html> everyone! 次は、 /sandbox/sleep エンドポイントをバックグラウンドジョブとして実行し、ジョブが終了した日付を表示するようにしています。 /sandbox/sleep は TimeUnit.sleep を無期限に実行する API です。応答に時間を要する API というのを簡易的に表現しています。 バックグラウンドジョブの後に /sandbox/greet を curl していますが、今度はレスポンスを取得できずに API コンテナが終了したため 502 エラーとなっています。 実際にタスクも停止されており、事象が再現しています。 sleep でアイドル状態になっているので自明ではあるのですが、リソース使用率も低いことがメトリクスより確認できます。 つまり、タスクサイズのチューニングにより解消するという私の予想には反して、本件はタスクサイズに依らず発生する事象であることがわかりました。 原因 Java のavailableProcessors バックエンド API は Java のマイクロサービス軽量 フレームワーク である Helidon を使用しています。 この フレームワーク ではデフォルトの動作として、スレッドプール数を Runtime.getRuntime().availableProcessors() の戻り値に設定します。 1 ECS/Fargate では availableProcessors が vCPU のサイズに依らず 1 となるため、すでにスレッドを使用中の場合に、リク エス トを処理するためのスレッドを新たに取得できないことが原因です。 実際に確認してみます。 確認は、 ECS Exec を利用して Fargate 内で CLI 操作をすることにより行いました。 対象のタスクは先ほどと同じ 4vCPU を割り当てています。 $ aws ecs describe-tasks --cluster m5infrasurvey-poc-ecs-cluster --tasks 6218b4dd29c146a6ac120c5395a6e462 { "tasks": [ { # 省略 "cpu": "4096", # 省略 "memory": "8192", # 省略 } ], "failures": [] } ECS Exec よりコンテナのシェルにアクセスし、 JShell より availableProcessors を実行します。 $ aws ecs execute-command --cluster m5infrasurvey-poc-ecs-cluster --task 6218b4dd29c146a6ac120c5395a6e462 --container sandbox --interactive --command "sh" The Session Manager plugin was installed successfully. Use the AWS CLI to start a session. Starting session with SessionId: ecs-execute-command-0dc2b2f03561dd7b9 # # jshell Dec 19, 2022 5:33:04 PM java.util.prefs.FileSystemPreferences$1 run INFO: Created user preferences directory. | Welcome to JShell -- Version 11.0.16.1 | For an introduction type: /help intro jshell> Runtime.getRuntime().availableProcessors() $1 ==> 1 jshell> /exit | Goodbye 戻り値が 1 であることを確認しました。 比較として、EC2 インスタンス として起動している Amazon Linux2 に Docker Server をインストールし、同じ Docker イメージを起動して確認してみます。 docker exec コマンドでシェルにアクセスして、上記同様に JShell を実行します。 $ docker exec -it sandbox "sh" # # lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian Address sizes: 46 bits physical, 48 bits virtual CPU(s): 8 On-line CPU(s) list: 0-7 Thread(s) per core: 2 Core(s) per socket: 4 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 85 Model name: Intel(R) Xeon(R) Platinum 8124M CPU @ 3.00GHz Stepping: 4 CPU MHz: 3416.106 BogoMIPS: 5999.99 Hypervisor vendor: KVM Virtualization type: full L1d cache: 128 KiB L1i cache: 128 KiB L2 cache: 4 MiB L3 cache: 24.8 MiB NUMA node0 CPU(s): 0-7 Vulnerability Itlb multihit: KVM: Mitigation: VMX unsupported Vulnerability L1tf: Mitigation; PTE Inversion Vulnerability Mds: Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknown Vulnerability Meltdown: Mitigation; PTI Vulnerability Mmio stale data: Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknown Vulnerability Retbleed: Vulnerable Vulnerability Spec store bypass: Vulnerable Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Vulnerability Spectre v2: Mitigation; Retpolines, STIBP disabled, RSB filling Vulnerability Srbds: Not affected Vulnerability Tsx async abort: Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknown Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe 1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowpr efetch invpcid_single pti fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves ida arat pku ospke # # jshell Dec 20, 2022 9:07:44 AM java.util.prefs.FileSystemPreferences$1 run INFO: Created user preferences directory. | Welcome to JShell -- Version 11.0.16.1 | For an introduction type: /help intro jshell> Runtime.getRuntime().availableProcessors() $1 ==> 8 jshell> /exit | Goodbye インスタンス タイプは c5.2xlarge です。参考として上記では lscpu も実行しています。 コンテナ起動時に CPU オプションは指定していないため、ホストの CPU がそのまま見えています。 availableProcessors() は EC2 インスタンス の vCPU 数を返却しており、ECS/Fargate とは挙動が異なっています。 cgroupのcpu.sharesパラメータ コンテナ仮想化におけるリソース割り当てに利用されるcgroupのcpuサブシステムのsharesパラメータは、コンテナが 利用可能なCPUリソースのスケジューリングに利用されます。Dockerでは run コマンドの --cpu-shares パラメータで指定します。 割合は cpu.shares パラメータの値を 1024 で除算した値で計算されます。 Dockerの場合はこのパラメータにデフォルトで 1024 が適用されます。 https://docs.docker.jp/config/container/resource_constraints.html#cfs コンテナへの配分を定めるもので、デフォルト値は1024 です。 つまり、ホスト上で実行するコンテナが1台で他にリソース制限を付与するパラメータが指定されていない場合、割合は 1024/1024=1 となりホストの CPUリソースを全て利用可能となります。 一方、ECSではデフォルト値として cpu.shares に 2 が適用されます。 https://aws.amazon.com/jp/blogs/news/how-amazon-ecs-manages-cpu-and-memory-resources/ 注: コンテナに CPU ユニットを指定しない場合、ECS は内部的に cgroup に対して 2 ( Linux カーネル が許容する最小値) という値の Linux CPU 配分 (cpu.shares) を設定します。 Fargateタスクに対し、 Java の -Xlog:os+container=trace オプションを使用して JVM のリソース認識状況を出力したものが以下になります。 $ aws ecs execute-command --cluster m5infrasurvey-poc-ecs-cluster --task 83d8e044611d4d22bbeaf65d164af34f --container sandbox --interactive --command "/bin/sh" The Session Manager plugin was installed successfully. Use the AWS CLI to start a session. Starting session with SessionId: ecs-execute-command-0dc479f32fcd9891d # # java -Xlog:os+container=trace -version [0.000s][trace][os,container] OSContainer::init: Initializing Container Support [0.001s][debug][os,container] Detected cgroups hybrid or legacy hierarchy, using cgroups v1 controllers [0.001s][trace][os,container] Path to /memory.use_hierarchy is /sys/fs/cgroup/memory/memory.use_hierarchy [0.001s][trace][os,container] Use Hierarchy is: 1 [0.001s][trace][os,container] Path to /memory.limit_in_bytes is /sys/fs/cgroup/memory/memory.limit_in_bytes [0.001s][trace][os,container] Memory Limit is: 9223372036854771712 [0.001s][trace][os,container] Non-Hierarchical Memory Limit is: Unlimited [0.001s][trace][os,container] Path to /memory.stat is /sys/fs/cgroup/memory/memory.stat [0.001s][trace][os,container] Hierarchical Memory Limit is: 8589934592 [0.001s][info ][os,container] Memory Limit is: 8589934592 [0.001s][trace][os,container] Path to /cpu.cfs_quota_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us [0.001s][trace][os,container] CPU Quota is: -1 [0.001s][trace][os,container] Path to /cpu.cfs_period_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us [0.001s][trace][os,container] CPU Period is: 100000 [0.001s][trace][os,container] Path to /cpu.shares is /sys/fs/cgroup/cpu,cpuacct/cpu.shares [0.001s][trace][os,container] CPU Shares is: 2 [0.001s][trace][os,container] CPU Share count based on shares: 1 [0.001s][trace][os,container] OSContainer::active_processor_count: 1 [0.001s][trace][os,container] CgroupSubsystem::active_processor_count (cached): 1 [0.001s][trace][os,container] CgroupSubsystem::active_processor_count (cached): 1 # 省略 実際に CPU Share is: 2 と出力されていることが確認できました。 2/1024≒0.002 のためコンテナに割り当てられる CPUリソース数が極端に少なく、 JVM は利用可能な CPU 数の最小値である 1 を適用する挙動をしたと判明しました。ECS/FargateとDockerにて挙動の異なる点にも説明がつきます。 対応 コンテナ定義のcpuパラメータの指定 前のセクションで説明した通り、 cpu.shares がデフォルトでは 2 であることが、タスクサイズに依らず1スレッドしか利用できない事象の深層的な原因であるとわかりました。 ECSにおいて cpu.shares を指定するには、コンテナ定義の cpu パラメータを指定すれば良いです。タスク定義におけるタスクサイズの cpu とは別のパラメータであることに注意してください。 私の検証では環境構築に AWS CDK を利用したので、対応例として ソースコード の一部を紹介します。 利用しているバージョンは package.json の一部の紹介で代替いたします。 { //省略 " devDependencies ": { " @types/jest ": " ^29.2.3 ", " @types/node ": " ^18.11.9 ", " @typescript-eslint/eslint-plugin ": " ^5.20.0 ", " @typescript-eslint/parser ": " ^5.20.0 ", " aws-cdk ": " ^2.51.0 ", " eslint ": " ^8.13.0 ", " eslint-config-prettier ": " ^8.5.0 ", " jest ": " ^29.3.1 ", " prettier ": " ^2.6.2 ", " ts-jest ": " ^29.0.3 ", " ts-node ": " ^10.9.1 ", " typescript ": " ^4.9.3 " } , " dependencies ": { " aws-cdk-lib ": " ^2.51.0 ", " constructs ": " ^10.0.0 ", " source-map-support ": " ^0.5.16 " } } const sandboxTaskdef = new TaskDefinition ( this , 'sandboxTaskdef' , { compatibility: Compatibility.FARGATE , networkMode: NetworkMode.AWS_VPC , family: ` ${ SYSTEM_NAME } - ${ props.m5Props.m5Env } -ecs-taskdef-sandbox` , executionRole: sandboxTaskRole , taskRole: sandboxTaskRole , cpu: '4096' , memoryMiB: '8192' , } ); sandboxTaskdef.addContainer ( 'sandbox' , { image: ContainerImage.fromEcrRepository ( Repository.fromRepositoryArn ( this , 'sandbox' , 'arn:aws:ecr:ap-northeast-1:XXXXXXXXXXXX:repository/m5infrasurvey-poc-ecr-sandbox' ) ), containerName: 'sandbox' , cpu: 1024 , // cpu.sharesに設定される /*省略*/ } ); 宣言した TaskDefinition クラスの addContaier メソッドからコンテナ定義の cpu パラメータを指定しています。 上記のコードをデプロイして起動されたFargateタスクの cpu.shares を実際に確認してみます。 まずは起動されたタスクの情報です。 $ aws ecs describe-tasks --cluster m5infrasurvey-poc-ecs-cluster --tasks 46e1d6fd883c47419093ad0e84a41ad1 { "tasks": [ { # 省略 "containers": [ { "containerArn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:container/m5infrasurvey-poc-ecs-cluster/46e1d6fd883c4741 9093ad0e84a41ad1/342343c2-0d87-4cdf-b60a-4496307cfc33", "taskArn": "arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task/m5infrasurvey-poc-ecs-cluster/46e1d6fd883c47419093ad0e84 a41ad1", "name": "sandbox", # 省略 "managedAgents": [ { "lastStartedAt": "2022-12-21T17:30:48.947000+09:00", "name": "ExecuteCommandAgent", "lastStatus": "RUNNING" } ], "cpu": "1024" } ], "cpu": "4096", # 省略 } ], "failures": [] } タスクサイズとは別にコンテナ定義として "cpu": "1024" が反映されていることを確認しました。 続いて、 JVM が認識するリソース情報と availableProcessors の戻り値を確認します。 $ aws ecs execute-command --cluster m5infrasurvey-poc-ecs-cluster --task 46e1d6fd883c47419093ad0e84a41ad1 --container sandbox --interactive --command "/bin/sh" The Session Manager plugin was installed successfully. Use the AWS CLI to start a session. Starting session with SessionId: ecs-execute-command-0d914bdaa48aec635 # # java -Xlog:os+container=trace -version [0.000s][trace][os,container] OSContainer::init: Initializing Container Support [0.001s][debug][os,container] Detected cgroups hybrid or legacy hierarchy, using cgroups v1 controllers [0.001s][trace][os,container] Path to /memory.use_hierarchy is /sys/fs/cgroup/memory/memory.use_hierarchy [0.001s][trace][os,container] Use Hierarchy is: 1 [0.001s][trace][os,container] Path to /memory.limit_in_bytes is /sys/fs/cgroup/memory/memory.limit_in_bytes [0.001s][trace][os,container] Memory Limit is: 9223372036854771712 [0.001s][trace][os,container] Non-Hierarchical Memory Limit is: Unlimited [0.001s][trace][os,container] Path to /memory.stat is /sys/fs/cgroup/memory/memory.stat [0.001s][trace][os,container] Hierarchical Memory Limit is: 8589934592 [0.001s][info ][os,container] Memory Limit is: 8589934592 [0.001s][trace][os,container] Path to /cpu.cfs_quota_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us [0.001s][trace][os,container] CPU Quota is: -1 [0.001s][trace][os,container] Path to /cpu.cfs_period_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us [0.001s][trace][os,container] CPU Period is: 100000 [0.001s][trace][os,container] Path to /cpu.shares is /sys/fs/cgroup/cpu,cpuacct/cpu.shares [0.001s][trace][os,container] CPU Shares is: 1024 [0.001s][trace][os,container] OSContainer::active_processor_count: 4 [0.001s][trace][os,container] CgroupSubsystem::active_processor_count (cached): 4 [0.001s][trace][os,container] CgroupSubsystem::active_processor_count (cached): 4 [0.037s][trace][os,container] Path to /cpu.cfs_quota_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us [0.038s][trace][os,container] CPU Quota is: -1 [0.038s][trace][os,container] Path to /cpu.cfs_period_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us [0.038s][trace][os,container] CPU Period is: 100000 [0.038s][trace][os,container] Path to /cpu.shares is /sys/fs/cgroup/cpu,cpuacct/cpu.shares [0.038s][trace][os,container] CPU Shares is: 1024 [0.038s][trace][os,container] OSContainer::active_processor_count: 4 # 省略 # # jshell Dec 21, 2022 5:55:00 PM java.util.prefs.FileSystemPreferences$1 run INFO: Created user preferences directory. | Welcome to JShell -- Version 11.0.16.1 | For an introduction type: /help intro jshell> Runtime.getRuntime().availableProcessors() $1 ==> 4 以下が確認できました。 CPU Shares is: 1024 と出力され、 cpu.shares が意図通りに設定されていること active_processor_count: 4 と出力され、タスクのvCPUと同値が認識されていること availableProcessors の戻り値が 4 と出力され、タスクのvCPUと同値であること 最後に、本件の事象が解消しているかを事象の再現方法と同じように確認します。 $ curl http://m5infrasurvey-poc-alb-sandbox-352400359.ap-northeast-1.elb.amazonaws.com:8080/sandbox/greet ; echo everyone! hello!everyone! $ $ (curl http://m5infrasurvey-poc-alb-sandbox-352400359.ap-northeast-1.elb.amazonaws.com:8080/sandbox/sleep ; echo done at `date`) & [1] 4454 $ (curl http://m5infrasurvey-poc-alb-sandbox-352400359.ap-northeast-1.elb.amazonaws.com:8080/sandbox/sleep ; echo done at `date`) & [2] 4457 $ (curl http://m5infrasurvey-poc-alb-sandbox-352400359.ap-northeast-1.elb.amazonaws.com:8080/sandbox/sleep ; echo done at `date`) & [3] 4460 $ $ curl http://m5infrasurvey-poc-alb-sandbox-352400359.ap-northeast-1.elb.amazonaws.com:8080/sandbox/greet ; echo everyone! hello!everyone! スレッドプール数は 4 になっているので、事象の再現に使用した /sandbox/sleep API を 3 リク エス ト受け付け後も、 /sandbox/greet API からレスポンスを取得できています。想定通りの結果を得ることができました。 XX:ActiveProcessorCountオプションの利用 前のセクションの対応で、 cpu.shares の設定方法がわかりました。 しかしながら、 18.0.2+ , 17.0.5+ , 11.0.17+ からOpenJDKにて cpu.shares を用いて利用可能なCPU数の制御を廃止する( 2 )ため、 Java のバージョン次第で前述した方法では事象が再現します。 そこで、 Java の拡張ランタイムオプションである -XX:ActiveProcessorCount=N を利用します。このパラメータを利用すると、 JVM が認識する CPU の数を上書きできます。 前述した対応ではコンテナのリソース量を環境に合わせて動的に割り当て可能ですが、こちらの場合は環境ごとにパラメータを変更する必要があります。 -XX:ActiveProcessorCount=N を利用するケースにおいても、対応例として AWS CDKの ソースコード の一部を紹介します。 const cpuNum = 4 ; const sandboxTaskdef = new TaskDefinition ( this , 'sandboxTaskdef' , { compatibility: Compatibility.FARGATE , networkMode: NetworkMode.AWS_VPC , family: ` ${ SYSTEM_NAME } - ${ props.m5Props.m5Env } -ecs-taskdef-sandbox` , executionRole: sandboxTaskRole , taskRole: sandboxTaskRole , cpu: String ( cpuNum * 1024 ), memoryMiB: '8192' , } ); sandboxTaskdef.addContainer ( 'sandbox' , { image: ContainerImage.fromEcrRepository ( Repository.fromRepositoryArn ( this , 'sandbox' , 'arn:aws:ecr:ap-northeast-1:XXXXXXXXXXXX:repository/m5infrasurvey-poc-ecr-sandbox' ) ), containerName: 'sandbox' , environment: { TZ: 'Asia/Tokyo' , JAVA_TOOL_OPTIONS: `-XX:ActiveProcessorCount= ${ cpuNum } ` , // 環境変数で-XX:ActiveProcessorCountを設定 } , } ); タスクに割り当てる vCPU の数をあらかじめ宣言しておき( cpuNum )、タスクサイズの cpu パラメータと -XX:ActiveProcessorCount= の値に使用します。 本番環境と開発環境間でタスクサイズは異なることが多いので、 -XX:ActiveProcessorCount= は JAVA_TOOL_OPTIONS 環境変数 を利用して外部から注入する形で付与するのがベターと考えました。 このように クラウド のサービスやリソースを宣言的に構築できる点や、値やオブジェクト等を再利用可能なところもIaCのメリットですね! 前のセクションと同じように反映されたか確認します。 $ aws ecs execute-command --cluster m5infrasurvey-poc-ecs-cluster --task e4696c0103574ad0a07a8eabc1360087 --container sandbox --interactive --command "/bin/sh" The Session Manager plugin was installed successfully. Use the AWS CLI to start a session. Starting session with SessionId: ecs-execute-command-0c5d73c5e08474f67 # # jshell Picked up JAVA_TOOL_OPTIONS: -XX:ActiveProcessorCount=4 Dec 20, 2022 6:58:07 PM java.util.prefs.FileSystemPreferences$1 run INFO: Created user preferences directory. | Welcome to JShell -- Version 11.0.16.1 | For an introduction type: /help intro jshell> Runtime.getRuntime().availableProcessors() $1 ==> 4 JAVA_TOOL_OPTIONS 環境変数 が適用されていること、および、 availableProcessors の戻り値も指定した値になっていることが確認できました。 実際に API にリク エス トを行う動作確認は前述と同じ結果になったため記載は割愛します。 非同期処理を検討する 前述までの対応は、タスクの vCPU を 2 以上に設定することが前提となっています。 常時多数のリク エス トを受けるつけるようなワークロードであればよいですが、それ以外の場合はリソースに余剰が発生しコスト最適化の設計原則に反しています。 理想は、必要最小限のタスクサイズとタスク数で ECS サービスを起動し、負荷に応じてスケールすることです。 今回の発端となったような応答まで時間を要するような処理は非同期で実行することで、スレッドを長時間占有することを回避するという案です。 AWS においては SQS と Lambda を利用してメッセージキューイングによる非同期処理をサーバレス アーキテクチャ で実現する方法が知られています。 上記の図の例では、バックエンド API は enqueue に成功した時点でレスポンスを返却するため、本件の事象を回避するという意図になります。 非同期化した場合は API クライアント側にポーリングやリフレッシュの仕組みが必要になるため、 API 仕様として許容可能かの調整も必要となる点には注意が必要です。 おわりに 今回は ECS/Fargate で発生した事象について紹介いたしました。 今後は他の クラウド プロバイダのコンテナ関連サービスにおける事象の発生有無についても調査したいと考えています。 最後までご覧いただきありがとうございました。皆さま良いお年を! 私たちは一緒に働いてくれる仲間を募集しています! 金融機関のようなお客様においても クラウド ファーストなアプローチやマイクロサービスのようなモダンな技術の採用が進みつつあります。ご自身のインフラ/ クラウド スキルを エンタープライズ 領域でも活用したい・挑戦したいという方がいらっしゃいましたら、ぜひご応募ください! 金融システム インフラ・アーキテクト 金融システム インフラエンジニア 執筆: 寺山 輝 (@terayama.akira) 、レビュー: @mizuno.kazuhiro ( Shodo で執筆されました ) https://github.com/helidon-io/helidon/blob/helidon-2.x/webserver/webserver/src/main/java/io/helidon/webserver/ServerConfiguration.java#L58-L65 , https://github.com/helidon-io/helidon/blob/helidon-3.x/common/configurable/src/main/java/io/helidon/common/configurable/ServerThreadPoolSupplier.java#L54-L68 ↩ https://bugs.openjdk.org/browse/JDK-8281181 ↩
こんにちは、X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループ 新卒入社2年目の大西です。これは、 電通国際情報サービス Advent Calendar 2022 12/21の記事です。今日は、私が所属するセキュリティグループについて記事を書いてみました!配属されて1年余りですが、グループの仕事内容や雰囲気、魅力などをお伝えできればと思います。 どうしてセキュリティグループに入ったの?? どんな仕事をしているの?? やりがいや達成感は?? 大変なところは?? グループの雰囲気はどんなかんじ?? ブログを見てくださった方に向けて どうしてセキュリティグループに入ったの?? 昨年セキュリティグループに配属された際、いろんな人に「どうしてセキュリティの仕事がしたいの?」と聞かれました。私は、入社する前からセキュリティに興味があり、セキュリティに関わる仕事がしたいと思っていました。その理由は、いくつかあります。 セキュリティの仕事=必要な仕事 世の中にはいろんな便利なものがありますが、便利なだけでは人は満足しないと思います。便利さ以前に、「安心」がないと、誰もそれを使ってくれません。例えば、音楽のストリーミングサービスで、いろんな曲が定額で聴き放題だけど、クレジットカードなどの支払い情報が外部に ダダ漏れ だったら誰もそれを使いたいとは思いません。 どんな便利なアプリやシステムでも絶対に必要なもの...安心とかセキュリティとか...それらを守る仕事がしたいとずっと思っていて、それを新人の時に人事の方に伝え、無事セキュリティグループに配属されました!(ISIDは、できるだけ希望の部署に入れてあげたいという思いの強い会社だと思います。) セキュリティエンジニア、足りてない... ニュースで セキュリティインシデント を目にすることはたまにしかないかもしれませんが、 セキュリティインシデント は毎日起こっています。 Security Next というサイトでは、情報セキュリティに関するニュースを日刊で届けてくれるのですが、これを見ていると本当に毎日インシデントだらけだなぁと思います。しかし、それらインシデントに対応できるようなセキュリティエンジニアは不足していて、多くの企業で課題となっています。セキュリティ人材が足りていない中で、少しでも貢献したいという気持ちがありました。今年もセキュリティグループに新たに4人の方が採用されて、やはりニーズは高まっているんだなと感じます。 セキュリティエンジニア、かっこいい! 私がセキュリティに興味を持ち始めたのは、ハッキングをしている人たちをTVで見て、ハッキングって面白そう!と思ったところからでした。そこから、 IPUSIRON さんの 「ハッキング・ラボの作り方」 を読みながら簡単なハッキングをしてみたり、CTF(Capture The Flag)と呼ばれるセキュリティコンテストの問題を解いてみたりして、ますます面白いと思うようになりました。 ハッキングの知識を悪いことに使えば犯罪ですが、いいことに使えば世の中のいろんなシステムを攻撃から守れます。セキュリティエンジニアは、プログラミングの知識だけでなく、ネットワーク、暗号化・認証技術、 クラウド 技術など様々なことに精通している必要があります。システムやアプリに存在するセキュリティの穴をどう塞ぐか、いろんな知識を持ち寄って考えなければなりません。それが、大変ではあるけれど、とてもかっこいいなと感じます! どんな仕事をしているの?? 現在9名のメンバーがセキュリティグループに所属し、部門横断で システム開発 ・運用におけるセキュリティを確保する支援を行っています。SRB(Security Review Board), SOC(Security Operation Center), IRG(Incident Response Group)という3つのグループがあり、図にすると以下のような感じです。 これまではSRB中心の業務でしたが、今年SOCとIRGチームが立ち上がりました。それぞれのグループの業務内容については以下のとおりです。 SRB: ISIDの事業部が担当している案件においてセキュリティに関する懸念事項を確認し、リリース前までに修正した状態にします。具体的には、案件の提案段階や設計段階でセキュリティに関する懸念事項がないか確認したり、セキュリティツールを用いた検査を行ったりし、事業部側に改善案を提案します。 SOC: クラウド 環境のセキュリティ対策を可視化し、被害の拡大を防止して問題の早期検知を行います。各案件のセキュリティ設定基準に対する準拠状況を把握し、チェックした結果を案件担当に伝え、改善を進めていきます。脅威検知ではアラートに対して、案件担当と連携し問題調査を行います。また、案件担当者に対し、 クラウド 専門の部署と合同でセキュリティ勉強会を行ったりもします。 IRG: セキュリティインシデント が発生した際に、状況を把握して被害の拡大を防止したり、被害の範囲を特定するなど適切に事後対応を行います。また、インシデントが起きた原因を突き止めそれを教訓化することで、将来のインシデントのリスクを低減させます。 この中で私はSRBチームに所属しており、セキュリティツールを用いた 脆弱性 検査(動的検査)の担当しています(実は、担当になったばかりで先月キャッチアップを終え、実際に案件を担当するのはこれからです!)。他にも、社内向けWeb アプリ開発 や、新人研修のセキュリティ講義、また、ISIDで使用しているソフトウェアやハードウェアなどの 脆弱性 が公開されればそれを全社に通知する業務なども担当しています。来年からは、セキュリティツールでは見つけにくい 脆弱性 を発見するため、マニュアル検査が本格的に始まります。実際に擬似的な攻撃コードなどを投げ、返ってきたレスポンスを見て脆弱かどうか検査していくのですが、経験と専門性がより問われるので、これから頑張って技術を習得していきたいと思います! やりがいや達成感は?? 業務によってやりがいや達成感を感じる瞬間は違いますが、例えばWeb アプリ開発 では、一つの機能を作り終えた時にすごくやりがいを感じますし、新人研修のセキュリティ講義をしたときは、講義やハッキング演習を通して新人がセキュリティに興味を持ってくれた時にもすごくやりがいを感じました。 これから 脆弱性 検査を本格的に担当していくと、リリース前に 脆弱性 が見つけられた時などにも、 セキュリティインシデント を未然に防ぐことができて大きなやりがいを感じるのではないかと思います。セキュリティ要件の高い案件や大きな規模の案件のセキュリティレビューや 脆弱性 検査をすることもあり、金融機関や官公庁の案件を担当することもあります。それらの案件のシステムがもし サイバー攻撃 を受けると、影響を受ける範囲がとても大きくなるので、それを未然に防ぐ仕事というのはとてもやりがいがあるのではないでしょうか。 大変なところは?? 身に付けなければならない知識・スキルが多いことです。それは最初から覚悟していたことなのですが、覚えても覚えても新しい技術が出てくるので、心が折れそうになることもあります。しかし、一歩ずつやっていくしかないと思うので、毎日の業務で新しいことを覚えたり、資格の勉強をしたりして地道に知識を増やしていきます。資格の勉強は、体系的にセキュリティのことを学べるのでいいなと思います。ISIDは資格試験や研修の費用を会社がお金を出してくれるのでとてもありがたいです。資格勉強に限らずですが、勉強を進めていると、初め聞いた時はよくわからなかった技術も他に新しいことを覚えていくうちに、あ、あの時のあれはそういうことだったんだ!!みたいな、点と点が繋がる瞬間がたまにあって、自分の成長を感じる瞬間がとても嬉しいです。この仕事は、本当に日々勉強です。 グループの雰囲気はどんなかんじ?? セキュリティグループの雰囲気は、「個」というよりは「チーム」、「上下関係」というよりは「フラット」、「静か」というよりは「にぎやか」という感じです。みんなで助け合いという感じで、今は助けられていることの方が多いんですが、もっと力がついてきたら先輩や後輩を助けられるようになりたいです。年代は20代~50代と幅広いですが、思ったことは割と上の人にもぶつけている印象で、発言しやすいなと感じます。テレワークが中心でほとんど出社することはないですが、オンラインで雑談できたりするので、寂しくなることもありません。また、今はTypeScriptという言語の勉強会をグループ中心でやっていて、みんなで学ぼうという姿勢がいいなと思います。雰囲気ではないですが、残業時間は平均20時間くらいで少なめで、総合的に見てとても働きやすいです。 ブログを見てくださった方に向けて このブログ記事は学生に向けた働き方紹介ということだったんですが、もしかしたら学生以外の方も見てくださっているかもしれません。セキュリティってちょっと気になるな、という方がいたら、ぜひカジュアル面談などを受けてみてください。グループの雰囲気などはやはり実際にメンバーに会ってみないと分からなかったりするし、こちらももっとここに書ききれていない弊社の魅力を伝えられたらと思います。 学生の方に向けたメッセージとしては、自分がいちばん何をしている時に感動したり、またこれをやってみたい!と思うかを大事にしてほしいです。イメージで会社を選ぶのではなく、その感動したことを仕事にできる会社を選ぶと、仕事をしていても楽しいなと思うことが多いはずです。自分の例で言うと、プログラミングしたものが自分の思い通りに動くとすごく感動するし、またコードを書いてみたい!と思います。また、攻撃者の目線に立ってハッキングしてみようとデモアプリにハッキングしたり、この攻撃を防ぐには・・・?と考えだすと、面白い!!となります。会社のイメージではなく、仕事内容をぜひ重視して会社を選んでみてください。もし、ワクワクどきどきするのがセキュリティという分野だったら、ぜひ一緒に働きましょう!! www.isid.co.jp 中途の方向け:セキュリティエンジニア(セキュリティ設計) 執筆: @onishi.mayu 、レビュー: @yamada.y ( Shodo で執筆されました )
電通国際情報サービス 、オープン イノベーション ラボの 比嘉康雄 です。 Stable Diffusionシリーズ、今回のテーマは、Stable Diffusion 2.1-金髪美女写真です。 Stability AI が Prompt Bookという呪文の解説スライド を出しているので、それを研究します。今回は、 Prompt Book の Photorealism (写真のようなリアルな描写法)の金髪美女の呪文を解説します。解説スライドでは、14, 15ページの内容になります。 Prompt Book は更新が入っているようなので、最新版では、内容が変わっている可能性もありますが、本質的な部分は変わっていないはずです。 Stable Diffusionのおすすめコンテンツはこちら。 Waifu Diffusion 1.3.5_80000 v2.1 金髪美女写真 v2.1 美少女アニメ画 v2.1 AUTOMATIC1111 v2.0 美少女イラスト v1.5 美少女画検証 美少女アニメ画改善版 美少女を高確率で出す呪文 美少女アニメ画 美少女写真 女性イラスト 長い呪文は切り捨てられる AUTOMATIC1111のインストール AUTOMATIC1111のセッティング 金髪美女写真の出力結果 金髪美女写真の通常呪文 portrait of a blonde woman in a white dress posing for a picture tumblr digital art glowing with colored light ethereal lighting forest ray light taken in 2022 handsome girl brooke ashling diffused natural skin glow 金髪美女写真のネガティブ呪文 gingerbread candy village, on a plate in a busy diner ice - t drinking beer and laughing cartoon, 1990s cartoon black show room breaking bad scene animal shaped bread broken down grey wall cheese and pepperoni black hair duplicate 仲間募集 Stable Diffusionの全コンテンツ AUTOMATIC1111のインストール Stable Diffusion 2.1 を実行する環境として、 AUTOMATIC1111 を使います。 AUTOMATIC1111 は、 Stable Diffusion を Google Colab 直接ではなく、 UI 経由で実行できるようにしています。似たような機能のものはいくつかありますが、 AUTOMATIC1111 は人気が高く、情報量も多いのでおすすめです。 Google Colab で動かすための公式のノートブックは こちら になります。 このノートブックを実行すると、下の方に Running on public URL: https://2c76db068be0e79a.gradio.app のようなリンクが表示されるので、クリックしましょう。 AUTOMATIC1111のセッティング パラメータは以下のようになります。 Sampling Steps: 50 Sampling Method: DPM2 Width: 768 Height: 768 CFG Scale: 7.5 Seed: -1 Sampling Stepsは、デフォルトの 20 だと少ないので、 50 くらいにしておきましょう。 Sampling Methodは DPM2 をお勧めしますが、 DDIM も悪くはありません。 Width と Height は 768 をお勧めします。今回使っているモデルは、 768 用のためです。 512 だとかを使うと画像が崩れることがあります。 CFG Scale は入力した呪文にどれだけ近い画像を生成するかのパラメータです。デフォルトの 7 でも問題ありませんが、僕はなんとなく 7.5 を指定しています。 金髪美女写真の出力結果 金髪美女写真の出力結果の例です。 金髪美女写真の通常呪文 金髪美女写真の通常呪文は次のようになります。 portrait of a blonde woman in a white dress posing for a picture, tumblr, digital art, glowing with colored light, ethereal lighting, forest ray light, taken in 2022, handsome girl, brooke ashling, diffused natural skin glow 見やすいように改行すると次のようになります。 portrait of a blonde woman in a white dress posing for a picture, tumblr, digital art, glowing with colored light, ethereal lighting, forest ray light, taken in 2022, handsome girl, brooke ashling, diffused natural skin glow 個々の呪文を解説しましょう。 portrait of a blonde woman portrait of a blonde woman は、「金髪女性の 肖像画 」という意味です。 in a white dress in a white dress は、「白いドレスを着て」という意味です。 posing for a picture posing for a picture は、「写真撮影のためにポーズを取る」という意味です。正面から撮った棒立ちの写真はつまらないので、この呪文は覚えておきましょう。 tumblr tumblr は、 SNS の一つです。指定するとなんとなくクオリティが上がる気がする呪文です。たぶん、外してもそれほど違いはないと思います。 digital art digital art は、「デジタルアート」という意味です。たぶん、外してもそれほど違いはないと思います。 glowing with colored light glowing with colored light は、「色付きの光で輝く」という意味です。この効果は、金髪女性に影響します。 ethereal lighting ethereal lighting は、「優美な照明」の意味です。 forest ray light forest ray light は、「森の光」という意味です。木々の間から木漏れ日が見えるような効果になることが多いです。単なる forest よりずっと美しくなるので、この呪文は覚えておきましょう。 taken in 2022 taken in 2022 は、「2022年に撮られた」という意味です。たぶん、外してもそれほど違いはないと思います。 handsome girl handsome girl は、「キリッとして目鼻立ちの整った少女」の意味です。 brooke ashling brooke ashling は、人の名前のような気がしますが、なんの意味があるのかわかりません。たぶん、外してもそれほど違いはないと思います。 diffused natural skin glow diffused natural skin glow は、「分散した自然な肌の輝き」の意味です。 金髪美女写真のネガティブ呪文 通常呪文を打ち消すのがネガティブ呪文です。 金髪美女写真のネガティブ呪文は次のようになります。 gingerbread candy village, on a plate in a busy diner, ice - t, drinking beer and laughing, cartoon, 1990s cartoon, black show room, breaking bad scene, animal - shaped bread, broken down grey wall, cheese and pepperoni, black hair, duplicat 見やすいように改行すると次のようになります。 gingerbread candy village, on a plate in a busy diner, ice - t, drinking beer and laughing, cartoon, 1990s cartoon, black show room, breaking bad scene, animal - shaped bread, broken down grey wall, cheese and pepperoni, black hair, duplicate 個々の呪文を解説しましょう。 gingerbread candy village, on a plate in a busy diner 結構意味不明ですが、「繁盛している食堂の皿の上のお菓子」くらいの意味でしょうか。通常呪文とほとんど関係がないので、たぶん、外してもそれほど違いはないと思います。 ice - t これも意味不明ですが、「アイス ティー 」のことなのかもしれません。通常呪文とほとんど関係がないので、たぶん、外してもそれほど違いはないと思います。 drinking beer and laughing drinking beer and laughing は、「ビールを飲んで笑う」の意味です。通常呪文とほとんど関係がないので、たぶん、外してもそれほど違いはないと思います。 cartoon, 1990s cartoon cartoon は、「漫画」、 1990s cartoon は、「1990年代の漫画」の意味です。リアルな写真が目的なので、漫画の要素を打ち消しているのでしょう。 black show room black show room は、「黒い展示室」の意味です。通常呪文とほとんど関係がないので、たぶん、外してもそれほど違いはないと思います。 breaking bad scene breaking bad scene は、「ハメを外したシーン」の意味です。ハメを外したシーンを打ち消します。 animal animal は、「動物」の意味です。動物を打ち消します。 shaped bread shaped bread は、「成形されたパン」の意味です。通常呪文とほとんど関係がないので、たぶん、外してもそれほど違いはないと思います。 broken down grey wall broken down grey wall は、「壊れた灰色の壁」の意味です。たまに、背景が灰色になってしまうことがあるので、それを打ち消しているんだと思いますが、打ち消しきれていない気がします。 cheese and pepperoni cheese and pepperoni は、「チーズとパペロニ」の意味です。通常呪文とほとんど関係がないので、たぶん、外してもそれほど違いはないと思います。 black hair black hair は、「黒い髪」の意味です。金髪にするために、黒い髪を打ち消します。 duplicate duplicate は、「複製」の意味です。体のパーツが複製されるのを打ち消したいんじゃないかと思います。例えば、鼻が2つあるとか。 仲間募集 私たちは同じグループで共に働いていただける仲間を募集しています。 現在、以下のような職種を募集しています。 ソリューションアーキテクト AIエンジニア Stable Diffusionの全コンテンツ 人物写真編 レンズ編 画像タイプ編 美少女アニメ画編 美少女写真編 女性イラスト編 美しい夜空を見渡す男編 魅惑的な女アニメ画(トゥーンレンダリング)編 美少女を高確率で出す呪文編 長い呪文は切り捨てられる編 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 A as Bの呪文による画像合成編 かわいい動物の擬人化編 バベルの塔のイラスト編 TPU版の使い方 美少女アニメ画改善版 v1.5 美少女画検証 東京タワーの写真 折り紙合体変形ロボ v2.0 美少女イラスト v2.1 AUTOMATIC1111 v2.1 美少女アニメ画 v2.1 金髪美女写真 Waifu Diffusion 1.3.5_80000 執筆: @higa 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )