aws-samples

Stars and mentions

Last 30 days, Oct 4 – Nov 2

GitHub stars36
mentions38
02468Oct 4Oct 18Nov 2
UTC days · repositories aws-samples owns19 repositories

Package downloads

Cumulative recorded downloads · since 2025-10-19

npm8.3M
02.1M4.2M6.2M8.3MOct 4Oct 18Nov 2
Oct 18npm: 1/2 packages observed

Across 2 known packages in repositories aws-samples owns. Cumulative totals include recorded downloads before the selected range. Missing observations leave gaps; totals may be incomplete.

Top repositories

aws-samples’s repositories ranked by new stars, as on trending.

Loading

Contributes to

Repositories outside aws-samples’s account where aws-samples opened or reviewed pull requests in the past 365 days.

Who noticed aws-samples

Everyone who starred or forked aws-samples’s repositories since the archive began in 2011.

Notable accounts

Ordered by the stars their own repositories have received.

Biggest fans

Accounts that starred the most of these repositories.

Breakout weeks

Each repository’s best week of new stars, with the release published around it.

Mentions

37posts
Nov 31 post
  1. AWS Kiro: utilizando IA para se preparar para as certificações da AWS 1. Introdução Este artigo tem como objetivo mostrar para que serve o Kiro Study Buddy e como configurá-lo para estudar para as certificações da AWS. Acertar uma questão no simulado nem sempre significa dominar o assunto, pois uma resposta pode estar correta por eliminação ou até por sorte, sem que o conceito tenha sido realmente compreendido. Por isso, entender o motivo de cada resposta é tão importante quanto acertar a questão. Com o Kiro Study Buddy, é possível resolver questões de simulado, receber feedback sobre as respostas e entender melhor os conceitos de cada alternativa. O Kiro Study Buddy é um power open-source para o Kiro, a IDE com IA da AWS, desenvolvido para tornar esse processo mais completo. Além de selecionar uma alternativa, também é possível justificar a escolha. A partir dessa explicação, a ferramenta analisa o raciocínio, identifica possíveis erros de entendimento e explica por que as demais alternativas estão incorretas. As análises utilizam a documentação oficial da AWS como referência, por meio do AWS Documentation MCP Server. Principais pontos: - Funciona com qualquer certificação da AWS, desde o nível foundational ao professional e specialty. - Não tem backend, banco de dados ou deploy, então, basta apenas instalar e utilizar. A configuração é realizada em poucos minutos. --- 2. Implementação 2.1 Pré-requisitos - É necessário instalar o Kiro IDE - É necessário instalar o uv, que é o gerenciador de pacotes Python que executa o servidor MCP de documentação usado pelo power. -- 2.2 Autenticação no Kiro IDE 1.Após instalar o Kiro IDE, será necessário clicar em “Sign in” para se autenticar, podendo escolher uma das opções de login abaixo: !Image description !Image description -- 2.3 Instalação do power 1.No painel Powers, clicar em “Add Custom Power”, “Import power from GitHub” e colar o endereço do repositório aws-samples/sample-kiro-study-buddy. !Image description 2.O Study Buddy já está disponível: !Image description !Image description 3.Outra forma de instalar é clonar o repositório (git clone https://github.com/aws-samples/sample-kiro-study-buddy), após o clone, clicar em “Powers”, “Import power from a folder” e selecionar a pasta do projeto: !Image description !Image description !Image description 4.O Study Buddy funciona como uma extensão do Kiro, utilizando arquivos markdown e uma configuração MCP para orientar o comportamento da IA durante os estudos. A estrutura define as instruções e os diferentes modos de estudo disponíveis. A estrutura dos arquivos é organizada da seguinte forma: kiro-study-buddy/ ├── POWER.md # metadados e roteamento do power ├── mcp.json # Configuração do servidor MCP de documentação da AWS └── steering/ # Arquivos Markdown com instruções para cada modo de estudo -- 2.4 Study Buddy na prática O Study Buddy pode ser utilizado diretamente no chat do Kiro, onde são realizadas as sessões de estudo. 1.No menu superior, clicar em “File”, “Open Folder”, selecionar a pasta “sample-kiro-study-buddy” que foi clonada. Ao abrir a pasta, o chat abrirá automaticamente no lado direito, com uma aba “New Session” e a tela “Let’s build”. Se o chat não abrir, o atalho é Ctrl+Shift+L, conforme a lista de atalhos apresentadas: !Image description 2.É possível escolher o modelo de IA: !Image description 3.Com o chat aberto, basta enviar uma mensagem informando a prova. Em seguida, o power fará uma checagem inicial e testará a conexão com o AWS Documentation MCP Server. Se essa etapa falhar, será necessário conferir se o uv está instalado corretamente, pois é ele que executa o servidor MCP. Pergunta 1: > “Estou me preparando para a certificação AWS Certified CloudOps Engineer Associate (SOA-C03) e quero começar uma sessão de estudo. Me mostre os domínios da prova, o peso de cada um, o número de questões, o tempo e a nota mínima de aprovação.” Abaixo, o Kiro trouxe as informações referentes ao exame SOA-C03: !Image description !Image description !Image description Guia do exame: docs.aws.amazon.com !Image description - Pergunta 2: > Explique o AWS Systems Manager Patch Manager como ele cai na SOA-C03. Abaixo, resposta do Kiro: !Image description !Image description - Pergunta 3: > Quero fazer um simulado completo da AWS Certified CloudOps Engineer Associate (SOA-C03), com o mesmo número de questões e o mesmo tempo da prova oficial. > Regras: > - Distribua as questões entre os domínios de acordo com o peso de cada um no guia oficial do exame. > - Use cenários no estilo da prova real. > - Baseie as questões e o feedback na documentação atual da AWS e cite as fontes. > - Depois de cada resposta, explique por que a alternativa correta está certa e por que cada uma das outras está errada, com base na documentação oficial. > - No final, mostre a pontuação, o desempenho por domínio, a análise de tempo e os tópicos que preciso revisar. Abaixo, questão de simulado: !Image description !Image description !Image description --- 3. Dicas Além do simulado, muitas outras perguntas podem ser feitas, como: - Comparar serviços parecidos e entender quando usar cada um. - Pedir a explicação de um tema da prova de forma simples, com exemplos. - Praticar um cenário guiado, resolvendo um problema passo a passo. - Desconstruir uma questão errada em outro simulado para entender onde o raciocínio falhou. - Pedir questões de um único domínio, para reforçar um ponto fraco. - Perguntar quais tópicos têm mais peso na prova e por onde começar a estudar. Boas práticas: - Sempre escrever a justificativa: é ali que está o valor da ferramenta, pois responder somente a letra desperdiça o feedback. - Treinar com tempo: o cronômetro ajuda a simular a pressão da prova real. - Levar para a desconstrução as questões erradas em outros simulados: isso ajuda a entender o erro, em vez de só decorar o gabarito. - A documentação e os guias oficiais dos exames continuam sendo uma base muito importante do estudo, o Study Buddy entra como complemento. --- 4. Conclusão O Kiro Study Buddy muda o foco da preparação, em vez de contar apenas acertos, ele analisa como se chegou à resposta e aponta onde está a lacuna, sempre com a documentação oficial como referência. Para quem está começando a se preparar para uma certificação, um bom ponto de partida é um simulado curto de 10 questões, com justificativas bem escritas em cada resposta e conforme avançar nos estudos, aumentar o número de questões. Na reta final da preparação, o ideal é praticar simulados completos de 65 questões para se familiarizar com a quantidade na hora do exame. Links úteis: - Repositório do Kiro Study Buddy - AWS Documentation MCP Server - [Guias oficiais dos exames AWS ](docs.aws.amazon.com) - Kiro IDE - Instalação do uv

  2. GenUの閉域版構成でPrivate APIGWの通信元となるVPC Endpointを指定できるようにしました。ついでにREST APIをPrivate化するリソースポリシー設定は以前私が作ったCDK組み込みの関数(grantInvokeFromVpcEndpointsOnly())を使うようにしてます。 generative-ai-use-cases#1723

    3 likes · 1 repost · 350 views
  3. Aurora DSQL対応のテストを、本物のクラスタなしでCIで回す PostgreSQL用の宣言的スキーマ管理ツールpistachioを、Amazon Aurora DSQLに対応させました。--engine dsqlを付けると、plan、apply、dumpがDSQLを相手に動きます。 DSQLはPostgreSQL 16のプロトコルを話しますが、受け付けるDDLも、カタログが返す値もPostgreSQLとは少し違います。この違いをテストしたいものの、CIから本物のクラスタには接続したくありません。そこで、次の順にテストを組み立てました。 本物のクラスタの応答をプロキシで記録し、CIでリプレイする ローカルのPostgreSQLをDSQLのように振る舞わせるプロキシを作り、シナリオテストをCIで回す そのプロキシが本物からずれていないかを、記録とconformance testで確かめる この記事では、各段階で何が解決し、何が残ったのかを説明します。 DSQLはPostgreSQLとどう違うのか まず、pistachioの対応で問題になった違いを示します。すべて実際のクラスタで確かめたものです。 操作 PostgreSQL DSQL インデックスの作成 CREATE INDEX idx ON t USING btree (c) CREATE INDEX ASYNC idx ON t (c)のみ。job_idが返り、CALL sys.wait_for_job(...)で完了を待つ デフォルト値付きの列追加 ADD COLUMN c text DEFAULT 'x' 拒否される。ADD COLUMNとALTER COLUMN ... SET DEFAULTに分ける 既存テーブルへのUNIQUE制約の追加 ADD CONSTRAINT ... UNIQUE (c) CREATE UNIQUE INDEX ASYNCの完了を待ち、ADD CONSTRAINT ... UNIQUE USING INDEXを実行する 既存テーブルへのCHECK制約・外部キーの追加 ADD CONSTRAINT ... NOT VALIDで追加し、ALTER TABLE ASYNC ... VALIDATE CONSTRAINTで検証する トランザクション内のDDL 複数実行できる 1つのみ 文法の違いであれば、生成するDDLを書き換えれば済みます。厄介なのは、文法は通るのにカタログの読み取り結果が違う場合です。 たとえばPRIMARY KEY (id)で作ったテーブルについて、DSQLのカタログは次の定義を返します。 PRIMARY KEY (id) INCLUDE (name, email) 主キー以外の全列がINCLUDEに入るためです。そのまま比較すると、実際には差分がないのに、planを実行するたびに主キーを削除して追加するDDLが出力されます。しかもDSQLは主キーのDROP CONSTRAINTを拒否するので、そのDDLは適用もできません。インデックスのアクセスメソッドがbtreeではなくbtree_indexと報告されること、text列の圧縮方式がlz4になることも、同じ種類の問題です。 つまり、DDLがエラーにならないことを確かめるだけでは足りません。applyの後にもう一度planを実行し、差分が出ないことまで確かめる必要があり、それには本物に近い応答が要ります。 CIから本物のクラスタを使いたくない DSQLはAWSのマネージドサービスなので、Dockerで手元に立てることができません。テストのたびに本物へ接続することも考えられますが、CIで回すには次の問題があります。 費用: DSQLは使用量に応じて課金されます。CIはプッシュのたびに動くので、テストを増やすほど費用も増えます。 安全性: クラスタに接続するには、CIにAWSの認証情報を置く必要があります。公開リポジトリのCIに認証情報を置きたくありません。また、GitHub Actionsはフォークからのプルリクエストにシークレットを渡さないので、外部からのプルリクエストではテストが動きません。 同時実行: テストはpublicスキーマが空の状態から始めます。そのため、複数のCIジョブが1つのクラスタを同時に使うことができません。 応答を記録してリプレイする 最初に作ったのがpgstubです。PostgreSQLのワイヤプロトコルを話すスタブで、recordモードではプロキシとして動きます。 record: テスト -> pgstub -> DSQLクラスタ (応答をYAMLに保存) replay: テスト -> pgstub (YAMLから応答を返す) クラスタに接続して一度テストを実行すると、送ったSQLと応答がYAMLに保存されます。 - query: CREATE INDEX ASYNC users_name_idx ON public.users (name); columns: [job_id] rows: - [job-1] complete: CREATE INDEX - query: CALL sys.wait_for_job('job-1') columns: [succeeded] types: [bool] rows: - [t] complete: CALL このファイルをコミットしておけば、CIはクラスタもPostgreSQLもなしにTestDSQLをリプレイできます。現在の記録は232クエリ分、約12,500行です。カタログを読むクエリも応答も丸ごと入っているので、INCLUDEやbtree_indexを含む値を読んで差分が出ないことも確かめられます。 記録を運用するうえでは、工夫が2つ必要でした。 1つ目は、実行ごとに変わる値の扱いです。OIDとジョブIDは記録し直すたびに変わるため、何も変更していなくても差分が出ます。pgstubのNormalizeOIDsとNormalizeColumn("job_id", "job-")で、これらを出現順の番号に置き換えました。上のjob-1がその結果です。応答が同じならファイルを書き換えないので、記録ファイルの差分は本当に応答が変わった箇所だけになります。 2つ目は、記録ファイルをリポジトリに公開することへの対策です。make record-dsqlは記録の後でファイルを検査し、クラスタの名前やAWSの認証情報らしき文字列が含まれていれば失敗します。 記録だけでは足りなかったこと リプレイには、仕組み上の限界があります。 pgstubはSQLの中身を解釈せず、一致するSQLに記録した応答を返すだけです。pistachioが送るSQLを1つでも変えると、カタログのクエリであってもリプレイは失敗します。クラスタの権限がなければ記録し直せないので、DSQLのCIジョブは、記録を更新するまで失敗したままになります。 記録にない操作を試すこともできません。もう少し複雑なテストとして、aws-samples/aurora-dsql-samplesのスキーマを段階的に構築、変更、削除し、そのたびに差分が残らないことを確かめるシナリオテストを書きました。しかし、これは本物のクラスタがないと動かないので、CIでは実行できませんでした。 DSQLのように振る舞うプロキシを作る 既存のDSQLモックもいくつか試しましたが、使えませんでした。試したものはPostgreSQLのラッパーで、SQLは受け付けるものの、カタログがDSQLと異なるためです。pistachioはカタログを読んで差分を計算するので、INCLUDEやbtree_indexが再現されないと、DSQLでの動作を確かめられません。 そこで、SQLに応じて答えを返せるものとしてinternal/dsqlproxyを作りました。クライアントとローカルのPostgreSQL 16の間に入り、SQLを書き換えて中継します。 pista -> dsqlproxy -> PostgreSQL 16 テスト以外のコードは、setup.sqlを含めて約840行です。やっていることは、大きく3つです。 1つ目は、DSQLが拒否するSQLを同じエラーで拒否することです。SQLSTATEとメッセージをDSQLに揃えるため、PostgreSQL側の関数で例外を投げます。 -- クライアントが送ったSQL ALTER TABLE t ALTER COLUMN c SET NOT NULL -- PostgreSQLに送るSQL SELECT dsql_proxy.refuse('0A000', 'unsupported ALTER TABLE ALTER COLUMN ... SET NOT NULL statement') 2つ目は、ASYNCのジョブを再現することです。ASYNCはPostgreSQLの文法にないので、構文解析の前に正規表現で取り出し、関数の呼び出しに置き換えます。 -- クライアントが送ったSQL CREATE INDEX ASYNC idx ON t (c) -- PostgreSQLに送るSQL SELECT job_id FROM dsql_proxy.run_job('INDEX_BUILD', 'CREATE INDEX idx ON t (c)') run_jobはインデックスをその場で作りますが、pg_index.indisvalidをfalseにしておき、sys.wait_for_jobが呼ばれたときにtrueへ戻します。こうすると、ジョブを待たずに次へ進むバグがあった場合に、DSQLと同じく無効なインデックスが見えます。カタログを直接書き換えるので、プロキシが接続するロールにはスーパーユーザー権限が必要です。 3つ目は、カタログの値をDSQLに合わせることです。pg_get_constraintdefやpg_get_indexdefの呼び出しを、dsql_proxyスキーマに定義した同名の関数に置き換えます。これらの関数がINCLUDEやbtree_indexを付け足します。 -- PRIMARY KEYの定義に、主キー以外の全列をINCLUDEとして足す SELECT pg_catalog.pg_get_constraintdef($1, $2) || ' INCLUDE (' || inc.cols || ')' これで、シナリオテストをCIで実行できるようになりました。 プロキシが本物からずれていないか確かめる 自作のモックには、テストが通っても本物で動く保証がないという問題があります。プロキシが間違っていれば、そのプロキシで通ったテストに意味はありません。そこで、本物から得た結果と比較する仕組みを2つ用意しました。 記録を比較する 本物のクラスタで記録したTestDSQLを、プロキシ経由でも記録して比較します。 TestDSQL -> pgstub -> dsqlproxy -> PostgreSQL 16 できた記録がコミット済みのdsql.yamlと1バイトでも違えば、CIのdsql-recordingジョブが失敗します。232クエリ分の応答について、プロキシがクラスタと同じ答えを返していることになります。CIで実行できるので、クラスタは要りません。 拒否されるSQLを本物で確かめる この比較には抜けがあります。記録にはエラー応答が1件も入っていないので、プロキシが返す拒否メッセージを検証できません。 そこで、TestConformanceというテストを作りました。SQLごとに、受け付けられるかどうかと、拒否される場合のSQLSTATEとメッセージを、約60件のテーブルにまとめました。 {sql: "CREATE INDEX probe_x_idx ON probe_t (c)", code: refused, msg: "unsupported mode. please use CREATE INDEX ASYNC."}, {sql: "CREATE INDEX ASYNC probe_x_idx ON probe_t (c)", undo: "DROP INDEX probe_x_idx"}, 同じテーブルを、普段のテストではプロキシに対して、記録を更新するときは本物のクラスタに対して実行します。 初めて本物のクラスタで実行すると、プロキシの拒否メッセージが8件間違っていました。たとえば次のような間違いです。 SQL プロキシの応答 DSQLの応答 ALTER COLUMN ... SET NOT NULL unsupported ALTER TABLE SET NOT NULL statement unsupported ALTER TABLE ALTER COLUMN ... SET NOT NULL statement CREATE TYPE ... AS ENUM unsupported statement: CreateEnum CREATE TYPE not supported プロキシは手で書いたものなので、こうした間違いが入り込みます。本物に対して実行して、初めてそれが見つかりました。 現在のテスト構成 テスト 相手 実行する場所 確かめること make test-dsql pgstubによるリプレイ CI 本物の応答に対してpistachioが正しく動くか make test-dsql-proxy dsqlproxy + PostgreSQL 16 CI 実際のスキーマの構築、変更、削除で差分が残らないか make check-dsql-recording pgstub + dsqlproxy + PostgreSQL 16 CI プロキシの応答が本物の記録と一致するか TestConformance dsqlproxy、または本物 CI(プロキシ)、手元(本物) SQLの受け付けと拒否が想定どおりか make record-dsql 本物 手元 記録の更新とconformance test make test-dsql-scenario 本物 手元 シナリオテストが本物でも通るか プロキシでは分からないこと プロキシは、本物で確かめて分かったことしか再現できません。次の点は、本物でなければ確かめられません。 DSQL自体の変化: DSQLは機能が増え続けています。調査中にも、DROP COLUMNなどが新たに使えるようになりました。こうした変化はCIでは検出できず、make record-dsqlを実行したときに初めて分かります。 非同期の実行: プロキシのジョブはその場で完了します。ビルドに時間がかかる場合の挙動は再現しません。 接続まわり: プロキシはTLSもIAM認証も扱いません。5分のトランザクションの上限と60分の接続の上限も再現していません。 プロキシに期待しているのは、本物を完全に再現することではなく、現状のDSQLの仕様をテストで固定することです。DSQLの変化を取り込むときや送るSQLを変えたときには、本物に対してmake record-dsqlを実行します。結果が違っていれば、テストのテーブルとプロキシを直します。 まとめ Aurora DSQLは手元に立てられず、CIから本物のクラスタに接続したくもありませんでした。そこで、本物の応答を記録したリプレイと、DSQLのように振る舞うプロキシを用意し、本物のクラスタなしでCIのテストを通せるようにしました。本物のクラスタに接続するのは、記録を更新するときなど、手元で実行するときだけです。 実装はpistachioのinternal/dsqlproxyとpgstubのリポジトリにあります。

  4. Hijacking a Refund Agent Through Poisoned Support Tickets: Cristian Leo and Daniel Begimher at Global AppSec USA 2026 Players in this hands-on pod attack a customer-returns AI agent that can read tickets, fetch URLs, look up orders, send email or issue refunds. A player wins by making the agent issue a refund, email an address the player picks or post order data to a URL the player controls. No payload is handed out. Players write the support ticket, the tracking page or the email that the agent is asked to summarize, then hide their instructions inside it. In their Global AppSec USA 2026 hands-on pod, "Hijack the Agent", on Thursday, November 5 at 10:10 a.m. in Marina, Cristian Leo and Daniel Begimher let attendees attack an AI agent that defends itself a little better at each stage. Speakers: - Cristian Leo, Co-Founder and CTO, Armorer Labs - Daniel Begimher, Co-Founder and CEO, Armorer Labs The pod runs the same app through four stages, each one harder. At the beginner stage the tools are wide open, so even direct injection in the chat works. At the intermediate stage a chat filter is on, so players must deliver their instructions through the web page or the email instead. That maps to ASI01, Agent Goal Hijack, in the OWASP Top 10 for Agentic Applications. At the advanced stage a static deny-list guards the issue_refund and send_email tools, yet the same string passes through lookup_order. Players must find a tool call the list did not anticipate, then a new fetch_url tool makes the previous round's rule wrong. That maps to ASI02, Tool Misuse. The final "Impossible" stage adds an in-process dispatcher hook that inspects every tool call. Attacks from the first three stages die there with a stated reason, which is the lesson. Each stage takes under 15 minutes, and players need only a laptop with a browser. The pod repeats on Thursday at 3:00 p.m., then on Friday at 11:30 a.m. and 1:30 p.m. Cristian Leo is Co-Founder and CTO of Armorer Labs, a Y Combinator Fall 2026 company that tests AI agents for exploitable failures. Previously at Amazon Web Services, he is corresponding author of ThreatForest, a multi-agent system that turns a source repository into attack trees mapped to MITRE ATT&CK or CAPEC. Daniel Begimher is Co-Founder and CEO of Armorer Labs. At AWS he led development of AWS's first customer-facing AI security agent, built red-team agents and wrote the open-source scanner Automated Security Helper. Leo and Begimher co-presented ThreatForest at Black Hat USA 2026. They also co-authored SIR-Bench, a 794-case benchmark that measures whether incident response agents actually investigate or merely triage. Begimher also co-wrote the AWS Security Blog post "Balancing speed and safety: A control framework for AI coding agents," which pairs scoped tool access for AI coding agents with build-time gates. To go deeper on the topic, start here: - OWASP Top 10 for Agentic Applications for 2026 - ThreatForest Black Hat USA 2026 slides - ThreatForest paper (arXiv) - SIR-Bench paper (arXiv) - ThreatForest code (aws-samples) AppSec engineers who need to see why deny-lists fail against agent tool calls will get a fast, concrete demonstration here. Which of your AI agent's tools would an attacker reach for first through a poisoned document?

    2 points · 1 comment
  5. 1台の VM の k3s で Deployment・Service・Job を動かして確かめる Kubernetes と EKS の入門 docker run を使うと、コンテナを1つ動かせます。ただ、たくさんの人がアクセスするようなシステムでは、コンテナが1つだけだと、アクセスが増えたときに処理が追いつかずに応答が遅くなり、そのコンテナが落ちれば全体が止まってしまいます。そのため、同じコンテナをいくつも並べて動かすことがよくあります。 コンテナを3つ並べておけば、リクエストを3つに分けて受けられ、1つが落ちても残りの2つで応答を続けられます。新しいバージョンへの入れ替えも、1つずつ行えば、サービスを止めずに済みます。ロボットの学習でも、同じシミュレーションを何本も並べて流せば、データを早くそろえられます。 並べる数が増えれば増えるほど、落ちたものを見つけて立て直す、順に入れ替える、といった作業を人が手でこなすのは大変になってきます。そこで活躍するのが Kubernetes(k8s)です。 AWS Physical AI Toolchain の記事では、データ作り・学習・評価といった段階をつなぐ OSMO が、Amazon EKS(AWS の k8s)の上で動く、と書きました。この記事は、その土台になる k8s の入門です。1台の VM に k3s(軽い k8s)を入れて、基本の部品を1つずつ動かしながら確かめます。最後に、EKS で何が変わるかと、OSMO とのつながりをまとめます。 Kubernetes が受け持つこと k8s には「このコンテナを3つ動かしておく」のように、こうなっていてほしい形を書いて渡します。k8s は、その形になるように動き、ずれたら直し続けます。この記事で動かすものの関係を、ノード3台とコントロールプレーン1台の、マシン4台の形で図にしました1。マシンごとに、中で何が動いているかを描いています。Pod をどのノードに何個置くかは、こちらでは書きません。コントロールプレーンのスケジューラーが決めます(図では、ノード1に2つ、ノード3に1つ)。この記事で試すのは、オレンジの点線で囲んだ範囲です。VM 1台の k3s が、コントロールプレーンとノード1台を兼ねるので、3つの Pod はすべてそのノードに置かれます。 指示の流れ(黒の①〜④)と、ノードが取りに行く流れ(紫)と、リクエストの道(緑)。Service は1つのプログラムではなく、記録はコントロールプレーンに、振り分けの決まりは各ノードにある。オレンジの点線の中が、この記事で試す範囲 Pod:コンテナを動かす最小の単位。Pod 1つに IP が1つ付く。消えたり立ったりするので、IP も変わる Deployment:「この Pod を何個」と書いたもの。バージョンごとに ReplicaSet を作り、ReplicaSet が Pod の数を保つ Service:同じラベル(Pod に付ける目印。ここでは app: web)の Pod をまとめ、変わらない名前と IP で呼べるようにする ノード:Pod が動くマシン。中で kubelet というプログラムが動き、言われた Pod のコンテナを起動する コントロールプレーン:クラスター全体を管理するプログラムのまとまり。マニフェストを受け取って、どのノードで動かすかを決め、書かれた形を保ち続ける。昔はマスターと呼ばれていた。普通はノードとは別のマシンで動かすが、この記事の k3s では、ノードと同じ VM で動く クラスター:k8s が面倒を見るマシンのまとまり。普通は何台ものマシンで1つのクラスターを作り、どのマシンで動かすかは k8s が決める。この記事では、k3s を入れた VM 1台がそのままクラスターになる。Pod や Service は、クラスターの中に作られる マニフェストと kubectl:マニフェストは、クラスターに作ってほしいもの(Deployment や Service など)を書いた YAML のファイル。この記事では web.yaml と job.yaml。kubectl は、マニフェストをクラスターに渡したり、中の様子を見たりするコマンド k3s を入れる k3s は、k8s を1つの実行ファイルにまとめたものです。1台に入れるだけで、全部が動きます。試した VM は Oracle Linux 9(Arm)、CPU 1コア、メモリ 6GB で、k3s の公式の最低条件(CPU 2コア)を下回っています。このあとの秒数や失敗の回数は、この小さな VM でのものです。 k3s には、兄弟にあたる RKE2 もあります。入れ方は k3s をもとにしていて、セキュリティの基準(CIS ベンチマーク。k8s を安全に設定するためのチェック項目)を、初期設定のままで満たしやすく作られています。公式の最低条件は k3s より大きく、メモリは k3s の 2GB に対して 4GB です。この記事は小さな VM での入門なので、k3s を使います。 curl -sfL get.k3s.io | \ INSTALL_K3S_VERSION='v1.36.5+k3s1' \ INSTALL_K3S_EXEC='server --disable traefik --disable servicelb' \ sh - k3s には、外から来たリクエストを受けるためのソフトが、最初から2つ入っています。 servicelb:Service には、外から受けるための type: LoadBalancer という種類があります。クラウドでは、これを作るとクラウドの側がロードバランサーを用意します(AWS なら NLB)。自分のマシンには用意してくれる相手がいないので、k3s では servicelb が代わりを務めます。各ノードで、Service に書いたポート番号(たとえば 80 番)をそのまま受けて、Service に渡します。ノードが1台なら振り分ける先はなく、外からの入口を開けるだけです。Pod への振り分けは、このあと出てくる kube-proxy が書いた決まりで行われます Traefik:リバースプロキシ(外から来た HTTP のリクエストを受けて、後ろに渡すソフト)です。Ingress(URL ごとに、どの Service へ渡すかを書いた決まり)に従って振り分けます。k3s では、Traefik 自身が type: LoadBalancer の Service になっていて、servicelb を通してノードのポートの 80 番と 443 番で受けます 2つは別々に外せます。組み合わせごとに、外からどこで受けるかを図にしました。 servicelb と Traefik の組み合わせと、外からの入口 この記事では、2つとも k3s を入れるときに外しました。外からは NodePort でつなぎます。NodePort は、ノードのポートを 30000〜32767 番の範囲から1つ開ける種類の Service で、ロードバランサーがなくても使えます。 RHEL 系の OS では、2つ気をつけることがあります。 SELinux:有効なら、導入スクリプトが k3s-selinux を入れます。この手順を INSTALL_K3S_SKIP_SELINUX_RPM=true で飛ばしたら、実行ファイルに SELinux のラベルが付かず「Permission denied」で起動しませんでした。sudo restorecon -v /usr/local/bin/k3s で直りました firewalld:公式の手順は firewalld を止めることを勧めています。止めない場合は、Pod と Service が使う範囲を信頼する側に足します sudo firewall-cmd --permanent --zone=trusted --add-source=10.42.0.0/16 # Pod の範囲 sudo firewall-cmd --permanent --zone=trusted --add-source=10.43.0.0/16 # Service の範囲 sudo firewall-cmd --reload OS に関係なく、気をつけることがもう2つあります。 ufw:Ubuntu などで使う ufw も、公式の手順は止めることを勧めています。止めない場合は、firewalld と同じく、Pod と Service の範囲からの通信を許します sudo ufw allow from 10.42.0.0/16 to any # Pod の範囲 sudo ufw allow from 10.43.0.0/16 to any # Service の範囲 範囲の重なり:Pod と Service の範囲(10.42.0.0/16 と 10.43.0.0/16)が、クラスターとやり取りする相手(つなぎに来る利用者、Pod からつなぐ先、VPN。Tailscale なら 100.64.0.0/10)の範囲と重なると、その相手に届かなくなったり、応答が戻らなくなったりします。重なるときは、入れるときに --cluster-cidr(Pod の範囲)と --service-cidr(Service の範囲)で、10.0.0.0/8 などのプライベートの範囲から、重ならない範囲を選びます。あとから変える手順は公式に載っていないので、最初に決めておきます。範囲を変えたら、firewalld や ufw に足した範囲も合わせて変えます kubectl は、root しか読めない設定ファイルを自分の場所に写してから使います。このファイルにはクラスターの管理者の鍵が入っているので、人に渡さないでください。 mkdir -p ~/.kube sudo cat /etc/rancher/k3s/k3s.yaml > ~/.kube/config chmod 600 ~/.kube/config export KUBECONFIG=~/.kube/config # 指定しないと /etc/rancher/k3s/k3s.yaml を読みに行く kubectl get nodes 30秒ほどでノードが使える状態(Ready)になりました。k3s 全体のメモリは、およそ 1GB でした。 Deployment で3つ並べる ここからは、1つのマニフェスト web.yaml を使います。コンテナは traefik/whoami という小さな Web サーバーで、自分の Pod の名前を返します。どの Pod が応答したかが分かるので、振り分けを見るのに向いています。 web.yaml apiVersion: apps/v1 kind: Deployment metadata: name: web spec: replicas: 3 # Pod を3つ動かしておく selector: matchLabels: app: web # ラベル app: web の Pod の面倒を見る template: # Pod の作り方 metadata: labels: app: web spec: containers: - name: whoami image: traefik/whoami:v1.11.0 args: ["--port", "8080"] ports: - containerPort: 8080 readinessProbe: # /health が失敗を返したら、振り分け先から外す httpGet: path: /health port: 8080 periodSeconds: 2 failureThreshold: 2 lifecycle: # 止める前に5秒待つ preStop: sleep: seconds: 5 resources: requests: cpu: 50m memory: 16Mi limits: memory: 64Mi --- apiVersion: v1 kind: Service metadata: name: web spec: type: NodePort selector: app: web # 振り分け先はラベル app: web の Pod ports: - port: 80 targetPort: 8080 nodePort: 30080 # クラスターの外からは、ノードのポート 30080 番で受ける kubectl apply -f web.yaml kubectl rollout status deployment/web kubectl get rs,pods 7.5 秒でそろいました。web という名前の Deployment が、web-5f94c944b という名前の ReplicaSet を作り、その ReplicaSet が web-5f94c944b-xxxxx という名前の Pod を3つ作っています。真ん中の 5f94c944b は、Pod の作り方(template)の中身から計算した値で、作り方を変えると変わります。最後の5文字は、Pod ごとにランダムに付きます。 NAME DESIRED CURRENT READY AGE replicaset.apps/web-5f94c944b 3 3 3 8s NAME READY STATUS RESTARTS AGE pod/web-5f94c944b-kftn5 1/1 Running 0 8s pod/web-5f94c944b-kpff5 1/1 Running 0 8s pod/web-5f94c944b-mrx7f 1/1 Running 0 8s kubectl delete pod で Pod を1つ消すと、数秒で代わりの Pod が立ち、3つに戻りました。マニフェストの kind は作るものの種類で、kind: Pod や kind: ReplicaSet と書いて直接作ることもできます。ただ、Pod だけを作ると、消えても誰も立て直しません。ReplicaSet は数を保ちますが、新しいバージョンへの入れ替えはできません(入れ替えは、Deployment が新旧2つの ReplicaSet を使い分けて行います)。そのため、ずっと動かすものは Deployment に、終わりのある仕事は Job に作らせるのが普通です。kind に書けるほかの種類は、記事の最後の付録にまとめました。 resources の requests は「このくらいは確保してほしい」量で、k8s はこれを見て Pod を置くノードを選びます。limits は上限で、メモリが超えるとコンテナは止められます。CPU は上限に当たっても遅くなるだけなので、メモリだけ上限を決めました(考え方が分かれるところです)。 Service でまとめる Pod の IP は変わるので、Pod を名指しで呼ぶと追いかけるのが大変です。Service は、ラベル app: web の Pod をまとめて、変わらない名前で呼べるようにします。 ラベルは キー: 値 の形の目印で、キーも値も自分で決めます。web.yaml では、Deployment の template の中で Pod に app: web を付け、Service の selector で同じ app: web を指定しました。app は決まった言葉ではなく、k8s のドキュメントの例でもよく使われるキーの名前です。metadata の name は、そのもの自身の名前です。名前空間(namespace。クラスターの中を分ける区切りで、指定しなければ default)ごとに、同じ種類の中で1つだけで、kubectl get service web のように名指しするときに使います。Service の名前は、このあとの名前引きの名前(web)にもなります。ラベルは何個のものに同じ値を付けてもよい目印で、Service や Deployment はこれで Pod を選びます。web.yaml では、Deployment の名前、Service の名前、ラベルの値をどれも web にそろえましたが、それぞれ別々に決められます。 クラスターの中からは、web という名前で呼べます。使い捨ての Pod を立てて試しました。 kubectl run tmp --rm -i --restart=Never --image=busybox:1.37 -- wget -qO- web Hostname: web-5f94c944b-kftn5 名前を答えているのは、クラスターの中で Pod として動く CoreDNS(名前引きのサーバー。k3s では最初から入っている)です。名前を引くと Service の IP(10.43.121.7)が返り、正式な名前は web.default.svc.cluster.local でした。Service の名前 web のあとに、名前空間の default が続きます。同じ名前空間の Pod からは web だけで、別の名前空間からは web.default のように呼びます。 Service の IP は、Pod の IP とは別の範囲から付きます。k3s の初期設定では、Pod は 10.42.0.0/16、Service は 10.43.0.0/16 です。Service の IP 宛に送ったリクエストは、ノードの Linux の iptables(通信の行き先を書き換えたり、通すか止めるかを決めたりする仕組み)によって、どれか1つの Pod の IP 宛に書き換えられて届きます。そのための決まりを iptables に書くのが kube-proxy です。kube-proxy は各ノードで動くプログラムで、Service と Pod の様子を見張り、Pod が増えたり減ったりするたびに決まりを書き直します。リクエストそのものは kube-proxy を通りません。書き換えるのは、決まりに従ったノードの Linux です。Service の IP はクラスターの中で使うものなので、外からは次の NodePort でつなぎます。 Service には種類があり、type で選びます。下の種類ほど、上の種類の働きを含みます。 種類 呼べる場所 ClusterIP(何も書かないとこれ) クラスターの中だけ。Service の IP と名前で呼ぶ NodePort 上に加えて、すべてのノードの同じポート(30000〜32767 番)で、外から呼べる LoadBalancer 上に加えて、外のロードバランサーを付ける。クラウドでは自動で用意され、k3s では servicelb が代わりをする web.yaml は NodePort にしました。NodePort はプログラムではなく、kube-proxy が各ノードに書く決まりです。ノードのポート 30080 番に来たリクエストを、web の Pod のどれかに渡します。ほかの入口を使うときの書き分けは、記事の最後の付録にまとめました。 クラスターの外からは、ノードの IP のポート 30080 番(NodePort)で呼べます。Pod の IP や Service の IP は、クラスターの中だけで使うものなので、外からは使えません。この記事ではノードは VM 1台なので、ノードの IP は VM の IP です。VM の外からつなぐときは、クラウドの側のファイアウォール(OCI のセキュリティ・リストなど)でも 30080 番を開けます。 ノードの IP の 30080 番に、30回送りました。 for i in $(seq 30); do curl -s http://<ノードの IP>:30080/ | grep Hostname; done | sort | uniq -c 8 Hostname: web-5f94c944b-kftn5 12 Hostname: web-5f94c944b-kpff5 10 Hostname: web-5f94c944b-mrx7f 3つに分かれましたが、順番ではありません。kube-proxy が書いた iptables の決まりが、リクエストごとに確率で行き先を選んでいます。 readinessProbe で調子の悪い Pod を外す readinessProbe は、Pod の調子を決まった間隔で確かめる仕組みです。web.yaml では、2秒ごとに /health を確かめ、2回続けて失敗したら、Service の振り分け先から外します。返ってきた状態コードが 200〜399 なら成功、それ以外は失敗です。 whoami は、/health に POST すると返す状態コードを変えられます。1つの Pod だけ 500 を返すようにしました。 curl -X POST -d 500 http://<Pod の IP>:8080/health 2.3 秒で、その Pod の READY が 0/1 になり、振り分け先の一覧(EndpointSlice)でも外れました。この間に30回送ると、外れた Pod には1回も渡りませんでした。 web-5f94c944b-kpff5 0/1 Running 0 48s 12 Hostname: web-5f94c944b-ml9l4 18 Hostname: web-5f94c944b-mrx7f ml9l4 は、Deployment の節で Pod を1つ消したときに、代わりに立った Pod です(実際には、Service の節の30回を送ったあとに消しました)。200 に戻すと、READY は 1/1 に戻りました。外すだけで Pod は止めないので、RESTARTS も 0 のままです。 似た仕組みの livenessProbe は、失敗したらコンテナを起動し直します。k8s のドキュメントは、間違った設定は連鎖的な障害につながるので気をつけて使うように、と書いています。この記事では試していません。 止めずに新しいバージョンへ入れ替える kubectl set image deployment/web whoami=traefik/whoami:v1.12.0 kubectl rollout status deployment/web Deployment は、新しい Pod を立てては古い Pod を止める、を繰り返して入れ替えます(ローリングアップデート)。何も書かなければ、一度に増やしてよい数も減らしてよい数も 25% で、Pod が3つなら「1つ増やし、使えるようになったら古いのを1つ止める」になります。10秒ほどで入れ替わりました。 入れ替えの途中の失敗 入れ替えの間、0.05 秒おきに NodePort へ送り続けて(1回の入れ替えで370〜540回)、失敗を数えました。 preStop 入れ替えた回数 1回の入れ替えでの失敗の数 なし 5回 2, 4, 2, 5, 6 あり(5秒) 9回 1, 1, 0, 0, 0, 0, 1, 0, 0 失敗には、すぐ断られるもの(curl の終了コード 7)と、3秒待っても応答がないもの(終了コード 28)がありました。 すぐ断られるほうには、はっきりした理由があります。Pod を止めると決まると、k8s は「振り分け先から外す」と「コンテナに止まれと合図(SIGTERM)を送る」を同時に進めます。コンテナが先に止まると、まだ外れる前の振り分けで届いたリクエストが、もういないコンテナに当たります。 Pod を止めるときの順番 preStop の sleep は、合図を送る前に決めた秒数だけ待ちます。その間に振り分け先から外れます。preStop ありでは、すぐ断られる失敗は、記録できた範囲で出ませんでした(最初の2回は種類を記録していません)。3秒の時間切れは、ありなしにかかわらず少し出て、理由は確かめられていません。CPU 1コアで、新しい Pod の起動と取り合っているのかもしれませんが、推測です。 sleep は、コンテナの中のコマンドを使わずに待てる書き方で、シェルの入っていないイメージでも使えます。待つ時間は、Pod を止めるまでの猶予(何も書かなければ30秒)に含まれます。 前のバージョンには kubectl rollout undo で戻せますが、kubectl apply で渡した Deployment に使うと「ファイルを戻して apply し直して」という意味の警告が出ました。set image も含めて、ファイルを正にするなら、バージョンもファイルで書き換えて apply するのが筋です。 Job で終わりのある仕事を流す Deployment は「ずっと動かしておく」もの、Job は「終わりのある仕事を、最後までやらせる」ものです。Deployment では、コンテナの中のプログラムが終わると「落ちた」とみなされて、起動し直されます。Job では、プログラムがうまく終われば「やり終えた」とみなされ、Pod は完了(Completed)のまま残ります。失敗して終わったときだけ、やり直します。データを作る、学習を回す、といった仕事は、こちらで流します。 試した job.yaml は、本物の仕事の代わりに、part 0 start と表示して3秒待ち、part 0 done と表示して終わるだけのコマンドを動かします。本物の仕事なら、command のところが、データを作るスクリプトや学習のスクリプトになります。 job.yaml apiVersion: batch/v1 kind: Job metadata: name: count spec: completionMode: Indexed # 0、1、2 の番号を振る completions: 3 # 3つの部分をそれぞれ1回成功させる parallelism: 1 # 同時に動かすのは1つ(CPU 1コアなので) backoffLimit: 2 # 失敗したら2回までやり直す ttlSecondsAfterFinished: 600 # 終わって10分たったら片付ける template: spec: restartPolicy: Never containers: - name: work image: busybox:1.37 command: ["sh", "-c", "echo part $JOB_COMPLETION_INDEX start; sleep 3; echo part $JOB_COMPLETION_INDEX done"] この Job は、同じ仕事を 0・1・2 の番号で3つに分けて、1つずつ流します。 completions: 3:Pod が3つ成功したら、Job は終わり completionMode: Indexed:Pod に 0・1・2 の番号を振る。番号は、環境変数 JOB_COMPLETION_INDEX でコンテナに渡る parallelism: 1:同時に動かす Pod は1つ。この VM は CPU 1コアなので、1つずつにした kubectl apply -f job.yaml で渡すと、23秒で 3/3 が終わりました。番号ごとのログは part 0 start、part 0 done、…、part 2 done でした。 いくつも同時に流す parallelism を 3 にすると、番号 0・1・2 の Pod が同時に動きます。番号で仕事を分けておけば、「データの 0 番目のかたまりは、番号 0 の Pod が受け持つ」のように、大きな仕事を分けて並べられます。 中身の違う仕事は、Job を別々に書いて、それぞれ kubectl apply で渡します。Job 同士は互いを待たず、ノードに空きがあれば同時に動きます。空きが足りなければ、Pod は Pending のまま、空くのを待ちます。 順番に流す 「データを作る Job が終わってから、学習の Job を流す」のような順番は、Job のマニフェストには書けません。Job には、ほかの Job を待つという書き方がないからです。一番簡単なのは、手元で前の Job が終わるのを待ってから、次を渡す方法です。3行を && でつないで、1つのコマンドとして流します。 kubectl apply -f make-data.yaml && kubectl wait --for=condition=complete job/make-data --timeout=1h && # 終わるまで待つ kubectl apply -f train.yaml 1行ずつ手で打つなら、kubectl wait が終わるまで次の行は打てないので、&& がなくても順番は守れます。&& でつないでおくと、まとめて貼り付けたときや、スクリプトにして放っておくときも、前が成功したときだけ次に進みます。; でつなぐと、前が失敗しても次に進んでしまいます。make-data が失敗すると、kubectl wait は1時間たつまで待ち続けて失敗で終わるので、train.yaml は渡されません。段が増えたり、枝分かれしたりするなら、Argo Workflows のような、Job の順番を書くための仕組みを使います。EKS の節で出てくる OSMO も、データ作り・学習・評価といった段階を、順につないで流す仕組みです。GPU を使う学習やシミュレーションを Job で流す話は、別の記事で扱う予定です。 k3s 以外の選び方 ここまでは k3s で動かしてきましたが、k8s を動かすソフトはほかにもいくつもあります。どれも中身は k8s なので、マニフェストの基本の書き方は同じです。違うのは、どこで、何のために動かすかです。この節は公式のページを読んでまとめたもので、k3s 以外は試していません。 やりたいこと 候補 手元の PC で触ってみる minikube・kind・k3d 小さなサーバーやエッジで動かす k3s・k0s・MicroK8s 自分のサーバーで本番を動かす RKE2・kubeadm・Talos Linux・OpenShift クラウドで本番を動かす EKS・GKE・AKS minikube:k8s の公式プロジェクト。アプリを作る人と、k8s を初めて使う人に向けている kind:Docker のコンテナをノードの代わりにする。もとは k8s そのもののテスト用で、CI にも使える k3d:k3s を Docker のコンテナの中で動かすツール k0s:k3s と同じく、1つの実行ファイルで動く MicroK8s:Canonical(Ubuntu の会社)製。snap で入れて、機能をコマンド1つで足したり外したりする kubeadm:公式の組み立てツール。クラスターを立てるところだけを受け持ち、マシンの用意や、ネットワークなどの追加部品(アドオン)は自分で入れる Talos Linux:k8s のためだけの OS。SSH もシェルもなく、API で操作する OpenShift:Red Hat 製。k8s に手を加え、部品をたくさん最初から入れた大きな作り。もとになっているのは、コミュニティが作る OKD で、無料で使える GKE・AKS:Google Cloud と Microsoft Azure の k8s。この記事では、次の節で EKS だけを取り上げる ここからは公式の基準ではなく、私の整理です。迷ったときは、次の順に考えると絞れます。 コントロールプレーンの面倒を誰が見るか 一番大きな分かれ目です。自分で持つと、バージョンを上げる、etcd(クラスターの状態を覚えておくデータベース)のバックアップを取る、といった作業も自分の仕事になります。クラウドを使えるなら、EKS のようなサービスに任せるのが最初に考える候補です 壊して作り直してよいか 試すだけなら、PC の上ですぐ作り直せる minikube・kind・k3d で足ります マシンの大きさ メモリが少ないマシンや、エッジの機械なら k3s・k0s・MicroK8s です セキュリティの基準を求められるか CIS ベンチマークなどへの対応を求められるなら、最初からそれを見込んで作られている RKE2 や OpenShift が候補です EKS では何が変わるか EKS は試していないので、公式のドキュメントから整理しました。 この記事の k3s Amazon EKS コントロールプレーン 同じ VM の中 AWS が動かす。1か所が止まっても続くように、いくつかのデータセンター(アベイラビリティーゾーン)に分けて置かれる。クラスター1つにつき1時間 0.10 ドル(標準サポートのバージョンの場合) ノード 同じ VM EC2。自分でノードグループを作るか、EKS Auto Mode に任せる 外からの入口 NodePort Service から NLB、Ingress から ALB を作る ディスク ノードのディスク EBS(AWS のブロックストレージ) kubectl 同じ 同じ。aws eks update-kubeconfig で設定ファイルを作る EKS Auto Mode を使うと、マシンの増減、ロードバランサー、ディスク、GPU まわりを AWS が最初から用意します。eksctl(EKS のクラスターを作るコマンド)なら、クラスターの名前と地域に autoModeConfig: {enabled: true} を足しただけの YAML で作れます。Auto Mode を使わない場合は、AWS Load Balancer Controller や EBS 用のドライバーを自分で入れます。入れないまま LoadBalancer の Service を作ると、NLB ではなく、古い種類のロードバランサー(CLB)ができます。Deployment、Service、Job、readinessProbe、preStop の考え方は、EKS でもそのまま使えます。 AWS Physical AI Toolchain のサンプルには、OSMO を EKS に入れる一式(osmo-on-aws)が入っています。OSMO には、イメージ、コマンド、GPU の枚数を書いたワークフローの YAML を渡します。すると OSMO が、EKS のクラスターの上で Pod を動かします。OSMO を使う人は Pod や Job を直接は書きませんが、その下では、この記事で動かした Pod やノードが働いています。GPU のマシンの用意と、サンプルの中身を読む話は、続きの記事で扱う予定です。 片付け kubectl delete -f web.yaml -f job.yaml /usr/local/bin/k3s-uninstall.sh sudo firewall-cmd --permanent --zone=trusted --remove-source=10.42.0.0/16 sudo firewall-cmd --permanent --zone=trusted --remove-source=10.43.0.0/16 sudo firewall-cmd --reload rm ~/.kube/config k3s-uninstall.sh で、k3s 本体、k3s-selinux、Rancher のリポジトリの設定が消えました。一緒に入った container-selinux は残るので、要らなければ別に消します。 まとめ k8s には「こうなっていてほしい」を書いて渡す。Pod を1つ消すと、数秒で立て直された Service はラベルで Pod をまとめ、変わらない名前で呼べるようにする。この k3s では、行き先は確率で選ばれた readinessProbe で Pod の調子を確かめる。失敗した Pod は振り分けから外れた 入れ替えの途中の「すぐ断られる」失敗は、preStop の sleep で出なくなった 終わりのある仕事は Job で流す。同時に流すのは Job を並べるだけだが、順番は Job には書けない k3s のほかにも、k8s を動かすソフトはいくつもある。選ぶときは、コントロールプレーンの面倒を自分で見るかどうかから考えると絞りやすい(私の整理) EKS では、マシン・入口・ディスクの用意が変わるが、マニフェストの考え方はそのまま使える AWS Physical AI Toolchain の OSMO も、EKS の上で Pod を動かす。ワークフローの YAML の下で、この記事の部品が働いている 付録 kind に書ける主な種類 kind に書けるものは、ほかにもたくさんあります。よく使うものを挙げます。 kind 何を表すか Pod コンテナを動かす最小の単位。普通は直接書かない ReplicaSet Pod の数を保つもの。普通は Deployment が作る Deployment ずっと動かしておく Pod の数と作り方 Service Pod をまとめて、変わらない名前で呼ぶための入口 Job 終わりのある仕事。最後までやったら完了 Ingress URL ごとに、どの Service へ渡すかの決まり ConfigMap 設定の値 Secret パスワードなどの秘密の値 Namespace クラスターの中を区切る仕切り そのクラスターで書ける種類の一覧は、kubectl api-resources で見られます。 外からの入口ごとの Service の書き方 この記事では NodePort でつなぎましたが、外からの入口の作り方を変えると、Service の type と、まわりに足すものが変わります。 入口 Service の type ほかに要るもの NodePort(この記事) NodePort なし。ノードのポートの 30000〜32767 番で受ける ロードバランサー LoadBalancer ロードバランサーを用意する仕組み。k3s では servicelb、自分のマシンでは MetalLB など。EKS では AWS が NLB を作る リバースプロキシ ClusterIP Traefik などのリバースプロキシと、Ingress。リバースプロキシ自身は LoadBalancer か NodePort の Service で外から受ける クラスターの外のロードバランサー NodePort 外のロードバランサーの行き先を、各ノードの NodePort にする。前から使っているロードバランサーを、そのまま入口にしたいときに使う どれを選んでも、Deployment や Pod の書き方は変わりません。 参考 Requirements・Advanced Options(k3s のドキュメント) Introduction・Requirements(RKE2 のドキュメント) minikube・kind・k3d・k0s・MicroK8s・kubeadm・Talos Linux・OpenShift・OKD(各ソフトの公式ページ) Deployments・Service・Jobs・Creating a cluster with kubeadm・kubectl wait(k8s のドキュメント) Argo Workflows Liveness, Readiness, and Startup Probes・Container Lifecycle Hooks(k8s のドキュメント) traefik/whoami Amazon EKS の料金 Amazon EKS architecture・Route TCP and UDP traffic with Network Load Balancers(EKS のドキュメント) EKS Auto Mode(eksctl のドキュメント) aws-samples/sample-the-physical-ai-toolchain-on-aws(AWS のサンプル。OSMO を EKS に入れる一式は osmo-on-aws) 脚注 本番のクラスターでは、コントロールプレーンとノードを別のマシンに分けるのが一般的です。公式の組み立てツールの kubeadm で作ると、安全のため、初期設定ではコントロールプレーンのマシンに Pod を置きません。EKS などのクラウドのサービスでは、コントロールプレーンのマシンは利用者からは見えず、Pod も置けません。この記事のように1台で兼ねるのは、試すときや小さな環境で、k3s は初期設定のままで兼ねます。 ↩︎

  6. AgentCore Gateway によるモデル利用の認証・認可と利用量・予算管理 はじめに こんにちは、AWS Japan AI Specialist Solutions Architect の Narimoto です。 業務での AI 活用には、問い合わせへの回答や文書の要約、コーディングエージェントによる実装やテストなど、さまざまな使い方があります。さらに、継続的な役割を持ち、人と協働しながら複数のタスクを進める AI Teammate (AI 社員) としての活用も考えられます。本稿では、このようなエージェントを AI 社員と呼びます。 利用者が一度依頼した後も、AI 社員はモデルを繰り返し呼び出します。組織でこうした利用を広げるには、呼び出し元の利用者やエージェントを認証し、役割や業務に応じて利用できるモデルを許可する必要があります。また、複数のエージェントが同時に動く場合は、特定の呼び出し元から要求が集中しないよう、呼び出し頻度や同時実行数にも上限を設けたいところです。さらに、調査や試行錯誤が続けば費用も積み上がります。できるだけ品質の高い結果を得られるようにしながら、どの予算へ費用を計上し、いくらまで使えるかも管理する必要があります。 LLM Gateway としての AgentCore Gateway このようなモデルの利用の課題 (認証・認可、利用量の制限、費用・予算) 以外にも、次のような課題が挙げられます。 こうしたモデルの利用の課題を共通のエントリポイントで管理するために、本稿では Amazon Bedrock AgentCore Gateway (以下 AgentCore Gateway) を LLM Gateway として活用します。 AgentCore Gateway の機能と、追加実装で扱う範囲を次の表に整理します。 観点 機能 接続・API AgentCore Gateway の inference target でモデル呼び出しを構成 モデル選択・最適化 AgentCore Gateway ルール でモデルの振り分けを設定 認証・認可 AgentCore Gateway の Inbound auth で呼び出し元を検証し、Amazon Bedrock AgentCore Policy (以下 AgentCore Policy) で操作とモデルの権限を管理、AgentCore Gateway Interceptors で業務固有の検査を追加 利用量の制限 AgentCore Gateway の rate limit で要求数・トークン数・同時接続数を制限 費用・予算 公開サンプル の AgentCore Gateway の REQUEST interceptor で予算を検査し、RESPONSE interceptor で応答の usage と設定単価から費用を計上 障害対応 AgentCore Gateway ルールの fallback で接続先の失敗などに対応 ガードレール AgentCore Policy と Bedrock Guardrails の連携 を利用 本稿で扱う構成と管理単位 今回は、「利用を管理する」観点から AgentCore Gateway における「認証・認可、利用量の制限、費用・予算」の範囲を紹介します。 その構成例として、利用者から依頼を受けた AI 社員が、利用者の権限と予算でモデルを呼び出す構成を考えます。AgentCore Gateway で利用者と許可されたモデルを確認し、呼び出し頻度や同時接続数を制限します。費用・予算管理には AWS の公開サンプル を使い、応答の利用量から費用を計上します。日次または月次の予算への到達を確認したら、新しいモデル呼び出しを拒否します。 モデルの利用権限や費用・予算は、例えば次の単位で管理する設計が考えられます。呼び出し元のユーザーやエージェントを認証したうえで、担当業務や所属、タスクの目的に応じて利用できるモデルと予算を設定します。 管理の単位 認証・認可の例 費用・予算の例 タスク単位 認証済みの利用者やエージェントに、対象タスクで必要なモデルの利用を許可 一つの調査やコード修正について、完了または停止までに使う費用を制限 プロジェクト単位 所属する利用者やエージェントに、プロジェクトで利用を認めたモデルへのアクセスを許可 参加する利用者やエージェントの費用を集計し、共有の枠で管理 ユーザー単位 利用者を認証し、担当業務や役割に応じて利用できるモデルを設定 一人の利用者が複数のタスクで使う費用を、月単位などで管理 AI 社員単位 AI 社員を呼び出し元として識別・認証し、任せる業務に必要なモデルの利用を許可 継続的な役割を任せたエージェントについて、複数タスクの費用を月単位などで管理 AI 社員へ継続的に仕事を任せるなら、「どの業務で、どのモデルを使わせるか」と「一カ月いくらまで使わせるか」を組み合わせて管理する必要があると考えています。 このうち、公開サンプルが実装するのは JWT から識別した利用者ごとの日次・月次予算です。本稿ではその実装を使い、AgentCore Gateway における inbound auth、AgentCore Policy、rate limit を追加する設定例を紹介します。 AgentCore Gateway のターゲットと推論の接続 AgentCore Gateway の接続先 は「target」と呼びます。集約したい呼び出しに合わせて target の種類を選びます。 MCP targets は、AWS Lambda、OpenAPI などで定義した API、既存の MCP サーバーなどのツールを一元管理します。エージェントへツールを公開し、一覧取得やセマンティック検索を使いたい場合の選択肢です。 HTTP targets は、リクエストのパスに応じて接続先を選び、HTTP のまま転送します。AgentCore Runtime 上のエージェント や HTTPS endpoint を共通のエントリポイントから呼ぶ場合に使います。 Inference targets は、指定されたモデル ID に応じて推論先を選びます。Amazon Bedrock、OpenAI、Anthropic などのモデル呼び出しを一元管理します。本稿の LLM Gateway 用途として使用します。 MCP targets を前提としたアクセス制御は、以下の「AgentCore Gateway で MCP サーバー・ツールのアクセス制御を実現する 3 つの方法の徹底比較」の Zenn 記事をご覧ください。 zenn.dev 図の青い実線は通信、紫の点線は AgentCore Gateway に関連付ける接続設定です。組み込みの定義を使う connector と、HTTPS endpoint、モデルの対応、操作のパスを指定する provider があります。 図の Responses、Messages、InvokeModel はモデル提供者側の API です。connector / provider は接続を設定する方法なので、API の種類とは別に選びます。 Connector によるターゲット登録 connector は、対応するプロバイダーの組み込み設定を使う方法です。接続先や操作、モデル ID の扱いを個別に設定する代わりに、connectorId を指定します。以下は bedrock-mantle の登録例です。 gateway_id には作成済み AgentCore Gateway の ID を指定します。Boto3 は実行環境の認証情報を使い、region_name で操作先のリージョンを明示します。 import boto3 control = boto3.client("bedrock-agentcore-control", region_name="<Region>") target = control.create_gateway_target( gatewayIdentifier=gateway_id, name="bedrock-mantle", targetConfiguration={ "inference": { "connector": {"source": {"connectorId": "bedrock-mantle"}} } }, credentialProviderConfigurations=[ {"credentialProviderType": "GATEWAY_IAM_ROLE"} ], ) 組み込み ID は bedrock-mantle、bedrock-runtime、openai、anthropic です。たとえば bedrock-runtime connector は Bedrock のモデルカタログから検出し、InvokeModel / InvokeModelWithResponseStream などの操作を設定します。モデルの検出元や対応 API は接続先の仕様を確認します。 ! この例の接続先は Amazon Bedrock です。GATEWAY_IAM_ROLE は AgentCore Gateway の実行ロールで送信要求を署名する設定であり、利用者の JWT を Bedrock へ転送する設定ではありません。OpenAI や Anthropic の直接契約は必須ではありません。 Provider による接続先・モデルの指定 provider は、HTTPS endpoint や操作ごとのモデルを明示する方法です。path は AgentCore Gateway 側の操作パス、providerPath は転送先で異なるパスを使う場合の指定です。 次は今回追加する bedrock-models target の例です。SDK から取得したリージョンの Bedrock Runtime endpoint に、Responses と Messages の 2 操作と、それぞれの global inference profile ID を登録します。 import boto3 region_name = "<Region>" control = boto3.client("bedrock-agentcore-control", region_name=region_name) runtime = boto3.client("bedrock-runtime", region_name=region_name) provider_target = control.create_gateway_target( gatewayIdentifier=gateway_id, name="bedrock-models", targetConfiguration={ "inference": { "provider": { "endpoint": runtime.meta.endpoint_url, "operations": [ {"path": "/v1/responses", "providerPath": "/openai/v1/responses", "models": [{"model": "global.openai.gpt-6-sol"}]}, {"path": "/v1/messages", "providerPath": "/anthropic/v1/messages", "models": [{"model": "global.anthropic.claude-haiku-5-5"}]}, ], } } }, credentialProviderConfigurations=[ {"credentialProviderType": "GATEWAY_IAM_ROLE"} ], ) 呼び出し元は /inference/v1/responses または /inference/v1/messages に要求を送ります。元の Mantle target と REQUEST / RESPONSE Lambda は保持し、AI 社員用の Policy は追加した bedrock-models の操作とモデル ID を許可します。 ! 追加実装では、AgentCore Gateway の実行ロールに選択した inference profile と参照先の foundation model に対する推論権限を付与します。Responses API の権限要件に合わせ、アカウント・リージョンの project/default にも bedrock:InvokeModel を許可します。既存の interceptor 呼び出し権限も保持します。 AWS サービス構成 今回の構成では、AgentCore Gateway の認証・認可、利用量の制限、費用・予算を組み合わせます。Inbound auth で呼び出し主体を検証し、AgentCore Policy で操作とモデルの利用を認可します。Rate limit で呼び出し頻度と同時接続数を制限し、公開サンプルの REQUEST / RESPONSE interceptors で費用・予算を管理します。 図では、利用者が Amazon Cognito から JWT を取得し、リクエストとともに AgentCore Runtime へ送ります。Runtime 上のエージェントは、その JWT を付けて AgentCore Gateway を呼び出します。AgentCore Gateway は利用者の主体を検証し、REQUEST interceptor で予算を確認してからモデルを呼びます。応答は RESPONSE interceptor で費用を計上した後、エージェントへ返します。 Lambda は AgentCore Gateway が呼び出す interceptor として配置します。Runtime と AgentCore Gateway の間に、モデル呼び出しを中継する専用のバックエンドは設けません。本稿の実装 は、公開サンプルの構成に AgentCore Runtime V2 上の簡易な AI 社員を追加しています。AI 社員は作業計画を考え、ツールで作業項目を記録し、その結果を利用者へ返します。 ! 同じ JWT を引き継ぐには、Runtime と AgentCore Gateway の両方で、その JWT を受け入れる authorizer を設定します。Runtime では requestHeaderConfiguration.requestHeaderAllowlist に Authorization を追加 し、エージェントコードで受け取った値を AgentCore Gateway 向けリクエストの Authorization に設定します。Runtime が AgentCore Gateway へ自動転送する機能ではありません。同じ利用者の JWT で動く複数のエージェントは、利用者の予算を共有します。 設計するもの 判断すること 使用するサービス・機能 呼び出し元の識別 誰の依頼としてモデルを呼び出しているか Amazon Cognito のユーザープール、AgentCore Runtime と AgentCore Gateway の inbound auth 操作とモデルの認可 その主体に Responses / Messages と対象モデルを許可するか AgentCore Policy の Policy Engine と Cedar ポリシー [Optional] 呼び出し頻度と同時実行数の制限 呼び出し元ごとに設定した RPM・同時接続数の範囲か AgentCore Gateway の rate limit (requests / connections) 予算の設定・変更 利用者ごとに日次・月次でいくら使えるか AWS CloudFormation の既定予算パラメータと Amazon DynamoDB の利用者別上限 予算の検査 計上済み費用が日次・月次予算へ到達したか AgentCore Gateway の REQUEST interceptor と AWS Lambda 利用者と応答の対応付け どの利用者の要求に対する応答か AgentCore Gateway の REQUEST_ID と Amazon DynamoDB のリクエストコンテキストテーブル 費用計上と可視化 どのモデルをどれだけ使ったか RESPONSE interceptor の AWS Lambda、Amazon DynamoDB、Amazon CloudWatch 多層防御とアクセス制御 AWS は、AWS AI セキュリティフレームワーク で、複数の制御を組み合わせる多層防御を推奨しています。判断に必要な情報に応じて実装場所を選びます。 仕組み 実装するもの 判断に使う情報 本構成での役割 AgentCore Gateway の Inbound auth AgentCore Gateway の authorizer 設定 JWT の発行元・client・scope・カスタム claim など AgentCore Gateway を利用できる主体か検証 AgentCore Policy Policy Engine とポリシー 主体・操作・リソース・評価可能な入力 呼び出せる API とモデルの認可ルールを独立して管理 AgentCore Gateway interceptors REQUEST / RESPONSE の Lambda 関数 リクエスト・レスポンスと外部情報 REQUEST で予算を検査し、RESPONSE で費用を計上 AgentCore Policy を使う理由は、認可ルールをモデルの判断から分離し、適用前に決定論的に検証できるようにするためです。累積費用による判断は REQUEST interceptor、どの API とモデルを使ってよいかというルールは AgentCore Policy に置きます。予算が残っていても、認可されていないモデルは使えません。 図は、モデルの呼び出しを例に、JWT の検証、API とモデルの認可、interceptors による独自処理の役割を示しています。AgentCore Gateway の設定やポリシーを変更する権限は、推論する主体から分離します。 AgentCore Gateway への inbound auth Inbound auth は、AgentCore Gateway へのアクセスを受け入れる段階の制御です。JWT を使う場合は、IdP の公開鍵を使った検証に加えて、指定した claim や scope の条件を満たすかを確認します。本稿では Cognito が利用者へ発行した JWT を使い、Runtime を経由する場合もその主体を引き継ぎます。 customJWTAuthorizer の主な設定 は次のとおりです。discoveryUrl に加え、受け入れ条件として allowedAudiences、allowedClients、allowedScopes、customClaims のうち少なくとも一つを指定します。複数を指定した場合は、それぞれの条件が検証されます。 設定 検証する内容 discoveryUrl JWT 検証に必要な公開鍵や認証サーバー情報を取得する IdP の OIDC discovery URL allowedAudiences JWT の aud が許可した宛先に含まれるか allowedClients JWT の client_id が許可したアプリケーションに含まれるか allowedScopes JWT に、指定した scope のうち少なくとも一つが含まれるか customClaims グループやロールなどの claim が、型と比較演算子で指定した条件を満たすか Cognito のアクセストークンを使う設定例では、sub で主体を識別します。Cognito のグループ による共通利用資格を設定するなら、cognito:groups に llm-gateway-access を含むことを要求できます。 この条件は、AgentCore Gateway 自体を使えるかどうかの判定です。利用できるモデルと累積費用は、AgentCore Policy と AgentCore Gateway interceptors で判定します。 次は、作成済みの user pool、app client、実行ロールを使う create_gateway の例です。以下では allowedClients だけではなく、追加のアクセス制御例として customClaims も指定し、利用者を事前に llm-gateway-access グループへ追加する構成にしています。 import boto3 control = boto3.client("bedrock-agentcore-control", region_name="<Region>") cognito = boto3.client("cognito-idp", region_name="<Region>") issuer = cognito.meta.endpoint_url.rstrip("/") + "/" + user_pool_id gateway = control.create_gateway( name="llm-gateway", roleArn=gateway_role_arn, protocolType="MCP", authorizerType="CUSTOM_JWT", authorizerConfiguration={ "customJWTAuthorizer": { "discoveryUrl": issuer + "/.well-known/openid-configuration", "allowedClients": [app_client_id], "customClaims": [ { "inboundTokenClaimName": "cognito:groups", "inboundTokenClaimValueType": "STRING_ARRAY", "authorizingClaimMatchValue": { "claimMatchOperator": "CONTAINS", "claimMatchValue": { "matchValueString": "llm-gateway-access" }, }, } ], } }, ) gateway_id = gateway["gatewayId"] allowedClients と customClaims を組み合わせ、対象のアプリケーション向けに発行された JWT であり、必要なグループも claim に含まれることを確認します。 Cognito のアクセストークンに独自の claim を追加する場合は、AWS Blog How to customize access tokens in Amazon Cognito user pools もあわせてご覧ください。 AgentCore Policy による API とモデルの認可 AgentCore Policy は、AgentCore Gateway が受けたリクエストに対し、ポリシーで定めた操作を許可・拒否する仕組みです。複数のポリシーを Policy Engine に登録して AgentCore Gateway へ関連付けます。Cedar の principal は主体、action は操作、resource は対象の AgentCore Gateway を表します。 Responses / Messages の本文には model があります。推論モデルを制限する公式ガイドのポリシー例 と同じように、context.input.model と主体・操作を組み合わせて認可します。AgentCore Policy は、公開サンプルで作成した AgentCore Gateway に追加する設定です。 次は、一人の利用者に Responses / Messages と対象モデルを許可する Cedar の例です。山括弧の値を実際の値へ置き換えます。action 名は target 名と操作の組み合わせ です。<responses-action-id> と <messages-action-id> には、登録した target のスキーマから確認した action を指定します。 permit( principal == AgentCore::OAuthUser::"<gateway-caller-sub>", action in [ AgentCore::Action::"<responses-action-id>", AgentCore::Action::"<messages-action-id>" ], resource == AgentCore::Gateway::"<gateway-arn>" ) when { ( action == AgentCore::Action::"<responses-action-id>" && context.input.model == "<approved-openai-model-id>" ) || ( action == AgentCore::Action::"<messages-action-id>" && context.input.model == "<approved-anthropic-model-id>" ) }; 本稿は一意に解決するモデル ID を本文へ指定する例です。target 名を付けたモデル ID やモデル名を書き換えるルールを使う場合は、Policy が評価する値との一致も確認します。すべての API を許可する広い permit を併存させると、モデルを限定した条件が意図どおりの制限にならないため、既存のルールも合わせて見直します。 まず、Boto3 で Policy Engine とポリシーを作成します。<cedar ポリシーを記述> には、上の Cedar の例を設定に合わせて記述します。validationMode="FAIL_ON_ANY_FINDINGS" で検証し、ポリシーが ACTIVE になるまで待ちます。 リソースを作成する管理者側には、Policy 作成時の検証に使う bedrock-agentcore:InvokeGateway などの管理権限 が必要です。AgentCore Gateway の実行ロールと、構築作業を行う管理者の権限は別々に設定します。 import boto3 control = boto3.client("bedrock-agentcore-control", region_name="<Region>") engine = control.create_policy_engine(name="model_access_engine") policy_engine_id = engine["policyEngineId"] control.get_waiter("policy_engine_active").wait( policyEngineId=policy_engine_id ) policy = control.create_policy( policyEngineId=policy_engine_id, name="allowed_model_apis", definition={ "cedar": { "statement": "<Cedar ポリシーを記述>" } }, validationMode="FAIL_ON_ANY_FINDINGS", enforcementMode="ACTIVE", ) control.get_waiter("policy_active").wait( policyEngineId=policy_engine_id, policyId=policy["policyId"], ) 関連付けの前に、Policy 評価に必要な IAM 権限 を AgentCore Gateway の実行ロールへ追加します。 IAM 権限を追加したら、update_gateway の policyEngineConfiguration に Policy Engine の ARN を指定して関連付けます。gateway_id は作成済みの AgentCore Gateway の ID です。この API は設定全体を置き換えるため、既存の認証や interceptor などの設定も引き継ぎます。 current = control.get_gateway(gatewayIdentifier=gateway_id) update = { key: current[key] for key in ( "name", "roleArn", "authorizerType", "authorizerConfiguration", "protocolType", "protocolConfiguration", "description", "exceptionLevel", "kmsKeyArn", "interceptorConfigurations", "customTransformConfiguration", "wafConfiguration", ) if key in current } control.update_gateway( gatewayIdentifier=gateway_id, **update, policyEngineConfiguration={ "arn": engine["policyEngineArn"], "mode": "ENFORCE", }, ) ENFORCE は拒否を強制し、LOG_ONLY は評価しても拒否しません。AgentCore Gateway の更新完了後、許可する要求と拒否する要求の両方を試して適用範囲を確認ください。 ポリシーの作成・検証・段階的な適用の進め方は、AWS Blog Secure AI agents with Policy in Amazon Bedrock AgentCore もあわせてご覧ください。 AgentCore Gateway interceptors による追加検査 AgentCore Gateway interceptors は、AgentCore Gateway が扱うリクエストやレスポンスを Lambda 関数へ渡し、独自の検査や変換を追加する仕組みです。REQUEST interceptor は接続先へ送る前、RESPONSE interceptor は接続先から応答を受け取った後に処理します。 実行箇所 受け取る情報 本稿での処理 REQUEST リクエスト本文と、転送を有効にしたリクエストヘッダー JWT から利用者を特定し、DynamoDB の日次・月次費用と予算上限を検査 RESPONSE 接続先から返されたレスポンス usage を解析し、設定単価から費用を計算して DynamoDB と CloudWatch へ記録 HTTP / inference のイベントでは、本文を Base64 から復号して扱います。REQUEST から transformedGatewayResponse を返すと、接続先のモデルを呼ばずに拒否できます。例えば、予算到達時に HTTP 403 と BUDGET_EXCEEDED を返すように設計します。 Inference target は、HTTP 形式の interceptor ペイロードを使用します。Inference target の場合、RESPONSE 側のイベントには、元のリクエスト情報が含まれません。公開サンプルでは、Lambda の context.client_context.custom に渡される REQUEST_ID をキーに、REQUEST 側で利用者とチームを DynamoDB に一時保存し、RESPONSE 側で参照します。 ! 以下は、公開サンプルをもとに処理の要点を示したコードです。_ で始まる補助関数、設定の読み込み、料金表にないモデルの拒否、ログ・例外処理の詳細は省略しています。単独でデプロイするコードではなく、実行にはリンク先の実装全体を使用してください。 REQUEST 側の Lambda では、inbound auth で検証済みの JWT から利用者を特定し、計上済み費用を検査します。予算到達時は拒否の応答を返し、それ以外は空の http を返して元のリクエストを通します。 cloudformation/standalone.yaml: RequestInterceptorFunction の簡略例 import base64 import json def lambda_handler(event, context): request = event["http"]["gatewayRequest"] headers = {k.lower(): v for k, v in (request.get("headers") or {}).items()} user, team = _user_id(headers) request_id = _request_id(context) stashed = _stash_context(request_id, user, team) if not stashed and request_id and user != "unknown" and ENFORCE: return _service_unavailable("context stash write failed") if user == "unknown": return {"interceptorOutputVersion": "1.0", "http": {}} 料金表にないモデルの拒否処理などは省略。 daily_spend, daily_cap, monthly_spend, monthly_cap = _lookup_state(user) if ENFORCE and (daily_spend >= daily_cap or monthly_spend >= monthly_cap): body = json.dumps({"error": {"code": "BUDGET_EXCEEDED"}}) return { "interceptorOutputVersion": "1.0", "http": { "transformedGatewayResponse": { "statusCode": 403, "headers": {"content-type": "application/json"}, "contentType": "application/json", "body": base64.b64encode(body.encode()).decode(), } }, } return {"interceptorOutputVersion": "1.0", "http": {}} RESPONSE 側の Lambda では、REQUEST_ID から利用者を参照し、応答の usage を費用へ換算します。DynamoDB の費用加算と CloudWatch 向けのメトリクス出力を行い、応答自体は変更せずに返します。費用計算は公開サンプルの _cost に任せます。 cloudformation/standalone.yaml: ResponseInterceptorFunction の簡略例 def lambda_handler(event, context): response = event["http"]["gatewayResponse"] passthrough = {"interceptorOutputVersion": "1.0", "http": {}} if response.get("statusCode", 200) >= 400: return passthrough user, team = _fetch_context(_request_id(context)) body = _decode_body(response.get("body"), response.get("contentType") or "") model = _normalize_model(body.get("model")) tokens = _extract_usage(body) if not any(tokens): return passthrough cost = _cost(model, *tokens) if cost > 0 and user != "unknown": _bump_spend(user, cost) _emf(user, team, model, *tokens, cost) return passthrough 次は、両方の interceptor を AgentCore Gateway に関連付ける例です。Lambda 関数の ARN には公開サンプルで作成した alias の ARN を使います。既存の authorizer や前節の Policy Engine の関連付けを保持して更新します。 current = control.get_gateway(gatewayIdentifier=gateway_id) update = { key: current[key] for key in ( "name", "roleArn", "authorizerType", "authorizerConfiguration", "protocolType", "protocolConfiguration", "description", "exceptionLevel", "kmsKeyArn", "policyEngineConfiguration", "customTransformConfiguration", "wafConfiguration", ) if key in current } control.update_gateway( gatewayIdentifier=gateway_id, **update, interceptorConfigurations=[ { "interceptor": {"lambda": {"arn": request_function_arn}}, "interceptionPoints": ["REQUEST"], "inputConfiguration": {"passRequestHeaders": True}, }, { "interceptor": {"lambda": {"arn": response_function_arn}}, "interceptionPoints": ["RESPONSE"], }, ], ) 上のコードは、その関連付けを Boto3 で設定する例です。追加の AgentCore Gateway 設定を持つ場合は、その設定も保持します。 ! 本稿の構成では、RESPONSE interceptor が応答の usage を解析して費用の加算を試みた後、エージェントが結果を返します。 Policy と interceptors の使い分けや組み合わせ方は、MCP ツールのアクセス制御を題材とした AWS Blog Secure AI agents with Policy and Lambda interceptors in Amazon Bedrock AgentCore gateway もあわせてご覧ください。 AWS 公開サンプルによる費用・予算管理 ! 本節は、2026 年 10 月 30 日時点で参照した公開サンプル (コミット d79bd57) に基づいています。サンプルの実装や設定項目は更新される場合があるため、利用する版の README とコードもご確認ください。 Guidance for per-user cost attribution and hard budget enforcement on Amazon Bedrock AgentCore Gateway の AWS 公開サンプルは、利用者ごとの計上済み費用を使って、次のリクエストを受け付けるか判断します。モデルが応答で返した usage を、RESPONSE interceptor が費用へ換算します。 利用者ごとの予算設定 公開サンプルでは、利用者ごとに日次・月次の予算を設定します。共通の既定予算に加え、DynamoDB で利用者別の上限を管理できます。利用者の識別方法と費用の集計単位を先に決め、予算の変更権限は管理側に限定します。 主な変更箇所は次のとおりです。共通の設定は、cloudformation/standalone.yaml の CloudFormation パラメータとして指定します。 変更したい内容 変更箇所 利用者に適用する既定の日次・月次予算と、予算到達時の拒否 DailyBudgetUsd / MonthlyBudgetUsd / EnforceBudget。本稿では拒否を有効にするため EnforceBudget=true 利用者別の予算上限 CloudFormation 出力の SpendTableName が示す DynamoDB テーブルの、対象利用者の daily_cap_usd / monthly_cap_usd 費用集計に使う利用者の識別情報 UserClaim。認可や rate limit と同じ JWT の sub を使う場合は sub を指定 利用するモデルと料金 PriceTableJson。リクエストと応答で扱うモデル ID に対応する単価を登録 日次・月次の期間更新のタイムゾーン RolloverTimezone 設定値の形式や変更手順は 公開サンプルの設定ガイド をご確認ください。 リクエスト時の検査と応答後の計上 REQUEST interceptor は、計上済み費用を日次・月次の予算と比較します。本稿では予算による拒否を有効にし、どちらかに到達した利用者の新しいモデル呼び出しを拒否します。RESPONSE interceptor は、応答の usage と設定したモデル単価から費用を計算し、DynamoDB に加算します。 usage の取得方法やキャッシュ料金の扱いは API・モデルによって異なるため、利用するモデルが計上処理と料金設定の両方に対応しているか確認します。解析・費用計算の詳細は 公開サンプルの Lambda コード、Amazon Bedrock の最新単価は 料金ページ をご確認ください。 ! 参照した版の _extract_usage は、Responses API の usage.input_tokens_details.cached_tokens を読み取らず、キャッシュ分も通常の入力トークンとして扱います。キャッシュ利用時の費用を区別するには、PriceTableJson の変更に加えて、usage の解析処理も対応させる必要があります。 対応する usage の形式や料金区分を拡張する場合は、同テンプレートの ResponseInterceptorFunction 内にある _extract_usage (利用量の解析) と _cost (費用計算) を確認し、必要な処理を追加します。既存の処理で対応できるモデルの単価変更は、PriceTableJson で行います。 ! ここで計上する金額は、usage と設定単価によるモデル推論費用の計算値です。AgentCore Gateway や Lambda などの実行費用、請求上の割引まで含む総額ではありません。 予算到達時の動作と制約 この方式では、予算への到達を確認した後の新しいモデル呼び出しを止めます。実行中の生成を、費用が一定額になった瞬間に中断する仕組みではありません。 ! 費用を事後計上するため、最後の呼び出しや並行要求によって予算を超える可能性があります。キャッシュなどによる状態反映の遅れも考慮が必要です。予算超過を許容できない用途では、事前予約など別の受付設計が必要です。 ! 参照した版の 費用計上時のエラー処理 は、DynamoDB の加算に失敗すると bump_failed を記録しますが、モデルの応答は返します。利用者を特定できない場合も加算を省略するため、usage_recorded の spend_recorded などで計上状況を確認し、未計上分の検出・復旧を設計します。 公開サンプルの 予算読み取り時の処理 も確認し、読み取りに失敗した場合の受付動作を要件に合わせて設計します。 利用量の可視化と期間更新 DynamoDB の費用情報を予算検査に使い、CloudWatch のメトリクスで利用者・チーム・モデルごとの利用傾向を確認します。予算検査の対象は利用者単位であり、チーム共有予算を制御する場合は別途設計が必要です。 日次・月次の費用カウンターの更新や履歴保存も、公開サンプルに含まれます。公開サンプルの メトリクスの出力項目 と 期間更新の実装 をご確認ください。 [Optional] AgentCore Gateway の Rate limit による呼び出し頻度と同時実行数の制限 ユースケースごとの利用ペースを管理したいときに、AgentCore Gateway の rate limit を追加します。例えば、バックグラウンドの調査を進める AI 社員に対して、短い要求を繰り返す頻度や、長時間の推論を並行して実行する数に上限を設ける使い方です。 ! この制限はモデルの処理能力を増やしたり、他の要求へ容量を予約したりするものではありません。上限を低くすれば待機時間が増えるため、すべての仕事を速く進めたいだけなら、制限の追加が有利とは限りません。 RPM と同時接続数の組み合わせ Rate limit の metric は、次の 3 種類です。 Metric 制限するもの 本構成での扱い requests 秒または分あたりの要求数 (Request Per Second / Request Per Minute: RPS / RPM) RPM を採用し、短い要求や再試行の集中を抑制 tokens 分あたりの入力・出力の合計トークン数 (Token Per Minute: TPM) 機能を紹介に留まる connections 受付から応答完了までの同時処理中の要求数 採用し、長い推論やストリーミングの並行数を制限 ! connections は connector の設定数ではなく、同時に処理している要求数です。設定の period は second ですが、毎秒の新規接続回数という意味ではありません。 Rate limit の dimension には、認証済み JWT の claim、IAM の主体、モデル ID、target などを指定できます。今回は $.context.jwt.sub で利用者を識別し、同じ利用者の要求をモデルにかかわらず一つの枠で扱います。* は全員の共有枠ではなく、異なる sub ごとに独立した枠を作る既定値です。Runtime が利用者の JWT を引き継ぐため、その利用者が動かす複数のエージェントも同じ枠を使います。 以下は、Boto3 による rate limit の作成 に二つの metric を指定した例です。300 RPM・同時 5 件は説明用の例の値で、推奨値やサービスの既定値ではありません。 control = boto3.client("bedrock-agentcore-control", region_name="<Region>") rate_limit = control.create_gateway_rate_limit( gatewayIdentifier=gateway_id, description="Per-caller request and concurrency limits", dimensionKeys=["$.context.jwt.sub"], entries=[ { "dimensions": {"$.context.jwt.sub": "*"}, "requests": [{"rate": 300, "period": "minute"}], "connections": [{"rate": 5, "period": "second"}], } ], ) 同じ entry の RPM と同時接続数は両方を評価し、いずれかの metric で制限されると要求を拒否 します。既存の設定を変更する場合は、作成時の rateLimitId を使って更新します。部署全体の共有枠も必要なら、部署を示す検証済み JWT claim に対する rate limit を別途設けます。 上限で拒否された場合の動作 短時間の利用ペースと金額予算では、拒否後の処理を分けます。以下は、呼び出し元のアプリケーションやエージェントで設計する動作です。 状況 呼び出し元の動作 AgentCore Gateway の rate limit による一時的な拒否 retryAfter を使って待機し、回数に上限を設けて再試行 REQUEST interceptor の予算到達による HTTP 403 即時再試行を繰り返さず、利用者へ停止理由を提示 モデル側で処理されたか不明なタイムアウト 再送による重複実行の可能性を考慮し、状態を確認 Rate limit では retryAfter は再試行まで待つ秒数 を設けることが可能です。待機時間と再試行回数には上限を設けます。上流が処理していないと識別できる AgentCore Gateway の拒否と、モデル側の処理状況が不明なタイムアウトを同じ扱いにしません。 Rate limit の詳細やプラクティスは、AWS Blog Configure rate limits for AI traffic on AgentCore gateway も合わせてご覧ください。 すぐに試せるサンプル 本稿の内容をご自身の AWS アカウントで確認できるサンプルリポジトリを用意しました。 SeongHaedu/amazon-bedrock-agentcore-gateway-llm-gateway-samples 以下を体験できます。 AgentCore Runtime V2 に簡易な AI 社員を配置し、作業項目のメモを記録しながら文章の成果物をまとめる処理を試せます。 Cognito が発行した利用者の JWT を Runtime から AgentCore Gateway へ引き継ぎ、不正な JWT やアクセス用グループに所属しない利用者の拒否を確認できます。 AgentCore Policy で利用者ごとにモデルの権限を変え、許可されたモデルの呼び出しと、許可されていないモデルの拒否を比較できます。 AgentCore Gateway の rate limit を利用者ごとに設定し、リクエスト数・同時接続数の制限による拒否を確認できます。 公開サンプルの REQUEST / RESPONSE interceptor による費用計上を DynamoDB と CloudWatch で確認し、日次・月次予算の変更と、予算到達後の新しい呼び出しの拒否を試せます。 リージョン、モデル、料金、予算、利用量の上限は実行環境や設定ファイルから指定します。Runtime は ZIP による直接コードデプロイを使うため Docker は不要です。構築・検証・クリーンアップの手順は、README.md をご覧ください。 おわりに 本稿では、AgentCore Gateway を共通のエントリポイントとして、モデル利用の認証・認可、利用量の制限、費用・予算を管理する構成を紹介しました。それぞれの機能は、次のように役割を分担します。 管理すること 本稿で使う機能と役割 誰の呼び出しを受け付けるか Inbound auth で JWT と共通の利用資格を検証 どの API・モデルを使えるか AgentCore Policy で利用者ごとの操作とモデルを認可 どのペースで使えるか 必要に応じて rate limit を追加し、呼び出し頻度と同時処理数を制限 予算上、新しい呼び出しを受け付けられるか REQUEST interceptor が DynamoDB の計上済み費用と日次・月次予算を比較 誰がどれだけ使ったか RESPONSE interceptor が usage から費用を計上し、DynamoDB と CloudWatch に記録 認証・認可と rate limit には AgentCore Gateway の機能を使い、費用・予算管理には公開サンプルの Lambda と DynamoDB を組み合わせています。認可ルールや費用管理をエージェントの外側に置くことで、複数のアプリケーションから共通の管理を適用できます。 導入時には、機能の設定に加えて次の点を決めておくことが重要です。 管理の単位を決めます。本稿のサンプルは利用者単位ですが、部署・プロジェクト・AI 社員単位で管理する場合は、認証情報と権限・費用を対応付ける設計が必要です。 業務に必要なモデルの権限と利用ペースを決めます。モデルを使う権限、短時間の利用量、累積費用の予算は、別々の条件として設定します。 制限に達した場合や計上に失敗した場合の扱いを決めます。本稿は費用を応答後に計上するため、予算超過を厳密に防ぐ構成ではありません。許容できる超過の範囲と、待機・停止・復旧の方針を要件に合わせて設計します。 本稿が、AgentCore Gateway を使って AI 社員やコーディングエージェントのモデル利用を管理する際の一助となれば幸いです。 参考 Developer Guide: Amazon Bedrock AgentCore Gateway の概要 Inference targets によるモデルへの接続 AgentCore Gateway の inbound auth Amazon Bedrock AgentCore Policy REQUEST / RESPONSE interceptor AgentCore Gateway の rate limit AWS Blog: AWS AI セキュリティフレームワーク: レイヤーとフェーズに応じた適切なセキュリティコントロール How to customize access tokens in Amazon Cognito user pools Secure AI agents with Policy in Amazon Bedrock AgentCore Secure AI agents with Policy and Lambda interceptors in Amazon Bedrock AgentCore gateway Configure rate limits for AI traffic on AgentCore gateway サンプルリポジトリ: 費用・予算管理の AWS 公開サンプル 本稿のサンプルリポジトリ

  7. AWSのこの仕様変更、かなり影響範囲広いと思うんだけれどみんな大丈夫なんだろうか。 更新期限は半年か。 github.com/aws-samples/sample-cloudwatch-logs-iam…

    138 likes · 15 reposts · 14,652 views
  8. #jawsug_bgnr aws.amazon.com aws-samples/baseline-environment-on-aws 『BLEA』メモメモ...

    2 likes · 100 views
  9. YouTube · · YouTube description · Tan Theta AI · aws-samples/aws-mlu-explain

    Maths heavy algorithm tutorials losing you? Try MLU #ai #statistics #ml #maths #datascience #aws 😵 Maths-heavy algorithm tutorials losing you? Learn the idea visually first 👇 🔗 mlu-explain.github.io MLU-Explain is a set of free, interactive visual essays on machine learning from Amazon's Machine Learning University: neural networks, logistic regression, decision trees, cross-validation, ROC & AUC and more. Picture first, formulas second. 🙌 Credit: MLU-Explain / Amazon Machine Learning University All topics: mlu-explain.github.io Source code (archived, read-only): aws-samples/aws-mlu-explain About MLU: aws.amazon.com ℹ️ Unofficial recommendation. Not affiliated with Amazon or AWS. #datascience #machinelearning #artificialintelligence #ml #aiinnovation #regression #aiengineering #ainews

    17 likes · 1,117 views
  10. Build an Agentic Application Modernization Platform with Strands Agents and AWS Transform Custom --- title: "Build an Agentic Application Modernization Platform with Strands Agents and AWS Transform Custom" published: true description: "Explore a practical AWS architecture for modernizing multiple applications with Strands Agents, AWS Transform custom, Amazon Bedrock AgentCore, and AWS Batch." tags: aws, ai, devops, python cover_image: --- !Image description What if you could submit 100 application repositories to one platform, analyze their modernization needs, reuse approved code transformations, and track execution results from a single dashboard? That is the idea behind ModernizeHub, a project architecture for agentic application modernization on AWS. Modernizing one application can be challenging. Modernizing hundreds of applications introduces a different level of complexity: repository discovery, dependency upgrades, code transformation, testing, execution capacity, and reporting. In this article, we'll explore how to design a practical modernization platform using: - Strands Agents for agent orchestration - AWS Transform custom for reusable code transformations - Amazon Bedrock AgentCore for running and operating agents - AWS Batch for parallel repository jobs - Amazon S3 for artifacts and reports - Amazon DynamoDB for job tracking - React, Amazon CloudFront, API Gateway, and Lambda for the application interface and backend > Note: ModernizeHub is a project name used for this walkthrough. The architecture is inspired by AWS's public sample implementation. The examples and results shown below are illustrative, not claimed production test results. 1. The problem: Modernization doesn't scale easily Imagine a company with 200 applications. Some use older Python runtimes. Others depend on legacy Java frameworks, outdated SDKs, or configurations that need to change before migration. The engineering team needs to: 1. Understand each repository. 2. Identify the required changes. 3. Find an existing transformation or create a new one. 4. Apply the transformation. 5. Run builds and tests. 6. Review failures and approve changes. 7. Report the outcome. Doing all this manually for every application consumes time and creates inconsistent results. An agentic workflow can help coordinate these activities, while reusable transformations and automated tests make the process more repeatable. The goal is not to let AI change everything without supervision. The goal is to automate repetitive work while keeping engineers in control. 2. What are we building? ModernizeHub is a web application where developers can submit one repository or upload a CSV file containing many repositories. The workflow analyzes each application, identifies an appropriate transformation, routes missing transformations for review, executes approved jobs, and displays the results. The platform includes: - Repository analysis - Transformation discovery - Custom transformation creation - Single-repository execution - CSV batch processing - Parallel job execution - Build and test validation - A dashboard for status and logs - Human approval for sensitive changes 3. Architecture Here's the high-level design. Developer / Platform Engineer | v React Dashboard | CloudFront + S3 | v API Gateway | v AWS Lambda | v Amazon Bedrock AgentCore | v Strands Orchestrator | +-------+--------+ | | | v v v Analysis Discovery Custom Agent Agent Creation Agent | Human Review | v Approved Transformation | v AWS Batch | v AWS Transform Custom CLI | v Source Repository | +------+------+ | | v v Amazon S3 DynamoDB Artifacts Job Tracking | | +------+------+ | v Web Dashboard This is a logical architecture. The application code must implement the API integrations, permissions, job submission, status updates, and result retrieval. What does each service do? React, S3, and CloudFront Provide the user interface for repository submission, batch uploads, transformation review, and job tracking. Amazon API Gateway and AWS Lambda Receive requests, validate input, create job records, check authorization, and initiate the asynchronous workflow. Strands Agents Coordinate specialized agents and tools. The orchestrator decides which step should happen next based on validated results. Amazon Bedrock AgentCore Provides infrastructure for running and operating agents. AgentCore Runtime can host the orchestrator, while supporting capabilities can help with context and observability. AWS Transform custom Provides reusable code transformation capabilities for supported modernization tasks. AWS Batch Runs independent repository jobs according to the configured queue, compute resources, and concurrency limits. Amazon S3 and DynamoDB Store output artifacts and job metadata so developers can retrieve results and track progress. 4. Why use multiple agents? Instead of asking one agent to analyze code, invent transformations, execute shell commands, and validate everything, we can separate the responsibilities. Agent 1: Repository Analysis Agent This agent inspects a repository and identifies its technology stack, dependencies, build system, tests, and potential modernization blockers. An illustrative output could be: { "language": "Java", "build_tool": "Maven", "framework": "Spring Boot", "target": "Spring Boot 3", "tests_detected": true, "manual_review_recommended": true } These values are examples. A real implementation must derive them from repository evidence. Agent 2: Transformation Discovery Agent This agent checks whether a suitable transformation already exists. If an approved transformation matches the repository and target, the workflow can use it. Otherwise, the orchestrator can request a candidate transformation. Agent 3: Custom Transformation Creation Agent This agent helps translate a modernization requirement into a candidate transformation definition. For example: > Create a reusable transformation for supported Spring Boot 2 to Spring Boot 3 migration patterns. Identify dependency changes, update supported configuration patterns, and flag unsupported cases for manual review. The candidate must be tested and reviewed before it is added to a shared transformation catalog. Never treat generated transformation logic as automatically trusted production code. Agent 4: Execution Agent This agent coordinates the execution request and submits approved work to the execution system. AWS Batch runs the configured transformation container. The job's exit code and validation results determine the actual outcome. The orchestrator The Strands orchestrator coordinates the workflow: 1. Validate the request. 2. Analyze the repository. 3. Find an appropriate transformation. 4. Request a new candidate if needed. 5. Route it for approval. 6. Submit approved work. 7. Collect execution and test results. 8. Update the job record. This division makes the workflow easier to understand, test, and govern. 5. Design the web application A useful platform needs a clear interface, not just an agent that responds to prompts. Screen 1: Dashboard The dashboard shows the status of the modernization portfolio. +--------------------------------------------------+ | ModernizeHub Account | +--------------------------------------------------+ | Total Repositories: 200 | | Completed: 142 Running: 18 | | Failed: 12 Awaiting Review: 28 | | | | [Analyze Repository] [Upload CSV Batch] | | | | Repository Transformation Status | | payments-service Java Upgrade Complete| | customer-api Python Upgrade Running | | billing-worker Custom Migration Review | +--------------------------------------------------+ These are mock numbers for illustrating the interface, not real execution results. The production dashboard should retrieve actual data from the backend. Screen 2: Analyze a repository A developer enters a repository URL and selects the modernization target. Repository URL: https://github.com/example-org/payments-service Modernization Goal: Upgrade supported Spring Boot 2 patterns to Spring Boot 3 Validation Profile: Maven build and unit tests [Analyze Repository] The API validates the request, creates a job ID, and starts the asynchronous workflow. The example repository URL is illustrative. Screen 3: Custom transformation builder If no suitable transformation exists, the developer can provide a natural-language requirement. Transformation Name: spring-boot-3-modernization Requirements: - Identify supported dependency changes - Update compatible configuration patterns - Flag unsupported changes - Produce a reviewable transformation [Generate Candidate] The application displays the generated candidate so an engineer can inspect, test, approve, or reject it. Screen 4: Batch processing The developer uploads a CSV file, previews the repositories, fixes invalid rows, and submits the batch. Each accepted repository becomes an independent job. Screen 5: Job details Each job should display: - Repository and revision - Transformation name and version - Current status - Execution logs - Build and test results - Output artifact location - Failure details - Approval history This makes it easier to troubleshoot one application without losing visibility into the rest of the batch. 6. Example: Submit multiple repositories with CSV Create a file named sample-batch.csv: repository_url,transformation_name,validation_profile,context https://github.com/example-org/service-a,python-runtime-upgrade,python-tests,Upgrade supported Python patterns https://github.com/example-org/service-b,spring-boot-modernization,maven-tests,Review framework dependencies https://github.com/example-org/service-c,aws-sdk-migration,java-tests,Update supported SDK usage These are example rows. The repositories must be accessible, and the transformation names and validation profiles must exist in the deployed platform. What happens after upload? Step 1 — Validate the input Check required fields, repository policies, transformation names, duplicate submissions, and file size. Step 2 — Preview the batch Show the parsed rows and allow the user to fix errors. Step 3 — Create job records Create a unique ID for each accepted repository. Step 4 — Resolve transformations Find approved transformations and route missing or newly generated definitions through the appropriate review process. Step 5 — Execute jobs Submit approved jobs to AWS Batch, respecting concurrency limits. Step 6 — Validate changes Run the configured build and test commands. Step 7 — Report results Update each job's status and expose available logs and artifacts. An illustrative outcome might be: | Repository | Status | Next step | |---|---|---| | service-a | Completed | Review validation report | | service-b | Failed validation | Investigate build error | | service-c | Awaiting approval | Review proposed transformation | These results are examples, not claimed test results. A failure in one repository should not automatically mark every other job in the batch as failed. 7. Validate the transformed code An agent saying "completed" does not prove that the application works. Each execution should: 1. Check out an approved repository revision. 2. Prepare an isolated working environment. 3. Run the selected transformation. 4. Capture logs and the exit code. 5. Run approved build and test commands. 6. Store the patch and reports. 7. Update the job status. 8. Flag failures for investigation. For a Maven-based Java application, a test step might be: mvn -B test For a Python application, it might be: python -m pytest These are examples only. Use commands appropriate to the repository and toolchain. Do not execute arbitrary commands supplied by an untrusted repository or model output in a privileged environment. For more complete validation, add static analysis, dependency security scanning, integration tests, and application-specific acceptance tests. A successful build is useful evidence, but it does not guarantee that all application behavior remains correct. 8. Infrastructure as code: CDK, SAM, or Terraform? Infrastructure as code makes the deployment reproducible. The platform needs resources for the frontend, API, agent runtime, execution environment, storage, tracking, and monitoring. A project might organize its code like this: modernizehub/ ├── frontend/ ├── api/ ├── agents/ │ ├── orchestrator.py │ ├── analyze_agent.py │ ├── discovery_agent.py │ ├── create_agent.py │ └── execute_agent.py ├── batch/ │ ├── Dockerfile │ └── entrypoint.sh ├── transformations/ ├── tests/ ├── samples/ │ └── sample-batch.csv └── infrastructure/ ├── cdk-sam/ └── terraform/ This is a suggested structure, not the exact structure of the AWS sample. AWS's public repository contains an implementation under agentic-atx-platform and documents deployment using AWS CDK and AWS SAM. Explore it here: github.com/aws-samples/aws-transform-custom-sampl… If your team uses Terraform, you can build an equivalent Terraform implementation for supported AWS resources and deployment steps. However, the linked sample should not be mistaken for a ready-made Terraform deployment. Before deploying, review current service availability, model access, IAM permissions, network requirements, and cleanup instructions. 9. Security considerations A modernization platform can read source code and execute build tools. Security must be part of the design. Least privilege: Give each component only the permissions it needs. Secure credentials: Do not embed repository tokens in prompts, logs, or container images. Isolated execution: Run jobs in controlled environments with resource limits and restricted network access where practical. Human approval: Review new transformation definitions before publishing them for reuse. Reviewable changes: Preserve the original revision and make patches easy to inspect. Safe retries: Track job IDs, transformation versions, and outputs to prevent blind repeat execution. Auditability: Record the requester, repository revision, transformation version, approval status, and validation results. Cost controls: Limit concurrency and monitor model usage, compute, storage, and logging costs. The goal is to automate repetitive work without removing engineers from important decisions. 10. Try the public AWS sample You do not have to build every component from scratch. Start with the public repository: aws-samples/aws-transform-custom-samples Then: 1. Review the agentic-atx-platform README and architecture. 2. Check the current prerequisites, AWS Region, model access, and IAM requirements. 3. Configure the required AWS credentials and development tools. 4. Deploy the sample using its documented instructions. 5. Test with one repository that you control. 6. Verify job status, transformation output, logs, and validation results. 7. Test a small CSV batch. 8. Increase concurrency only after reviewing reliability and cost. 9. Follow the documented cleanup procedure when finished. Deployment commands and requirements can change, so use the repository's current instructions. 11. How do we measure success? Measure the platform using actual outcomes rather than the number of agents. Useful metrics include: - Number of repositories submitted and completed - Percentage matched to existing transformations - Custom transformations approved or rejected - Transformation execution success rate - Build and test pass rate - Average processing time per repository - Manual intervention rate - Cost per completed repository - Changes successfully reviewed and merged Compare these metrics with your existing modernization process before claiming productivity improvements. Conclusion Modernizing hundreds of applications is a coordination challenge involving code analysis, transformation selection, execution, testing, and governance. Strands Agents can coordinate the workflow. AWS Transform custom provides reusable transformation capabilities. Amazon Bedrock AgentCore supports the agent runtime, while AWS Batch enables independent repository jobs to run in parallel. A dashboard, API, S3, DynamoDB, and infrastructure as code bring these capabilities together into an application that engineers can monitor and extend. The most important lesson is this: Don't give AI unrestricted control over every repository. Let agents help plan the work, use approved transformations to make changes, validate the results, and keep engineers in control of important decisions. Start with one repository. Prove the workflow. Test a small batch. Then scale based on evidence. References - AWS Blog: Agentic application modernization at scale with Strands and AWS Transform custom - AWS Transform custom samples on GitHub - Agentic ATX Platform sample - Strands Agents documentation - Amazon Bedrock AgentCore

Trending awards, every completed day and week
Gold
01st place finishes
Silver
02nd place finishes
Bronze
33rd place finishes
Awarded repositories
2Owned by aws-samples now

Repositories

Ordered by gold, then silver, then bronze.

  1. modern-cicd-with-github-and-aws-codepipelineBest: 3rd by forks, 145 forks002
  2. ecs-demo-php-simple-appBest: 3rd by forks, 242 forks001

A repository earns an award for finishing first, second or third in a completed trending day or week, ranked by new stars, new forks or pull request authors. Awards follow a repository through renames and transfers and count toward its current owner. Weeks run Monday to Sunday, UTC.