TECH PLAY

SCSKクラウドソリューション

SCSKクラウドソリューション の技術ブログ

1141

本記事は 夏休みクラウド自由研究 8/27付の記事です 。 こんにちは。SCSKの島村です。 Googleが提供するオープンAIモデル Gemma についてご存じでしょうか??? Gemma は、 Googleが公開した商用利用可能なオープンモデル で、「軽量かつ高性能なLLM」という特徴があります。 本記事では、 『 Gemma 』について色々調査いたしましたので、それらを整理してみたいと思います。 また、実際にGoogle Cloud上でGemmaを展開し、利用してみました。その魅力について少しだけご紹介させていただければと思います。 Google Gemmaとは?? Gemma は、「アプリケーション内、ハードウェア、モバイル デバイス、ホスト型サービス」で実行できる 軽量型の生成 AIオープンモデルセット です。 ( Gemini モデルの作成に使用されたのと同じ研究とテクノロジーから構築された、軽量で最先端のオープンモデルです。) Gemma モデルは、ノートパソコン、ワークステーション、または Google Cloud で実行できます。 また、Colab や Kaggle ノートブック、JAX、PyTorch、Keras 3.0、Hugging Face Transformers などのフレームワークなどでもサポートをしています。 詳細については、以下、Google Blog公式からご確認ください。 Gemmaについて- Google Blog 大規模言語モデル(LLM)の性能を評価するためのベンチマークの一つであるMMLUでも 他のモデルと比較して性能が高いとのことです。(2024-06-27時点) MMLU(Massive Multitask Language Understanding) は、 様々な分野、多岐にわたるタスクを網羅した膨大な量の質問と回答のペアで構成されており、LLMが幅広い知識と理解能力を持っているかを測るために用いられます。                      横軸: 評価されたLLMのモデル名と、そのモデルのパラメータ数(数十億単位) 縦軸: MMLUベンチマークにおける正解率(%)   Gemma モデル ファミリー Gemmaは「様々なサイズや用途に合わせて、複数のモデルが提供」されています。 それらを表で整理してみました。 Gemma 2 200 億、900 億、270 億のパラメータ サイズで利用可能です。 3 つの新しい パワフルで効率的なモデル を提供し、すべてセーフティ機能を備えています。 Gemma 1 軽量でテキストからテキストを生成する、 デコーダのみの 大規模言語モデルです。 テキスト、コード、数学コンテンツの膨大なデータセットでトレーニングされます。 RecurrentGemma 再帰型ニューラル ネットワークとローカル アテンションを活用してメモリ効率を向上させる、技術的に異なるモデルです。 PaliGemma PaLI-3 に着想を得たオープンなビジョン言語モデル SigLIP と Gemma を活用しており、幅広い視覚言語タスクに転送するための汎用モデルとして設計されています。 CodeGemma CodeGemma は、オリジナルの事前トレーニング済み Gemma モデルの基盤を利用して、ローカル コンピュータに適したサイズの強力なコード補完と生成機能を提供します。   Google AI Studio上でGemmaを試してみた。 ここからは実施にGemmaモデルを利用してみたを共有できればと思います。 まずは簡単に試してみるということで、『 Google AI Studio 』からモデルを選択して、そのレスポンスを見てみます。 Google AI Studioとは?? Googleが提供 する、生成AIモデルであるGeminiを使って、様々なタスクを実行できるプラットフォームです。 ユーザーフレンドリーなインターフェースによって 開発の経験がないユーザーでも簡単に利用可能なことが特徴です。 Google AI Studioへのログインはこちら Gemini appとの違いは、 「APIキーの発行」や「モデルの選択」、「パラメータの調整」などのその他開発者向けの機能が充実しております。 Google AI StudioでモデルGemmaを選択してみる。 Gemmaは3つのサイズから選択可能です。 実際にpromptを入力して実行してみました。☟☟☟ 複数プロンプト実行してみた結果、 Gemini1.5 Flashに比べると出力までの時間は多少要しましたが、精度は申し分ないかと思います。   Google Cloud上でGemmaを動かしてみた。 Vertex AI で Gemma モデルを使用すると、 開発者はモデルの調整、管理、監視をシンプルかつ直感的に行えるエンドツーエンドのMLプラットフォームを活用できます。 Google CloudからGemmaを利用するには??? Gemma は、Vertex AI Model Garden からノートブックを起動して利用開始することができます。 また、Google Kubernetes Engine や Dataflow などのGoogle Cloud プロダクトでも利用可能です。 Google Cloud から利用できるGemma モデルのサイズと機能 https://ai.google.dev/gemma?hl=ja GCE(ローカル環境)上にGemamモデルをデプロイして使ってみる!!!! 今回、Gemmaの実行環境として Ollama を利用しました。 *『Ollam』はローカル環境でLLMモデルを動かすことができる無料でツールあり、使いやすいインターフェースが特徴です。 GCEインスタンを作成する。今回はGPUとしてNVIDIA T4を利用しました。 作成したインスタンスにSSHして DokcerとOllamaをインストールする。 Ollamaは公式ドキュメントの手順通りにインストールをします。 Download Ollama on Linux Download Ollama on Linux ollama.com                curl -fsSL https://ollama.com/install.sh | sh Ollama Open WebUIを起動する。 インストールできたら以下のコマンドでDockerを起動します。                 sudo docker run -d --network=host -v open-webui:/app/backend/data -e OLLAMA_BASE_URL=http://127.0.0.1:11434 --name open-webui --restart always ghcr.io/open-webui/open-webui:main ブラウザからOllama Open WebUIにアクセスする。 正しく起動でき、アクセスできると以下の画面が現れます。 *起動したOpenWebUI(GCE)へのアクセスは適切なネットワークとファイアウォールの設定を実施して接続してください。 モデル(Gemma)を選択し、プロンプトを送信してみる。 今回は「Gemma:7b」を利用してみした。 Gemmaをローカル環境でも利用することができました!!!!!!                 初回利用時は、Gemmaモデルをインストールする必要があります。 [設定]-[モデル]から[Ollama.comからモデルをプル]にてモデル名(例:gemma:7b)と入力しダウンロードしてください。   ローカル環境のリソースということもあり、出力には数十秒の時間を要しました。 ですが、実際の精度は申し分ないかと思います。 Gemma以外の他のオープンモデルについても試してみてそれらの使いやすさをい整理していこうと思います。   最後に 今回は Google のオープンAIモデル『Gemma』 についてご紹介させていただきました。 また、実際にローカル環境で実行してみてその手軽さを少しでもお伝え出来たかなと思います。 より詳細な機能については、追って公開させていただきます。引き続き本ブログをお楽しみください!!!!!! 今後とも、AIMLに関する情報やGoogle CloudのAIMLサービスのアップデート情報を掲載していきたいと思います。 最後まで読んでいただき、ありがとうございました!!!
アバター
こんにちは。SCSKの上田です。 今回は Zabbixで複雑な条件のログ監視を行う方法 をご紹介します。 ログ監視は、例えば「”ERROR”という文字列が含まれる」「イベントIDが”777″」などシンプルな条件なら簡単に作成できるのですが、 “Error”という文字列と”CPU”という文字列をともにを含む 深刻度が”警告”以上、但しイベントIDが”777″の場合は除外する といった 複合条件 や 除外条件 が加わると、作成が難しくなります。 そこで今回は、ログ監視の作成方法と、複雑な条件のログ監視を設定する方法について紹介していきます。 Linuxのテキストログ監視とWindowsのイベントログ監視でやり方が異なるので、それぞれについて書いていきます。 Linuxのログ監視 まずは、 Linuxのログ監視 についてです。 ログ監視のやり方 Linuxのログは、以下のアイテムキーで取得できます。 アイテムキー: log[監視するファイル名] 以下は、実際に取得されたアイテムの情報です。 Linuxログのアイテム取得画面 このように、出力されたログが プレーンテキスト として取得できます。 このログから特定の文字列を検知するには、以下のトリガー関数を使います。 トリガー関数: find(/ホスト名/log[監視するファイル名],,,”検知したい文字列”) このfind関数は、 アイテムの最新の値に検知したい文字列が 含まれている場合1 を、 含まれていない場合0 を返します。 例えば、/var/log/messagesで “ERROR” が含まれるログを検知したい場合、アイテムキーが “log[/var/log/messages]” のアイテムを作成し、トリガー条件式が “find(ホスト名/log[/var/log/messages],,,”ERROR”)=1″ となるトリガーを作成します。 複雑なログ監視のやり方 Linuxでは、 複合条件 も 除外条件 も、 グローバル正規表現 を使うのが有効です。 別の記事 “正規表現の使い方” にて正規表現の使い方とログ監視への応用方法を紹介しておりますので、そちらをご参照ください。 ログ監視に役立つZabbix正規表現の使い方 Zabbixにおける正規表現の使い方を説明します。正規表現を使うことで、複雑な条件にマッチするログの検知を行うことができます。 blog.usize-tech.com 2024.07.24   Windowsのログ監視 続いて、 Windowsのログ監視 についてです。こちらはLinuxと比べて少々複雑です。(理由は後述) ログ監視のやり方 まずログ取得のアイテムですが、 アイテムキー: eventlog[イベントログ名](または eventlog[イベントログ名称,,,,,,skip]) で取得します。パラメータに「 skip 」を指定しないと、 ホストに蓄積された過去のログも全て取得されてしまいます ので、アイテム登録した時点からのログだけ取得したい場合はskip付きののアイテムキーを使ってください。(本記事ではskip無しのアイテムキーを使用しています。) 以下は、実際に取得されたアイテムの情報です。 Windowsイベントログのアイテム取得画面 Linuxのログとは異なり、1つのプレーンテキストではなく 「ソース」 、 「深刻度」 、 「イベントID」 、 「値(ログの内容)」 と分かれて値が取得され、要素ごとにトリガー関数も分かれています。 (これがWindowsのイベントログ監視が複雑になる理由です) ソース: logsource (/ホスト名/eventlog[イベントログ名],,”検知したいソース”) 深刻度: logseverity(/ホスト名/eventlog[イベントログ名]) イベントID: logeventid (/ホスト名/eventlog[イベントログ名],,”検知したいイベントID”) 値: find(ホスト名/log[/var/log/messages],,,”検知したい文字列”) ソース、イベントID、値の関数は、 最新のイベントログに検知したい要素が 含まれている場合1 を、 含まれていない場合0 を返します。 深刻度の関数は、深刻度が “情報”なら1、”警告”なら2、,”エラー”なら4、”クリティカル”なら9 を返します。 例えば、システムログでイベントの 深刻度がエラー のログを検知したい場合、” logseverity(/ホスト名/eventlog[System]) =4″、 イベントIDが777 のログを検知したいときは” logeventid (/ホスト名/eventlog[System],,”777″)=1″ という風に、適切な関数を選んでトリガーを設定します。 複雑なログ監視のやり方 それでは、複雑な条件のログ監視を設定してみましょう。 ①複合条件 まず、「ソースが●● かつ 深刻度が●● かつ ・・・」という 複合条件 を考えてみます。 トリガー条件式は、 論理演算子”and” や “or” が使えるので、それを使って条件式を組み立ててみます。 例として、以下のすべての条件を満たす条件式を作ってみましょう。 ソースがtest 深刻度が警告以上 イベントIDが777 この場合、以下のような条件式になります。 logsource(/ホスト名/eventlog[System],,”test”)=1 and logseverity(/ホスト名/eventlog[System])>=2 and logeventid(/ホスト名/eventlog[System],,”777″)=1 イベントログ監視トリガー① これで実際に該当のイベントログを検知できるか試してみましょう。イベントログを生成するには、 “EVENTCREATE” コマンドを使います。 監視対象機器のコマンドプロンプトで、以下のコマンドを実行してみましょう。 EVENTCREATE /ID 777 /L system /SO test /T ERROR /D "イベントテスト" すると、想定通り障害として検知しました。 障害検知 ②除外条件 続いて、 除外条件 も考えてみましょう。例えば、「深刻度がエラー以上 但しソースが●●のモノは除く」といった条件です。 トリガー条件式では、 否定演算子”not” も使えるので、これを使って条件を組み立てます。 以下の条件を考えてみましょう。 深刻度が警告以上 但し、イベントIDが”777″のログは除く この場合、以下のような条件式になります。 logseverity(/ホスト名/eventlog[System])>=2 and not logeventid(/ホスト名/eventlog[System],,”777″)=1 イベントログ監視トリガー② その後、EVENTCREATEで以下のイベントを生成します。 EVENTCREATE /ID 888 /L system /SO test /T ERROR /D "イベントテスト" これは、 深刻度が警告以上 で イベントIDは”777″ではない ので、条件にマッチして障害として検知されます。 障害検知② その後、今度は除外条件にマッチする以下のイベントを生成します。 EVENTCREATE /ID 777 /L system /SO test /T ERROR /D "イベントテスト" こちらは除外条件にマッチするので、想定通り 障害が発生しません。 ③複合条件と除外条件のMIX 最後に、さらに複雑な、 複合条件 と 除外条件 の 合わせ技 をやってみます。 例えば、以下のような条件を考えます。 深刻度が警告以上 但し、以下の条件のいずれかを満たすものは除外する:  1:「ソースが”test”」かつ「イベントIDが”777″」  2:「ソースが”hoge”」かつ「イベントIDが”888″」かつ「内容に”テスト”という文字列が含まれる」 複雑なので、一つ一つ紐解いていきます。 まず、”深刻度が警告以上”という条件は、今まで出てきている通り、 logseverity(/ホスト名/eventlog[System])>=2 となります。 続いて1と2の条件式は、複合条件なので以下のように書けます。 1: logsource (/ホスト名/eventlog[System],,”test”)=1 and logeventid(/ホスト名/eventlog[System],,”777″)=1 2:logsource(/ホスト名/eventlog[System],,”hoge”)=1 and logeventid(/ホスト名/eventlog[System],,”888″)=1 and find(/ホスト名/eventlog[System],,,”テスト”)=1 これらの条件を満たす場合は検知しないので、この条件をnotで否定し、最初の条件と結合します。複数条件に演算子を適用する場合は、()で括ります。 logseverity(/ホスト名/eventlog[System])>=2 and not (logsource(/ホスト名/eventlog[System],,”test”)=1 and logeventid(/ホスト名/eventlog[System],,”777″)=1) and not (logsource(/ホスト名/eventlog[System],,”hoge”)=1 and logeventid(/ホスト名/eventlog[System],,”888″)=1 and find(/ホスト名/eventlog[System],,,”テスト”)=1) イベントログ監視トリガー③ それでは、これが正しい動作をするかテストしてみましょう。 まずは除外条件に当てはまらないログを生成し、障害検知するかテストします。 EVENTCREATE /ID 888 /L system /SO test /T ERROR /D "イベントテスト" これは除外条件1,2ともにすり抜けているので、障害として検知されます。 障害検知③ 続いて、以下のログを生成します。 EVENTCREATE /ID 777 /L system /SO test /T ERROR /D "イベントテスト" これは除外条件1にマッチしているので、障害として検知されません。 以下のログでも試してみましょう。 EVENTCREATE /ID 888 /L system /SO hoge /T ERROR /D "イベントテスト" これは除外条件2にマッチしているので、こちらも障害としては検知されません。 以上のテストより、想定通り 除外条件にマッチするログは検知しない ことが分かります。   まとめ 今回は、LinuxとWindowsのログ監視について紹介しました。 Linuxは正規表現を使えば複合条件も除外条件も簡単に作成できますが、Windowsはイベントログの要素によって関数が分かれているため、どうしても複雑なトリガー条件式になってしまいます。しかし、論理演算子 “and” “or” “not” をうまく組み合わせれば柔軟な条件式が作成できるので、この記事を参考にぜひ試してみてください。 最後に、弊社が参加するイベントについて宣伝させてください。 ① Zabbix全国5都市キャラバン2024 Zabbix社主催の、 全国5都市を回るセミナーイベント です。東京・名古屋は終了しましたが 2024年9月に大阪・九州・北海道でも開催 しますので、是非お近くの会場に足を運んでみてください! Zabbix5都市キャラバン2024 www.zabbix.com ② Zabbix7.0セミナー こちらは 2024年10月2日(水) に開催される、 SCSK主催のWEBセミナー です。Zabbix7.0の新機能やバージョンアップの勘所についてご紹介します。 本記事の筆者が講師として登壇します ので、是非ご視聴ください! Zabbix7.0セミナー~新機能とバージョンアップの要点~ 本セミナーでは、Zabbix 7.0の新機能と改善点について詳しくご紹介させていただきます。実際のアップグレード手順についてもご説明し、皆様のZabbix 7.0への移行をスムーズに進めるためのヒントもお伝えいたします。 www.scsk.jp 最後まで読んでいただき、ありがとうございました。 弊社ではZabbix関連サービスを展開しています。以下ページもご参照ください。 ★SCSK Plus サポート for Zabbix★ SCSK Plus サポート for Zabbix 世界で最も人気のあるオープンソース統合監視ツール「Zabbix」の導入構築から運用保守までSCSKが強力にサポートします www.scsk.jp ★YouTubeに、SCSK Zabbixチャンネルを開設しました!★ SCSK Zabbixチャンネル 本チャンネルでは、SCSK株式会社でのZabbixに関するトレンド/事例紹介などを動画にまとめて取り上げております。 最新のトピックについては、以下の弊社HPもしくはツイッターアカウントをぜひ参照ください。 ツイッターアカウント: www.youtube.com ★X(旧Twitter)に、SCSK Zabbixアカウントを開設しました!★ x.com x.com
アバター
本記事は 夏休みクラウド自由研究 8/26付の記事です 。 「夏休みクラウド自由研究」ということで、Microsoft Azure の Azure AI サービスの TTS (Text to speech) / SST (Speech to text) を使って LLM (gpt-4o-mini) と音声で会話してみようと思います。 準備 まずはいろいろ試せるように、Azure AI Studio をセットアップします。 Azure AI Studio は Azure AI 関連サービス (Azure ML や Azure OpenAI なども含む) を一元的にエンドツーエンドで管理できるようにしてくれます。すべてを集めてきてくれており、簡単に使えていろいろ捗るので、目的からは必須ではありませんが使ってみます。 Azure AI Studio ハブの作成 Azure AI Studio ハブは、次の 2 つの方法で作成できます。 Azure AI Studio (ai.azure.com) から作成する Azure Portal (portal.azure.com) から作成する 1 は必要最低限のパラメーターで作成できるため簡単ですが、ネットワーク設定などのエンタープライズ利用においては必須の設定ができなかったりしますので、まじめに使うときは 2 で作成いただくのがよろしいかと思います。 ※ 今回は特にカスタマイズしたいこともないのですが、どんな設定があるか見たいので、 2 で設定内容などを眺めながら作成します。 ※ なお、Azure OpenAI 利用申請は終わっている前提です。 作成手順 (クリック) Azure Portal の検索バーで Azure AI Studio を検索してアクセスします。 「新しい Azure AI ハブ」をクリックします。 基本設定を行い、「次へ」をクリックします。 サブスクリプション: デプロイ先のサブスクリプションを指定 リソースグループ: デプロイ先の RG を指定 リージョン: デプロイ先のリージョンを指定 ※ 利用可能なモデルは下の「Azure AI サービスのベース モデル」で接続するリソースのリージョン依存 名前: リソースの名前を指定 フレンドリ名: Azure AI Studio 上で利用される表示名 既定のプロジェクトリソースグループ: 別途、Azure AI Studio プロジェクトを作成する際のデフォルトの RG を指定 OpenAI を含む AI サービスに接続する: Azure AI Studio と接続する Azure AI サービスのリソースを指定 ※ 今回は新規作成で Azure お任せ ストレージ設定を行い、「次へ」をクリックします。 ストレージアカウント: Azure AI Studio 上で扱うファイルや設定などを格納するストレージアカウントを指定 ※ 今回は新規作成で Azure お任せ キーコンテナー: Azure AI Studio 上で扱うシークレットなどを格納する Key Vault を指定 ※ 今回は新規作成で Azure お任せ Application Insights: 分析情報などを取得するために使う Application Insights を指定 ※ 今回は必要ないのでなし コンテナーレジストリ: Azure AI Studio 上で扱う Docker イメージなどを格納するレジストリを指定 ※ 今回は必要ないのでなし ネットワーク設定を行い、「次へ」をクリックします。 ※ 今回はデフォルトのまま 暗号化設定を行い、「次へ」をクリックします。 ※ 今回はデフォルトのまま ID 設定を行い、「確認および作成」をクリックします。 ※ 今回はデフォルトのまま ※ タグ設定はすっとばします   Azure AI Studio と 付帯リソースが作成されました。 ※ リソースグループには指定したストレージアカウントやKey Vaultも作成されています。 モデルのデプロイ Azure AI Studio ハブが作成できたら、 Azure AI Studio にアクセスして、利用するモデルをデプロイします。 Azure Speech (Text to speech, Speech to text) Azure OpenAI (gpt-4o-mini) Azure Speech の方は、先ほど作成した AzureAI リソースに含まれており個別にモデルをデプロイする必要はないため、gpt-4o-mini だけ追加でデプロイします。 作成手順 (クリック) Azure AI Studio のホーム画面で「すべてのハブ」をクリックします。 ※ 「管理」カテゴリが見えていない場合はログインできていない可能性がありますので右上の方を見てみてください。 モデルをデプロイするハブをクリックします。 「デプロイ」メニューに移動して、「モデルのデプロイ」をクリックします。 デプロイするモデルを選択して「確認」をクリックします。 デプロイ名やその他のパラメーターを指定して、「デプロイ」をクリックします。 ※ モデルのデプロイ単位で固有の API パスを持つことになります ※ 今回は、デプロイの種類を Global standard から Standard に変更しています モデルがデプロイされました。   gpt-4o-mini と音声で会話してみる MS 公式サンプルを参考に会話する Microsoft がサンプルコードを公開してくれているので、今回はそちらを参考に試してみたいと思います。 Azure OpenAI 音声読み上げチャット - Speech サービス - Azure AI services この攻略ガイドでは、Speech を使用して Azure OpenAI と会話します。 Speech ではオーディオを認識し、それを Azure OpenAI に送信し、音声応答を合成します。 learn.microsoft.com ソースコード (クリック) 自分のために少し手直ししています。 コメントを日本語に変更 環境変数を .env ファイルから取得するように変更 認識する言語を日本語 (ja-jp) に変更 import os import azure.cognitiveservices.speech as speechsdk from openai import AzureOpenAI from dotenv import load_dotenv # .envファイルから環境変数を読み込みます load_dotenv() # この例では、"OPEN_AI_KEY"、"OPEN_AI_ENDPOINT"、および "OPEN_AI_DEPLOYMENT_NAME" という名前の環境変数が必要です # エンドポイントは次のような形式である必要があります https://YOUR_OPEN_AI_RESOURCE_NAME.openai.azure.com/ client = AzureOpenAI( azure_endpoint=os.environ.get('OPEN_AI_ENDPOINT'), api_key=os.environ.get('OPEN_AI_KEY'), api_version="2023-05-15" ) # これは、モデルをデプロイしたときに選択したカスタム名に対応します。 deployment_id=os.environ.get('OPEN_AI_DEPLOYMENT_NAME') # この例では、"SPEECH_KEY" と "SPEECH_REGION" という名前の環境変数が必要です speech_config = speechsdk.SpeechConfig(subscription=os.environ.get('SPEECH_KEY'), region=os.environ.get('SPEECH_REGION')) audio_output_config = speechsdk.audio.AudioOutputConfig(use_default_speaker=True) audio_config = speechsdk.audio.AudioConfig(use_default_microphone=True) # スピーカーの言語に合わせたロケールを設定する必要があります speech_config.speech_recognition_language="ja-JP" speech_recognizer = speechsdk.SpeechRecognizer(speech_config=speech_config, audio_config=audio_config) # Azure OpenAIが代わりに応答する音声の言語にします speech_config.speech_synthesis_voice_name='en-US-JennyMultilingualNeural' speech_synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config, audio_config=audio_output_config) # tts sentence end mark tts_sentence_end = [ ".", "!", "?", ";", "。", "!", "?", ";", "\n" ] # Azure OpenAIにリクエストを送信し、応答を合成します。 def ask_openai(prompt): # Azure OpenAIにストリーミングでリクエストを送信する response = client.chat.completions.create(model=deployment_id, max_tokens=200, stream=True, messages=[ {"role": "user", "content": prompt} ]) collected_messages = [] last_tts_request = None # ストリームレスポンスをイテレートする for chunk in response: if len(chunk.choices) > 0: chunk_message = chunk.choices[0].delta.content # extract the message if chunk_message is not None: collected_messages.append(chunk_message) # save the message if chunk_message in tts_sentence_end: # sentence end found text = ''.join(collected_messages).strip() # join the recieved message together to build a sentence if text != '': # if sentence only have \n or space, we could skip print(f"Speech synthesized to speaker for: {text}") last_tts_request = speech_synthesizer.speak_text_async(text) collected_messages.clear() if last_tts_request: last_tts_request.get() # 継続的に音声入力をリッスンし、認識してテキストとしてAzure OpenAIに送信する def chat_with_open_ai(): while True: print("Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation.") try: # マイクから音声を取得し、それをTTSサービスに送信します。 speech_recognition_result = speech_recognizer.recognize_once_async().get() # 音声が認識された場合、それをAzure OpenAIに送信して応答を待ちます。 if speech_recognition_result.reason == speechsdk.ResultReason.RecognizedSpeech: if speech_recognition_result.text == "Stop.": print("Conversation ended.") break print("Recognized speech: {}".format(speech_recognition_result.text)) ask_openai(speech_recognition_result.text) elif speech_recognition_result.reason == speechsdk.ResultReason.NoMatch: print("No speech could be recognized: {}".format(speech_recognition_result.no_match_details)) break elif speech_recognition_result.reason == speechsdk.ResultReason.Canceled: cancellation_details = speech_recognition_result.cancellation_details print("Speech Recognition canceled: {}".format(cancellation_details.reason)) if cancellation_details.reason == speechsdk.CancellationReason.Error: print("Error details: {}".format(cancellation_details.error_details)) except EOFError: break # Main try: chat_with_open_ai() except Exception as err: print("Encountered exception. {}".format(err)) 環境変数の確認方法 (クリック) いろいろ導線はありますが、一例を示します。 項目 確認方法 OPEN_AI_KEY 種類が Azure OpenAI の行のキー値 ※ 右側にコピーボタンがあります OPEN_AI_ENDPOINT 種類が Azure OpenAI の行のターゲット値 ※ マウスオーバーでコピーできます OPEN_AI_DEPLOYMENT_NAME 先の手順で指定したモデルのデプロイ名 SPEECH_KEY 種類が Azure OpenAI の行のキー値 ※ 右側にコピーボタンがあります SPEECH_REGION 先の手順で指定した Azure AI サービスのデプロイ先リージョン では、さっそく Python スクリプトを実行して会話してみましょう。 Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. Recognized speech: こんにちは最近どうですか? Speech synthesized to speaker for: こんにちは! Speech synthesized to speaker for: 私は元気です。 Speech synthesized to speaker for: あなたはどうですか? Speech synthesized to speaker for: 最近何か面白いことがありましたか? Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. document.createElement('video'); https://blog.usize-tech.com/contents/uploads/2024/08/azure-ai-tts-sst_audio1.mp4 うまく日本語を認識して会話できているようです。 男性の声は、ローカル PC のテキスト読み上げ機能で発声させており、女性の声が gpt-4o-mini の応答を TTS で読み上げたものです。 ざっくり、こんな動きをしています。 処理の流れイメージ カスタマイズしてみる 音声合成のレートを変更する 話し方がゆっくりしているので、音声合成のレートを変更してみます。 54行目を次のように (無理やり) 変更して、SSML で音声合成をカスタマイズします。 # last_tts_request = speech_synthesizer.speak_text_async(text) ssml = f"<speak version='1.0' xmlns='http://www.w3.org/2001/10/synthesis' xml:lang='ja-JP'><voice name='en-US-JennyMultilingualNeural'><prosody rate='1.3'>{text}</prosody></voice></speak>" last_tts_request = speech_synthesizer.speak_ssml_async(ssml) collected_messages.clear() 音声合成マークアップ言語 (SSML) の概要 - 音声サービス - Azure AI services 音声合成マークアップ言語を使用して、テキスト読み上げの発音と韻律を制御する方法を説明します。 learn.microsoft.com それでは実行して会話してみましょう。 Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. Recognized speech: こんにちは最近どうですか? Speech synthesized to speaker for: こんにちは! Speech synthesized to speaker for: 私は元気です。 Speech synthesized to speaker for: あなたはいかがですか? Speech synthesized to speaker for: 最近何か楽しいことがありましたか? Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. https://blog.usize-tech.com/contents/uploads/2024/08/azure-ai-tts-sst_audio2.mp4 先ほどより早めに話すようになりました。   音声モデルを変更してみる 音声モデルを日本人男性の声  ja-JP-DaichiNeural に変更してみます。 言語サポート - 音声サービス - Azure AI services 音声サービスでは、音声翻訳に加え、音声テキスト変換とテキスト読み上げ変換のためのさまざまな言語がサポートされています。 この記事では、サービス機能によってサポートされている言語の包括的な一覧を示します。 learn.microsoft.com 30行目を次のように変更します。 # speech_config.speech_synthesis_voice_name='en-US-JennyMultilingualNeural' speech_config.speech_synthesis_voice_name='ja-JP-DaichiNeural' ※ 音声合成のレート変更 (SSML) はロールバックしています。   それでは実行して会話してみましょう。   Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. Recognized speech: こんにちは最近どうですか? Speech synthesized to speaker for: こんにちは! Speech synthesized to speaker for: 私は元気です。 Speech synthesized to speaker for: あなたはいかがですか? Speech synthesized to speaker for: 最近のことについて教えてください。 Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. https://blog.usize-tech.com/contents/uploads/2024/08/azure-ai-tts-sst_audio3.mp4 男性の声に変りました。   システムロールをカスタマイズする システムロールのカスタマイズは TTS / SST というよりは、LLM の方の制御ですが、一応やっておきます。 39 行目に role が system のプロンプトを追加します。       {"role": "system", "content": "織田信長になりきってください。性格や語気もトレースします。"},         {"role": "user", "content": prompt} それでは実行して会話してみましょう。 Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. Recognized speech: あなたのことを教えてください。 Speech synthesized to speaker for: 我は織田信長。 Speech synthesized to speaker for: 尾張の大名として、天下統一を目指す者なり。 Speech synthesized to speaker for: かつては小さな領地を治めていたが、今やその力を壮大に広げつつある。 Speech synthesized to speaker for: 強さや革新を重んじ、古きものを打破することに執念を燃やしておる。 Speech synthesized to speaker for: 敵には容赦せず、味方には厚く接するが、今は戦国の混乱を収め、安定した世を築くことが我が使命よ。 Speech synthesized to speaker for: 何か聞きたいことがあれば、問うてみよ! Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. https://blog.usize-tech.com/contents/uploads/2024/08/azure-ai-tts-sst_audio4.mp4 織田信長のようなことを言う何かに変りました。   まとめ 今回の夏休みクラウド自由研究では、Microsoft Azure の Azure AI サービスの TTS (Text to Speech) / SST (Speech to Text) 機能を活用し、LLM(gpt-4o-mini)と音声で対話する方法を試してみました。 Azure AI Studio を使ってみたい気持ちと、Azure の音声サービスに入門したい気持ちから今回はこういった内容にしてみましたが、実用を考えると、Azure OpenAI の Function Calling や Assistants API といったプラグイン機能や、LangChain や Semantic Kernel などのフレームワークを利用したほうが、より効率よく高度な処理を実現できる気がします。また、gpt-4o / mini の音声対応版や、Azure OpenAI の TTS / SST も一部プレビューが始まっています。 その辺りも追って挑戦しながら、AI ともっと自然に高度な会話ができないかもくもく試していきたいと思います。
アバター
本記事は 夏休みクラウド自由研究 8/25付の記事です 。 こんにちは、Terraform学習中のSCSK稲葉です。 Terraformを使用してAWS上にWordpressの環境を構築する方法を学習したのでご紹介いたします。  Terraformとは インフラの構成をソースコードとして管理できるIaCツールです。   AWSやAzure、GCPなどの様々なクラウドサービスに対応しています。 Terraform | HashiCorp Developer Explore Terraform product documentation, tutorials, and examples. developer.hashicorp.com   作成するWordpress環境の構成 Terraformで以下のような環境を構築します。 ALBの後ろに配置するEC2インスタンスは、オートスケーリングによって可用性を持たせています。 複数のEC2インスタンスがWordpressのファイルにアクセスできるように、WordpressのファイルをEFSに配置しています。 RDSもマルチAZによって可用性を持たせています。   Terraformの構成 下記のようなディレクトリ構成を作成しました。 実際の開発では開発環境と本番環境のように複数の環境を作成することになると思います。 環境ごとに分ける必要がある内容をenvironmentsディレクトリの配下に配置しました。 . ├── environments # 環境管理ディレクトリ │   ├── dev # 開発環境用ディレクトリ │   │   ├── dev.tfbackend # tfstateの管理場所を指定するファイル │   │   └── dev.tfvars # 変数に指定するパラメータを定義するファイル │   └── prd # 本番環境用ディレクトリ │   ├── prd.tfbackend # tfstateの管理場所を指定するファイル │   └── prd.tfvars # 変数に指定するパラメータを定義するファイル ├── main.tf # リソースを定義するファイル ├── variables.tf # 変数を定義するファイル ├── output.tf # 実行結果として出力する値を指定するファイル ├── provider.tf # 指定したプロバイダの設定をするファイル └── user_data_script.tpl # ユーザーデータ ダウンロードはこちらからどうぞ WordPressの環境構築IaCコード Download Now! 6 Downloads 各ファイルのコードは本稿の最後に載せています。 main.tf main.tfファイルでは作成するリソースを定義します。 下記コードはVPCを定義しています。 他のリソースもこのコードと同じようにresource ブロックで定義できます。 リソースごとの書き方は Terraformのドキュメント でその都度調べながら書くことになります。 resource aws_vpc vpc { cidr_block = "10.0.0.0/16" instance_tenancy = "default" enable_dns_support = true enable_dns_hostnames = true tags = { Name = "dev-vpc" } } また、main.tfの1番初めにあるTerraformブロックは、Terrafrom自体の設定を定義する箇所です。 下記コードでは、バージョンが5.57.Xの”hashicorp/aws”プロバイダーを使用すると記載されています。 terraform { backend s3 {} required_providers { aws = { source = "hashicorp/aws" version = "~> 5.57.0" } } } variable.tf variable.tfファイルでは変数を定義します。 下記コードのようにvariableブロックで変数を指定することで、 varable vpc_cidr_block {} variable vp_instance_tenancy {} variable enable_dns_support {} variable enable_dns_hostnames {} variable vpc_name_tag {} main.tfファイルで変数を使用できるようになります。 変数を使用する場合、”var.<変数名>”と書きます。 resource aws_vpc vpc { cidr_block = var.vpc_cidr_block instance_tenancy = var.vpc_instance_tenancy enable_dns_support = var.enable_dns_support enable_dns_hostnames = var.enable_dns_hostnames tags = { Name = var.vpc_name_tag } } output.tf output.tfファイルではTerraformの実行結果に出力する内容を定義します。 下記コードはVPCのIDをTerraformの実行結果に出力すると記載されていて、 output vpc_id { value = aws_vpc.vpc.id } 下記のように出力されます。 Apply complete! Resources: xx added, 0 changed, 0 destroyed. Outputs: vpc_id = "vpc-xxxxxxxxxxxxxxxxxx" provider.tf provider.tfファイルではmain.tfで指定したプロバイダーの設定を定義します。 本稿ではawsプロバイダーが指定されているので、awsの設定を記載します。 特にdefault_tagの機能は、Terraformで作成するリソースに対して一括でタグ付けできるので便利だなと思っています。 provider aws { region = "ap-northeast-1" profile = "inaba-poc" default_tags { tags = { Project = "wordpress" Terraform = "true" } } } environmentsディレクトリ 開発環境と本番環境で分けるファイルを配置します。 tfbackendファイルについて Terraformではリソースの管理をjson形式でtfstateというファイルにまとめます。 Terraformは後述するTerraformのリソース作成コマンド(terraform apply)を実行するたびに、このファイルを作成、参照、更新して現在のリソースの状態とコマンド実行後のリソースの状態の差を取得します。 リソースの状態に差があるとリソースを変更し、無い場合変更しません。 この仕組みでTerraformは冪等性を実現しています。 tfbackendファイルではtfstateファイルを管理する場所を定義します。 下記コードではS3のバケットを指定しているので、s3バケットにtfstateが作成されます。 S3で管理することで他者も同じtfstateファイルにアクセスできます。 S3バケットを指定しない場合、Terraformのディレクトリにtfstateが作成されます。 bucket = "s3-inaba" key = "terraform/techharmony/tfstate" region = "ap-northeast-1" profile = "inaba-poc" tfvarsファイルについて tfvarsファイルでは変数に指定するパラメータを定義します。 variable.tfファイルが下記コードの場合 variable vpc_cidr_block {} variable vpc_instance_tenancy {} variable enable_dns_support {} variable enable_dns_hostnames {} variable vpc_name_tag {} tfvarsファイルで、variable.tfファイルで定義されている変数とパラメータの組を記載することで、変数にパラメータが代入されます。 vpc_cidr_block = "10.0.0.0/16" vpc_instance_tenancy = "default" enable_dns_support = true enable_dns_hostnames = true vpc_name_tag = "vpc" また、変数はmap形式で管理することもできます。 variable.tfファイルで変数を下記のように1つにまとめて variable vpc_args {} tfvarsファイルでは下記のようにmap形式でパラメータを記載します。 vpc_args = { cidr_block = "10.0.0.0/16" instance_tenancy = "default" enable_dns_support = true enable_dns_hostnames = true name_tag = "vpc" } main.tfファイルでは下記のようにlookup(変数名、キー)で変数を使用することができます。 resource aws_vpc vpc { cidr_block = lookup(var.vpc_args, "cidr_block") instance_tenancy = lookup(var.vpc_args, "instance_tenancy") enable_dns_support = lookup(var.vpc_args, "enable_dns_support") enable_dns_hostnames = lookup(var.vpc_args, "enable_dns_hostnames") tags = { Name = lookup(var.vpc_args, "name_tag") } } user_data_script.tplファイル user_data_script.tplファイルではEC2の起動時に実行するスクリプトを定義しています。 本稿では詳細を省きますが、EFSのマウント、nginxのインストールと設定、phpとphp-fpmのインストールと設定、wordpressのインストールを行っています。 取り上げたいところとして、EFSをマウントする際に設定しているウェイトタイムですが、 これはEFS作成後、DNSの伝播が終わるまで90秒かかるためウェイトタイムを入れています。 私はEFSがマウントされず1日以上悩むことになりました。 Troubleshooting mount issues - Amazon Elastic File System Find information about troubleshooting EFS file system mounting issues. docs.aws.amazon.com # EFSマウント設定 yum install -y amazon-efs-utils efs_id="${efs_id}" mkdir /efs echo "$efs_id:/ /efs/ efs _netdev,nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport 0 0" >> /etc/fstab sleep 150 mount -a mkdir /efs/document_root   Terraformのセットアップと実行、Wordpressのセットアップ Terraformのセットアップ Terraformはtfenvを使用してインストールします。 tfenvを使用することで簡単にバージョン管理できます。 Cloud9上でセットアップする想定で、プロファイルは設定済みであることとします。 tfenvのインストール $ git clone https://github.com/tfutils/tfenv.git ~/.tfenv $ sudo ln -s ~/.tfenv/bin/* /usr/local/bin $ tfenv -v terraformのバージョン指定ファイルを作成 $ touch .terraform-version $ vi .terraform-version 1.8.5 terraformのインストールとバージョン指定する $ tfenv install $ tfenv use ※ M1 macの場合 $ TFENV_ARCH=amd64 tfenv install $ tfenv use Terraformの実行方法 コマンドを実行したディレクトリをTerraformで使用するために、下記コードで初期化します。 $ terraform init -backend-config="environments/dev/dev.tfbackend" 下記コードでDry Runの結果を確認します。 $ terraform plan -var-file="environments/dev/dev.tfvars" 下記コードでリソースを作成します。 $ terraform apply -var-file="environments/dev/dev.tfvars" 下記コードでリソースの削除ができます。 $ terraform destroy -var-file="environments/dev/dev.tfvars" WordPressのセットアップ Terraform実行後、outputに下記4つの変数が出力されるので、セットアップで使用します。 Outputs: alb_dns_name = "tf-lb-xxxxxxxxxxxxxxxxxx-xxxxxxxxx.ap-northeast-1.elb.amazonaws.com" # albへのアクセス先 rds_database_name = "xxxxxxxxxx" # データベース名 rds_endpoint = "xxxxxxxxx.xxxxxxxx.ap-northeast-1.rds.amazonaws.com:3306" # データベースのエンドポイント rds_password = "xxxxxxxxxxx" # データベースのパスワード 1. albへのアクセス先にブラウザでアクセスします。 2. 言語選択画面に遷移するので、日本語を指定してください。 3. その後データベースについての情報を入力することが求められます。 terraformのoutputに出力されたデータベース名、データベースのエンドポイント(データベースのホスト名)、データベースのパスワードを入力してください。 4. その後サイト名やWordpressユーザーの設定画面に遷移します。 サイト名やWordpressユーザー名を考え、入力してください。 先ほど作成したWordpressユーザーでログインできるようになります!   課題 本稿で作成したWordpressのサイトは非常に不安定でした(頻繁にタイムアウトします)。 EFSのメトリクスをみると、頻繁にメタデータへのアクセスがある状態です。 EFSのパフォーマンスチューニングが今後の課題です。   最後に WordPressの設定簡単だろうと思っていたら痛い目に会いました。。 相談に乗っていただいた方々( 木澤さん 、 広野さん 、 兒玉さん )には、本当に感謝しています。 非常に簡単にIaCできるのでTerraformはおすすめです!ぜひ触ってみてください!   コード main.tf terraform { backend s3 {} required_providers { aws = { source = "hashicorp/aws" version = "~> 5.57.0" } } } # ネットワーク ############################################################################################################## # VPC resource aws_vpc vpc { cidr_block = lookup(var.vpc_args, "cidr_block") instance_tenancy = lookup(var.vpc_args, "instance_tenancy") enable_dns_support = lookup(var.vpc_args, "enable_dns_support") enable_dns_hostnames = lookup(var.vpc_args, "enable_dns_hostnames") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.vpc_args, "name_tag")) } } # サブネット resource aws_subnet public_subnet_1a { vpc_id = aws_vpc.vpc.id cidr_block = lookup(var.public_subnet_1a_args, "cidr_block") map_public_ip_on_launch = true availability_zone = lookup(var.public_subnet_1a_args, "availability_zone") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.public_subnet_1a_args, "name_tag")) } } resource aws_subnet private_subnet_1a { vpc_id = aws_vpc.vpc.id cidr_block = lookup(var.private_subnet_1a_args, "cidr_block") availability_zone = lookup(var.private_subnet_1a_args, "availability_zone") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.private_subnet_1a_args, "name_tag")) } } resource aws_subnet public_subnet_1c { vpc_id = aws_vpc.vpc.id cidr_block = lookup(var.public_subnet_1c_args, "cidr_block") map_public_ip_on_launch = true availability_zone = lookup(var.public_subnet_1c_args, "availability_zone") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.public_subnet_1c_args, "name_tag")) } } resource aws_subnet private_subnet_1c { vpc_id = aws_vpc.vpc.id cidr_block = lookup(var.private_subnet_1c_args, "cidr_block") availability_zone = lookup(var.private_subnet_1c_args, "availability_zone") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.private_subnet_1c_args, "name_tag")) } } # インターネットゲートウェイ resource aws_internet_gateway internet_gateway { vpc_id = aws_vpc.vpc.id tags = { Name = format("%s-%s", var.name_prefix, var.internet_gateway_name_tag) } } # ルートテーブル resource aws_route_table route_table_to_internet { vpc_id = aws_vpc.vpc.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.internet_gateway.id } tags = { Name = format("%s-%s", var.name_prefix, var.route_table_to_internet_name_tag) } } # ルートテーブル 関連付け resource aws_route_table_association route_association_public_subnet_1a { subnet_id = aws_subnet.public_subnet_1a.id route_table_id = aws_route_table.route_table_to_internet.id } resource aws_route_table_association route_association_public_subnet_1c { subnet_id = aws_subnet.public_subnet_1c.id route_table_id = aws_route_table.route_table_to_internet.id } # EFS ################################################################################################################### resource "aws_efs_file_system" "efs" { performance_mode = lookup(var.efs_args, "performance_mode") throughput_mode = lookup(var.efs_args, "throughput_mode") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.efs_args, "name_tag")) } } # マウントターゲット resource "aws_efs_mount_target" "mount_target_1a" { file_system_id = aws_efs_file_system.efs.id subnet_id = aws_subnet.public_subnet_1a.id security_groups = [aws_security_group.security_group_for_efs.id] } resource "aws_efs_mount_target" "mount_target_1c" { file_system_id = aws_efs_file_system.efs.id subnet_id = aws_subnet.public_subnet_1c.id security_groups = [aws_security_group.security_group_for_efs.id] } # セキュリティグループ resource aws_security_group security_group_for_efs { description = lookup(var.security_group_for_efs_args, "description") vpc_id = aws_vpc.vpc.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_for_efs_args, "name_tag")) } } resource aws_vpc_security_group_ingress_rule ingress_rule_for_efs { from_port = lookup(var.security_group_ingress_for_efs_args, "ingress_from_port") to_port = lookup(var.security_group_ingress_for_efs_args, "ingress_to_port") ip_protocol = lookup(var.security_group_ingress_for_efs_args, "ingress_protocol") cidr_ipv4 = lookup(var.security_group_ingress_for_efs_args, "ingress_cidr_ipv4") referenced_security_group_id = aws_security_group.security_group_for_ec2.id security_group_id = aws_security_group.security_group_for_efs.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_for_efs_args, "name_tag")) } } resource aws_vpc_security_group_egress_rule egress_rule_for_efs { from_port = lookup(var.security_group_egress_for_efs_args, "egress_from_port") to_port = lookup(var.security_group_egress_for_efs_args, "egress_to_port") ip_protocol = lookup(var.security_group_egress_for_efs_args, "egress_protocol") cidr_ipv4 = lookup(var.security_group_egress_for_efs_args, "egress_cidr_ipv4") referenced_security_group_id = null security_group_id = aws_security_group.security_group_for_efs.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_egress_for_efs_args, "name_tag")) } } # EC2 #################################################################################################################### # ec2 launch template resource aws_launch_template ec2_launch_template { image_id = lookup(var.ec2_launch_template_args, "ami_id") instance_type = lookup(var.ec2_launch_template_args, "instance_type") user_data = base64encode(templatefile("user_data_script.tpl", { efs_id = aws_efs_file_system.efs.id #efs_id = aws_efs_file_system.efs.dns_name })) block_device_mappings { device_name = lookup(var.ec2_launch_template_args, "block_device_name") ebs { volume_size = lookup(var.ec2_launch_template_args, "ebs_volume_size") volume_type = lookup(var.ec2_launch_template_args, "ebs_volume_type") delete_on_termination = lookup(var.ec2_launch_template_args, "ebs_delete_on_termination") } } tag_specifications { resource_type = "instance" tags = { Name = format(lookup(var.ec2_launch_template_args, "instance_name_tag")) } } iam_instance_profile { name = aws_iam_instance_profile.instance_profile.name } network_interfaces { associate_public_ip_address = true security_groups = [aws_security_group.security_group_for_ec2.id] } tags = { Name = format(lookup(var.ec2_launch_template_args, "launch_template_name_tag")) } # efsのマウントをするため、マウントポイントが作成後EC2を作成する depends_on = [ aws_efs_file_system.efs ] } # EC2用セキュリティグループ resource aws_security_group security_group_for_ec2 { description = lookup(var.security_group_for_ec2_args, "description") vpc_id = aws_vpc.vpc.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_for_ec2_args, "name_tag")) } } resource aws_vpc_security_group_ingress_rule ingress_rule_from_alb_for_ec2 { from_port = lookup(var.security_group_ingress_from_alb_for_ec2_args, "ingress_from_port") to_port = lookup(var.security_group_ingress_from_alb_for_ec2_args, "ingress_to_port") ip_protocol = lookup(var.security_group_ingress_from_alb_for_ec2_args, "ingress_protocol") cidr_ipv4 = lookup(var.security_group_ingress_from_alb_for_ec2_args, "ingress_cidr_ipv4") referenced_security_group_id = aws_security_group.security_group_for_alb.id security_group_id = aws_security_group.security_group_for_ec2.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_from_alb_for_ec2_args, "name_tag")) } } resource aws_vpc_security_group_ingress_rule ingress_rule_from_internet_for_ec2 { from_port = lookup(var.security_group_ingress_from_internet_for_ec2_args, "ingress_from_port") to_port = lookup(var.security_group_ingress_from_internet_for_ec2_args, "ingress_to_port") ip_protocol = lookup(var.security_group_ingress_from_internet_for_ec2_args, "ingress_protocol") cidr_ipv4 = lookup(var.security_group_ingress_from_internet_for_ec2_args, "ingress_cidr_ipv4") referenced_security_group_id = null security_group_id = aws_security_group.security_group_for_ec2.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_from_internet_for_ec2_args, "name_tag")) } } resource aws_vpc_security_group_egress_rule egress_rule_for_ec2 { from_port = lookup(var.security_group_egress_for_ec2_args, "egress_from_port") to_port = lookup(var.security_group_egress_for_ec2_args, "egress_to_port") ip_protocol = lookup(var.security_group_egress_for_ec2_args, "egress_protocol") cidr_ipv4 = lookup(var.security_group_egress_for_ec2_args, "egress_cidr_ipv4") referenced_security_group_id = null security_group_id = aws_security_group.security_group_for_ec2.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_egress_for_ec2_args, "name_tag")) } } # インスタンスプロファイル(インスタンスとIAM Roleの関連付け) resource aws_iam_instance_profile instance_profile { tags = { Name = format("%s-%s", var.name_prefix, lookup(var.ec2_role_settings_args , "instance_profile_name_tag")) } role = aws_iam_role.instance_role.name } # IAM ロール resource aws_iam_role instance_role { tags = { Name = format("%s-%s", var.name_prefix, lookup(var.ec2_role_settings_args , "iam_role_name_tag")) } assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json } data aws_iam_policy_document assume_role_policy { statement { actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["ec2.amazonaws.com"] } } } # SSM用ポリシー resource aws_iam_role_policy_attachment attachment_ssm { role = aws_iam_role.instance_role.name policy_arn = data.aws_iam_policy.ssm_policy.arn } data aws_iam_policy ssm_policy { name = "AmazonSSMManagedInstanceCore" } # cloudwatchエージェント用ポリシー resource aws_iam_role_policy_attachment attachment_cloudwatch_agent { role = aws_iam_role.instance_role.name policy_arn = data.aws_iam_policy.cloudwatch_agent_policy.arn } data aws_iam_policy cloudwatch_agent_policy { name = "CloudWatchAgentServerPolicy" } # ALB #################################################################################### # alb resource aws_lb alb { internal = false load_balancer_type = "application" security_groups = [aws_security_group.security_group_for_alb.id] subnets = [aws_subnet.public_subnet_1a.id, aws_subnet.private_subnet_1c.id] tags = { Name = format("%s-%s", var.name_prefix, lookup(var.alb_args, "name_tag")) } } # ターゲットグループ resource aws_lb_target_group target_group { port = 80 protocol = "HTTP" vpc_id = aws_vpc.vpc.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.target_group_args, "name_tag")) } health_check { interval = lookup(var.target_group_args, "health_check_interval") path = lookup(var.target_group_args, "health_check_path") port = "traffic-port" protocol = "HTTP" timeout = lookup(var.target_group_args, "health_check_timeout") healthy_threshold = lookup(var.target_group_args, "healthy_threshold") unhealthy_threshold = lookup(var.target_group_args, "unhealthy_threshold") } stickiness { cookie_duration = lookup(var.target_group_args, "stickiness_cookie_duration") enabled = lookup(var.target_group_args, "stickiness_enables") type = lookup(var.target_group_args, "stickiness_type") } } # リスナー resource aws_lb_listener listener { load_balancer_arn = aws_lb.alb.arn port = "80" protocol = "HTTP" default_action { target_group_arn = aws_lb_target_group.target_group.arn type = "forward" } tags = { Name = format("%s-%s", var.name_prefix, var.listener_name_tag) } } # Auto Scaling Group resource aws_autoscaling_group auto_scaling_group { name = format("%s-%s", var.name_prefix, lookup(var.auto_scaling_args, "name")) max_size = lookup(var.auto_scaling_args, "max_size") min_size = lookup(var.auto_scaling_args, "min_size") health_check_grace_period = lookup(var.auto_scaling_args, "health_check_grace_period") health_check_type = lookup(var.auto_scaling_args, "health_check_type") desired_capacity = lookup(var.auto_scaling_args, "desired_capacity") vpc_zone_identifier = [aws_subnet.public_subnet_1a.id, aws_subnet.public_subnet_1c.id] target_group_arns = [aws_lb_target_group.target_group.arn] launch_template { id = aws_launch_template.ec2_launch_template.id version = aws_launch_template.ec2_launch_template.latest_version } } # セキュリティグループ resource aws_security_group security_group_for_alb { description = lookup(var.security_group_for_alb_args, "description") vpc_id = aws_vpc.vpc.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_for_alb_args, "name_tag")) } } resource aws_vpc_security_group_ingress_rule ingress_rule_for_alb { from_port = lookup(var.security_group_ingress_for_alb_args, "ingress_from_port") to_port = lookup(var.security_group_ingress_for_alb_args, "ingress_to_port") ip_protocol = lookup(var.security_group_ingress_for_alb_args, "ingress_protocol") cidr_ipv4 = lookup(var.security_group_ingress_for_alb_args, "ingress_cidr_ipv4") referenced_security_group_id = null security_group_id = aws_security_group.security_group_for_alb.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_for_alb_args, "name_tag")) } } resource aws_vpc_security_group_egress_rule egress_rule_for_alb { from_port = lookup(var.security_group_egress_for_alb_args, "egress_from_port") to_port = lookup(var.security_group_egress_for_alb_args, "egress_to_port") ip_protocol = lookup(var.security_group_egress_for_alb_args, "egress_protocol") cidr_ipv4 = lookup(var.security_group_egress_for_alb_args, "egress_cidr_ipv4") referenced_security_group_id = null security_group_id = aws_security_group.security_group_for_alb.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_egress_for_alb_args, "name_tag")) } } # RDS ########################################################################################################### # RDS DB インスタンス resource aws_db_instance rds { allocated_storage = lookup(var.rds_args, "allocated_storage") max_allocated_storage = lookup(var.rds_args, "max_allocated_storage") storage_type = lookup(var.rds_args, "storage_type") engine = lookup(var.rds_args, "engine") engine_version = lookup(var.rds_args, "engine_version") instance_class = lookup(var.rds_args, "instance_class") multi_az = lookup(var.rds_args, "multi_az") skip_final_snapshot = lookup(var.rds_args, "skip_final_snapshot") identifier = lookup(var.rds_args, "identifier") db_name = lookup(var.rds_args, "db_name") username = lookup(var.rds_args, "username") password = lookup(var.rds_args, "password") vpc_security_group_ids = [aws_security_group.security_group_for_rds.id] parameter_group_name = aws_db_parameter_group.parameter_group.name option_group_name = aws_db_option_group.option_group.name db_subnet_group_name = aws_db_subnet_group.subnet_group.name tags = { Name = format("%s-%s", var.name_prefix, lookup(var.rds_args, "name_tag")) } } # パラメータグループ resource aws_db_parameter_group parameter_group { family = lookup(var.parameter_group_args, "family") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.parameter_group_args, "name_tag")) } } # オプショングループ resource aws_db_option_group option_group { engine_name = lookup(var.option_group_args, "engine_name") major_engine_version = lookup(var.option_group_args, "major_engine_version") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.option_group_args, "name_tag")) } } # サブネットグループ resource aws_db_subnet_group subnet_group { subnet_ids = [aws_subnet.private_subnet_1a.id, aws_subnet.private_subnet_1c.id] tags = { Name = format("%s-%s", var.name_prefix, var.subnet_group_name_tag) } } # セキュリティグループ resource aws_security_group security_group_for_rds { description = lookup(var.security_group_for_rds_args, "description") vpc_id = aws_vpc.vpc.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_for_rds_args, "name_tag")) } } resource aws_vpc_security_group_ingress_rule ingress_rule_for_rds { from_port = lookup(var.security_group_ingress_for_rds_args, "ingress_from_port") to_port = lookup(var.security_group_ingress_for_rds_args, "ingress_to_port") ip_protocol = lookup(var.security_group_ingress_for_rds_args, "ingress_protocol") cidr_ipv4 = lookup(var.security_group_ingress_for_rds_args, "ingress_cidr_ipv4") referenced_security_group_id = aws_security_group.security_group_for_ec2.id security_group_id = aws_security_group.security_group_for_rds.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_for_rds_args, "name_tag")) } } resource aws_vpc_security_group_egress_rule egress_rule_for_rds { from_port = lookup(var.security_group_egress_for_rds_args, "egress_from_port") to_port = lookup(var.security_group_egress_for_rds_args, "egress_to_port") ip_protocol = lookup(var.security_group_egress_for_rds_args, "egress_protocol") cidr_ipv4 = lookup(var.security_group_egress_for_rds_args, "egress_cidr_ipv4") referenced_security_group_id = null security_group_id = aws_security_group.security_group_for_rds.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_for_rds_args, "name_tag")) } } variable.tf variable name_prefix {} # ネットワーク variable vpc_args {} variable public_subnet_1a_args {} variable private_subnet_1a_args {} variable public_subnet_1c_args {} variable private_subnet_1c_args {} variable internet_gateway_name_tag {} variable route_table_to_internet_name_tag {} # efs variable efs_args {} variable security_group_for_efs_args {} variable security_group_ingress_for_efs_args {} variable security_group_egress_for_efs_args {} # wordpress ec2 variable ec2_launch_template_args {} variable security_group_for_ec2_args {} variable security_group_ingress_from_alb_for_ec2_args {} variable security_group_ingress_from_internet_for_ec2_args {} variable security_group_egress_for_ec2_args {} variable ec2_role_settings_args {} # alb variable alb_args {} variable target_group_args {} variable listener_name_tag {} variable auto_scaling_args {} variable security_group_for_alb_args {} variable security_group_ingress_for_alb_args {} variable security_group_egress_for_alb_args {} # rds variable rds_args {} variable option_group_args {} variable parameter_group_args {} variable subnet_group_name_tag {} variable security_group_for_rds_args {} variable security_group_ingress_for_rds_args {} variable security_group_egress_for_rds_args {} output.tf output vpc_id { value = aws_vpc.vpc.id } output alb_dns_name { value = aws_lb.alb.dns_name } output rds_endpoint { value = aws_db_instance.rds.endpoint } output rds_user { value = lookup(var.rds_args, "username") } output rds_password { value = lookup(var.rds_args, "password") } output rds_database_name { value = lookup(var.rds_args, "db_name") } provider.tf provider aws { region = "ap-northeast-1" profile = "inaba-poc" default_tags { tags = { Project = "wordpress" Terraform = "true" } } } user_data_script.tpl #!./bin/bash # yumアップデート yum update -y # EFSマウント設定 yum install -y amazon-efs-utils efs_id="${efs_id}" mkdir /efs echo "$efs_id:/ /efs/ efs _netdev,nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport 0 0" >> /etc/fstab sleep 150 mount -a mkdir /efs/document_root # RDS接続用のsqlクライアントのインストール yum install -y mariadb # nginxのインストール yum install -y nginx systemctl start nginx systemctl enable nginx # phpのインストール yum install -y php php-fpm php-mysqlnd systemctl start php-fpm mv /etc/php-fpm.d/www.conf /etc/php-fpm.d/bk-www.conf # php-fpmの設定 cat < /etc/php-fpm.d/www.conf [www] user = nginx group = nginx listen = /run/php-fpm/www.sock listen.owner = nginx listen.group = nginx listen.acl_users = apache,nginx listen.allowed_clients = 127.0.0.1 pm = dynamic pm.max_children = 50 pm.start_servers = 5 pm.min_spare_servers = 5 pm.max_spare_servers = 35 slowlog = /var/log/php-fpm/www-slow.log php_admin_value[error_log] = /var/log/php-fpm/www-error.log php_admin_flag[log_errors] = on php_value[session.save_handler] = files php_value[session.save_path] = /var/lib/php/session php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache EOF systemctl restart php-fpm systemctl enable php-fpm # wordpressのインストール wget https://wordpress.org/latest.tar.gz -P /tmp tar -xzf /tmp/latest.tar.gz -C /tmp/ mv /tmp/wordpress/* /efs/document_root chown -R nginx:nginx /efs/* # nginx の設定 cat < /etc/nginx/conf.d/wordpress.conf server { listen 80; server_name _; root /efs/document_root/; index index.php index.html index.htm; location / { try_files \$uri \$uri/ /index.php?\$args; } location ~ \.php$ { include /etc/nginx/fastcgi_params; fastcgi_pass unix:/run/php-fpm/www.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; } } EOF # ヘルスチェック用ファイルの作成 mkdir /efs/document_root/health_check touch /efs/document_root/health_check/health_check_file systemctl restart nginx environments/dev/dev.tfvars ※セキュリティグループのインバウンドルールに指定するIPアドレスは、コピペ後埋めてください。 name_prefix = "inaba-wp-dev" # ネットワーク ############################################################################## vpc_args = { cidr_block = "10.0.0.0/16" instance_tenancy = "default" enable_dns_support = true enable_dns_hostnames = true name_tag = "vpc" } public_subnet_1a_args = { cidr_block = "10.0.0.0/24" availability_zone = "ap-northeast-1a" name_tag = "public-subnet-1a" } private_subnet_1a_args = { cidr_block = "10.0.2.0/24" availability_zone = "ap-northeast-1a" name_tag = "private-subnet-1a" } public_subnet_1c_args = { cidr_block = "10.0.1.0/24" availability_zone = "ap-northeast-1c" name_tag = "public-subnet-1c" } private_subnet_1c_args = { cidr_block = "10.0.3.0/24" availability_zone = "ap-northeast-1c" name_tag = "private-subnet-1c" } internet_gateway_name_tag = "igw" route_table_to_internet_name_tag = "route_table_to_internet" # EFS ########################################################################################### efs_args = { name_tag = "efs" performance_mode = "generalPurpose" throughput_mode = "elastic" } security_group_for_efs_args = { name_tag = "security-group-for-efs" description = "for efs" } security_group_ingress_for_efs_args = { name_tag = "ingress-rule-for-efs" ingress_from_port = 2049 ingress_to_port = 2049 ingress_protocol = "tcp" ingress_cidr_ipv4 = null } security_group_egress_for_efs_args = { name_tag = "egress-rule-for-efs" egress_from_port = 0 egress_to_port = 0 egress_protocol = "-1" egress_cidr_ipv4 = "0.0.0.0/0" } # EC2 #################################################################################### ec2_launch_template_args = { ami_id = "ami-03350e4f182961c7f" # Amazon Linux 2023 AMI instance_type = "t3.medium" block_device_name = "/dev/xvde" #ebsよくわからない 調べる ebs_volume_size = "30" ebs_volume_type = "gp3" ebs_delete_on_termination = true instance_name_tag = "wordpress-ec2" launch_template_name_tag = "launch-template-for-wordpress-ec2" } security_group_for_ec2_args = { name_tag = "security-group-for-ec2" description = "for ec2" } security_group_ingress_from_alb_for_ec2_args = { name_tag = "ingress-rule-from-alb-for-ec2" ingress_from_port = 80 ingress_to_port = 80 ingress_protocol = "tcp" ingress_cidr_ipv4 = null } security_group_ingress_from_internet_for_ec2_args = { name_tag = "ingress-rule-from-internet-for-ec2" ingress_from_port = 80 ingress_to_port = 80 ingress_protocol = "tcp" ingress_cidr_ipv4 = "xxx.xxx.xxx.xxx/32"# マイIP } security_group_egress_for_ec2_args = { name_tag = "egress-rule-for-ec2" egress_from_port = 0 egress_to_port = 0 egress_protocol = "-1" egress_cidr_ipv4 = "0.0.0.0/0" } ec2_role_settings_args = { instance_profile_name_tag = "instance-profile-for-wordpress-ec2" iam_role_name_tag = "iam-role-for-wordpress-ec2" } # alb ############################################################################################ alb_args = { name_tag = "alb" } target_group_args = { name_tag = "target-group" health_check_interval = 10 health_check_path = "/health_check/health_check_file" health_check_timeout = 5 healthy_threshold = 3 unhealthy_threshold = 3 stickiness_cookie_duration = 1800 stickiness_enables = true stickiness_type = "lb_cookie" } listener_name_tag = "linstener" auto_scaling_args = { name = "auto-scaling" max_size = 2 min_size = 1 health_check_grace_period = 300 health_check_type = "EC2" desired_capacity = 2 } security_group_for_alb_args = { name_tag = "security-group-for-alb" description = "for alb" } security_group_ingress_for_alb_args = { name_tag = "ingress-rule-for-alb" ingress_from_port = 80 ingress_to_port = 80 ingress_protocol = "tcp" ingress_cidr_ipv4 = "xxx.xxx.xxx.xxx/32"# マイIP } security_group_egress_for_alb_args = { name_tag = "egress-rule-for-alb" egress_from_port = 0 egress_to_port = 0 egress_protocol = "-1" egress_cidr_ipv4 = "0.0.0.0/0" } # RDS ################################################################################################ rds_args = { allocated_storage = 20 max_allocated_storage = 200 storage_type = "gp3" engine = "mariadb" engine_version = "10.11" instance_class = "db.t3.micro" multi_az = true skip_final_snapshot = true identifier = "wordpressdb" db_name = "wordpressdb" username = "root" password = "password" name_tag = "db" } option_group_args = { engine_name = "mariadb" major_engine_version = "10.11" name_tag = "option-group" } parameter_group_args = { family = "mariadb10.11" name_tag = "parameter-group" } subnet_group_name_tag = "subnet_group" security_group_for_rds_args = { name_tag = "security-group-for-eds" description = "for rds" } security_group_ingress_for_rds_args = { name_tag = "egress-rule-for-rds" ingress_from_port = 3306 ingress_to_port = 3306 ingress_protocol = "tcp" ingress_cidr_ipv4 = null } security_group_egress_for_rds_args = { name_tag = "egress-rule-for-rds" egress_from_port = 0 egress_to_port = 0 egress_protocol = "-1" egress_cidr_ipv4 = "0.0.0.0/0" } environments/dev/dev.tfbackend bucket = "s3-inaba" key = "terraform/techharmony/tfstate" region = "ap-northeast-1" profile = "inaba-poc"
アバター
本記事は 夏休みクラウド自由研究 8/24付の記事です 。 皆さんこんにちは。UGです。 自分が書いた字を見て、ふと子供の頃は大人になったら自然と字って綺麗になっていくものだと思っていたなーと。 もちろん自然と綺麗になることなどなく、何なら昔の方が綺麗だったんじゃないか??と思った今日この頃。。。 さて本題ですが、以前AWS情報で見かけて気になっていながら触れられていなかった、Amazon CloudWatchでAIを活用した自然言語クエリ生成を試してみました。 CloudWatch Logs InsightsとCloudWatch Metrics Insightsにて自然言語でクエリ生成ができるとのことです。 Amazon CloudWatch announces AI-Powered natural language query generation - AWS Discover more about what's new at AWS with Amazon CloudWatch announces AI-Powered natural language query generation aws.amazon.com 現時点(2024/8/25時点)では、米国東部 (バージニア北部)、米国西部 (オレゴン)、アジアパシフィック (東京) でのみ使用できるようです。 はてさてどれほど便利なものなのか。 やってみる CloudWatch Logs Insights まずはCloudWatch Logs Insightsの自然言語クエリ生成から試してみます。 [CloudWatch] → [ログのインサイト]を開くと 「Query generator」 なるものが画面に表示されています。 「Query generator」 をクリックして展開します。 プロンプトの横の 「情報」 をクリックすると、画面右側にQuery generatorの説明が表示されます。(以下に説明文からプロンプトの例のみを抜粋) 良いプロンプトの例 このプロンプトでは、選択したロググループ内のさまざまなクライアントの例外を一覧表示するクエリを生成できます。 What types of client exceptions are in my logs? このプロンプトでは、最新の 5 つのログパターンを一覧表示するクエリを生成できます。 List the 5 most frequent patterns in my exception logs このプロンプトでは、請求額が最も高い Lambda 呼び出しの上位 100 件を検索するクエリを生成できます。 Return the top 100 highest billed lambda invocations このプロンプトでは、IAM ロールまたはポリシーが変更された最新の CloudTrail イベントを検索するクエリを生成できます。 Return the most recent events with changes to IAM role or policy events このプロンプトでは、仮想プライベートクラウドログ内の最新の 20 件の TCP リクエストを返すクエリを生成できます。 What are the 20 most recent TCP requests? 上記の例のように、自然言語には 英語のみ が利用できます。 では実際に試してみます。 ロググループを選択し、 「Show the oldest 3 logs(最も古いログを3件表示)」 をプロンプトに入力して、「新しいクエリを生成」をクリックします。 そうすると画像のようなクエリ文が自動で生成されました。 「クエリを更新」はクエリ文が記載済みの場合に、新しいプロンプトの内容からクエリを生成し更新を行います。 「クエリを更新」はクエリ文が記載されていない場合は選択ができません。 「新しいクエリを生成」はクエリ文が記載済みであろうとなかろうと選択できるので、「クエリを更新」は使わず、常に「新しいクエリを生成」を選択で良いと思います。 「クエリの実行」をクリックし、クエリを実行すると、最も古いログが3件表示されていました。 CloudWatch Metrics Insights 次にCloudWatch Metrics Insightsの自然言語クエリ生成を試してみます。 [CloudWatch] → [すべてのメトリクス]から[マルチソースクエリ]タブを開くと、今回も 「Query generator」 なるものが画面に表示されています。 プロンプトの横の 「情報」 をクリックすると、画面右側にQuery generatorの説明が表示されます。(以下に説明文からプロンプトの例のみを抜粋) 適切なプロンプトの例 このプロンプトは、消費された読み取りキャパシティユニットごとにソートされた 10 個の DynamoDB テーブルのリストを返すクエリを生成できます。 消費された読み取りキャパシティユニットの順に上位 10 個の DynamoDB テーブルを検索する このプロンプトは、エラー数が最も多い 10 個の DynamoDB テーブルのリストを返すクエリを生成できます。 トランザクション競合エラーの数が最も多い上位 10 個の DynamoDB テーブルを検索する このプロンプトは、書き込み数でランク付けされた 10 個の RDS クラスターのリストを返すクエリを生成できます。 書き込み順で上位 10 個の RDS クラスターを検索する このプロンプトは、ダウンロードされたバイト数の順に整理された上位 10 個の S3 バケットのリストを返すクエリを生成できます。 ダウンロードされたバイト数の順で上位 10 個の S3 バケットを検索する このプロンプトは、どの AWS サービスの使用率が最も高いかを示すクエリを生成できます。 自分のアカウントで最も多く使用されている AWS サービスを検索する あれ?今回は日本語で表示されているぞ? つまりは日本語でできるのか?と思いダメ元でチャレンジ。 怒られました…やはり日本語は対応していないようです。例文はミスかと。 では丁度良いので上の日本語例文をGoogle翻訳で英文にして自動生成を行ってみます。 翻訳:「自分のアカウントで最も多く使用されている AWS サービスを検索する」⇒「Find the most used AWS services in your account」 上記翻訳結果をプロンプトに入力して、「新しいクエリを生成」をクリックします。 そうすると画像のようなクエリ文が自動で生成されました。 「Editor」画面ではクエリ文が以下のようになります。 んん?自動生成されたクエリが明らかにおかしいなと。。。見るからにAPIのリクエスト数を調べるクエリですね… どうやら失敗のようです。。。 100%の精度があるわけではもちろんないので仕方がないですね。 まとめ ということでAIを活用した自然言語クエリ生成を試してみました。 クエリ言語に関する知識が少ないという方には、一からコードを書く必要がないため良い手助けになるなと思いました。 しかしその半面、少ないからこそ今回の失敗例のようなときに気づくことができない恐れもあるため、頼り切った利用は危険とも思いました。 他のAI利用でも同じですが、あくまで参考であって自分で調べて確かめることが大事だなと。 最後までお読みいただきありがとうございました!!
アバター
本記事は 夏休みクラウド自由研究 8/23付の記事です 。 こんにちは。AWS の作業を日々少しでも楽にしようと取り組んでいる兒玉です。 皆さん、AWS CloudFormation を使ってテンプレートを作成する際に、実行時エラーの修正を何度も行う際に、AWS Management Console を使って CloudFormation スタックへのパラメータの入力を何度も繰り返して行わないといけなくて、うんざりした経験はありませんか? 今回は、そんな際に CloudFormation のスタックを AWS CLI のコマンドを使って楽に何度も同じパラメータ入力をしなくても良いようにしよう、というちょっとした小技の紹介です。 なぜAWS CLI? CloudFormation スタックの実行時は様々なパラメータを毎回 4 ステップ分入力する必要があります。 テンプレートファイルを選択して、ローカルからアップロード スタック名を入力して、スタックのパラメータをパラメータ数分だけ入力 タグを必要な数だけ入力、その他詳細オプション等あれば入力 入力した値を確認して送信 という手順になります。1回や2回くらいなら、「まぁ、手打ちでもいいか…」 となるのですが、テンプレートを作成中などで、テンプレートに不具合があってうまくスタックが作成完了しなかった場合には、ロールバックして、再度スタックを作成するために上記の4手順を行って… と繰り返していくと、テンプレート内の不具合がなかなか解消しなかった場合には段々とイライラしてきます… 何度も同じパラメータも同じで何度も実行するので、1回ちょっと手間をかけたら、あとはサッとスムーズに実行して、テンプレートの不具合修正に集中したいところです。 そこで、 CLI の出番です。 CLI なら、テキストエディタでコマンドを一回編集して貼り付ければ、あとは何度も同じ操作を実行する場合にはコマンド履歴からキーボード数回打鍵するだけで実行可能です! やってみよう 早速、やってみましょう。 今回利用するのは以下の CloudFormationテンプレートです。VPCと、インターネットゲートウェイ、S3ゲートウェイエンドポイントを作るだけなのですが、パラメータの入力(4つ)を使ってタグ付けをしていて、しかも CreateDate は今日の日付を入れようという、スタック作成時に面倒なテンプレートです。 --- AWSTemplateFormatVersion: "2010-09-09" Description: Create VPC*1, Subnet*2, InternetGateway*1, RouteTable*1 NACL*1 S3 GatewayEndpoint * 1 Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Common Settings Parameters: - ProjectName - Environment - CostTagValue - CreateDate - Label: default: VPC Settings Parameters: - VPCCidr - PublicSubnetCidr1 - PublicSubnetCidr2 - PrivateSubnetCidr1 - PrivateSubnetCidr2 Parameters: ProjectName: Description: Project Name Type: String Default: unnamed Environment: Description: Environment Type: String Default: sbx AllowedValues: - prd - dev - stg - sbx VPCCidr: Description: VPC IP Range Type: String Default: 10.0.0.0/16 AllowedPattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$' PublicSubnetCidr1: Description: Public Subnet 1 IP Range Type: String Default: 10.0.1.0/24 AllowedPattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$' PublicSubnetCidr2: Description: Public Subnet 2 IP Range Type: String Default: 10.0.2.0/24 AllowedPattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$' PrivateSubnetCidr1: Description: Private Subnet 1 IP Range Type: String Default: 10.0.17.0/24 AllowedPattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$' PrivateSubnetCidr2: Description: Private Subnet 2 IP Range Type: String Default: 10.0.18.0/24 AllowedPattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$' CostTagValue: Description: Tag Value for Cost allocation tag. Type: String Default: nanashi CreateDate: Description: Create Date Type: String Default: 2023/09/15 Resources: # Create VPC VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VPCCidr EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-vpc - Key: Environment Value: !Sub ${Environment} - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} # Create InternetGateway & VPC Attach InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-igw - Key: Environment Value: !Sub ${Environment} - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} AttachGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway # Create Public RouteTable & Setting Routing PublicRouteTable1: Type: AWS::EC2::RouteTable DependsOn: AttachGateway Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-public-rtb1 - Key: Environment Value: !Sub ${Environment} - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} PublicRoute1: Type: AWS::EC2::Route DependsOn: AttachGateway Properties: RouteTableId: !Ref PublicRouteTable1 DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway # Create Public Subnet *2 # Public 1 PublicSubnet1: Type: AWS::EC2::Subnet DependsOn: AttachGateway Properties: VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ""] CidrBlock: !Ref PublicSubnetCidr1 MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-public-subnet1 - Key: Environment Value: !Sub ${Environment} - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} PublicSubnetRouteTableAssociation1: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet1 RouteTableId: !Ref PublicRouteTable1 # Public 2 PublicSubnet2: Type: AWS::EC2::Subnet DependsOn: AttachGateway Properties: VpcId: !Ref VPC AvailabilityZone: !Select [1, !GetAZs ""] CidrBlock: !Ref PublicSubnetCidr2 MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-public-subnet2 - Key: Environment Value: !Sub ${Environment} - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} PublicSubnetRouteTableAssociation2: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet2 RouteTableId: !Ref PublicRouteTable1 # Create Private Subnet *2 # Private 1 PrivateSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ""] CidrBlock: !Ref PrivateSubnetCidr1 Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-private-subnet1 - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} PrivateRouteTable1: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-private-rtb1 - Key: Environment Value: !Sub ${Environment} - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} PrivateSubnetRouteTableAssociation1: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PrivateSubnet1 RouteTableId: !Ref PrivateRouteTable1 # Private 2 PrivateSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [1, !GetAZs ""] CidrBlock: !Ref PrivateSubnetCidr2 Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-private-subnet2 - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} PrivateRouteTable2: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-private-rtb2 - Key: Environment Value: !Sub ${Environment} - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} PrivateSubnetRouteTableAssociation2: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PrivateSubnet2 RouteTableId: !Ref PrivateRouteTable2 # Create Network ACL # Public NACL PublicNetworkACL1: Type: AWS::EC2::NetworkAcl Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-public-nacl1 - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} NetworkACLEntryPublicIngress1: Type: AWS::EC2::NetworkAclEntry Properties: CidrBlock: "0.0.0.0/0" Egress: false NetworkAclId: !Ref PublicNetworkACL1 Protocol: -1 RuleAction: "allow" RuleNumber: 100 NetworkACLEntryPublicEgress1: Type: "AWS::EC2::NetworkAclEntry" Properties: CidrBlock: "0.0.0.0/0" Egress: true NetworkAclId: !Ref PublicNetworkACL1 Protocol: -1 RuleAction: "allow" RuleNumber: 100 # Private NACL PrivateNetworkACL1: Type: AWS::EC2::NetworkAcl Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-Private-nacl1 - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} NetworkACLEntryPrivateIngress1: Type: AWS::EC2::NetworkAclEntry Properties: CidrBlock: "0.0.0.0/0" Egress: false NetworkAclId: !Ref PrivateNetworkACL1 Protocol: -1 RuleAction: "allow" RuleNumber: 100 NetworkACLEntryPrivateEgress1: Type: "AWS::EC2::NetworkAclEntry" Properties: CidrBlock: "0.0.0.0/0" Egress: true NetworkAclId: !Ref PrivateNetworkACL1 Protocol: -1 RuleAction: "allow" RuleNumber: 100 # VPC Endpoint for S3 gateway Endpoint # prod-region-starport-layer-bucket is ECR used S3 bucket for Docker image download from ECR. # https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/vpc-endpoints.html#ecr-minimum-s3-perms S3Endpoint: Type: AWS::EC2::VPCEndpoint Properties: PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: '*' Action: - s3:* Resource: - !Sub arn:aws:s3:::*${AWS::Region}.amazon.com/* - !Sub arn:aws:s3:::*${AWS::Region}.amazon.com/ - Effect: Allow Principal: '*' Action: - s3:GetObject Resource: - !Sub arn:aws:s3:::prod-${AWS::Region}-starport-layer-bucket/* RouteTableIds: - !Ref PublicRouteTable1 - !Ref PrivateRouteTable1 - !Ref PrivateRouteTable2 ServiceName: !Sub com.amazonaws.${AWS::Region}.s3 VpcId: !Ref VPC VpcEndpointType: Gateway # NetworkACL Association PublicNetworkACLAssocation1: Type: AWS::EC2::SubnetNetworkAclAssociation Properties: SubnetId: !Ref PublicSubnet1 NetworkAclId: !Ref PublicNetworkACL1 PublicNetworkACLAssocation2: Type: AWS::EC2::SubnetNetworkAclAssociation Properties: SubnetId: !Ref PublicSubnet2 NetworkAclId: !Ref PublicNetworkACL1 PrivateNetworkACLAssocation1: Type: AWS::EC2::SubnetNetworkAclAssociation Properties: SubnetId: !Ref PrivateSubnet1 NetworkAclId: !Ref PrivateNetworkACL1 PrivateNetworkACLAssocation2: Type: AWS::EC2::SubnetNetworkAclAssociation Properties: SubnetId: !Ref PrivateSubnet2 NetworkAclId: !Ref PrivateNetworkACL1 Outputs: ExportVPC: Value: !Ref VPC Export: Name: !Sub ${ProjectName}-${Environment}-VPC ExportVPCCidr: Value: !Ref VPCCidr Export: Name: !Sub ${ProjectName}-${Environment}-VPCCidr ExportPublicSubnet1: Value: !Ref PublicSubnet1 Export: Name: !Sub ${ProjectName}-${Environment}-PublicSubnet1 ExportPublicSubnet2: Value: !Ref PublicSubnet2 Export: Name: !Sub ${ProjectName}-${Environment}-PublicSubnet2 ExportPrivateSubnet1: Value: !Ref PrivateSubnet1 Export: Name: !Sub ${ProjectName}-${Environment}-PrivateSubnet1 ExportPrivateSubnet2: Value: !Ref PrivateSubnet2 Export: Name: !Sub ${ProjectName}-${Environment}-PrivateSubnet2 ExportPrivateRouteTable1: Value: !Ref PrivateRouteTable1 Export: Name: !Sub ${ProjectName}-${Environment}-PrivateRouteTable1 ExportPrivateRouteTable2: Value: !Ref PrivateRouteTable2 Export: Name: !Sub ${ProjectName}-${Environment}-PrivateRouteTable2 ExportS3GatewayEndpoint: Value: !Ref S3Endpoint Export: Name: !Sub ${ProjectName}-${Environment}-S3GatewayEndpoint 今回は AWS のアクセスキー設定等が不要で便利な AWS CloudShell 環境(Amazon linux 2023でした)から実行します。 [cloudshell-user@ip-10-130-56-54 kodama-th-cloundformation-cli]$ cat /etc/os-release | grep PRETTY_NAME PRETTY_NAME="Amazon Linux 2023.5.20240708" 上記のCloudFormationテンプレートを、vpc.yaml として保存して、カレントディレクトリに配置しておきます。 [cloudshell-user@ip-10-130-56-54 kodama-th-cloundformation-cli]$ [cloudshell-user@ip-10-130-56-54 kodama-th-cloundformation-cli]$ ls -la total 20 drwxr-xr-x. 2 cloudshell-user cloudshell-user 4096 Aug 21 14:51 . drwxr-xr-x. 21 cloudshell-user cloudshell-user 4096 Aug 21 14:51 .. -rw-r--r--. 1 cloudshell-user cloudshell-user 11885 Aug 21 14:51 vpc.yaml この状態で、以下コマンドをのCLIをテキストエディタなどで編集したあと、コマンドラインにはりつけて実行します。 STACK_NAME= <作成する CloudFormationスタックの名前 kodama-th-sample-stackname> TEMPLATE_FILE= <CloudFormation テンプレートファイルの名前> TIMEOUT_IN_MINUTES= <スタックのタイムアウト時間(分)> PROJECT_NAME= <作成するリソースに付与する Project タグ名> COST= <作成するリソースに付与する Cost タグ名> Environment= <デプロイするリソースの環境, prd, dev, stg, sbx のいずれか> aws cloudformation create-stack \ --stack-name ${STACK_NAME} \ --template-body "file://${TEMPLATE_FILE}" \ --parameters \ ParameterKey="ProjectName",ParameterValue="${PROJECT_NAME}" \ ParameterKey="Environment",ParameterValue="${Environment}" \ ParameterKey="CostTagValue",ParameterValue="${COST}" \ --tags \ Key=Cost,Value="${COST}" \ Key=Project,Value="${PROJECT_NAME}" \ Key=Environment,Value="${Environment}" \ Key=Name,Value=${STACK_NAME} \ Key=CreateDate,Value=$(date '+%Y/%m/%d') \ --timeout-in-minutes="${TIMEOUT_IN_MINUTES}" \ --capabilities CAPABILITY_NAMED_IAM 今日の日付を CreateDate タグにつけているのですが、これを Linux の date コマンドを利用して自動的にちゃんと実行した日付になるようにしています。 赤字の部分は、必要に応じて書き直すのですが、今回は、 STACK_NAME= kodama-th-sample-stackname TEMPLATE_FILE= vpc.yaml TIMEOUT_IN_MINUTES= 10 PROJECT_NAME= kodama-th-cloudformation-cli COST ="j.kodama" Environment= sbx としました。 実際に貼り付けて実行すると、以下のようになりました。 “StackID”: “arn:aws:cloudformation:~” の応答が返ってくればスタックが作成されて実行が開始されています。 Managemend Console の CloudFormation スタックの画面を見ると、無事作成されています! 削除したい場合 スタックでAWSリソースの作成に失敗したりして、削除したい場合は、簡単です。 すでにスタックは環境変数STACK_NAMEとして登録済みなので、以下を貼り付けるだけで実行できます。 aws cloudformation delete-stack \ --stack-name "${STACK_NAME}" Management Consoleでスタック名を「削除済み」で検索すると、削除されていることがわかります。 あとは、これを理想のCloudFormation テンプレートに仕上がるまで繰り返していきます。 GUIでは 4ページ分必要だったパラメータ入力が、Linux Shell のコマンド履歴から矢印キーを数回 + Enter キーで実行できるようになります! 終わりに いかがでしょうか? これで CloudFormation テンプレートを作ろうとしているけど、デバッグ時の入力作業の繰り返しがうんざりしてやめてしまった方でも「もう一度トライしてみよう!」と思えませんか? 皆様の良き CloudFormation テンプレート作成ライフをお祈りしています!
アバター
こんにちは。SCSKの山口です。 本ブログは BigQuery のアクセス制御まとめ その① の続編です。 今回は、BigQueryの「列と行のアクセス制御」について書きます。 BigQuery のアクセス制御 概要については下記ブログをご参照ください。 【GCP】BigQuery のアクセス制御まとめ その① BigQuery の様々なレベルでのアクセス制御についてまとめます。今回のブログ(その①)では、リソースレベルでのアクセス制御について詳しく見ていきます。 blog.usize-tech.com 2024.08.22 データレベルのアクセス制御 本ブログでは、列と行のアクセス制御を「データレベル」のアクセス制御と位置付けます。 列レベルのアクセス制御 列レベルのアクセス制御の概要  |  BigQuery  |  Google Cloud BigQuery の列レベルのアクセス制御、ワークフロー、制限事項について説明します。サンプル ユースケースを使用して、列レベルのアクセス制御が設定されたテーブルとビューにクエリを実行する方法を示します。 cloud.google.com 列レベルのアクセス制御では、文字通り列に対するアクセスを制御することができます。 列レベルのアクセス制御を実現するには、以下の手順を踏む必要があります。 分類階層とポリシータグを定義する BigQuery 列にポリシータグを割り当てる 分類階層にアクセス制御を適用する ポリシータグへのアクセス権を管理する 聞きなれない 「ポリシータグ」 という単語が出てきました。ポリシータグについて説明します。 ポリシータグ BigQuery でポリシータグを使用する際のベスト プラクティス  |  Google Cloud ポリシータグの階層(テーブル列に適用して列レベルのアクセス制御を行う)を設計し、モニタリング専用モードを使用してアクセスをテストするためのガイダンスです。 cloud.google.com ポリシータグとは、 カラム単位のアクセス制限 や、 動的データマスキング を行うために、BigQuery の 列にタグを付与する 機能です。 ※動的データマスキングについてはまた別のブログで触れようと思います。 ポリシータグを使用する際に重要になるのが、 「データクラス階層の構築」 です。 取り扱うデータの種類を検討し、データ特性や重要度、機密性等を加味してデータクラスを決定します。 上記、公式ドキュメント内の図で説明します。 最上段の黄色四角形が 最上位ポリシータグ です。すべてのデータタイプが高、中、低で分類されています。 最上位ポリシータグにぶら下がっている青色四角形が リーフポリシータグ です。 このように、ポリシータグは ツリー状にまとめること が可能です。 これらのポリシータグをBigQuery の列に付与し、アクセス制御や動的データマスキングを実現します。   行レベルのアクセス制御 BigQuery の行レベルのセキュリティの概要  |  Google Cloud 行レベルのアクセス ポリシー、そのパフォーマンスおよびセキュリティの制限について説明し、他のアクセス制御方法(承認済みビューおよびテーブルレベルのアクセス制御)と比較します。 cloud.google.com こちらも文字通り、行に対するアクセスを制御できます。 行レベルのアクセス制御は、 「アクセスポリシー」 を使用して実現します。データに対するアクションがされた際に、 ユーザまたはグループが許可リストに含まれているかどうか に応じて 特定のデータ行を表示または非表示 します。 1つのテーブルに対して、複数の行レベルアクセスポリシーを設定することも可能です。   実践1:列レベルのアクセス制御 実際に列レベルのアクセス制御をやってみます。 今回も前ブログ(その①)同様、AdminとMemberに分けて実装していきます。 まずは「分類階層の定義」と「ポリシータグの定義」でしたね。 Admin:分類階層の定義 今回は公式ドキュメントに記載のある分類階層のテーブルをそのまま使用します。 テスト用に、最上位ポリシータグの高、中、低のカラム含むテーブルを用意します。 Admin:ポリシータグの定義 次にポリシータグを定義します。 BigQuery 画面の左ペインから「管理」-「ポリシータグ」を選択 「分類を作成」をクリック ポリシータグの分類を作成 Admin:BigQuery 列にポリシータグを割り当てる 作成したポリシータグを割り当てます。 今回のテーブルのカラムとポリシータグの対応は以下の通りです。 カラム名 最上位ポリシータグ リーフポリシータグ ユーザID – – クレジットカード番号 High Credit card 住所_都道府県 Medium Location 氏名 Low Name メールアドレス Low Email 上記の対応に基づいてポリシータグを割り当てます。 対象テーブルの「スキーマ」タブの「スキーマの編集」をクリック 割り当て対象のスキーマを選択した状態で「ADD POLICY TAG」をクリック 対応付けたいポリシータグを選択 該当するすべてのスキーマにタグを割り当てる →「氏名」スキーマを見てわかる通り、あえて上位ポリシータグの「Low」を割り当てることも可能です。 Admin:分類階層にアクセス制御を適用する 次にアクセス制御を適用します。 今回はMemberユーザに対して、MediumとLowのデータのみアクセスを許可(Highのデータはアクセス禁止)する制御とします。 BigQuery の「ポリシータグの分類」画面から、 「Medium」「Low」配下のすべてのポリシータグを選択 した状態で、「プリンシパルを追加」をクリック ※最上位のポリシータグを選択しても、リーフポリシータグは選択されていない状態になるので注意が必要です。 「新しいプリンシパル」にMemberユーザのアカウントを入力し、「ロール」で「プロダクトまたはサービス」-「データカタログ」-「きめ細かい読み取り」を選択 ここまででAdmin側の作業は完了です。 Member:テーブル確認 Admin側で、アクセス制御の適用を行っていない状態でMemberのアカウントからテーブルを見てみます。 ポリシータグを付与していないスキーマはデータがみれていますが、 ポリシータグを付与したスキーマ関してはデータが閲覧不可 になっています。 Admin側でのアクセス制御の適用が完了した後に再度確認すると。 Admin側でアクセスを許可したMedium,Lowのスキーマがアクセス可能になりました。   実践2:行レベルのアクセス制御 次に行レベルのアクセス制御をやってみます。 あらかじめ、Memberユーザからテーブル内のすべてのデータがみれるようにしておきます。 Admin:行データのフィルタリングをクエリ Admin側から下記クエリを発行します。 CREATE ROW ACCESS POLICY location_filter ON `evocative-entry-277709.yamaguchi_test_acctrl.user` GRANTTO ("user:shXXXX@XXXX.com") FILTER USING (`住所_都道府県`="Tokyo") これで、Memberユーザに対して` 住所_都道府県`=”Tokyo”のデータのみにしかアクセスできない制限 がかかりました。 Member:クエリ結果確認 Memberユーザ側でデータを全件SELECTしてみます。 ` 住所_都道府県`=”Tokyo”のデータのみが表示 されました。 Memberユーザがアクセスできる行を絞り込むことができました。   まとめ BigQuery の様々なレベルのアクセス制御について、二本にわたって書きました。 今回紹介した各レベルの制御方法は組み合わせることができます。各方法のベストプラクティスを確認し、 要件に適した組み合わせ、実装方法を検討すること が重要だと思います。 どんなデータがあって、だれに見せたくないのか(見せたいのか)を確認すること最初のステップが重要です。 その次の実装のステップでこのブログが皆さんのお役に立てると幸いです。   BigQuery の行レベルのセキュリティに関するベスト プラクティス  |  Google Cloud サイドチャネル攻撃の軽減、更新中のアクセス ウィンドウの防止、フィルタ済みデータ閲覧者のロールの慎重な使用、パーティション分割テーブルのパフォーマンスへの影響など、BigQuery の行レベルのセキュリティの使用に関する考慮事項について説明... cloud.google.com BigQuery でポリシータグを使用する際のベスト プラクティス  |  Google Cloud ポリシータグの階層(テーブル列に適用して列レベルのアクセス制御を行う)を設計し、モニタリング専用モードを使用してアクセスをテストするためのガイダンスです。 cloud.google.com
アバター
こんにちは。SCSKの山口です。 今回は、BigQuery の、様々なレベルでのアクセス制御についてまとめます。 BigQuery のアクセス制御 BigQuery の IAM ロールと権限  |  Google Cloud 事前定義ロールとカスタムロールを含む、BigQuery 向け Identity and Access Management(IAM)によるアクセス制御のロールと権限について説明します。 cloud.google.com BigQuery では、下記のレベルでのアクセス制御が可能です。 リソースレベル データセット テーブル データレベル 列 行 公式ドキュメントには「データレベル」というワードありませんが、わかりやすくするために使用しています。 図式化すると以下の通りです。 アクセス制御が実装されているBigQuery では、ユーザは目的のデータ(宝石)を入手するために 各レベルに設定されたアクセス制御を潜り抜ける 必要があります。 もちろん、アクセス制御がされていない場合もあります。 今回のブログ(その①)では、 リソースレベルでのアクセス制御 について詳しく見ていきます。 リソースレベルのアクセス制御 前述しましたが、ここでいう「リソース」は データセット/テーブル を指します。 下記方法で設定することが可能です。 IAMを使用したアクセス制御 承認によるアクセス制御 VPC Service Controlsを使用する タグを使用する IAM Conditionsを使用する IAMを使用したアクセス制御 IAM を使用してリソースへのアクセスを制御する  |  BigQuery  |  Google Cloud cloud.google.com IAMを使用してBigQuery のアクセス制御を実装する場合は、下記のロールが必要です。 BigQuery データオーナー(roles/bigquery.dataOwner) 既に実装されているアクセス制御については、下記手順で、コンソール上で確認することができます。 データセット名の横の点三つをクリックし「アクションを表示」 「共有-権限の管理」をクリック 新たにアクセス権を付与する場合もコンソール上での操作が可能です。 (上記と同様の手順) (上記と同様の手順) 「プリンシパルを追加」をクリック 「新しいプリンシパル」欄にプリンシパルを入力 「ロールを選択」リストで付与するロールを選択 「保存」をクリック   承認によるアクセス制御 VPC Service Controlsを使用する BigQuery の VPC Service Controls  |  Google Cloud cloud.google.com VPC Service Controls の詳細については下記ドキュメントをご参照ください。 VPC Service Controls の概要  |  Google Cloud cloud.google.com BigQuery で VPC Service Controls を使用することで、データアクセスとデータの引き出しを制限することができます。   タグを使用する テーブルとデータセットにタグを付ける  |  BigQuery  |  Google Cloud cloud.google.com 事前に作成したタグを使用し、 リソースにタグが付いているかどうかに基づいて条件付きでポリシーを適用する 方法です。 タグはKey-Value ペアとして構成されるリソースで、組織リソースまたはプロジェクトリソース配下に作成することができます。詳細は下記をご参照ください。 タグの概要  |  Resource Manager Documentation  |  Google Cloud cloud.google.com タグを使用することで、例えば下記のような運用・制御が可能です。 [前提] 組織を管理している 組織内のデータアナリストはすべてグループ「 analysts@example.com  」のメンバ アナリストはプロジェクト「 userData 」に対して「 BigQuery データ閲覧者IAMロール 」を持つ アナリストの インターンの学生 が一名入ってきた [やりたいこと] インターンの学生にはuserData プロジェクトの 「anonymousData」 データセットを表示する権限のみ を付与したい [実現方式] 「anonymousData」 データセットにタグを付与 する インターン生のIAM(もしくはサービスアカウント)の「 BigQuery データ閲覧者IAMロール 」に対して タグの条件を追加する (公式ドキュメント内の例を参考にしています。) テーブルとデータセットにタグを付ける  |  BigQuery  |  Google Cloud cloud.google.com この方法に関しては、後ほど実践したいと思います。   IAM Conditionsを使用する IAM Conditions によるアクセス制御  |  BigQuery  |  Google Cloud cloud.google.com この方法では、指定された条件が満たされた場合のみBigQuery リソースへのアクセスを認可できます。 IAM Conditions は、プロジェクト、フォルダ、組織レベルでサポートされ、BigQuery データセット、テーブル、ルーティン、モデルに適用できます。 次の属性に基づいた設定が可能です。 属性 概要 値 request.time ユーザがBigQuery リソースへアクセスした時刻 – resource.name BigQuery リソースのパス projects/ PROJECT_ID /datasets/ DATASET_ID projects/ PROJECT_ID /datasets/ DATASET_ID /tables/ TABLE_ID resource.type BigQuery リソースのタイプ bigquery.googleapis.com/Dataset(Table) resource.service BigQuery リソースが使用するGoogle Cloud サービス bigquery.googleapis.com resource.tags BigQuery リソースに付加されたタグ –   具体的な実践は今回は省きますが、タグの使用でも説明した「IAMの条件を追加」から設定することが可能です。 [例:request.time]   実践1:IAMを使用したアクセス制御 IAMを使ってアクセス制御してみます。 以降はAdminとMemberでアカウントを分けて進めます。 Admin:データセット+テーブル作成 下記データセットとテーブルを作成します。 データセット:yamaguchi_test_acctrl テーブル:test1,test2 次に、AdminのBigQueryで、 test1テーブル の権限の共有で下記を設定します。 プリンシパル:shXXXXX@XXXX(MemberのGoogleアカウントのアドレス) ロール:BigQuery データ閲覧者 Member:テーブル確認 Admin側で共有設定をする前は、test1.test2テーブルともに閲覧ができない状態でした。 Adminでtest1テーブルの共有設定を行うと、 test1テーブルのみ閲覧することができるようになりました。   実践2:タグを使用したアクセス制御 次に、同じことをタグを使って実現してみます。 今度はtest2テーブルに対する閲覧許可を実装します。 Admin:タグ作成+付与 まず、タグを作成します。 次に、test2テーブルに作成したタグを付与します。 「詳細」タブから「詳細を編集」 タグの「スコープの選択」でプロジェクトを選択し、作成したタグ情報を入力 Admin:IAMの条件を追加 権限付与対象のプリンシパルの「BigQuery データ閲覧者」ロールに、下記IAMの条件を追加します。 条件タイプ:タグ 演算子:値IDがある キーID:tagKeys/281476642126196(タグ値詳細画面の「親キー」) 値ID:tagValues/281483470283076(タグ値詳細画面の「タグ値ID」) Member:テーブル確認 Admin側でタグ設定をする前は、test2テーブルが閲覧できない状態でした。 タグとIAMの設定完了後にtest2テーブルを再度確認すると、 test2テーブルも閲覧可能になりました。   まとめ 今回はBigQuery のアクセス制御 その①ということで、リソースレベルのアクセス制御を実践してみました。 本ブログで実践した通り、IAMによる制御と承認(タグ)による制御は共存させることができます。便利ではあるのですが、闇雲に設定してしまうと 意図しない認可が発生してしまう 恐れもあります。 IAMの設定に関しては下記ドキュメント等のプラクティスに準拠することをお勧めします。 IAM を安全に使用する  |  IAM のドキュメント  |  Google Cloud cloud.google.com まとめ②では、BigQueryテーブル内の行・列単位のアクセス制御について取り扱います。
アバター
本記事は 夏休みクラウド自由研究 8/22付の記事です 。 こんにちは。SCSKの吉田です。 本記事は、ServiceNowの開発者向け生成AI機能であるNow Assist for Creatorに関する記事となります。 Now Assist for Creatorには、いくつかの機能がありますが、今回は Code generation を紹介させていただきます。 本記事は執筆時点(2024年8月)の情報です。最新の情報は製品ドキュメントを参考にしてください。 Code generationとは Code generationは、自然言語で記載したいコードの説明を入力すると、その内容をもとにAIがコードをサジェスト、生成してくれる機能となります。 Code generationの使用には以下のようなメリットがあると個人的に感じており、ServiceNowの開発業務を大幅に効率化することができます。 開発経験の有無に関係なく、ServiceNowスクリプトの文法に沿ったコードを簡単に作成できる 過去作成したコードを見返したり、ドキュメントを読んだりなど、調査の時間を短縮できる 普段、ロード・ノーコード開発に慣れていると、久しぶりにコーディングする際に「どういう構文だったっけ?」となることがあります。 そんなとき、Code generationを使用すれば、ドキュメントを調べる必要もなくなるので非常に便利なツールです。 使い方 Now Assist for Creatorをインストールした後、Code generationをアクティベートとすることで、Business rule、Script Includeなどのスクリプトエディターや、Flow Designerで利用可能になります。 Now Assistのセットアップ方法は、以下の記事で簡単にご紹介していますので併せてご覧ください。 【ServiceNow×生成AI】Now Assistをセットアップしてみる ServiceNowの生成AI機能であるNow Assistをセットアップしてみましたので、その手順を簡単にご紹介します。 blog.usize-tech.com 2024.08.15 ここではシステムで一般的な要件として存在する、以下のシナリオを想定してコードを作成してみます。 セキュリティの観点から、一定期間ログインが無いユーザーを無効化したい 自動生成したコードは、非本番環境でレビュー・動作確認の上、本番利用してください。 コードのサジェスト まず始めにコードのサジェスト機能のご紹介です。 画像のようにCode with Now Assistダイアログボックスに、作成したいコードの説明を記載します。 「ユーザーテーブルを検索し、最終ログイン日が180日以上前のアカウントを非アクティブ化する」 次に記載した内容をSubmitすると、Now Assistが入力された内容をもとにコードをサジェストしてくれます。(ハイライト部分) サジェストされた内容で問題なければ、Acceptを選択することで自動生成されたコードが反映されます。 最後に、変数名やログ出力処理など、各開発チームが持つ開発標準に合わせて微修正して保存すれば作成完了となります。 実際に自動生成された処理を実行したところ正しく動作することが確認できました。   コードの補完 続いて、コードの補完機能のご紹介です。 ここではあえてコードを途中まで記載した状態からスタートします。 コメントで作成したいコードの説明を記載のうえ、右クリック→Auto-generate code completionを選択します。 すると画像のように残りのコードを補完してくれます。(グレーアウト部分) 補完された内容は、先ほどのサジェストされたコードと同じ内容であることが確認できます。   生成AIが考えたお題にチャレンジ シナリオ 弊社内で利用できる生成AIにシナリオを考えてもらい、Code generationでコードを作成してみようと思います。 (吉田) ServiceNowのスクリプティングを勉強しています。複数のテーブルからデータを取得して特定の条件でクエリするような、複雑なスクリプトのお題をください。 (生成AI) ServiceNowのスクリプティングを学ぶためのスクリプトの課題をご紹介します。 シナリオ:ユーザーのアクティビティを監視し、特定の条件に基づいて一覧を表示するスクリプトを作成します。 要件: 1.ユーザーテーブルからアクティブなユーザーを取得します。 2.ログイン履歴テーブルから、過去1週間以内のログイン履歴を取得します。 3.各ユーザーのログイン回数を集計し、1回以上ログインしているユーザーのリストを表示します。 実践 まず始めにアクティブなユーザーをクエリするコードを作成します。 次に各ユーザーのログイン履歴を取得し、ログへ出力するコードを作成します。 最後に変数名などを分かりやすく修正した上で完成した処理がこちらになります。 実際にこの処理を動かしてみます。 過去1週間のうちにログインしているユーザーは、私自身のアカウントとテスト用ユーザーの2アカウントとなります。 なおテスト用ユーザーは非アクティブな状態に更新したため、ログは1件のみ出力されるのが想定している動作となります。 ログを確認すると、1件のみ出力されており、正しくコードを作成できていることが確認できました。   まとめ 今回は、Now Assist for Creatorの各機能のうち、コードを自動生成してくれるCode generationを使ってみました。 Code generationを使用すれば、ServiceNowの文法に沿った高品質のコードを簡単に作成することができ、また、手動でコードを書く時間を短縮できるので、開発者の業務効率を向上させることが可能な強力なツールと感じました。 Now Assist for Creatorにはその他の機能も用意されているので、今後ご紹介していきます。   最後に・・・ 弊社では、ITSMやCSM、ESGなど様々なServiceNow製品を扱っています。 以下から問合せ可能ですので、是非ご参照ください。 ServiceNow ServiceNowは、企業の生産性向上や業務プロセス改善を支えるサービスマネジメントクラウドソリューションです。従業員満足度・顧客満足度の向上、業務効率化を強力に支援します。 www.scsk.jp
アバター
こんにちは!Zabbixを担当している曽我です。 今回、Zabbixの 新しい構築サービス をリリースしましたので紹介いたします。 本サービスは、お客様からの導入時の以下の悩み事を解決できる内容になっています。 ・Zabbixの導入を依頼するといくら必要なの? ・要件を満たすには、どんな構成でZabbixを構築する必要があるの? ・導入後のサポートは何があるの? Quick Start Package for Zabbixのサービス概要 本サービスは、弊社にて2017年よりZabbix構築サービスを提供してきた中で、よくある構築作業をパッケージ化したサービスです。 お客様のご要望に応じて、複数の選択肢を用意しており、それらを組み合わせることで、構築から、構築後のサポートまで提供します。 お客様は、以下の①~④のZabbix環境を構築する上で必要なコンポーネントより、要件にあったメニューを選択頂くことで、ご希望の 監視環境を得ることができます。 Quick Start Package for Zabbixの全体メニュー 以降で、①~④のコンポーネントについて説明します。 ①サーバ環境 Zabbixサーバの環境として、大きく3つの選択肢があります。 選択1)Zabbix Enteprise アプライアンス(監視対象数の目安:~1000台) Zabbix Enterprise アプライアンスは、ZS-5000シリーズ(監視対象数の目安:200台)と ZS-7000シリーズ(監視対象数の目安:1000台)の2種類があります。 機器の詳細については、こちらの リンク より確認してください。 ZS-5000 / ZS-7000シリーズ 選択2)仮想アプライアンス Zabbix Enteprise サポート契約者さま向けに仮想アプライアンスが提供されています。 対応している仮想基盤は、以下です。(2024/8/21時点) VMware 5.5/6.0/6.5/7.0/8.0 VirtualBox 必要なサーバスペックについては、 ご相談 ください。 選択3)物理サーバ/仮想マシン/クラウド 本サービス上は、お客様にてご用意頂いた物理サーバ/仮想マシン/クラウドにOS環境を ご用意頂き、Zabbixを導入させて頂く内容となっております。 ※もし環境の準備をご希望される場合は、別途ご相談ください。   ②構築サービス 構築サービスは、構築する環境に応じて3種類ご用意しております。 構築サービスメニュー 環境によっては、Zabbixプロキシが必要になり、上記の構築メニューでは不十分なケースが御座います。 その場合は、個別見積で対応させて頂きますので、ご相談ください。   ③オプション 構築オプションメニュー 構築サービスの内容に以下のオプションを追加で加えることが可能です。 構築オプションメニュー 運用支援オプションメニュー 構築後、Zabbixのサポートはあるけど、お客様自身だけでは不安な場合、導入後の支援をご依頼頂けます。 構築後支援メニュー ④Zabbixサポート 当社のサポートは全部で、5種類あり、一番お勧めは、問合せ無制限の「ゴールド」です。 以下、サービスメニューです。 赤い★マーク がついているところは、当社のオリジナルメニューです。 Zabbix Enterprise サポート ※ 1 平日営業時間内は日本時間月曜~金曜日(祝祭日、弊社規定休日を除く)9時~17時30分となります。 ※ 2 ご契約のZabbixサーバに接続されているZabbixプロキシの台数分プロキシオプションの契約が必要となります。サーバとプロキシのサポートレベルは同一であることが必須となります。 ※ 3 18時~翌9時まで、対応言語は英語のみとなります。 ※ 4 VALinux社提供のVAQuestサービスを利用しています。 ※ 5 本サポートをご契約頂けるお客様は、新規でサポートをご契約頂くお客様または他社様のZabbixサポートから乗り換えのお客様に限ります。 Zabbixアプライアンスのサポートには利用できません。   構築例 ①Zabbix Enteprise アプライアンス ZS-5000シリーズ+②構築サービス エントリー+③ Zabbix Enteprise サポート シルバーの場合 No 製品名 数量 価格 1 Zabbixアプライアンス ZS-5000シリーズ 1 \298,000 2 構築サービス エントリー 1 \100,000 3 Zabbix Enteprise サポート シルバー 1年 1 \1,600,000 合計 \1,998,000 (税込\2,197,800)   まとめ 「Quick Start Package for Zabbix」は、監視システムを導入されようとしているお客様にとっての メリットは、「スピーディーな導入」「分かりやすい料金体系」「安心のサポート」が御座いますので、 是非、ご興味がございましたら、 こちら よりご連絡ください。 また、オプションメニューについては、拡充することを予定しておりますので、 ご期待ください!   参考 弊社ではZabbix関連サービスを展開しています。以下ページもご参照ください。 ★SCSK Plus サポート for Zabbix★ SCSK Plus サポート for Zabbix 世界で最も人気のあるオープンソース統合監視ツール「Zabbix」の導入構築から運用保守までSCSKが強力にサポートします www.scsk.jp ★YouTubeに、SCSK Zabbixチャンネルを開設しました!★ SCSK Zabbixチャンネル 本チャンネルでは、SCSK株式会社でのZabbixに関するトレンド/事例紹介などを動画にまとめて取り上げております。 最新のトピックについては、以下の弊社HPもしくはツイッターアカウントをぜひ参照ください。 ツイッターアカウント: www.youtube.com ★X(旧Twitter)に、SCSK Zabbixアカウントを開設しました!★ x.com X.com  
アバター
こんにちは、SCSK株式会社の中野です。 Zabbixの脆弱性に関して、深刻な脆弱性が発表されましたので、本記事にて共有いたします。 Zabbixをご利用の方は一度ご覧いただき、対象の場合はアップデート等のご検討お願い致します。 Zabbix脆弱性情報 2024年8月9日(現地時間)にZabbix社は、監視ソリューション「Zabbix」に深刻な脆弱性があると以下URLにて公表しております。 ———————— CVE/Advisory number: CVE-2024-22116 Synopsis: Remote code execution within ping script Zabbix Security Advisories and CVE database ———————— この脆弱性が悪用された場合は、リモートコード実行の攻撃を受け、システム全体が危険にさらされる可能性がございます。 例えスクリプト実行を制限された権限を持つ管理者であっても、監視しているホストでスクリプト実行機能を悪用できる可能性があり、 scriptのパラメータはデフォルトでエスケープされていないため、攻撃者はping scriptを介して任意のコードを実行し、インフラ全体を侵害することが可能となります。 影響を受けるとされるZabbixのバージョンは以下となります。 ・Zabbix 6.4.0 ~ 6.4.15  ・Zabbix 7.0.0alpha1 ~ 7.0.0rc2  脆弱性を修正するためには、修正されたZabbixのバージョンへアップデートする必要がございますので 以下バージョンへのアップデートのご検討をお願い致します。 ・Zabbix 6.4.16rc1 ・Zabbix 7.0.0rc3 最後に 弊社では本件に関してのお問い合わせもお受けしております。 ご相談事項がございましたら、以下ページよりお問い合わせいただければと思います。 お問い合わせ 製品・サービスについて 入力 | SCSK株式会社 また、以下Zabbixのイベントが直近で開催されます。 本件に限らずご質問をお受けする時間もございますので、ご興味がございましたら是非ご参加ください。 2024.8.23 (金) Zabbix全国5都市キャラバン2024 名古屋 2024.10.02(水) Zabbix7.0セミナー ~新機能とバージョンアップの要点~ 以上、最後までご覧いただきありがとうございました。
アバター
こんにちは。SCSKの吉田です。 今年リリースされたWashington DCバージョンから「Customized Metadata Detail」というテーブルが追加されていることを最近発見しました。 このテーブルを使用することで、インスタンスに加えたカスタマイズを簡単にトレースすることができるようになりました。 公式ドキュメントにはおそらく記載はなく(見逃していたらすいません)、あくまでも個人で調べた内容となりますが、共有させていただきます。 はじめに ServiceNowを導入する際は、OOTB(Out of the Box)と呼ばれる標準機能を利用して、カスタマイズを最小限に抑えることが推奨されています。標準機能を利用することで初期構築期間の短縮、システム稼働後のメンテナンスコスト削減などのメリットがあります。 その一方で、業務要件のためにカスタマイズが必要となる場面もあります。その際は以下の点を考慮する必要があります。 メンテナンス工数の増大 カスタマイズは自身でメンテナンスを行っていく必要があります。カスタマイズの程度にもよりますが、発生した問題の原因がカスタマイズの場合、サポート対象外となることがあります。 また、ServiceNowでは1年に1回はインスタンスのアップグレードを実施する必要があり、カスタマイズが多いほどリグレッションテストにかかる工数は増大します。 カスタマイズ箇所のブラックボックス化 もちろんですがカスタマイズで実装した内容は、公式ドキュメントに記載されていません。そのため、設計書に残していない場合、カスタマイズを実施した特定の開発者に属人化してしまいます。 また、きちんと引継ぎがなされないまま開発者が離任した場合、カスタマイズ箇所の特定が困難になります。 上記のことから、不要なカスタマイズを避けることが求められ、またカスタマイズを実施する場合は、設計書等にドキュメント化しておく必要があります。 しかし、ドキュメント化のルールを整備しないまま開発を進めてしまい、後からカスタマイズをトレースするのに苦労しているという方も多いのではないでしょうか。   カスタマイズをトレースする 以前までは、例えば以下のようにカスタマイズをトレースしていました。 テーブルに追加したカスタムフィールドを探す場合:sys_dictionaryテーブル上で名前が「u_」から始まるレコードを検索する カスタマイズしたBusiness ruleを探す場合:sys_scriptテーブル上で、作成/更新者、作成/更新日時、スクリプトの中身を確認してカスタマイズか否かを確認する このように、各テーブル上で、それぞれの探し方でトレースする必要がありました。 しかし、Washington DCからは、カスタマイズのトレースを簡単にする以下テーブルが追加されました。 Customized Metadata Detail[sys_metadata_customization] どのテーブル上のレコードを変更したかに関係なく、カスタマイズと分類される変更は、Customized Metadata Detailテーブル上にレコードとして格納されるようになったようです。 各テーブル毎に探す手間が省け、かつカスタマイズのみが格納されるテーブルの為、OOTBかカスタマイズかの判別も不要となりました。 また、Author Typeの値を使用することで、以下のように更に詳細な分類ができます。 「ServiceNow」の場合:OOTBのレコードに対して、変更を加えカスタマイズしている 「Custom」の場合:レコードを新規作成してカスタマイズしている 他にもAuthor Typeが「Unknown」や「ToBeDetermined」となっているレコードがありましたが、カスタマイズを特定する上では上記2つを確認するだけで問題なさそうです。   注意点として、Customized Metadata Detailに格納されるのは、 更新セットにキャプチャされる変更のみ のようです。 試しにScheduled Jobを作成しましたが、Customized Metadata Detailにはレコードが作成されませんでした。   最後に 今回は、Washington DCで追加されたテーブルを使用し、カスタマイズをトレースする方法をご紹介しました。 カスタマイズのトレースにお困りの方にとって、本記事が参考になれば幸いです。 また、弊社では豊富な構築・運用ノウハウにより、ServiceNow導入のご支援が可能です。 以下HPも併せてご参照ください。 ServiceNow ServiceNowは、企業の生産性向上や業務プロセス改善を支えるサービスマネジメントクラウドソリューションです。従業員満足度・顧客満足度の向上、業務効率化を強力に支援します。 www.scsk.jp
アバター
本記事は 夏休みクラウド自由研究 8/21付の記事です 。 クラウドサービスのオブジェクトストレージの利便性 便利なストレージサービス AWSのS3(Simple Storage Service)や、Google CloudのCloud Storage、Microsoft AzureのAzure Blob Storageなど、パブリッククラウド各社には代表的なオブジェクトストレージサービスが存在しています。これらは非常にシンプルで便利なストレージサービスです。とりあえずデータを入れておけば、連携するサービスや対応するソフトウェアが豊富にあり様々な活用ができます。さらに、ストレージ料金も非常に安価で、クラウド利用時のデータレイクとして最適です。 思わぬ課金項目に注意! クラウド上のオブジェクトストレージは確かに便利ですが、その活用方法によっては想定に反して思わぬ請求が来てびっくりしてしまうケースが存在します。見落としがちな課金項目として挙げられるのが、クラウド外へのデータ転送課金です。 クラウド外へのデータ転送課金(ダウンロード課金)とは? 主要なパブリッククラウドにはデータをクラウド外に送信する際に 従量 課金が発生します。一般的には Egress課金 やダウンロード課金と呼ばれます。 クラウド内や他のリージョンでのデータ送受信はゼロ円もしくは極めて安価でほとんど気にする必要はありませんが、他のクラウドやオンプレミス環境、またはクライアントへデータをダウンロードする際にはGBごとに課金が発生します。 この課金は単価が安いため見過ごしがちですが、使用量が増えるとコストがじわじわと上昇していきます。以下はあるオブジェクトストレージサービスにデータを保存してクラウド外に読み出しを行った場合の課金額シミュレーションです。読み出し量が多いと保存料金以上にダウンロード料金がかかることがわかります。   注意すべきユースケース 特に以下のようなユースケースでは、思いもよらなかった高額な課金になることがあります。 クライアント向けに頻繁にもしくは大量にデータ送信するケース ファイル配布、モジュール配信、ファイルサーバ利用など、様々なユースケースが考えられますが、データ量が大量になったり、データの送付先・配布先が大量になるケースは場合によって注意が必要です。 マルチクラウド環境でのデータ活用 パブリッククラウドの大手各社はデータ活用領域でも様々な魅力的なサービスを提供しています。各社の強味や特性を活かすために様々なクラウドサービスへデータを連携させていると、結果としてデータレイクやデータベースの存在するクラウドからのEgressトラフィックが増加します。 ハイブリッド環境でのデータ連携が多いケース 様々な理由があってパブリッククラウドとオンプレミスもしくはパブリッククラウド以外のクラウドサービスとの組合せ構成をとる場合。ある程度のEgress発生は想定内のはずですが、ハイブリッド構成をとるシステムが増えてくると意図せずEgressが多くなるケースが発生しえます。   解決策 この課金問題を回避するための方法をいくつか記載します。 解決策1:データ連携の多いシステムやサーバは同じクラウドに配置する 外に送るのにお金がかかるのなら送り先を中にしてしまおうという発想です。 クライアントなどもクラウド内に置いておけば追加のダウンロード料金が発生しません。 複数のクラウドを利用する必要がない場合は、これが最もシンプルな解決策です。 解決策2:ダウンロード課金がかからないサービスを活用する 複数のクラウドを使い分ける必要がある場合や、どうしても外部へ大量のデータを送らなければならない場合には、こちらの方法が適しています。Egress従量料金の代わりに固定の回線費用が発生する場合もありますので、扱うデータ量によって最適な構成の見極めが必要です。   まとめ ダウンロード課金による予想外のコスト増加を避けるためには、データの取り扱い方をあらかじめ計画し、最適な配置を行うことが重要です。 1つのクラウドですべてが完結する場合は問題ありませんが、複数のクラウドを利用する場合は特に注意が必要です。 オンプレ回帰は最適解か? 最近「オンプレ回帰」というワードを良く耳にします。クラウド利用したは良いけど、様々な理由で効果が出ずクラウドの利用をやめてオンプレミスのシステムに戻るという動きです。オンプレ回帰の理由の1つにコストの最適化があげられます。課金の仕組みをただしく理解して最適なデータ配置をすれば、コスト上昇を抑えてパブリッククラウドを利用し続ける事も可能と考えます。先進的なサービスが次々と実装されるパブリッククラウドの利用をあきらめるのはDXを推し進める上でもデメリットと考えています。今回の記事が読者の皆様のDX推進の一助になればうれしいです。 最後に宣伝 SCSKではUSiZE(ユーサイズ)というプライベートクラウドを提供中です。 USiZEには今回の記事でテーマにしたダウンロード課金はありません。 またSCNXというパブリッククラウドとの優れた接続性を有するサービスとも直結しており、 これによりパブリッククラウドとの連携も低コスト、低遅延で行うことができます。 直近でデータの蓄積場所として活用いただけるクラウドストレージというサービスもリリースをしております。 今回の記事に該当するようなお悩みをもっている方は、是非選択肢の一つとして「USiZE」をご検討頂ければと思います。   関連情報 データ主権を担保したソブリンクラウド ユーサイズ│SCSK株式会社|サービス|クラウド移行だけでは描けない、理想のDXを実現する プライベートクラウド「USiZE」でクラウドストレージサービスを提供開始 ~データ転送料金不要の純国産サービスでコストダウン、海外法影響排除を実現~ SCSK Cloud netXchange マルチクラウド接続サービス|SCSK株式会社
アバター
こんにちは、広野です。 本記事はシリーズもので、以下の記事の続編です。 Amazon Bedrock RAG 環境用 AWS CloudFormation テンプレート series 1 VPC 編 Agents for Amazon Bedrock を使用した最小構成の RAG 環境を構築する AWS CloudFormation テンプレートを紹介します。3部構成になっており、本記事は1つ目、VPC 編です。 blog.usize-tech.com 2024.08.01 以前、以下の記事で Amazon Bedrock や Agents for Amazon Bedrock を使用した最小構成 RAG 環境構築を紹介しておりました。当時はAmazon Bedrock 関連のリソースを一部 AWS CloudFormation ではデプロイできなかったのですが、今はサポートされたためにできるようになりました。 React アプリに Agents for Amazon Bedrock への問い合わせ画面を組み込む [RAG・レスポンスストリーミング対応] Agents for Amazon Bedrock を使用して簡単な RAG をつくってみましたので、問い合わせ画面コードの一部を紹介します。 blog.usize-tech.com 2024.02.15 当時の構成を現在は変更しており、Knowledge Base に使用するデータベースを Amazon OpenSearch Serverless から Aurora Serverless v2 Postgresql に変更したり、モデルを Claude 3.5 Sonnet に変更したりしています。 本シリーズ記事では、環境構築用の AWS CloudFormation のサンプルテンプレートを 3 記事に分けて紹介します。説明を分割するため、テンプレートを3つに分けていますのでご了承ください。 2回目は Amazon Aurora Serverless v2 Postgresql 編です。 本記事で取り扱う構成 RAG 環境全体の構成 以下のアーキテクチャで RAG アプリケーションを構築しています。このうち、赤枠の部分が本シリーズ記事で取り扱う箇所です。series 2 Aurora 編では、Knowledge Base のベクトルデータベースとなる Amazon Aurora Serverless v2 Postgresql と、それに取り込むドキュメントを格納する Amazon S3 バケットについて説明します。 今回は Agents for Amazon Bedrock がアクセスするリソース、Amazon Aurora Serverless v2 Postgresql と Amazon S3 バケットをデプロイします。 Amazon S3 バケットは RAG の参照先にしたいドキュメントを放り込むだけなので、特別なオプションはありません。 Amazon Aurora の構成 (前回のおさらい含む) Amazon Aurora Serverless v2 をデプロイするためには VPC が必要になります。サーバーレスなんですが、VPC リソースからアクセス可能にするためにそのような仕様にしているのだと思います。 Aurora Serverless はプライベートサブネットに配置します。リーダーインスタンスやレプリカは設定していません。 Aurora Serverless を配置するときに、RDS サブネットグループが必要になります。任意の 2 つ以上のサブネットをグループに登録します。これが Aurora Serverless の設定で必要になるため、マルチ AZ 構成が必須になります。 データベースなので、プライベートサブネットに配置します。選択したサブネットに、VPC 内からアクセスするためのエンドポイントが作成されます。ただし Agents for Amazon Bedrock からは Data API 経由で接続するため、VPC は通りません。 エンドポイントにはセキュリティグループを関連付けます。ここでは、サブネットの CIDR から Postgresql に接続するためのデフォルトポート番号を開けておきます。 Agents for Amazon Bedrock が Aurora Serverless に接続するときのクレデンシャルは、Secrets Manager から取得します。Postgresql のマスターユーザのパスワードは自動で Secrets Manager に作成されます。Agents for Amazon Bedrock が使用するユーザを bedrock_user とし、パスワードは自動生成させています。自動生成にあたり、パスワードに使用できない記号が入ることを避けるため、ExcludePunctuation のオプションを true にしています。この CloudFormation テンプレートでは、bedrock_user は作成されません。作成されるのはパスワードです。後述する手動によるベクトルデータベース構築コマンド実行の際にユーザを作成します。 Amazon Aurora Serverless のキャパシティやメンテナンスの設定は適当に入れているので、適宜変更してください。 AWS CloudFormation テンプレート 図に掲載している Amazon VPC は前回のテンプレートで作成しています。Amazon Aurora Serverless で使用する RDS サブネットグループとセキュリティグループは 前回のテンプレート でエクスポートした情報をインポートしています。また、今回のテンプレートで、次のテンプレートで使用する Amazon Aurora、Amazon S3、IAM ロールの情報をエクスポートしています。 IAM ロールは Agents for Amazon Bedrock 用のものです。以下の許可が入っています。 Amazon Aurora、Amazon S3、Secrets Manager へのアクセス ドキュメントの内容をベクトルデータに変換する AI モデル (Amazon Titan Text Embeddings) へのアクセス AWSTemplateFormatVersion: 2010-09-09 Description: The CloudFormation template that creates an Aurora Serverless v2 cluster and a S3 bucket as a RAG Knowledge base. # ------------------------------------------------------------# # Input Parameters # ------------------------------------------------------------# Parameters: SubName: Type: String Description: System sub name of sample. (e.g. test) Default: test MaxLength: 10 MinLength: 1 Resources: # ------------------------------------------------------------# # S3 # ------------------------------------------------------------# S3BucketKbDatasource: Type: AWS::S3::Bucket Properties: BucketName: !Sub sample-${SubName}-kbdatasource PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true Tags: - Key: Cost Value: !Sub sample-${SubName} # ------------------------------------------------------------# # Secrets Manager for Aurora # ------------------------------------------------------------# SecretAurora: Type: AWS::SecretsManager::Secret Properties: Name: !Sub aurora-database-user-sample-${SubName} Description: !Sub Aurora database credential for sample-${SubName} GenerateSecretString: SecretStringTemplate: '{"username": "bedrock_user"}' GenerateStringKey: password PasswordLength: 28 ExcludePunctuation: true Tags: - Key: Cost Value: !Sub sample-${SubName} # ------------------------------------------------------------# # Aurora Serverless v2 PostgreSQL # ------------------------------------------------------------# AuroraDBCluster: Type: AWS::RDS::DBCluster Properties: DatabaseName: bedrockragkb DBClusterIdentifier: !Sub bedrock-rag-kb-sample-${SubName}-cluster Engine: aurora-postgresql EngineVersion: 16.2 EngineMode: provisioned DBSubnetGroupName: Fn::ImportValue: !Sub sample-${SubName}-PrivateSubnetGroupName MasterUsername: postgresql ManageMasterUserPassword: true ServerlessV2ScalingConfiguration: MinCapacity: 0.5 MaxCapacity: 2.0 EnableHttpEndpoint: true AutoMinorVersionUpgrade: true BackupRetentionPeriod: 1 CopyTagsToSnapshot: true DeletionProtection: true EngineLifecycleSupport: open-source-rds-extended-support-disabled NetworkType: IPV4 Port: 5432 PreferredBackupWindow: "15:00-18:00" PreferredMaintenanceWindow: "Sun:01:00-Sun:14:00" VpcSecurityGroupIds: - Fn::ImportValue: !Sub sample-${SubName}-AuroraSecurityGroupId Tags: - Key: Cost Value: !Sub sample-${SubName} AuroraDBInstance: Type: AWS::RDS::DBInstance Properties: Engine: aurora-postgresql DBInstanceClass: db.serverless DBClusterIdentifier: !Ref AuroraDBCluster DBInstanceIdentifier: !Sub bedrock-rag-kb-sample-${SubName} Tags: - Key: Cost Value: !Sub sample-${SubName} # ------------------------------------------------------------# # IAM Role for Bedrock KB # ------------------------------------------------------------# IAMRoleBedrockKb: Type: AWS::IAM::Role Properties: RoleName: !Sub AmazonBedrockExecutionRoleForKnowledgeBase_sample-${SubName} AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - sts:AssumeRole Principal: Service: - bedrock.amazonaws.com Condition: StringEquals: "aws:SourceAccount": !Sub ${AWS::AccountId} ArnLike: "aws:SourceArn": !Sub "arn:aws:bedrock:${AWS::Region}:${AWS::AccountId}:knowledge-base/*" Policies: - PolicyName: AmazonBedrockRDSClusterPolicyForKnowledgeBase PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - rds:DescribeDBClusters - rds-data:BatchExecuteStatement - rds-data:ExecuteStatement Resource: !GetAtt AuroraDBCluster.DBClusterArn - PolicyName: AmazonBedrockS3PolicyForKnowledgeBase PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "s3:GetObject" - "s3:ListBucket" Resource: - !GetAtt S3BucketKbDatasource.Arn - !Sub ${S3BucketKbDatasource.Arn}/* Condition: StringEquals: "aws:PrincipalAccount": !Sub ${AWS::AccountId} - PolicyName: AmazonBedrockSecretsPolicyForKnowledgeBase PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "secretsmanager:GetSecretValue" Resource: !Ref SecretAurora - PolicyName: AmazonBedrockFoundationModelPolicyForKnowledgeBase PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "bedrock:ListFoundationModels" - "bedrock:ListCustomModels" - "bedrock:RetrieveAndGenerate" Resource: "*" - Effect: Allow Action: - "bedrock:InvokeModel" Resource: - !Sub arn:aws:bedrock:${AWS::Region}::foundation-model/amazon.titan-embed-text-v1 DependsOn: - AuroraDBCluster - S3BucketKbDatasource - SecretAurora # ------------------------------------------------------------# # Output Parameters # ------------------------------------------------------------# Outputs: # S3 KbDatasourceBucketName: Value: !Ref S3BucketKbDatasource KbDatasourceBucketArn: Value: !GetAtt S3BucketKbDatasource.Arn Export: Name: !Sub sample-${SubName}-S3BucketKbDatasourceArn # Aurora AuroraDBClusterArn: Value: !GetAtt AuroraDBCluster.DBClusterArn Export: Name: !Sub sample-${SubName}-AuroraDBClusterArn AuroraDBClusterIdentifier: Value: !Ref AuroraDBCluster Export: Name: !Sub sample-${SubName}-AuroraDBClusterIdentifier AuroraAdminUserSecretArn: Value: !GetAtt AuroraDBCluster.MasterUserSecret.SecretArn AuroraBedrockUserSecretArn: Value: !Ref SecretAurora Export: Name: !Sub sample-${SubName}-SecretAurora IAMRoleBedrockKbArn: Value: !GetAtt IAMRoleBedrockKb.Arn Export: Name: !Sub sample-${SubName}-IAMRoleBedrockKbArn ベクトルデータベース構築 (手動) 上述の AWS CloudFormation テンプレートを流しただけでは、Amazon Aurora Serverless の箱だけが出来上がった状態ですので、ユーザやテーブルがありません。Agents for Amazon Bedrock の Knowledge Base として使用できるようにするため、AWS 提供の手順を実行する必要があります。 Amazon Bedrock のナレッジベースとしての Aurora PostgreSQL の使用 - Amazon Aurora Aurora PostgreSQL をナレッジベースとして使用する方法について説明します。 docs.aws.amazon.com 私は AWS マネジメントコンソールの RDS の画面から該当の Amazon Aurora Serverless のインスタンスを選択して、Data API 経由で SQL を入力しています。 SQL を実行するにあたり、Postgresql の Admin ユーザを確認する必要があります。AWS CloudFormation で Secrets Manager 内にパスワードが自動生成されていますので、それを確認しておきます。 手順内で、bedrock_user を作成しますが、そのときのパスワードも Secrets Manager 内に自動生成されていますので、そちらも確認しておきます。いずれも、一度構築してしまえばほぼほぼ今後使用することはありません。 本記事の範囲はこれで終了です。 まとめ いかがでしたでしょうか? Amazon Aurora Serverless 作成テンプレートはどこにでもある情報だと思いますが、一度できるようになると他の案件にも応用できるので便利です。 次回は Agents for Amazon Bedrock や周辺の AWS Lambda 関数のデプロイがテーマです。 本記事が皆様のお役に立てれば幸いです。 謝辞 本記事の構成作成にあたり、以下 AWS Ambassador 2 名の方のご知見が大変参考になりました。 ソニービズネットワークス 濱田様 サーバーワークス 福島様 濱田様には、以前お会いしたときに「RAG の Knowledge Base を最も安く構築するなら Aurora Serverless 一択ですよ、いろいろ検証してそれに落ち着きました」とお聞きして、私が OpenSearch から Aurora Serverless に乗り換えるきっかけになりました。 福島様には、Aurora Serverless v2 Postgresql でベクトルデータベースを構築する際の手順 (コマンド) が AWS の公式ドキュメントのままではエラーになってしまうところ、ドンピシャな回避策をブログ記事で紹介してくれていました。大変助かりました。おそらく SQL 実行時に途中でユーザを切り替えずにコマンドを実行すると権限不足のエラーになってしまうものと想像します。 濱田様には今度 AWS Ambassador コミュニティでお会いしたときに御礼を言いたいと思います。福島様にもそうしたいと思っていたのですが、AWS Ambassador をご勇退されていたことに気付き、直接御礼を言う機会がありません。この場を借りて、御礼申し上げます。 本当にありがとうございました。
アバター
今回は、Catoクラウドの機能を整理してご紹介したいと思います。 もちろん、すべての機能をブログに記載するのは難しいため、Catoクラウドに興味を持たれた方に向けて「現在のネットワークで使用している機能がCatoクラウドに移行しても使えるのか?」という視点から整理してみました。 また、CatoクラウドはSD-WANを利用しており、すべての設定はWeb管理コンソール(CMA)で行うため、オンプレミスの機器で構築されたネットワークと単純に比較することはできません。しかし、より具体的なイメージを持っていただくために、「拠点ネットワーク」「ネットワーク全体」「リモート接続」「セキュリティ」「運用」の5つのカテゴリに分類して説明します。少しでも「なるほど、Catoってこんな感じなんだ」と感じていただければ幸いです。 拠点ネットワーク編 まずはCato Socket周辺の機能です。ここでは拠点にルータを置いて回線と接続した場面を想定しています。Catoに切り替える場合はこのルータをSocketに入れ替える事になります。尚、Socketはサブスクリプションでの提供となります。 機能 対応有無 補足事項 Socketポート数 – シリーズ毎に以下のポート数(1000baseT)があります。 X1500:1GbE×4 X1600:2.5GbE×4、1GbE(RJ45/SFP)×2、10G SFP×2 X1700:1GbE×8(10Gカード別搭載) ラックマウント 〇 X1500:マウントキット別売り X1600:マウントキット別売り X1700:ラックマウントレール(標準) HA構成 〇 Act/SbyでのHA構成が可能です。lanポート同士をVRRPで制御してます。 回線冗長 〇 1台のSocketに複数回線を接続してAct/Actでの利用や、回線毎に重みづけを行い負荷分散させる事も可能です。 回線接続 〇 SocketのWAN接続は「DHCP・Static・PPPoE」の3つをサポートしています。デフォルトがDHCPなので、上位ルータからSocket wanポートのアドレスをDHCPで払い出す環境であれば完全なゼロタッチプロビジョニングが可能です。因みにSocketの上位機器がIPマスカレードでNATしている環境でも問題ありません。 ブリッジ接続 〇 wanポートとlanポートが同じセグメントでも問題ありませんが、ワンアーム接続は不可です。 IPv6回線接続 × Catoは今のところIPv6には対応していませんが、Socktの上位ルータがIPv4に変換する事でIPv6回線を使用する事は可能です。尚、最近のCatoのロードマップにはIPv6対応が追加されました。 IPsec接続 〇 Socketを使用せずオンプレルータとCatoクラウドをIPsecで接続できます。但しSocket利用時に比べると利用できる機能は制限されます。 スタティックルート 〇 LAN内の複数セグメント宛てにスタティックルート設定が可能です。 BGP 〇 LAN側のBGP機器とSocket間でBGPによるルート交換が可能です。 OSPF・RIP他 × Catoではサポートしていません。 タグ付きVLAN 〇 LAN側の接続機器と802.1QでTrunk接続が可能です。 またSocketの物理ポート毎にVLANを分けて、各L2スイッチと接続できます。 VLAN間アクセスリスト 〇 CatoのLANファイヤーウォールでセグメント間のパケットフィルタリングが可能です。その場合Socketで折り返しとなるので回線側に不要なトラフィックを流す事を回避できます。 DHCP 〇 Socket配下のPCなどにアドレスを払い出すイメージです。Socketで設定したVLAN毎にDHCPが利用できます。但し、除外設定はないので分割したアドレスレンジを設定する事はできません。 DHCPリレー 〇 問題なく使えます。 全体ネットワーク編 次にネットワーク全体の機能です。SD-WANとしてもっと細かい機能や設定は沢山あるのですが、お客様からのお問い合わせやその回答の中で話にあがる機能をピックアップしてみました。 機能 対応有無 補足事項 DNSキャッシュサーバ 〇 Catoが提供するDNSサーバがあります。このサーバを参照するのが推奨です。 社内サーバの名前解決 〇 CatoのDNSサーバのフォワーディング設定で、フォワード先に社内DNSサーバを指定する事で社内サーバの名前解決が可能となります。 固定グローバルアドレス 〇 Catoからインターネットに出ていく送信元アドレスを、お客様固有のグローバルアドレスに設定する事ができます。M365などのIPアドレスによるアクセス制限用として利用できます。尚、固定グローバルアドレスを使用しない通信は、Catoのランダムなアドレスでインターネットに出ていきます。 QoS(帯域制御) 〇 プライオリティ毎に帯域を占める割合(%)を設定し、常時その割合に制限するか?混雑時だけ制限するか?が選択できます。例えばWindows Update通信は常に帯域の10%にして業務通信に影響を与えない様にするなどの事例があります。 QoS(優先制御) 〇 プライオリティを各通信に割り当てる事で輻輳時の優先制御を設定できます。小さい値が優先度高になるので、Zoom会議はプライオリティ10、GCP宛て通信は20、通常のインターネット通信は255にしておけば、ネットワーク混雑時もWeb会議は安定して利用できます。 ルートピア 〇 これはSD-WANならではの機能ですが、インターネットへ出ていくPoPを指定する事ができます。例えばOCI東京リージョンに構築したシステムにベトナム拠点からアクセスする際、その通信の出口を東京PoPを指すればホーチミンPoPからCatoバックボーン経由で東京PoPから接続するので、低遅延で安定した通信が可能になります。 バックホーリング 〇 これもSD-WANならではの機能です。通常インターネット接続はCato PoPから出ていきますが、ある通信だけはCatoに接続しているデータセンター経由でインターネットに出したいという要件にも対応可能です。このケースはIPアドレスの問題やCato移行期間中の措置といたたケースが多いようですが、どうしてもホップ数が増えるのでパフォーマンスは落ちると思います。 NAT 〇 Catoに接続する拠点アドレスが重複する場合、サブネットごと別アドレスに変換する事ができます。 ダイレクトコネクト 〇 AWS・Azure・GCP・OCIとはCatoの「クラウド・インターコネクト」で専用接続が可能です。インターネット接続より低遅延/高帯域での通信が可能です。 ローカルブレークアウト △ いくつか方法はありますが、いずれも宛先はIPアドレス指定での設定しかできません。例としては、ドメイン指定でgoogle.comはCatoを通さないという設定は不可です。SASEのポリシーは「全ての通信をチェックする」というものなのでブレークアウトはあくまで例外設定という位置づけと思っていたのですが、最近のロードマップにはドメイン指定をサポートするという話がありました。 公開サーバ 〇 固定グローバルアドレスにアクセスしたトラフィックをNAT及びポート変換して、内部にあるサーバに転送させる事ができます。 モバイル接続編 次はモバイルアクセスです。従来のネットワークでは、データセンターにVPN装置を設置し、PCにVPNソフトをインストールして自宅や外出先から社内システムに接続する場面を想定しています。Catoの場合も同様で「Cato Client」をPCやスマートデバイスにインストールしてCatoクラウドにVPN接続します。尚、CatoではこのCato Clientで接続したユーザーを「SDPユーザー」と呼びます。 話はそれますが、これまで、オンプレミスのVPN装置を経由して社内システムに侵入され、ランサムウェアなどの被害に遭うケースが多数発生していました。その主な原因は、パッチの適用遅れや未適用です。脆弱性が発見されるとメーカーから修正パッチが配布されますが、そもそも脆弱性をチェックしていたのか?という点や、チェックをしていても、いざパッチを適用する際には業務時間外での作業となり、運用管理者に大きな負荷がかかっていたと思います。これは、クラウド利用時とは比較にならないほどの負担です。 機能 対応有無 補足事項 サイレント・インストール 〇 Cato Clientのインストールファイルをダウンロード後、コマンドの実行でインストールが可能です。グループポリシーを使用してインストールされているお客様の例があります。 インストール時の管理者権限 〇 Cato Clientのインストール時は管理者権限が必要です。その後の自動アップグレード時は必要ありません。 SDPユーザーのグルーピング 〇 部署やグループ会社毎にグルーピングし、作成したグループをファイヤーウォールやネットワークルールのオブジェクトに設定する事ができます。 アンインストール禁止 × 現状はユーザーによるアンインストールができてしまいます。「アンインストールすると結局業務ができませんよ」というスタンスのようです。ただし少し前のロードマップに「2024年中に実装予定」との内容が追加されていました。 バージョンアップ制御 〇 Cato Clientのバージョンアップはお客様の環境に合わせた制御が可能です。バージョンアップ操作を全てユーザーやらせるか、ダウンロードまで自動を行ってユーザーの都合のいいタイミングでアップデートさせるか、サイレントアップデートかを選択できます。 ユーザー割り当てアドレス 〇 SDPユーザー用のPoolアドレスレンジを設定しておき、接続にしたユーザーにはその中からアドレスを割り当てCatoに接続させます。また特定のSDPユーザーにはアドレス固定にする事も可能です。 オンプレADとのLDAP同期 〇 Catoからの到達性があるADサーバのOUやセキュリティグループのユーザー情報をCatoに取り込む事ができます。ユーザー管理はAD側で一元管理できます。 SCIMでのユーザープロビジョニング 〇 連携しているIdPサービスからユーザー情報をCatoに取り込む事ができます。ユーザー管理はIdPサービス側で一元管理が可能です。 シングルサインオン 〇 現在は計6つのIdpと連携しシングルサインオンが可能です。 ユーザー識別 〇 AD及びEntra IDとユーザー同期している場合、Catoの中でもユーザー名で識別が可能です。ログ上IPアドレスだけの表示だと誰なのか?確認するのが手間ですが、ユーザー名で表示されるので一目でどのユーザーがどんな通信をしているのかが判別できます。 デバイス証明書認証 〇 お客様で発行されたルートCA証明書をCatoクラウドにアップロードし、SDPユーザー端末にデバイス証明書を配布しておけば、証明書によるデバイス認証が可能となります。 デバイスポスチャ 〇 SDPユーザー端末の環境やステータスをチェックしてCatoへの接続を制限します。例えば会社指定のアンチウィルスソフトのバージョンいくつ以上が入っていて、且つデバイス証明書が入っている端末はCato接続を許可するといった事ができるので、BYOD利用の制限が可能となります。 スプリット・トンネル 〇 特定の宛先IPアドレスや送信元IPアドレスはCatoトンネルから除外する設定です。SDPユーザー端末からCatoに接続してない複合機を利用する場合など、複合機のIPアドレスを除外する事で利用が可能となります。 IPv6接続 〇 2024年8月に対応が可能になりましたが、利用するISPに条件があるようです。 セキュリティ編 次にセキュリティです。これまでも、データセンターに各種オンプレミス機器を積み重ねたり、各セキュリティサービスを契約することで、一通りのセキュリティ機能を実装することは可能でした。しかし、各機器やサービスはそれぞれ独自の仕様であり、ユーザーインターフェースも異なるため、各機能を習得するのが大変です。また、メーカーが異なるため、問い合わせも保守更新もそれぞれ別々に行わなければなりませんでした。Catoでは、必要なセキュリティライセンスを購入していただければ、あとは管理コンソール(CMA)で設定を行うだけで済みます。さらに、各セキュリティオプションのログもすべてCMAで確認できるため、運用管理にかかる工数を大幅に削減できるでしょう。 機能 対応有無 補足事項 インターネット・ファイヤーウォール 〇 インターネット通信を制御するファイヤーウォールです。レイヤ7でのフィルタリングが可能です。 URLフィルタリング 〇 インターネット・ファイヤーウォールで対応しています。他製品やサービスと同様、通信禁止になりそうなジャンルのカテゴリが用意されており、カテゴリ単位でブロック・プロンプト・許可が設定できます。またいつくかのカテゴリはデフォルトでブロック設定がされています。 WANファイヤーウォール 〇 Catoクラウド内の拠点間通信やSDPユーザー~拠点間通信用を制御します。 LANファイヤーウォール 〇 前述の「拠点ネットワーク編」に記載した「VLAN間アクセスリスト」です。 TLSインスペクション 〇 インターネットのHTTPSの暗号化通信を、復号化>セキュリティチェック>再暗号化する機能です。これを有効にしないと以降のセキュリティは機能しません。またこの動作を行うためにCatoに接続する各デバイスにはCatoの証明書をインストールする必要があります。インストールできないデバイスやTLSインスペクションで通信が阻害されるサイトはBypassで逃がす事になります。 アンチマルウェア 〇 シグネチャベースのアンチマルウェア機能です。 Threat Preventionというオプションライセンスが必要です。 ネクストジェネレーション・アンチマルウェア(NGAM) 〇 機械学習を用いた次世代のアンチマルウェア機能です。 Threat Preventionというオプションライセンスが必要です。 IPS 〇 所謂IPS機能です。 Threat Preventionというオプションライセンスが必要です。 コンテンツ制限 〇 本機能を有効にすると、インターネット検索エンジンと YouTube のコンテンツ検索時に適切なセーフサーチ設定が適用され、露骨な表現を含む結果がすべて削除されます。 CASB 〇 ユーザーのSaaSやアプリケーション利用を可視化し制御できます。シャドウIT対策もCASBの領域です。また「政府機関等の対策基準策定のためのガイドライン(令和5年度版)」にもCASB導入が推奨されており、今後はスタンダードなセキュリティ機能になるのではと考えられます。 CASBのオプションライセンスが必要です。 DNSプロテクション 〇 DNSで名前解決する時点で疑わしいドメインや公開されて日の浅いドメインをブロックする機能です。 CASBのオプションライセンスが必要です。 DLP 〇 機密情報や重要データの紛失や情報漏洩を防ぐ機能です。「Confidential」の文字が入ったファイルやマイナンバー情報のアップロードをブロックします。 CASBおよびDLPのオプションライセンスが必要です。 RBI 〇 Webブラウザの分離機能です。本機能を有効にすると疑わしいサイトへのアクセス時にはCatoのブラウザが代理アクセスして、お客様のPCへの感染ファイルのダウンロードを防ぐ事ができます。 RBIのオプションライセンスが必要です。 Sandbox × 隔離された環境で危険性のあるソフトウェアの実行し、実環境には影響を及ぼさないような機能はサポートしていません。 SaaS Security API 〇 ユーザーがCatoを経由せず直接アクセスするクラウドでの操作を監視し、設定したルールの違反状況などを可視化する事ができます。 SaaS Security APIのオプションライセンスが必要です。 Endpoint Protection Platform (EPP) 〇 所謂EPPでマルウェアの検出と駆除を行います。最大の特徴はEPPが検知するログもCatoコンソールで管理され、他のセキュリティ機能で検知したログを合わせて総合的な分析ができる点です。この分析とレポートは後述するXDRの機能となります。EPPのオプションライセンスが必要です。 Endpoint Detection and Response (EDR) × EDRは提供していません。但しその他セキュリティ機能(FirewallやNGAM、IPSなど)との組み合わせによるXDRの提供でよりトータルな分析・追跡を行っています。 XDR 〇 Cato上の様々なログを統合し総合的に分析したインシデント情報を提供します。インシデントは重要度でスコアリングがされますので、クリティカルなものを検知(通知も可能!)したら対応を行い、対応が済めばクローズしていくといサイクルで運用する事が可能になります。インシデントはドリルダウンしていくと発生要因や対策が提示されます。またXDRにはThreat Preventionのログの対象としたXDR Core(無償)と、イベントとトラフィックログにもとづく攻撃、通常とは違う振る舞いの検出を加えたXDR Proの2つがあります。 運用編 最後に運用編なのですが、こはシンプルな表にまとめるのが難しいため、内容をかなり省略させていただきました。Catoの料金体系は「接続帯域ライセンス」「Socket台数」「SDPユーザーライセンス数」「オプションライセンス」で構成されていますが、通知機能や通信の可視化、脅威分析などの多彩な運用機能は、すべて各ライセンス料金に含まれているため、非常にお得感があるのではないでしょうか。また、ログの形式や検索機能も見やすいとお客様に好評であり、Catoの導入により、運用レベルの向上と対応工数の削減が見込まれると思います。 機能 対応有無 補足事項 管理コンソールの日本語表示 〇 英語・日本語含め、2024年8月現在では11の言語に切り替えが可能です。 アラート通知 〇 EmailやWebhook、Slackに通知先を指定しておけば、各種システム通知・Socketの切断・セキュリティブロック通知などが可能です。 通信状況モニタリング 〇 ネットワークレイヤの状況はもちろん、利用アプリの状況、個々の通信の詳細から俯瞰的な視点から見た全体の傾向、各セキュリティ機能の活動状況、脅威ダッシュボードでの分析結果など、さまざまな角度から必要十分な情報を得ることができます。 SaaS・アプリケーションのスコアリング 〇 通信先となるSaaS・アプリケーションはCato独自のスコアリングがされており、お客様の利用状況とセキュリティ診断結果を常に確認できます。 監査ログの保存 〇 Catoコンソールの操作ログが保持されています。 自動設定チェック 〇 お客様が行うネットワーク設定やセキュリティ設定について、ベストプラクティスとのGAPを提示してくれます。多くの機能を使用すれば設定量も増え管理が大変ですが、本機能を活用する事で一定水準の品質が保たれるかと思います。 障害・メンテナンス情報の公開 〇 Catoが提供するWebサイトにて全世界のPoPの障害情報・メンテナンス情報を確認する事ができます。また日本のPoPに関する情報をEmailやWebhook、Slackなどで受信する事も可能です。 ログの外部保存 〇 APIによりCatoのログを外部ストレージなどに転送・保存する事が可能です。但しCatoの管理コンソールに戻す事はできません。 Catoサポートへの問い合わせ 〇 英語にはなりますが、Catoサポートに直接問い合わせする事が可能です。尚、SCSKではこれを日本語で受付け問い合わせ代行するサービスをご提供しています。 さいごに Catoは新しい機能やより利便性の高い機能が日々リリースされています。今回一旦まとめはしたものの、この先仕様が変わったりする可能性は大いにあり得ますので、正確な情報はCatoナレッジサイトでご確認いただくかお問い合わせいただくようお願いします。
アバター
本記事は 夏休みクラウド自由研究 8/20付の記事です 。 こんにちは、SCSK池宮です。 今年7月から、Visual Studioでも利用ができるようになったAmazon Q Developerはどんな機能があるのか…今回は色々な機能を試してみました。 Visual Studio IDE で Amazon Q Developer の一般提供開始 (GA) - AWS AWS の新機能についてさらに詳しく知るには、 Visual Studio IDE で Amazon Q Developer の一般提供開始 (GA) aws.amazon.com Amazon Q Developerとは? AWSの生成AIアシスタントサービスの総称であるAmazon Qですが、中でもQ Developerは開発者向けに特化したサービスです。 AI コーディングアシスタント - Amazon Q Developer - AWS Amazon Q Developer は、AWS Well-Architected フレームワークのパターン、ベストプラクティス、ドキュメント、ソリューション実装に関するエキスパートです。これを利用することで、新しいサービスや機能の探索、な... aws.amazon.com 開発者がコーディングをする際のアシスタントを担ってくれるため、生産性の向上が期待できます。 今回は、コード提案をしてくれる前身サービス「Amazon CodeWhisperer」 から追加された機能を中心に見ていきたいと思います。 チャット機能を使ってみる Amazon Q Developerでは、統合開発環境(IDE)上でのチャット機能が追加されています。 (今回はVisual Studio Code(VSCode)上で試していきます!) VS Codeを立ち上げ、左側にある「Amazon Q」アイコンをクリックします。 右側にチャット画面が出てきました。ここでAmazon Qとやり取りができるようになります。 コード生成してもらおう! このチャット欄に「変数Aと変数Bの合計を計算するコードを生成してください」と送ります。(現在チャット機能は英語のみ対応しています)   回答が返ってきました。 Pythonのコードとアウトプット、そしてどのようなコードなのかという説明を返してくれました。 Python以外の場合として、JavaScriptのコードも回答してくれています。(赤線部分) コードの説明をしてもらおう! 次に、Q DeveloperのExplainの機能を試してみます。 以下のような「Redshiftテーブルを作成し、S3 バケットから CSV データをテーブルにコピーする」コードを用意して、読み取ってもらいます。 #Connect to the cluster and create a Cursor >>> import redshift_connector >>> with redshift_connector.connect(...) as conn: >>> with conn.cursor() as cursor: #Create an empty table >>> cursor.execute("create table category (catid int, cargroup varchar, catname varchar, catdesc varchar)") #Use COPY to copy the contents of the S3 bucket into the empty table >>> cursor.execute("copy category from 's3://testing/category_csv.txt' iam_role 'arn:aws:iam::123:role/RedshiftCopyUnload' csv;") ※以下ページを参考にしています。 Amazon Redshift Python コネクタの使用例 - Amazon Redshift Amazon Redshift Python コネクタの使用例をご覧ください。 docs.aws.amazon.com コード全体を選択し、右クリックで「Explain」を選択します。 すると、コードの説明が返ってきました。 内容も「このコードは Amazon Redshift クラスターに接続し、新しいテーブルを作成し、Amazon S3 バケットに保存されている CSV ファイルからそのテーブルにデータを入力します。」と、きちんと中身を読み取って回答を生成していることが分かります。 コードを改善してもらおう! 最後に、コードをリファクタリングしてくれる機能を試してみます。 別の生成AIに「変数Aと変数Bの合計を計算するコード」を複雑に変換してもらいました。(本当に無駄が多い!) # 変数Aと変数Bを定義 A = 5 B = 10 # 無駄な変数を大量に使って中間処理を行う temp1 = A temp2 = B temp3 = temp1 temp4 = temp2 # 足し算をする前にさらに無駄な代入を行う step1 = temp3 + 0 step2 = temp4 + 0 # 不要な計算を追加 dummy_calculation1 = step1 * 1 dummy_calculation2 = step2 * 1 # 何度も再代入を行う intermediate_result = dummy_calculation1 intermediate_result2 = dummy_calculation2 # 無駄なリストを作成して値を追加 useless_list = [] useless_list.append(intermediate_result) useless_list.append(intermediate_result2) # 和の代わりにリストから値を取り出して計算 useless_var1 = useless_list[0] useless_var2 = useless_list[1] final_result = useless_var1 + useless_var2 # 再度無駄に別の変数に代入 output_result = final_result # 結果を出力 print("変数Aと変数Bの和は:", output_result) このコードを選択し、Amazon Q機能の「Refactor」をクリックします。 こちらも返答が返ってきました。 コードを簡潔に直したものが載っています。さらに、「元のコードには不要な変数の割り当て、冗長な計算、不要なリストの作成が多数あったため削除した」というような補足まで返してくれました。 このように、Amazon Q Developer では様々な「開発者にとって痒い所に手が届く機能」が追加されていることが分かりました。 現時点、チャットは英語対応のみですが、日本語利用もできるようになる日が待ち遠しいですね! 最後までお読みいただきありがとうございました。
アバター
本記事は 夏休みクラウド自由研究 8/19付の記事です 。 残暑お見舞い申し上げます。 立秋とはいえ、連日の猛暑にいささか参っておりますが、皆様いかがお過ごしでしょうか。Masedatiです。 この記事は「 夏休みクラウド自由研究 」の一環として投稿しています。自由研究は小学生ぶりです。 ちなみに小学生のときの自由研究のテーマは「トルコアイスの仕組みと作り方」でした。 突然ですがヒエログリフをご存じでしょうか。ヒエログリフとは古代エジプトの象形文字のことで、 𓀁 ←こんなものです。 これには「eat, drink, speak, think」等の意味があるとのこと。ここから現在の文字に進化するのですから、人類ってすごい。 アイスを食べながら、ふと思いました。ヒエログリフの画像をFine-tuningしたら、存在しないヒエログリフをそれっぽく生成してくれるのではないかと。現在の文字(プロンプト)から象形文字を生成するので逆進化です。 今回、「 Amazon BedrockのFine-tuningでヒエログリフを創作する 」をテーマとして自由研究を行いたいと思います。 実は執筆時点でまだ試していないので、成功するのか失敗するのかわかりません。 でもやってみた結果、失敗でもいいのではないかなと思いました。それもまた自由研究だと思うので。 前提 以下でFine-tuningを実施しました。 リージョン:オレゴン モデル:Amazon Titan Image Generator G1 公式ドキュメントに沿ってFine-tuningを行います。 カスタムモデル - Amazon Bedrock モデルをカスタマイズして、特定のタスクや特定のドメインでの機能やパフォーマンスを向上させる方法について説明します。 docs.aws.amazon.com 手順 データセットの準備 Text-to-imageでは以下のJSONL形式でデータを準備する必要があります。 {"image-ref": "s3://bucket/path/to/image001.png", "caption": "<prompt text>"} {"image-ref": "s3://bucket/path/to/image002.png", "caption": "<prompt text>"} {"image-ref": "s3://bucket/path/to/image003.png", "caption": "<prompt text>"} S3にPNGもしくはJPEG画像を格納し、その画像のプロンプト(英語のみ)を記述します。 今回以下のように画像(512×512)をS3に格納し、プロンプトとしてそのキャプションを記載しました。 {"image-ref": "s3://bucket/image-train-data/ ", "caption": "Hieroglyphics of a man eating"} ※イメージです。 訓練データ一覧 以下のヒエログリフ50個を訓練データ(traindata.jsonl)として用意しました。 ランダムで人・体の部位・動物・物体のヒエログリフをピックアップしています。 {"image-ref": "s3://bucket/image-train-data/ 𓀁 ", "caption": "Hieroglyphics of a man eating"} {"image-ref": "s3://bucket/image-train-data/ 𓀌 ", "caption": "Hieroglyph of a seated man with an oar"} {"image-ref": "s3://bucket/image-train-data/ 𓀠 ", "caption": "Hieroglyph of a man with his hands raised"} {"image-ref": "s3://bucket/image-train-data/ 𓀥 ", "caption": "Hieroglyph of one man dancing"} {"image-ref": "s3://bucket/image-train-data/ 𓀫 ", "caption": "Hieroglyph of the man with the leopard's head"} {"image-ref": "s3://bucket/image-train-data/ 𓀿 ", "caption": "Hieroglyph on a reclining mummy"} {"image-ref": "s3://bucket/image-train-data/ 𓀬 ", "caption": "Hieroglyph of a man riding two giraffes"} {"image-ref": "s3://bucket/image-train-data/ 𓁃 ", "caption": "Hieroglyph of a man hoeing"} {"image-ref": "s3://bucket/image-train-data/ 𓁏 ", "caption": "Hieroglyph of a seated man with arms raised"} {"image-ref": "s3://bucket/image-train-data/ 𓁍 ", "caption": "Hieroglyph of a man holding a knife"} {"image-ref": "s3://bucket/image-train-data/ 𓁐 ", "caption": "Hieroglyph of a seated woman"} {"image-ref": "s3://bucket/image-train-data/ 𓁶 ", "caption": "Hieroglyph of head"} {"image-ref": "s3://bucket/image-train-data/ 𓁷 ", "caption": "Hieroglyph of face"} {"image-ref": "s3://bucket/image-train-data/ 𓁸 ", "caption": "Hieroglyph of hair"} {"image-ref": "s3://bucket/image-train-data/ 𓁹 ", "caption": "Hieroglyph of eye"} {"image-ref": "s3://bucket/image-train-data/ 𓁿 ", "caption": "Hieroglyph of eye with flowing tears"} {"image-ref": "s3://bucket/image-train-data/ 𓂂 ", "caption": "Hieroglyph of pupillary"} {"image-ref": "s3://bucket/image-train-data/ 𓂃 ", "caption": "Hieroglyph of eyebrow"} {"image-ref": "s3://bucket/image-train-data/ 𓂈 ", "caption": "Hieroglyph of ear"} {"image-ref": "s3://bucket/image-train-data/ 𓂋 ", "caption": "Hieroglyph of mouth"} {"image-ref": "s3://bucket/image-train-data/ 𓂎 ", "caption": "Hieroglyph of on upper lip with teeth"} {"image-ref": "s3://bucket/image-train-data/ 𓂧 ", "caption": "Hieroglyph of hand"} {"image-ref": "s3://bucket/image-train-data/ 𓂬 ", "caption": "Hieroglyph of fist"} {"image-ref": "s3://bucket/image-train-data/ 𓂭 ", "caption": "Hieroglyph of one finger"} {"image-ref": "s3://bucket/image-train-data/ 𓂮 ", "caption": "Hieroglyph of two finger"} {"image-ref": "s3://bucket/image-train-data/ 𓂯 ", "caption": "Hieroglyph of three finger"} {"image-ref": "s3://bucket/image-train-data/ 𓂰 ", "caption": "Hieroglyph of four finger"} {"image-ref": "s3://bucket/image-train-data/ 𓂱 ", "caption": "Hieroglyph of five finger"} {"image-ref": "s3://bucket/image-train-data/ 𓂲 ", "caption": "Hieroglyph of six finger"} {"image-ref": "s3://bucket/image-train-data/ 𓂳 ", "caption": "Hieroglyph of seven finger"} {"image-ref": "s3://bucket/image-train-data/ 𓂴 ", "caption": "Hieroglyph of eight finger"} {"image-ref": "s3://bucket/image-train-data/ 𓂵 ", "caption": "Hieroglyph of nine finger"} {"image-ref": "s3://bucket/image-train-data/ 𓂾 ", "caption": "Hieroglyph of leg"} {"image-ref": "s3://bucket/image-train-data/ 𓃀 ", "caption": "Hieroglyph of foot"} {"image-ref": "s3://bucket/image-train-data/ 𓃒 ", "caption": "Hieroglyph of bull"} {"image-ref": "s3://bucket/image-train-data/ 𓃟 ", "caption": "Hieroglyph of pig"} {"image-ref": "s3://bucket/image-train-data/ 𓃠 ", "caption": "Hieroglyph of cat"} {"image-ref": "s3://bucket/image-train-data/ 𓃡 ", "caption": "Hieroglyph of dog"} {"image-ref": "s3://bucket/image-train-data/ 𓃬 ", "caption": "Hieroglyph of lion"} {"image-ref": "s3://bucket/image-train-data/ 𓅓 ", "caption": "Hieroglyph of owl"} {"image-ref": "s3://bucket/image-train-data/ 𓆛 ", "caption": "Hieroglyph of tilapia"} {"image-ref": "s3://bucket/image-train-data/ 𓆤 ", "caption": "Hieroglyph of bee"} {"image-ref": "s3://bucket/image-train-data/ 𓆭 ", "caption": "Hieroglyph of tree"} {"image-ref": "s3://bucket/image-train-data/ 𓇯 ", "caption": "Hieroglyph of sky"} {"image-ref": "s3://bucket/image-train-data/ 𓇳 ", "caption": "Hieroglyph of sun"} {"image-ref": "s3://bucket/image-train-data/ 𓇼 ", "caption": "Hieroglyph of star"} {"image-ref": "s3://bucket/image-train-data/ 𓇿 ", "caption": "Hieroglyph of land"} {"image-ref": "s3://bucket/image-train-data/ 𓈌 ", "caption": "Hieroglyph of sun over mountain"} {"image-ref": "s3://bucket/image-train-data/ 𓉐 ", "caption": "Hieroglyph of house"} {"image-ref": "s3://bucket/image-train-data/ 𓏌 ", "caption": "Hieroglyph of pot"} S3の構成は以下のとおりです。 bucket ┣image-train-data ┃ ┣image001.png ┃ ┣image002.png ┃ ┣ ︙ ┃ ┗image050.png ┣traindata.jsonl ┗output-bucket 学習終了後、Fine-tuning中の推移データが出力されるので、「output-bucket」を用意してあげます。 (需要が謎ですが、おまけとしてヒエログリフ文字を画像に変換するコードを置いておきます。) from PIL import Image, ImageDraw, ImageFont import os def text_to_images(text, base_file_path, folder_path="train_data", image_size=(512, 512), font_size=300):   # フォントの設定   try:       font = ImageFont.truetype("NotoSansEgyptianHieroglyphs-Regular.ttf", font_size)  # Noto Sansフォントファイルを使用   except IOError:       font = ImageFont.load_default()   # フォルダが存在しない場合、作成   if not os.path.exists(folder_path):         os.makedirs(folder_path)   # 各文字ごとに画像を作成して保存   for i, char in enumerate(text):       # 画像を作成       image = Image.new('RGB', image_size, color=(255, 255, 255))       draw = ImageDraw.Draw(image)       # 文字のバウンディングボックスを測定       text_bbox = draw.textbbox((0, 0), char, font=font)         textwidth, textheight = text_bbox[2] - text_bbox[0], text_bbox[3] - text_bbox[1]       # 文字を中央に配置       x = (image_size[0] - textwidth) // 2         y = (image_size[1] - textheight) // 8       # 画像に文字を書き込む         draw.text((x, y), char, font=font, fill=(0, 0, 0))       # 画像を保存       file_path = os.path.join(folder_path, f"{base_file_path}{i + 1}.png")       image.save(file_path)         print(f"{file_path}に画像を保存しました。") # 文字入力例 text = "𓀁𓀌𓀠𓀥𓀫𓀿𓀬𓁃𓁏𓁍𓁐𓁶𓁷𓁸𓁹𓁿𓂂𓂃𓂈𓂋𓂎𓂧𓂬𓂭𓂮𓂯𓂰𓂱𓂲𓂳𓂴𓂵𓂾𓃀𓃒𓃟𓃠𓃡𓃬𓅓𓆛𓆤𓆭𓇯𓇳𓇼𓇿𓈌𓉐𓏌" base_file_path = "image"  # 連番の基本ファイル名 text_to_images(text, base_file_path) Fine-tuning 以下でFine-tuningを行いました。手順詳細については公式ドキュメントをご参照ください。 入力データ s3://bucket/traindata.jsonl ハイパーパラメータ(デフォルト値) ステップ:自動 エポック:5 バッチサイズ:8 学習率:0.00001 出力データ s3://bucket/output-bucket/ パラメータの値についてはガイドラインが掲載されています。 モデルカスタマイズに関するガイドライン - Amazon Bedrock モデルをカスタマイズする理想的なパラメータは、データセットと、モデルが対象とするタスクによって異なります。値をいろいろ試して、どのパラメータがお客様自身のケースで最も適切に機能するかを確認する必要があります。参考までに、モデル評価ジョブを実... docs.aws.amazon.com 結果 学習は 約 4 時間 で終了しました。この4時間、学習経過を確認できないのはムズムズしますね… リアルタイムで推移を観測できれば、Fine-tuningを途中でストップしたり、パラメータを調整できたりと便利なのですが。 学習がおわるとoutput-bucketに「training_artifacts/step_wise_training_metrics.csv」が格納されます。 格納された学習推移データをグラフ化したものは以下です。 ※こう見えて折れ線グラフです。 学習ステップをAutoにしたせいで、8000回も学習してしまっています。画像数が多くなると学習回数も増えます。 学習がうまくいっているのかの判別は、簡単に言えばtraining_lossがきれいに収束すればいいのですが、収束しているように見えませんね… 雲行きが怪しくなってきました。 では、さっそくFine-tuned modelを購入してモデルを使用してみます。 と思い、プレイグランドでいつものようにプロンプトを入力したところ以下のように怒られてしまいました。 Malformed input request, please reformat your input and try again. ドキュメントを確認しましたが、解決法がわからず…仕方ないので、Lambdaで実行します。 Lambdaでの実行方法は以下を参考にさせていただきました。ありがとうございます! Amazon Titan Image Generator G1 を AWS Lambda から試してみた Amazon Titan Image Generator G1 を AWS Lambda から実行するときの手順を紹介します。 blog.usize-tech.com 2024.02.14 参考ブログではmodelIdとして”amazon.titan-image-generator-v1″を指定していますが、 Fine-tuned modelではプロビジョンドスループット購入後のARNを指定します。 データセットに存在するプロンプト まずは、データセットに存在するプロンプトの出力を確認します。 プロンプトに「 Hieroglyph of a man eating 」を入力しました。 上:Original model 下:Fine-tuned model まさかFine-tuned modelもカラーで出力されるとは思いませんでした。もとのmodelの影響を受けているのでしょう。 Fine-tuned modelでは、元データ「 𓀁 」に近いものが出力されることがわかります。絵柄はFine-tuningで変えることができるようです。 色々と他のものも試していくうちにうまく学習できるものと、できていないものがあることに気が付きました。 以下の「 Hieroglyph of star 」が失敗例です。 上:Original model 下:Fine-tuned model 他の学習データと比べて「 𓇼 」のヒエログリフ自体が異質なことが原因と考えられます。 データセットに存在するプロンプトを複数組み合わせる 次に、データセットに存在するプロンプトを複数組み合わせてみます。 プロンプトに「 Hieroglyph of a man eating a pig 」を入力しました。 上:Original model 下:Fine-tuned model データセットに存在する「Hieroglyph of a man eating」 𓀁 +「Hieroglyph of pig」 𓃟 が一緒に出力されました。 pigと戯れている男性にしか見えませんが、許しましょう。象形文字ですから。 データセットのpigは左向きですが、右向きにいい感じに修正してくれています。そっぽ向いてると寂しいですもの。 では数の概念は学んでいるのでしょうか?データセットには1~9本の指の画像が存在しています。 「 Hieroglyph of five pots 」を入力してみます。 _人人人人人人_ >  6個  <  ̄Y^Y^Y^Y^Y ̄ データセットに存在しないプロンプト 最後にデータセットに存在しないプロンプトを入力します。 古代エジプトになかったであろう「エレキギター」を入力してみます。 上:Original model 下:Fine-tuned model エレキギターですね。こんなものが出土したらビックリです。 う~ん、データセットに存在しないものは全く変化ありませんでした。もう少し抽象的なものになるかと期待していました。 どうすれば期待した結果を得ることができるのでしょう…? 皆様のご意見お待ちしております。 まとめ step_wise_training_metricsのグラフを見た時はどうなるかと思いましたが、一部うまく学習してくれてよかったです。 たまにtrain_lossが跳ね上がるのは、データ量が少ないのか、質が悪いのか、パラメータが悪いのか考えられる原因は多いですが、まだまだ実験が必要ですね。 余力と予算があれば、またチャレンジしたいと思います。 感想 これで夏休みの宿題は終わりです。これからBBQに行ってきます。
アバター
本記事は 夏休みクラウド自由研究 8/18付の記事です 。 こんにちは。SCSKのふくちーぬです。 2024/7/11に Amazon ECS のアップデートが発表されました。今回は、Amazon ECS においてローリングアップデート時のソフトウェアの一貫性が保証されるようになりましたので紹介します。 Amazon ECS でコンテナ化されたアプリケーションにソフトウェアバージョンの一貫性が強制されるようになりました 以前まではECSにおいてlatestタグを利用していた場合、latestタグの更新・タスクのスケールアウトのタイミング次第で、latestタグが参照するコンテナイメージが異なるため、サービス内でコンテンツが異なるタスクがデプロイされてしまう事象が発生していました。 Amazon ECS でコンテナ化されたアプリケーションにソフトウェアバージョンの一貫性が強制されるように - AWS AWS の新機能についてさらに詳しく知るには、 Amazon ECS でコンテナ化されたアプリケーションにソフトウェアバージョンの一貫性が強制されるように aws.amazon.com 2024/7/11のアップデートにより、イメージタグが更新された場合において、サービス内のすべてのタスクが同一であることを保証し、ユーザーに一貫性のあるアプリケーションを提供することが可能です。 以前までのデプロイ方式 実際にどのようなデプロイ方式であったか説明します。 以前の方式では、各タスク内でその都度コンテナイメージタグのイメージダイジェスト解決をしていました。 そのため、例えば以下のようなシナリオにおいてスケールアウトのタイミングでコンテンツが異なるタスクがユーザーに公開される可能性があります。 ①タスク定義内のlatestタグに従い,2つのタスクが起動 ②開発者がlatestタグを更新(latestタグを新しいコンテナイメージへ参照先を変更する) ③タスクのスケールアウトが発生し,タスク定義内のlatestタグに従い,1つのタスクが新規起動 このように、サービス内でタスク間で異なるイメージダイジェストを参照することで、意図しないWebコンテンツの公開が行われてしまいます。 Announcing software version consistency for Amazon ECS services | Amazon Web Services Introduction Container image tags offer a user-friendly way to manage and keep track of different versions of container ... aws.amazon.com 最新のデプロイ方式 最新のデプロイ方式では、一連のデプロイメントにおいて、ECSサービス内でコンテナイメージタグがイメージダイジェストに解決されて保存されます。よって、同じタスクをユーザーに公開することが可能になりました。 先程と同様のシナリオで違いをみてみます。 ①タスク定義内のlatestタグに従い,2つのタスクが起動 ②開発者がlatestタグを更新(latestタグを新しいコンテナイメージへ参照先を変更する) ③タスクのスケールアウトが発生し,タスク定義内のlatestタグに従い,1つのタスクが新規起動 Announcing software version consistency for Amazon ECS services | Amazon Web Services Introduction Container image tags offer a user-friendly way to manage and keep track of different versions of container ... aws.amazon.com 検証 今回のアップデートを早速検証してみます。イメージダイジェストに基づいてタスクが起動し、一連のデプロイでタスク間で同一のイメージダイジェストを参照していることを確認することがゴールとなります。 事前準備 VPC、サブネット、ルートテーブル、インターネットゲートウェイ、ネットワークACL、ECRが作成済みであることを確認してください。 ECRへコンテナイメージをpush nginx-helloリポジトリにイメージをpushします。 下記のdockerfileを利用して、コンテナイメージを作成します。 # ベースイメージとしてnginxの公式イメージを使用 FROM nginx:latest # "Hello, world!" を返すHTMLファイルを作成 RUN echo "Hello, world!" > /usr/share/nginx/html/index.html #80番ポートで公開 EXPOSE 80  Cloud9やCloudShell等のdockerインストール済みのサーバを用意して、上記のdockerfileをビルドします。 サーバのIAMロールには、下記の権限を付与しておいてください。 ・arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser docker build . -t <AWSアカウントId>.dkr.ecr.ap-northeast-1.amazonaws.com/nginx-hello:latest ECRへログインした後に、ECRのリポジトリにコンテナイメージをpushします。 aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin <AWSアカウントId>.dkr.ecr.ap-northeast-1.amazonaws.com docker push <AWSアカウントId>.dkr.ecr.ap-northeast-1.amazonaws.com/nginx-hello:latest 以下のように、ECRのリポジトリ内にコンテナイメージが1つ格納されます。 CloudFormationテンプレート 以下のテンプレートを使用して、デプロイします。 AWSTemplateFormatVersion: 2010-09-09 # --------------------------------- # パラメータ # --------------------------------- Parameters: Env: Type: String VpcId: Type: String PublicSubnetA: Type: String PublicSubnetC: Type: String MyIp: Type: String Resources: # ================================ # ECS (Cluster) # ================================ ECSCluster: Type: "AWS::ECS::Cluster" Properties: ClusterName: !Sub "ECS-${Env}-helloworld-cluster" ServiceConnectDefaults: Namespace: !Sub "ECS-${Env}-helloworld-cluster" CapacityProviders: - FARGATE # ================================ # ECS (Task Difinition) # ================================ ECSTaskDefinition: Type: "AWS::ECS::TaskDefinition" UpdateReplacePolicy: Retain Properties: Cpu: 256 ExecutionRoleArn: !Sub "arn:aws:iam::${AWS::AccountId}:role/ecsTaskExecutionRole" Family: !Sub "ECS-${Env}-helloworld-taskdef" Memory: 512 NetworkMode: awsvpc RequiresCompatibilities: - FARGATE ContainerDefinitions: - Name: helloworld Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/nginx-hello:latest" LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Sub "/ecs/ECS-${Env}-helloworld-service" awslogs-region: !Ref AWS::Region awslogs-stream-prefix: latest PortMappings: - AppProtocol: http HostPort: 80 Protocol: tcp ContainerPort: 80 Name: helloworld-8080-tcp ReadonlyRootFilesystem: false RuntimePlatform: CpuArchitecture: X86_64 OperatingSystemFamily: LINUX # ------------------------------------------------------------# # Security Group # ------------------------------------------------------------# ECSServiceSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: ecs security group VpcId: !Ref VpcId SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: !Ref MyIp SecurityGroupEgress: - IpProtocol: -1 FromPort: -1 ToPort: -1 CidrIp: "0.0.0.0/0" # ------------------------------------------------------------# # ECS Service # ------------------------------------------------------------# ECSService: Type: AWS::ECS::Service Properties: Cluster: !Ref ECSCluster DesiredCount: 2 DeploymentConfiguration: DeploymentCircuitBreaker: Enable: TRUE Rollback: TRUE MaximumPercent: 200 MinimumHealthyPercent: 100 DeploymentController: Type: ECS LaunchType: FARGATE NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED SecurityGroups: - !Ref ECSServiceSecurityGroup Subnets: - !Ref PublicSubnetA - !Ref PublicSubnetC PlatformVersion: 1.4.0 ServiceName: !Sub "ECS-${Env}-helloworld-service" TaskDefinition: !Ref ECSTaskDefinition # ------------------------------------------------------------# # ECS LogGroup # ------------------------------------------------------------# ECSLogGroup: Type: "AWS::Logs::LogGroup" Properties: LogGroupName: !Sub "/ecs/ECS-${Env}-helloworld-service"   Webサーバのコンテンツを確認 デプロイ済みのタスクのパブリックIPアドレスにアクセスして、コンテンツを確認します。 2つのコンテナどちらも”Hello, world!”が表示されます。 ECRへコンテナイメージを再push 下記のdockerfileを利用して、コンテナイメージを作成します。 # ベースイメージとしてnginxの公式イメージを使用 FROM nginx:latest # "Hello, world! Welcome" を返すHTMLファイルを作成 RUN echo "Hello, world! Welcome" > /usr/share/nginx/html/index.html #80番ポートで公開 EXPOSE 80  上記のdockerfileをビルドします。 docker build . -t <AWSアカウントId>.dkr.ecr.ap-northeast-1.amazonaws.com/nginx-hello:latest </awsアカウントid> ECRのリポジトリにコンテナイメージをpushします。 docker push <AWSアカウントId>.dkr.ecr.ap-northeast-1.amazonaws.com/nginx-hello:latest </awsアカウントid> 以下のように、ECRのリポジトリ内のlatestタグの参照先が更新されます。 タスクの再起動 今回は検証目的のため、タスクを手動停止することで新規タスクを起動させます。もしAuto Scalingが設定されていれば、スケールアウトでも同様に新規タスクを起動させることができます。 タスクを1つ選択後に、「選択されたものを停止」を押下します。 「停止」を押下します。 すぐにタスクが停止され、新規タスクの再起動が始まります。 Webサーバのコンテンツを再確認 新規に起動したタスクのパブリックIPアドレスにアクセスして、コンテンツを確認します。 こちらも”Hello, world!”が表示されます。コンテナイメージとしては、古いのバージョンのものを参照していますね。タスクの詳細を確認してみます。 新規に起動したタスクのイメージURIを確認すると、古いバージョンのもの(以前のイメージダイジェスト)を参照していることが分かります。 ソフトウェアバージョンの一貫性の挙動を確かめました。これによってユーザーには、同一のコンテンツを提供することが可能になります。 注意事項 ・実環境でECSプラットフォームバージョン1.3.0についても、ソフトウェアバージョンの一貫性がサポートされていました。つまり、現AWS環境ではECSプラットフォームバージョン1.3.0,1.4.0が利用できるため、全てソフトウェアバージョンの一貫性がサポートされることに注意してください。 Deploy Amazon ECS services by replacing tasks - Amazon Elastic Container Service When you create a service that uses the rolling update deployment type, the Amazon ECS service scheduler replaces the cu... docs.aws.amazon.com タスクを置き換えて Amazon ECS サービスをデプロイする - Amazon Elastic Container Service ローリング更新デプロイタイプを使用するサービスを作成すると、Amazon ECS サービススケジューラは現在実行中のタスクを新しいタスクに置き換えます。 docs.aws.amazon.com ※2024/8/13にて、本検証を行ったところ、1.3.0以上でもサポートされている挙動を確認したため、AWSサポートに問い合わせ、AWSドキュメントを修正いただいています。日本語ドキュメントでは、1.4.0以上でのみサポートされていると記述されておりますが、英語ドキュメントでは1.3.0以上でサポートしている旨に修正されています。   最後に いかがだったでしょうか。 コンテナでlatestタグを利用している場合でも、ECSでのデプロイがより快適なものになりました。 最新アップデートを鵜吞みにするだけではなくきちんと動作検証をすることで、AWSドキュメントの不備にも気づくことができました。 本記事が皆様のお役にたてば幸いです。 ではサウナラ~🔥
アバター
本記事は 夏休みクラウド自由研究 8/17付の記事です 。 こんにちは、SCSKでAWSの内製化支援『 テクニカルエスコートサービス 』を担当している貝塚です。 昨日の寺内の記事 で、VPC環境に AWS CloudShell を作成し、ネットワークまわりのテストにも使用できそうだという話が出ていました。本記事では、ネットワークテストツールとしてCloudShellを利用できるのか、という観点でもう少し考察してみることにします。 VPC環境にCloudShellを作成する手順については、上記記事をご覧ください。 ネットワークコマンドを試してみる さっそく、VPCに作成されたCloudShellで、代表的なネットワークコマンドを試してみることにします。 ping もちろん、インストールされています。 スクリーンショットを見ても分かるわけがないのですが、実はあて先のIPアドレスはもうひとつ起動したCloudShellです。 寺内の記事 にあった通り、VPC環境CloudShellはIAMユーザごとに2つまで作成できるので、CloudShellのみでエンド・トゥ・エンドの疎通確認を行うことが可能です。(セキュリティグループでpingを許可する必要がある点に注意) curl curlもインストールされています。 なお、CloudShellは、DNSとしてAmazon Provided DNSを参照しているので、DNS名前解決をすることができます。 dig dig はインストールされていません。また、nslookup もインストールされていません。EC2用のAmazon Linux 2023 AMIにはインストールされていましたので、CloudShell化の際に落とされてしまったコマンドなのでしょう。 DNS名前解決の動作確認は個人的には必須と思っているので、digが使えるように、リポジトリからパッケージをインストールしてあげることにします。 その他のコマンド EC2用Amazon Linux 2023には入っていた tcpdump は入っていませんでした。また、EC2用Amazon Linux 2023に入っていなかった telnet や nc (netcat)も、もちろん入っていません。 これらのコマンドも必要に応じてインストールできるといいですよね。 リポジトリにアクセスする方法を考える CloudShellの /etc/yum.repos.d/amazonlinux.repo を見ると、ミラーリストにcdn.amazonlinux.com が指定されています。これはインターネット上のサイトなので、CloudShellからインターネットへ接続できるようにする必要があります。 インターネットに接続する NATゲートウェイ経由 NATゲートウェイ経由でインターネットに接続可能なサブネットにCloudShellを作成した場合、特に考えることはありません。CloudShellもサブネットに設定されたルートテーブルに従って通信するため、NATゲートウェイ経由でインターネットに接続することができ、Amazon Linux 2023のリポジトリを参照することができます。 パブリックIPを持たせる パブリックサブネットにCloudShellを作成した場合ですが、CloudShell作成時に自動でパブリックIPが割り当てられることはありません。そのため、 寺内の記事 にある手順でCloudShellのENIを特定し、「アクション」→「アドレスの関連付け」からパブリックIPを関連付けてあげる必要があります。パブリックIPを関連付けると、インターネットに接続することができるようになり、Amazon Linux 2023のリポジトリを参照することができます。 S3 VPCエンドポイントに接続する 次に、インターネット接続が全くできないサブネットに配置したCloudShellを考えます。 通常のAmazon Linux 2023では、S3エンドポイント(s3.dualstack.ap-northeast-1.amazonaws.com など)に接続できればリポジトリにアクセスできるようになっていますが、前述の通り、CloudShellのリポジトリ設定では、cdn.amazonlinux.comを参照しており、S3エンドポイントを参照していません。 通常(EC2)のAmazon Linux 2023のリポジトリ設定 そこで、EC2 Amazon Linux 2023に設定された /etc/yum.repos.d/amazonlinux.repo の内容で、CloudShellの /etc/yum.repos.d/amazonlinux.repo の内容を置き換えてあげます。どちらもAmazon Linux 2023のリポジトリなので問題はないはず……と試してみると、問題なくリポジトリを参照することができました。 インターネットに接続できないサブネットに作成したCloudShellでも、S3 VPCエンドポイント(ゲートウェイ/インターフェイス)にアクセスできるようになっていればリポジトリへのアクセスは問題なさそうです。(※) (※)もしAWSサポートに問い合わせたら、想定していない利用方法ということで使用非推奨と答えられるかもしれませんが…… パッケージをインストールする リポジトリにアクセスできるようになったら、パッケージを入れていきます。 通常のパッケージインストールと何ら変わりないので、詳細は割愛しますが、bind-utilsパッケージをインストールすることでdigコマンドを(ついでにnslookupコマンドも)実行できるようになりました。 bind-utilsがdigを提供している digコマンド実行 制約事項の確認 ここからは、VPC環境CloudShellを使っていて分かった制約事項の類を解説していきます。 制約事項:インアクティブ状態になってから20~30分でセッションが終了する まず、VPC環境特有の話ではありませんが、CloudShellを使わずに20~30分おいておくと、セッションが終了します。セッション終了時の挙動が、通常のCloudShellとVPC環境CloudShellでは異なり、VPC環境CloudShellはだいぶ厳しい制約があることが分かりました。 セッションが終了すると変更したデータは初期状態に戻る 通常のCloudShellは、ホームディレクトリは永続ストレージになっておりセッションが終了してもデータは削除されませんが、VPC環境CloudShellではセッション終了時にホームディレクトリのデータも削除されます。 また、ホームディレクトリ以外の変更(例えば /bin にインストールしたコマンドなど)も元に戻ってしまいます。 そのため、せっかくパッケージをインストールしてもセッションが終了すると一からやり直しになります。 セッションが終了するとネットワークインターフェイス(ENI) IDが変わる/プライベートIPが変わる 一度セッションが終了し、CloudShellを再起動すると、ネットワークインターフェイスIDが変わってしまいます。また、プライベートIPも変わってしまいます。そもそもVPC環境CloudShellを作成するときにIPアドレスは指定できませんでした。 環境によっては、サブネットサイズよりも狭い範囲(例えば1 IP単位)で通信をフィルタリングしなければならないこともあると思いますので、この仕様はうれしくありません。 ただしこれについては、ENIにセカンダリIPを割り当てることができるので、明示的にアドレスを指定してセカンダリIPを割り当てたのちにOS側でIPアドレスを設定してあげれば、特定のIPアドレスを使って通信させることが可能です。 ENIとパブリックIPの関連付けが解除される セッションが終了したときにENIがなくなってしまっているので、CloudShellを再起動して新しいENIが作られたときにはパブリックIPが関連付けられていない状態になってしまいます。 面倒ですが、セッションが終了してしまった時にはおとなしく再設定してあげるしかなさそうです。 制約事項:ファイルのダウンロード/ファイルのアップロード機能がない デフォルトのCloudShellで使えたファイルのダウンロード/ファイルのアップロード機能が使用できません。 sftp/scpコマンド、CodeCommitを使うためのgitコマンド、S3を使うためのAWS CLIなどが入っているので、これらで代用することを考えましょう。 まとめ 本記事では、ネットワークテストツールとして使用するという視点でCloudShellを見てきました。 OSにAmazon Linux 2023を使っているだけあって、リポジトリにアクセスできてしまえば思う存分ネットワークテストに活用できそうですね。 一方、インターネットにもS3エンドポイントにもアクセスできない環境に作成する場合、ネットワークテストツールとして使うにはインストールされているコマンドが少なすぎる印象です。とはいえpingとcurlが使えて、pingに応答してくれるだけで十分助かる場面はありそうです。 また、永続ストレージがなくセッションが終了してしまうとディスクへの変更がすべて失われてしまうのは大きな制約と言えます。しかし永続ストレージについては今後の機能追加が期待できると思いますので、これについては時間の問題と言えるかもしれません。
アバター
こんにちは。SCSK株式会社の杉田です。 2024年4月~6月にかけて、 ServiceNow資格取得支援セミナー「Now Rally Season 3」 が開催されました。 SCSKからも5名参加いたしましたので、参加レポートをご紹介いたします。 Now Rallyとは 「Now Rally」とは、約 2 ヶ月間で ServiceNow® の認定技術資格を取得 することを支援するセミナーです ​。 Now Rallyの概要 本セミナーの概要に関しては以下の通りです。 2024 年4月 – 6 月にかけて開催(全8回のMTG) ​ 招待制の合同トレーニングコース 対象 ​ 資格試験合格にコミットし、業務として参加可能な人 ​ ServiceNow 認定技術資格に初めて挑戦する人 ​​ 内容 CSA 合格は必須要件であり、上位資格( CDA 、または CIS )の合格も 狙う ​ ServiceNow のメンバーによる勉強ガイドや Q&A だけでなく、オン ラインコミュニティでの参加者同士の交流なども通して、資格取得の 目標達成を支援 Now Rallyの特徴 認定資格取得をゲームとして楽しみながら、個人チャンピオンを目指します。 また、パートナー枠でチーム作成しチームチャンピオンを競い合います。 個人で上位3名、チームで上位3チームが表彰となります。 個人・チームでポイント数を競い合い、わくわくした気持ちでServiceNowに触れ合うことができることができました。  合格/不合格体験記の投稿、 Training コースの完了、認定資格の取得、外部Communityへの投稿、ミニクイズの順位など様々な場面でポイントを積み上げていくことが可能です。   Now Rallyに参加して 私はNow Rallyに参加以前は、ServiceNowの事前知識が殆どない状態でした。 このような状況で感じたメリットと、最終的な表彰結果をお伝えいたします。 メリット ServiceNow初学者として、私が感じたメリットは以下5点です。 ServiceNowを学習するにあたり、活用できるリソースを共有してくださる 毎MTGの最後に質問コーナーがあり、不明点を解消できる 参加者は私と同じようにServiceNow初学者が多く、周りに感化されながら学習に励むことができる チーム戦であるため、社内メンバとの交流が深まる 表彰と景品があるためやる気がでる! セミナー主催の方々は非常に穏やかで優しく接してくださったため、安心してセミナーに参加することができました。 また、全8回のうち2回は対面で開催されたため、同じ目標を持つ方々と交流を持つことができたため自身のモチベーションを保つことができました。 表彰結果 なんと、SCSKチームは チーム総合1位 を獲得することができました! また、 4名は資格取得も達成 し好調な成績を残すことができました。   最後に SCSKチームは、それぞれ既に案件を抱えており、業務の合間をぬって本セミナーに参加しておりました。 抱えている案件と本セミナーを両立させることは非常に難易度が高いものだったかと思いますが、最終的にServiceNowの基礎知識を得ることができ非常に良い経験となりました。 今後もNow Rally Season 4.5.6…と続いていくかと思いますので、気になる方はぜひ参加してみてください! 最後に・・・ 弊社では、ITSMやESGなど様々なServiceNow製品を扱っています。 以下から問合せ可能ですので、ご参照ください。 ServiceNow ServiceNowは、企業の生産性向上や業務プロセス改善を支えるサービスマネジメントクラウドソリューションです。従業員満足度・顧客満足度の向上、業務効率化を強力に支援します。 www.scsk.jp
アバター