<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>AWSコンソール - CayTech Lab</title>
	<atom:link href="https://caymezon.com/tag/aws%e3%82%b3%e3%83%b3%e3%82%bd%e3%83%bc%e3%83%ab/feed/" rel="self" type="application/rss+xml" />
	<link>https://caymezon.com</link>
	<description></description>
	<lastBuildDate>Sat, 04 Apr 2026 07:34:06 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://caymezon.com/wp-content/uploads/2026/01/cropped-CayTechLab-32x32.jpg</url>
	<title>AWSコンソール - CayTech Lab</title>
	<link>https://caymezon.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<atom:link rel='hub' href='https://caymezon.com/?pushpress=hub'/>
	<item>
		<title>AWSコンソールでVPC設計からAP+DB 2層構成を構築する手順【踏み台SSH / CloudFormation版との比較付き】</title>
		<link>https://caymezon.com/aws-handson-console-ec2-2tier/</link>
					<comments>https://caymezon.com/aws-handson-console-ec2-2tier/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Sat, 04 Apr 2026 07:34:06 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[2層構成]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[AWSコンソール]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[IAM]]></category>
		<category><![CDATA[MariaDB]]></category>
		<category><![CDATA[SG参照]]></category>
		<category><![CDATA[UserData]]></category>
		<category><![CDATA[VPC]]></category>
		<category><![CDATA[セキュリティグループ]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[パブリックサブネット]]></category>
		<category><![CDATA[プライベートサブネット]]></category>
		<category><![CDATA[初心者]]></category>
		<category><![CDATA[踏み台]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20325</guid>

					<description><![CDATA[<p>目次 はじめにキーワード解説前フェーズとの違い使用するAWSサービス構築するリソース一覧全体の作業順序【重要】⓪ 自分のIPアドレスを確認する① キーペアの作成② IAMロールの作成③ VPCの作成④ インターネットゲー [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-console-ec2-2tier/">AWSコンソールでVPC設計からAP+DB 2層構成を構築する手順【踏み台SSH / CloudFormation版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-2" checked><label class="toc-title" for="toc-checkbox-2">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">キーワード解説</a></li><li><a href="#toc3" tabindex="0">前フェーズとの違い</a></li><li><a href="#toc4" tabindex="0">使用するAWSサービス</a></li><li><a href="#toc5" tabindex="0">構築するリソース一覧</a></li><li><a href="#toc6" tabindex="0">全体の作業順序</a></li><li><a href="#toc7" tabindex="0">【重要】⓪ 自分のIPアドレスを確認する</a></li><li><a href="#toc8" tabindex="0">① キーペアの作成</a></li><li><a href="#toc9" tabindex="0">② IAMロールの作成</a></li><li><a href="#toc10" tabindex="0">③ VPCの作成</a></li><li><a href="#toc11" tabindex="0">④ インターネットゲートウェイの作成・アタッチ</a><ol><li><a href="#toc12" tabindex="0">4-1. インターネットゲートウェイを作成する</a></li><li><a href="#toc13" tabindex="0">4-2. VPCにアタッチする</a></li></ol></li><li><a href="#toc14" tabindex="0">⑤ サブネットの作成</a><ol><li><a href="#toc15" tabindex="0">5-1. パブリックサブネット</a></li><li><a href="#toc16" tabindex="0">5-2. プライベートサブネット</a></li><li><a href="#toc17" tabindex="0">5-3. パブリックサブネットのパブリックIP自動割り当てを有効化</a></li></ol></li><li><a href="#toc18" tabindex="0">⑥ ルートテーブルの設定</a><ol><li><a href="#toc19" tabindex="0">6-1. パブリックルートテーブルを作成する</a></li><li><a href="#toc20" tabindex="0">6-2. プライベートルートテーブルを作成する</a></li><li><a href="#toc21" tabindex="0">6-3. S3 VPC Gateway Endpointを作成する（重要）</a></li></ol></li><li><a href="#toc22" tabindex="0">⑦ セキュリティグループの作成</a><ol><li><a href="#toc23" tabindex="0">7-1. APサーバSGの作成</a></li><li><a href="#toc24" tabindex="0">7-2. DBサーバSGの作成</a></li></ol></li><li><a href="#toc25" tabindex="0">⑧ APサーバEC2の起動（パブリックサブネット）</a><ol><li><a href="#toc26" tabindex="0">8-1. 基本設定</a></li><li><a href="#toc27" tabindex="0">8-2. ネットワーク設定</a></li><li><a href="#toc28" tabindex="0">8-3. IAMロール・UserDataの設定</a></li></ol></li><li><a href="#toc29" tabindex="0">⑨ DBサーバEC2の起動（プライベートサブネット）</a><ol><li><a href="#toc30" tabindex="0">9-1. 基本設定</a></li><li><a href="#toc31" tabindex="0">9-2. ネットワーク設定</a></li><li><a href="#toc32" tabindex="0">9-3. IAMロール・UserDataの設定</a></li></ol></li><li><a href="#toc33" tabindex="0">⑩ 動作確認</a><ol><li><a href="#toc34" tabindex="0">10-1. APサーバのWeb確認</a></li><li><a href="#toc35" tabindex="0">10-2. APサーバへのSSH接続</a></li><li><a href="#toc36" tabindex="0">10-3. キーペアをAPサーバにコピーする（踏み台SSH準備）</a></li><li><a href="#toc37" tabindex="0">10-4. APサーバ経由でDBサーバにSSH接続（踏み台接続）</a></li><li><a href="#toc38" tabindex="0">10-5. APサーバからMySQLに接続（AP→DB通信確認）</a></li></ol></li><li><a href="#toc39" tabindex="0">⑪ リソースの削除</a><ol><li><a href="#toc40" tabindex="0">削除順序</a></li></ol></li><li><a href="#toc41" tabindex="0">CloudFormation版との比較</a></li><li><a href="#toc42" tabindex="0">トラブルシューティング</a></li><li><a href="#toc43" tabindex="0">まとめ</a></li><li><a href="#toc44" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>「APサーバはインターネットに公開しつつ、DBサーバはインターネットから完全に隔離したい」——これが実際のAWSシステム設計でよく使われる <strong>AP+DB 2層構成</strong> です。</p>
<p>この記事では、<strong>AWSコンソール（GUI）のみ</strong>を使って、カスタムVPCを設計し、パブリックサブネット（APサーバ）とプライベートサブネット（DBサーバ）に分離した2層アーキテクチャをゼロから手動構築するハンズオンを紹介します。</p>
<pre><code class="language-plaintext">インターネット
  ↓ HTTP(80) / SSH(22)  ← 自分のIPのみ
[インターネットゲートウェイ（my-igw）]
  ↓
[VPC: my-vpc（10.0.0.0/16）]
  │
  ├─ [パブリックサブネット: 10.0.1.0/24]
  │    └── APサーバEC2（my-ap-instance）
  │          ├── Apache（ポート80）   ← インターネットから直接アクセス可
  │          └── my-ap-sg
  │                ↓ SSH(22) / MySQL(3306) ← APサーバSGのみ許可（SG参照）
  └─ [プライベートサブネット: 10.0.2.0/24]
       └── DBサーバEC2（my-db-instance）
             ├── MariaDB（ポート3306）
             ├── パブリックIPなし       ← インターネットから隔離
             └── my-db-sg</code></pre>
<p><strong>このハンズオンで体験できること：</strong></p>
<ul>
<li>カスタムVPC・サブネット・インターネットゲートウェイ・ルートテーブルを一から設計・構築</li>
<li>パブリックサブネット（APサーバ）とプライベートサブネット（DBサーバ）の分離</li>
<li>DBサーバにパブリックIPを付与せずインターネットから隔離する設計</li>
<li>APサーバを踏み台（Bastion）としてDBサーバにSSH接続する方法</li>
<li>S3 VPC Gateway Endpointでプライベートサブネットからパッケージをインストールする方法</li>
</ul>
<p><strong>このハンズオンのポイント：</strong></p>
<p>Phase 1-3（MySQL）まではデフォルトVPCを使っていましたが、今回は<strong>カスタムVPCを一から設計</strong>します。実際のAWS本番環境に近いネットワーク設計を体験できます。</p>
<hr>
<blockquote>
<p><strong>この記事は <a href="https://caymezon.com/aws-handson-cloudformation-ec2-2tier/">CloudFormation版ハンズオン</a> の比較記事です。</strong><br />コンソール操作でVPCリソースの依存関係・設定手順を視覚的に学び、CloudFormationとの違いを比較したい方向けです。</p>
</blockquote>
<hr>
<p><!-- ![ハンズオン完成後の構成確認画面](images/ec2-2tier-top.jpg) --></p>
<p><!-- <a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"> --></p>
<p><!-- <!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWSの基本・仕組み・重要用語が全部わかる教科書 (見るだけ図解)","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51DEDQXj6oL._SL500_.jpg","\/41F589smNwL._SL500_.jpg","\/41R6f9yyCWL._SL500_.jpg","\/41HqWQ9BvmL._SL500_.jpg","\/41p8p0ZU79L._SL500_.jpg","\/41qLC-fndBL._SL500_.jpg","\/41fcLv9VT5L._SL500_.jpg","\/51lRvCsvHqL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815607850","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815607850","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"eaCUB","s":"s"});</script></p>
<div id="msmaflink-eaCUB">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --> --></p>
<h2><span id="toc2">キーワード解説</span></h2>
<table>
<thead>
<tr>
<th>用語</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>VPC（Virtual Private Cloud）</strong></td>
<td>AWS上に作るプライベートなネットワーク空間。今回は <code>10.0.0.0/16</code> のCIDRで作成する</td>
</tr>
<tr>
<td><strong>パブリックサブネット</strong></td>
<td>インターネットゲートウェイへのルートを持つサブネット。APサーバを配置する</td>
</tr>
<tr>
<td><strong>プライベートサブネット</strong></td>
<td>インターネットへの経路を持たないサブネット。DBサーバを配置し外部から隔離する</td>
</tr>
<tr>
<td><strong>インターネットゲートウェイ（IGW）</strong></td>
<td>VPCとインターネットを接続する出入り口</td>
</tr>
<tr>
<td><strong>ルートテーブル</strong></td>
<td>サブネット内のEC2がパケットを送るときの「経路表」</td>
</tr>
<tr>
<td><strong>S3 VPC Gateway Endpoint</strong></td>
<td>プライベートサブネットからS3（パッケージリポジトリ）にアクセスするための無料エンドポイント</td>
</tr>
<tr>
<td><strong>踏み台（Bastion）</strong></td>
<td>プライベートサブネットのEC2にアクセスするための中継サーバ。今回はAPサーバが踏み台を兼ねる</td>
</tr>
<tr>
<td><strong>SG参照（SG-to-SG）</strong></td>
<td>セキュリティグループのルールで、アクセス元として別のSGを指定する設定</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc3">前フェーズとの違い</span></h2>
<table>
<thead>
<tr>
<th>比較項目</th>
<th>Phase 1-3（MySQL）</th>
<th>Phase 1-4（2層構成・今回）</th>
</tr>
</thead>
<tbody>
<tr>
<td>ネットワーク</td>
<td>デフォルトVPC</td>
<td><strong>カスタムVPC</strong></td>
</tr>
<tr>
<td>サブネット</td>
<td>デフォルトサブネット（パブリック）</td>
<td><strong>パブリック + プライベート</strong></td>
</tr>
<tr>
<td>DBのパブリックIP</td>
<td>あり</td>
<td><strong>なし（インターネット隔離）</strong></td>
</tr>
<tr>
<td>DBへのSSH</td>
<td>直接SSH可能</td>
<td><strong>APサーバ経由の踏み台接続</strong></td>
</tr>
<tr>
<td>リソース数</td>
<td>4〜5個</td>
<td><strong>12個以上（VPC関連が多数）</strong></td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc4">使用するAWSサービス</span></h2>
<table>
<thead>
<tr>
<th>サービス</th>
<th>役割</th>
<th>料金</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>VPC</strong></td>
<td>カスタムネットワーク空間</td>
<td>無料</td>
</tr>
<tr>
<td><strong>EC2 × 2台</strong></td>
<td>APサーバ（Apache） + DBサーバ（MariaDB）（各t2.micro）</td>
<td>月750時間まで無料枠あり（2台で消費が倍）</td>
</tr>
<tr>
<td><strong>セキュリティグループ × 2</strong></td>
<td>APサーバSG / DBサーバSGのアクセス制御</td>
<td>無料</td>
</tr>
<tr>
<td><strong>S3 VPC Gateway Endpoint</strong></td>
<td>プライベートサブネットからS3へのアクセス</td>
<td><strong>無料</strong></td>
</tr>
<tr>
<td><strong>IAM</strong></td>
<td>EC2へのSession Manager接続権限</td>
<td>無料</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>注意</strong>: EC2を2台同時に稼働させるため、無料枠の消費が2倍になります。ハンズオン後は必ず2台とも削除してください。</p>
</blockquote>
<hr>
<h2><span id="toc5">構築するリソース一覧</span></h2>
<table>
<thead>
<tr>
<th>カテゴリ</th>
<th>リソース</th>
<th>役割</th>
</tr>
</thead>
<tbody>
<tr>
<td>ネットワーク</td>
<td>VPC（<code>my-vpc</code>）</td>
<td>独自のネットワーク空間（10.0.0.0/16）</td>
</tr>
<tr>
<td>ネットワーク</td>
<td>インターネットゲートウェイ（<code>my-igw</code>）</td>
<td>VPCとインターネットを接続</td>
</tr>
<tr>
<td>ネットワーク</td>
<td>パブリックサブネット（<code>my-public-subnet</code>）</td>
<td>APサーバ用（インターネットアクセスあり）</td>
</tr>
<tr>
<td>ネットワーク</td>
<td>プライベートサブネット（<code>my-private-subnet</code>）</td>
<td>DBサーバ用（インターネットアクセスなし）</td>
</tr>
<tr>
<td>ネットワーク</td>
<td>パブリックルートテーブル（<code>my-public-rt</code>）</td>
<td>インターネットへの経路（→IGW）</td>
</tr>
<tr>
<td>ネットワーク</td>
<td>プライベートルートテーブル（<code>my-private-rt</code>）</td>
<td>VPC内のみ（インターネット経路なし）</td>
</tr>
<tr>
<td>ネットワーク</td>
<td>S3 VPC Gateway Endpoint</td>
<td>プライベートサブネットからS3へのアクセス（無料）</td>
</tr>
<tr>
<td>セキュリティ</td>
<td>APサーバSG（<code>my-ap-sg</code>）</td>
<td>SSH(22)・HTTP(80)を自分のIPから許可</td>
</tr>
<tr>
<td>セキュリティ</td>
<td>DBサーバSG（<code>my-db-sg</code>）</td>
<td>SSH(22)・MySQL(3306)をAPサーバSGのみ許可</td>
</tr>
<tr>
<td>認証</td>
<td>キーペア（<code>my-ec2-2tier-key</code>）</td>
<td>SSH接続の認証鍵</td>
</tr>
<tr>
<td>認証</td>
<td>IAMロール（<code>my-ec2-2tier-role</code>）</td>
<td>EC2にSession Manager権限を付与</td>
</tr>
<tr>
<td>コンピュート</td>
<td>APサーバEC2（<code>my-ap-instance</code>）</td>
<td>Apacheを実行するWebサーバ（パブリックサブネット）</td>
</tr>
<tr>
<td>コンピュート</td>
<td>DBサーバEC2（<code>my-db-instance</code>）</td>
<td>MariaDBを実行するDBサーバ（プライベートサブネット）</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc6">全体の作業順序</span></h2>
<p>ネットワーク系リソースはEC2より先に作成する必要があります。</p>
<pre><code class="language-plaintext">⓪ 自分のIPアドレスを確認する
      ↓
① キーペアを作成する
      ↓
② IAMロールを作成する
      ↓
③ VPCを作成する
      ↓
④ インターネットゲートウェイを作成・アタッチする
      ↓
⑤ サブネットを作成する（パブリック・プライベート）
      ↓
⑥ ルートテーブルを設定する（S3 VPC Endpoint作成を含む）
      ↓
⑦ セキュリティグループを作成する（APサーバSG → DBサーバSGの順）
      ↓
⑧ APサーバEC2を起動する（パブリックサブネット）
      ↓
⑨ DBサーバEC2を起動する（プライベートサブネット）
      ↓
⑩ 動作確認
      ↓
⑪ リソースを削除する</code></pre>
<hr>
<h2><span id="toc7">【重要】⓪ 自分のIPアドレスを確認する</span></h2>
<pre><code class="language-cmd">curl https://checkip.amazonaws.com</code></pre>
<p>またはルーター管理画面（<code>http://192.168.0.1</code> など）の「WAN IPアドレス」で確認します。</p>
<p><strong>控えておく情報</strong>: 自分のIPアドレス（例: <code>203.0.113.1</code>）</p>
<hr>
<h2><span id="toc8">① キーペアの作成</span></h2>
<p>APサーバとDBサーバの両方で使用します。1つのキーペアを共用します。</p>
<p><strong>AWSコンソール → EC2 → キーペア → 「キーペアを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-ec2-2tier-key</code></td>
</tr>
<tr>
<td>キーペアのタイプ</td>
<td><strong>RSA</strong></td>
</tr>
<tr>
<td>プライベートキーファイル形式</td>
<td><strong>.pem</strong></td>
</tr>
</tbody>
</table>
<pre><code class="language-plaintext">C:\Users\ユーザー名\.ssh\my-ec2-2tier-key.pem</code></pre>
<hr>
<h2><span id="toc9">② IAMロールの作成</span></h2>
<p><strong>AWSコンソール → IAM → ロール → 「ロールを作成」</strong></p>
<table>
<thead>
<tr>
<th>ステップ</th>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>信頼されたエンティティタイプ</td>
<td><strong>AWSのサービス</strong></td>
</tr>
<tr>
<td>1</td>
<td>ユースケース</td>
<td><strong>EC2</strong></td>
</tr>
<tr>
<td>2</td>
<td>許可ポリシー</td>
<td><code>AmazonSSMManagedInstanceCore</code></td>
</tr>
<tr>
<td>3</td>
<td>ロール名</td>
<td><code>my-ec2-2tier-role</code></td>
</tr>
</tbody>
</table>
<p>「ロールを作成」をクリック。</p>
<hr>
<h2><span id="toc10">③ VPCの作成</span></h2>
<p><strong>AWSコンソール → VPC → 仮想プライベートクラウド → 「お使いのVPC」→ 「VPCを作成」</strong></p>
<blockquote>
<p><strong>VPCとは</strong>: AWS上に作るプライベートなネットワーク空間。この中にEC2などを置きます。CIDR（サイダー）でIPアドレスの範囲を指定します。<code>10.0.0.0/16</code> は <code>10.0.0.0 〜 10.0.255.255</code> の65536個のIPアドレスを表します。</p>
</blockquote>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>作成するリソース</td>
<td><strong>VPCのみ</strong></td>
</tr>
<tr>
<td>名前タグ</td>
<td><code>my-vpc</code></td>
</tr>
<tr>
<td>IPv4 CIDR</td>
<td><code>10.0.0.0/16</code></td>
</tr>
<tr>
<td>IPv6 CIDR ブロック</td>
<td><strong>なし</strong></td>
</tr>
<tr>
<td>テナンシー</td>
<td>デフォルト</td>
</tr>
</tbody>
</table>
<p>「VPCを作成」をクリック。</p>
<p><strong>控えておく情報</strong>: 作成された VPC ID（<code>vpc-xxxxxxxxxx</code>）</p>
<p><!-- ![VPC作成画面](images/vpc-create.jpg) --></p>
<hr>
<h2><span id="toc11">④ インターネットゲートウェイの作成・アタッチ</span></h2>
<blockquote>
<p><strong>インターネットゲートウェイ（IGW）とは</strong>: VPCとインターネットを接続する出入り口です。これをVPCにアタッチすることで、VPC内のEC2がインターネットと通信できるようになります。</p>
</blockquote>
<h3><span id="toc12">4-1. インターネットゲートウェイを作成する</span></h3>
<p><strong>AWSコンソール → VPC → インターネットゲートウェイ → 「インターネットゲートウェイの作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前タグ</td>
<td><code>my-igw</code></td>
</tr>
</tbody>
</table>
<p>「インターネットゲートウェイの作成」をクリック。</p>
<h3><span id="toc13">4-2. VPCにアタッチする</span></h3>
<p>作成直後の画面から「アクション」→「VPCにアタッチ」をクリック。</p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>使用可能なVPC</td>
<td><code>my-vpc</code> を選択</td>
</tr>
</tbody>
</table>
<p>「インターネットゲートウェイのアタッチ」をクリック。</p>
<p>ステータスが <strong>「Attached」</strong> になることを確認します。</p>
<hr>
<h2><span id="toc14">⑤ サブネットの作成</span></h2>
<blockquote>
<p><strong>サブネットとは</strong>: VPC内をさらに分割したネットワークです。パブリックサブネットはインターネットと通信でき、プライベートサブネットはVPC内部とのみ通信します。</p>
</blockquote>
<p><strong>AWSコンソール → VPC → サブネット → 「サブネットを作成」</strong></p>
<p>VPC ID で <code>my-vpc</code> を選択します。</p>
<h3><span id="toc15">5-1. パブリックサブネット</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>サブネット名</td>
<td><code>my-public-subnet</code></td>
</tr>
<tr>
<td>アベイラビリティーゾーン</td>
<td><code>ap-northeast-1a</code></td>
</tr>
<tr>
<td>IPv4 CIDR</td>
<td><code>10.0.1.0/24</code></td>
</tr>
</tbody>
</table>
<h3><span id="toc16">5-2. プライベートサブネット</span></h3>
<p>「新しいサブネットを追加」をクリックして2つ目のサブネットを設定します。</p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>サブネット名</td>
<td><code>my-private-subnet</code></td>
</tr>
<tr>
<td>アベイラビリティーゾーン</td>
<td><code>ap-northeast-1a</code></td>
</tr>
<tr>
<td>IPv4 CIDR</td>
<td><code>10.0.2.0/24</code></td>
</tr>
</tbody>
</table>
<p>「サブネットを作成」をクリック。</p>
<h3><span id="toc17">5-3. パブリックサブネットのパブリックIP自動割り当てを有効化</span></h3>
<p><strong>サブネット一覧 → <code>my-public-subnet</code> を選択 → 「アクション」→「サブネットの設定を編集」</strong></p>
<p>「パブリック IPv4 アドレスの自動割り当てを有効化」にチェックを入れる → 「保存」。</p>
<blockquote>
<p>APサーバEC2を起動したときに自動でパブリックIPが割り当てられるようになります。プライベートサブネットはこの設定をしません（DBサーバにパブリックIPを付与しない）。</p>
</blockquote>
<p><!-- ![サブネット作成画面](images/subnet-create.jpg) --></p>
<hr>
<h2><span id="toc18">⑥ ルートテーブルの設定</span></h2>
<blockquote>
<p><strong>ルートテーブルとは</strong>: サブネット内のEC2がパケットを送るときの「経路表」です。パブリックサブネットはインターネット向けのルート（→IGW）を持ち、プライベートサブネットは持ちません。</p>
</blockquote>
<h3><span id="toc19">6-1. パブリックルートテーブルを作成する</span></h3>
<p><strong>AWSコンソール → VPC → ルートテーブル → 「ルートテーブルを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-public-rt</code></td>
</tr>
<tr>
<td>VPC</td>
<td><code>my-vpc</code></td>
</tr>
</tbody>
</table>
<p>「ルートテーブルを作成」をクリック。</p>
<p><strong>インターネット向けルートを追加します:</strong></p>
<p><code>my-public-rt</code> を選択 → 「ルート」タブ → 「ルートを編集」→「ルートを追加」</p>
<table>
<thead>
<tr>
<th>送信先</th>
<th>ターゲット</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>0.0.0.0/0</code></td>
<td><code>my-igw</code>（インターネットゲートウェイを選択）</td>
</tr>
</tbody>
</table>
<p>「変更を保存」をクリック。</p>
<blockquote>
<p><strong><code>0.0.0.0/0</code> とは</strong>: 「それ以外のすべての宛先」を意味します。VPC内向けのルートはデフォルトで存在するため、インターネット向けのルートだけ追加すれば OKです。</p>
</blockquote>
<p><strong>パブリックサブネットを関連付けます:</strong></p>
<p><code>my-public-rt</code> の「サブネットの関連付け」タブ → 「サブネットの関連付けを編集」→ <code>my-public-subnet</code> にチェック → 「関連付けを保存」。</p>
<h3><span id="toc20">6-2. プライベートルートテーブルを作成する</span></h3>
<p><strong>VPC → ルートテーブル → 「ルートテーブルを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-private-rt</code></td>
</tr>
<tr>
<td>VPC</td>
<td><code>my-vpc</code></td>
</tr>
</tbody>
</table>
<p>「ルートテーブルを作成」をクリック。</p>
<blockquote>
<p><strong>インターネット向けルートは追加しません</strong>。プライベートサブネットからインターネットへの経路を意図的に持たせないことで、DBサーバをインターネットから完全に隔離します。</p>
</blockquote>
<p><strong>プライベートサブネットを関連付けます:</strong></p>
<p><code>my-private-rt</code> の「サブネットの関連付け」タブ → 「サブネットの関連付けを編集」→ <code>my-private-subnet</code> にチェック → 「関連付けを保存」。</p>
<h3><span id="toc21">6-3. S3 VPC Gateway Endpointを作成する（重要）</span></h3>
<blockquote>
<p><strong>なぜ必要か</strong>: プライベートサブネットはインターネットに出られないため、EC2起動時の <code>dnf install</code> でパッケージをダウンロードできません。Amazon Linux 2023のパッケージリポジトリはS3上にあるため、S3だけインターネットを経由せずアクセスできるGateway Endpointを作成することで解決します。<strong>Gateway Endpointは無料</strong>です。</p>
</blockquote>
<p><strong>AWSコンソール → VPC → エンドポイント → 「エンドポイントを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前タグ</td>
<td><code>my-s3-endpoint</code></td>
</tr>
<tr>
<td>サービスカテゴリ</td>
<td><strong>AWSのサービス</strong></td>
</tr>
<tr>
<td>サービス</td>
<td>検索欄に <code>s3</code> と入力 → <code>com.amazonaws.ap-northeast-1.s3</code> の <strong>タイプ: Gateway</strong> を選択</td>
</tr>
<tr>
<td>VPC</td>
<td><code>my-vpc</code></td>
</tr>
<tr>
<td>ルートテーブル</td>
<td><strong><code>my-private-rt</code></strong> にチェックを入れる</td>
</tr>
</tbody>
</table>
<p>「エンドポイントを作成」をクリック。</p>
<p><strong>確認</strong>: <code>my-private-rt</code> の「ルート」タブを開くと、S3向けのルートが自動追加されていることを確認します。</p>
<p><!-- ![S3 VPC Endpoint作成画面](images/s3-endpoint-create.jpg) --></p>
<hr>
<h2><span id="toc22">⑦ セキュリティグループの作成</span></h2>
<blockquote>
<p><strong>注意</strong>: APサーバSGを先に作成します。DBサーバSGがAPサーバSGをSG参照するためです。</p>
</blockquote>
<h3><span id="toc23">7-1. APサーバSGの作成</span></h3>
<p><strong>EC2 → セキュリティグループ → 「セキュリティグループを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>セキュリティグループ名</td>
<td><code>my-ap-sg</code></td>
</tr>
<tr>
<td>説明</td>
<td><code>AP server SG (public subnet)</code></td>
</tr>
<tr>
<td>VPC</td>
<td><strong><code>my-vpc</code></strong>（デフォルトVPCではなく今回作成したVPCを選択）</td>
</tr>
</tbody>
</table>
<p><strong>インバウンドルール:</strong></p>
<table>
<thead>
<tr>
<th>タイプ</th>
<th>ポート</th>
<th>ソース</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td>SSH</td>
<td>22</td>
<td><code>203.0.113.1/32</code>（自分のIP）</td>
<td>SSH from my IP</td>
</tr>
<tr>
<td>HTTP</td>
<td>80</td>
<td><code>203.0.113.1/32</code>（自分のIP）</td>
<td>HTTP from my IP</td>
</tr>
</tbody>
</table>
<p><strong>アウトバウンドルール</strong>: 「すべてのトラフィック / 0.0.0.0/0」があることを確認します。</p>
<p>「セキュリティグループを作成」をクリック。</p>
<h3><span id="toc24">7-2. DBサーバSGの作成</span></h3>
<p><strong>EC2 → セキュリティグループ → 「セキュリティグループを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>セキュリティグループ名</td>
<td><code>my-db-sg</code></td>
</tr>
<tr>
<td>説明</td>
<td><code>DB server SG (private subnet)</code></td>
</tr>
<tr>
<td>VPC</td>
<td><strong><code>my-vpc</code></strong></td>
</tr>
</tbody>
</table>
<p><strong>インバウンドルール（「ルールを追加」で2つ追加します）:</strong></p>
<p><strong>ルール1: SSH（APサーバ経由の踏み台接続）</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>タイプ</td>
<td>SSH</td>
</tr>
<tr>
<td>ソースタイプ</td>
<td>カスタム</td>
</tr>
<tr>
<td>ソース</td>
<td><code>my-ap-sg</code> を検索して選択</td>
</tr>
<tr>
<td>説明</td>
<td><code>SSH from AP server only (bastion)</code></td>
</tr>
</tbody>
</table>
<p><strong>ルール2: MySQL（APサーバからのDB接続）</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>タイプ</td>
<td>MySQL/Aurora</td>
</tr>
<tr>
<td>ソースタイプ</td>
<td>カスタム</td>
</tr>
<tr>
<td>ソース</td>
<td><code>my-ap-sg</code> を検索して選択</td>
</tr>
<tr>
<td>説明</td>
<td><code>MySQL from AP server only</code></td>
</tr>
</tbody>
</table>
<p><strong>アウトバウンドルール</strong>: 「すべてのトラフィック / 0.0.0.0/0」があることを確認します。</p>
<p>「セキュリティグループを作成」をクリック。</p>
<p><!-- ![DBサーバSG作成画面](images/db-sg-create.jpg) --></p>
<hr>
<h2><span id="toc25">⑧ APサーバEC2の起動（パブリックサブネット）</span></h2>
<p><strong>EC2 → インスタンス → 「インスタンスを起動」</strong></p>
<h3><span id="toc26">8-1. 基本設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-ap-instance</code></td>
</tr>
<tr>
<td>AMI</td>
<td><strong>Amazon Linux 2023 AMI</strong>（デフォルトで選択済み）</td>
</tr>
<tr>
<td>インスタンスタイプ</td>
<td><strong>t2.micro</strong>（無料枠対象）</td>
</tr>
<tr>
<td>キーペア</td>
<td><code>my-ec2-2tier-key</code></td>
</tr>
</tbody>
</table>
<h3><span id="toc27">8-2. ネットワーク設定</span></h3>
<p>「ネットワーク設定」→「編集」をクリックして以下を設定します。</p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>VPC</td>
<td><strong><code>my-vpc</code></strong></td>
</tr>
<tr>
<td>サブネット</td>
<td><strong><code>my-public-subnet</code></strong></td>
</tr>
<tr>
<td>パブリック IP の自動割り当て</td>
<td><strong>有効</strong></td>
</tr>
<tr>
<td>セキュリティグループ</td>
<td><strong>既存のセキュリティグループを選択</strong> → <code>my-ap-sg</code></td>
</tr>
</tbody>
</table>
<h3><span id="toc28">8-3. IAMロール・UserDataの設定</span></h3>
<p>「高度な詳細」を開きます。</p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>IAM インスタンスプロファイル</td>
<td><code>my-ec2-2tier-role</code></td>
</tr>
</tbody>
</table>
<p>「ユーザーデータ」に以下を貼り付けます。</p>
<pre><code class="language-bash">#!/bin/bash
dnf update -y
dnf install -y httpd
systemctl start httpd
systemctl enable httpd
cat &gt; /var/www/html/index.html &lt;&lt; 'HTMLEOF'
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;&lt;meta charset="UTF-8"&gt;&lt;title&gt;AP Server - Phase 1-4&lt;/title&gt;&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;AP Server (Public Subnet)&lt;/h1&gt;
&lt;p&gt;This AP server is in the PUBLIC subnet and can reach the DB server in the PRIVATE subnet.&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
HTMLEOF</code></pre>
<p>「インスタンスを起動」をクリック。</p>
<p><strong>控えておく情報</strong>: APサーバのパブリックIPアドレス</p>
<p><!-- ![APサーバEC2起動後の画面](images/ap-ec2-running.jpg) --></p>
<hr>
<h2><span id="toc29">⑨ DBサーバEC2の起動（プライベートサブネット）</span></h2>
<p><strong>EC2 → インスタンス → 「インスタンスを起動」</strong></p>
<h3><span id="toc30">9-1. 基本設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-db-instance</code></td>
</tr>
<tr>
<td>AMI</td>
<td><strong>Amazon Linux 2023 AMI</strong></td>
</tr>
<tr>
<td>インスタンスタイプ</td>
<td><strong>t2.micro</strong></td>
</tr>
<tr>
<td>キーペア</td>
<td><code>my-ec2-2tier-key</code></td>
</tr>
</tbody>
</table>
<h3><span id="toc31">9-2. ネットワーク設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>VPC</td>
<td><strong><code>my-vpc</code></strong></td>
</tr>
<tr>
<td>サブネット</td>
<td><strong><code>my-private-subnet</code></strong></td>
</tr>
<tr>
<td>パブリック IP の自動割り当て</td>
<td><strong>無効</strong>（プライベートサブネットのため）</td>
</tr>
<tr>
<td>セキュリティグループ</td>
<td><strong>既存のセキュリティグループを選択</strong> → <code>my-db-sg</code></td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>パブリックIPを付与しない</strong>: DBサーバはインターネットから直接アクセスされる必要がありません。プライベートサブネットに置き、パブリックIPを持たせないことで、インターネットから完全に隔離します。</p>
</blockquote>
<h3><span id="toc32">9-3. IAMロール・UserDataの設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>IAM インスタンスプロファイル</td>
<td><code>my-ec2-2tier-role</code></td>
</tr>
</tbody>
</table>
<p>「ユーザーデータ」に以下を貼り付けます。</p>
<pre><code class="language-bash">#!/bin/bash
dnf update -y
dnf install -y mariadb105-server mariadb105
systemctl start mariadb
systemctl enable mariadb
sudo mysql -u root &lt;&lt; 'SQLEOF'
SET PASSWORD FOR root@localhost = PASSWORD('Admin1234!');
CREATE USER IF NOT EXISTS 'handson'@'%' IDENTIFIED BY 'Handson1234!';
GRANT ALL PRIVILEGES ON *.* TO 'handson'@'%' WITH GRANT OPTION;
CREATE DATABASE IF NOT EXISTS sampledb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
FLUSH PRIVILEGES;
SQLEOF</code></pre>
<blockquote>
<p><strong>⑥-3でS3 VPC Endpointを作成済みの場合</strong>: <code>dnf install</code> はS3経由で正常に動作します。Endpointを作成せずにEC2を起動した場合はMariaDBがインストールされないため、踏み台SSH接続後に手動で <code>sudo dnf install -y mariadb105-server mariadb105</code> を実行してください。</p>
</blockquote>
<p>「インスタンスを起動」をクリック。</p>
<p><strong>控えておく情報</strong>: DBサーバのプライベートIPアドレス（パブリックIPはありません）</p>
<p>インスタンス詳細 → 「プライベート IPv4 アドレス」（例: <code>10.0.2.xxx</code>）を確認してメモします。</p>
<hr>
<h2><span id="toc33">⑩ 動作確認</span></h2>
<blockquote>
<p><strong>待機時間</strong>: EC2起動後、UserDataの完了まで数分かかります。APサーバは2〜3分、DBサーバは5〜8分待ちます。</p>
</blockquote>
<h3><span id="toc34">10-1. APサーバのWeb確認</span></h3>
<p>ブラウザで以下にアクセスします。</p>
<pre><code class="language-plaintext">http://（APサーバのパブリックIP）</code></pre>
<p><code>AP Server (Public Subnet)</code> が表示されれば成功です。</p>
<p><!-- ![APサーバWebページ確認](images/ap-web-browser.jpg) --></p>
<h3><span id="toc35">10-2. APサーバへのSSH接続</span></h3>
<pre><code class="language-cmd">ssh -i C:\Users\ユーザー名\.ssh\my-ec2-2tier-key.pem ec2-user@（APパブリックIP）</code></pre>
<h3><span id="toc36">10-3. キーペアをAPサーバにコピーする（踏み台SSH準備）</span></h3>
<p>APサーバを踏み台としてDBサーバにSSH接続するために、ローカルPCからAPサーバにキーペアをコピーします。</p>
<p><strong>ローカルPCの別ターミナルで実行します:</strong></p>
<pre><code class="language-cmd">scp -i C:\Users\ユーザー名\.ssh\my-ec2-2tier-key.pem ^
  C:\Users\ユーザー名\.ssh\my-ec2-2tier-key.pem ^
  ec2-user@（APパブリックIP）:~/.ssh/</code></pre>
<p>APサーバ上でキーペアのパーミッションを設定します。</p>
<pre><code class="language-bash">chmod 400 ~/.ssh/my-ec2-2tier-key.pem</code></pre>
<h3><span id="toc37">10-4. APサーバ経由でDBサーバにSSH接続（踏み台接続）</span></h3>
<p><strong>APサーバのSSHセッションから実行します:</strong></p>
<pre><code class="language-bash">ssh -i ~/.ssh/my-ec2-2tier-key.pem ec2-user@（DBプライベートIP）</code></pre>
<p><code>[ec2-user@ip-10-0-2-xxx ~]$</code> のプロンプトが表示されれば踏み台接続成功です。</p>
<pre><code class="language-bash">sudo systemctl status mariadb

# MariaDBに接続
mysql -u root -pAdmin1234!</code></pre>
<p>MariaDBのプロンプトで確認します。</p>
<pre><code class="language-sql">SHOW DATABASES;
EXIT;</code></pre>
<p>DBサーバから切断します。</p>
<pre><code class="language-bash">exit</code></pre>
<h3><span id="toc38">10-5. APサーバからMySQLに接続（AP→DB通信確認）</span></h3>
<p>APサーバのSSHセッションで実行します。</p>
<pre><code class="language-bash"># mysqlクライアントのインストール
sudo dnf install -y mariadb105

# DBサーバのプライベートIPにMySQL接続
mysql -h （DBプライベートIP） -u handson -pHandson1234! sampledb</code></pre>
<p>接続成功すれば <code>MariaDB [sampledb]&gt;</code> が表示されます。</p>
<pre><code class="language-sql">CREATE TABLE IF NOT EXISTS messages (id INT AUTO_INCREMENT PRIMARY KEY, text VARCHAR(100));
INSERT INTO messages (text) VALUES ('Hello from AP server!');
SELECT * FROM messages;
EXIT;</code></pre>
<p>APサーバから切断します。</p>
<pre><code class="language-bash">exit</code></pre>
<p><!-- ![踏み台SSHとMySQL接続確認](images/bastion-mysql-connect.jpg) --></p>
<hr>
<h2><span id="toc39">⑪ リソースの削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ず削除してください。削除する順番が重要です。</strong></p>
<blockquote>
<p><strong>CloudFormation版と比較</strong>: コンソール版はリソースの依存関係を意識して手動で削除する必要があります。CloudFormation版は <code>delete-stack</code> 1本で全て自動削除できます。</p>
</blockquote>
<h3><span id="toc40">削除順序</span></h3>
<p><strong>1. EC2インスタンスを終了する（2台）</strong></p>
<p><strong>EC2 → インスタンス → <code>my-ap-instance</code> と <code>my-db-instance</code> を選択 → 「インスタンスを終了」</strong></p>
<p>「終了済み」になるまで待ちます（2〜5分）。</p>
<p><strong>2. セキュリティグループを削除する（DBサーバSG → APサーバSGの順）</strong></p>
<p>DBサーバSGがAPサーバSGを参照しているため、DBサーバSGを先に削除します。</p>
<p>① <strong><code>my-db-sg</code></strong> を選択 → 「アクション」→「セキュリティグループを削除」</p>
<p>② <strong><code>my-ap-sg</code></strong> を選択 → 「アクション」→「セキュリティグループを削除」</p>
<p><strong>3. S3 VPC Endpointを削除する</strong></p>
<p><strong>VPC → エンドポイント → <code>my-s3-endpoint</code> を選択 → 「アクション」→「エンドポイントを削除」</strong></p>
<p><strong>4. ルートテーブルの関連付けを解除・削除する</strong></p>
<p>① <code>my-public-rt</code> を選択 → 「サブネットの関連付け」タブ → 「サブネットの関連付けを編集」→ チェックを外す → 「保存」</p>
<p>② <code>my-private-rt</code> も同様に関連付けを解除する</p>
<p>③ <code>my-public-rt</code> を選択 → 「ルート」タブ → 「ルートを編集」→ <code>0.0.0.0/0</code> のルートを削除 → 「保存」</p>
<p>④ <code>my-public-rt</code> を選択 → 「アクション」→「ルートテーブルの削除」</p>
<p>⑤ <code>my-private-rt</code> も同様に削除する</p>
<p><strong>5. サブネットを削除する（2つ）</strong></p>
<p><strong>VPC → サブネット → <code>my-public-subnet</code> → 「アクション」→「サブネットを削除」</strong></p>
<p>同様に <code>my-private-subnet</code> も削除します。</p>
<p><strong>6. インターネットゲートウェイをデタッチ・削除する</strong></p>
<p><strong>VPC → インターネットゲートウェイ → <code>my-igw</code> → 「アクション」→「VPCからデタッチ」</strong></p>
<p>デタッチ完了後、「アクション」→「インターネットゲートウェイの削除」。</p>
<p><strong>7. VPCを削除する</strong></p>
<p><strong>VPC → お使いのVPC → <code>my-vpc</code> → 「アクション」→「VPCを削除」</strong></p>
<p><strong>8. IAMロールを削除する</strong></p>
<p><strong>IAM → ロール → <code>my-ec2-2tier-role</code> → 「削除」</strong></p>
<p><strong>9. キーペアを削除する（任意）</strong></p>
<p><strong>EC2 → キーペア → <code>my-ec2-2tier-key</code> → 「削除」</strong></p>
<pre><code class="language-plaintext">C:\Users\ユーザー名\.ssh\my-ec2-2tier-key.pem</code></pre>
<hr>
<h2><span id="toc41">CloudFormation版との比較</span></h2>
<table>
<thead>
<tr>
<th>作業</th>
<th>コンソール（手動）</th>
<th>CloudFormation</th>
</tr>
</thead>
<tbody>
<tr>
<td>VPC・IGW・サブネット・RTの設定</td>
<td>6画面・20ステップ以上</td>
<td>template.yaml に定義済み</td>
</tr>
<tr>
<td>S3 VPC Endpoint作成</td>
<td>画面でポチポチ</td>
<td>template.yaml に定義済み</td>
</tr>
<tr>
<td>EC2×2台の起動</td>
<td>2回インスタンス起動操作</td>
<td>コマンド1本（並列作成）</td>
</tr>
<tr>
<td>削除（依存関係あり）</td>
<td>8ステップ・手動管理</td>
<td><code>delete-stack</code> 1本</td>
</tr>
<tr>
<td>全体の所要時間</td>
<td>30〜40分</td>
<td>8〜12分</td>
</tr>
<tr>
<td>再現性</td>
<td>低い（手順漏れのリスク大）</td>
<td>高い</td>
</tr>
</tbody>
</table>
<p><strong>コンソール版で実感できたポイント:</strong></p>
<ul>
<li>VPC・IGW・サブネット・ルートテーブルの依存関係が視覚的に理解できる</li>
<li>プライベートサブネットにEC2を置くとパブリックIPが付かないことを実感できる</li>
<li>踏み台接続（APサーバ経由でDBサーバにSSH）の意味と手順が身につく</li>
<li>S3 VPC Endpointがなければ <code>dnf install</code> が失敗することを体験できる</li>
</ul>
<p><strong>CloudFormation版でも試してみる</strong>: <a href="https://caymezon.com/aws-handson-cloudformation-ec2-2tier/">CloudFormationでAP+DB 2層構成（VPC設計）を自動デプロイする手順</a></p>
<hr>
<h2><span id="toc42">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td>APサーバのWebページが表示されない</td>
<td>UserDataが完了していない</td>
<td>2〜3分待ってリロード</td>
</tr>
<tr>
<td>DBサーバの <code>dnf install</code> が失敗する</td>
<td>S3 VPC Endpointが未作成</td>
<td>⑥-3の手順でEndpointを作成後、踏み台SSH接続して手動で <code>sudo dnf install -y mariadb105-server mariadb105</code> を実行</td>
</tr>
<tr>
<td>APサーバからDBサーバにSSH接続できない</td>
<td><code>my-db-sg</code> のSSHソースが <code>my-ap-sg</code> になっていない</td>
<td>DBサーバSGのインバウンドルールを確認</td>
</tr>
<tr>
<td>APサーバからMySQLに接続できない</td>
<td><code>my-db-sg</code> のMySQL(3306)ソースが <code>my-ap-sg</code> になっていない</td>
<td>DBサーバSGのインバウンドルールを確認</td>
</tr>
<tr>
<td>セキュリティグループが削除できない</td>
<td>EC2インスタンスがまだ「使用中」またはDBサーバSGを先に削除していない</td>
<td>EC2「終了済み」後に、DBサーバSG → APサーバSGの順で削除</td>
</tr>
<tr>
<td>VPCが削除できない</td>
<td>サブネット・IGW・RTが残っている</td>
<td>削除順序を守る（サブネット・RT・IGWを先に削除）</td>
</tr>
<tr>
<td>SGを作成するとき <code>my-vpc</code> のSGが選択できない</td>
<td>EC2起動時にVPCをデフォルトVPCにしている</td>
<td>ネットワーク設定でVPCを <code>my-vpc</code> に変更してから再選択</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc43">まとめ</span></h2>
<p>今回のハンズオンで体験できたこと：</p>
<table>
<thead>
<tr>
<th>確認項目</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>VPC設計</strong></td>
<td>カスタムVPC・パブリック/プライベートサブネット・IGW・ルートテーブルを一から構築</td>
</tr>
<tr>
<td><strong>ネットワーク分離</strong></td>
<td>DBサーバをプライベートサブネットに配置してインターネットから隔離</td>
</tr>
<tr>
<td><strong>S3 VPC Endpoint</strong></td>
<td>プライベートサブネットからインターネットなしでパッケージをインストール</td>
</tr>
<tr>
<td><strong>踏み台接続</strong></td>
<td>APサーバを中継してプライベートサブネットのDBサーバにSSH接続</td>
</tr>
<tr>
<td><strong>SG参照</strong></td>
<td>DBサーバSGのルールをIPアドレスではなくAPサーバSGで指定</td>
</tr>
<tr>
<td><strong>削除手順</strong></td>
<td>依存関係を意識して8ステップで全リソースを削除</td>
</tr>
</tbody>
</table>
<p>20ステップ以上の手動作業でリソースを一つひとつ作ると、CloudFormationが裏で何を自動化しているかが理解できます。ぜひ次は <a href="https://caymezon.com/aws-handson-cloudformation-ec2-2tier/">CloudFormation版</a> でコマンド1本の差を体感してみてください。</p>
<hr>
<h2><span id="toc44">関連記事</span></h2>
<p><!-- <a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"> --></p>
<p><!-- <!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWS運用入門 改訂第2版 押さえておきたいAWSの基本と運用ノウハウ [AWS深掘りガイド]","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51AAOubymTL._SL500_.jpg","\/51VMG6YKHdL._SL500_.jpg","\/41EdPB8azAL._SL500_.jpg","\/41v2JFE-9jL._SL500_.jpg","\/41FEEqR-yDL._SL500_.jpg","\/41JfZAdnTPL._SL500_.jpg","\/41vGK0czQrL._SL500_.jpg","\/41-SnYtz2aL._SL500_.jpg","\/41sPrV5fi3L._SL500_.jpg","\/41p7JtvYJ1L._SL500_.jpg","\/4169GVNTs8L._SL500_.jpg","\/41BPI5HP3zL._SL500_.jpg","\/41QOyk60CYL._SL500_.jpg","\/41APjk6FphL._SL500_.jpg","\/41ezKUu7VRL._SL500_.jpg","\/41A1n3K+r5L._SL500_.jpg","\/41aY2T8lEOL._SL500_.jpg","\/419Ca1V6HZL._SL500_.jpg","\/41zQkYyLPzL._SL500_.jpg","\/41YpHcyxiTL._SL500_.jpg","\/41-tKN5mt6L._SL500_.jpg","\/419Mv6m55IL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815631085","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815631085","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"E8MM1","s":"s"});</script></p>
<div id="msmaflink-E8MM1">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --> --></p><p>The post <a href="https://caymezon.com/aws-handson-console-ec2-2tier/">AWSコンソールでVPC設計からAP+DB 2層構成を構築する手順【踏み台SSH / CloudFormation版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-console-ec2-2tier/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>EC2サーバ構築ハンズオン：AWSコンソールでEC2 MySQLのDBサーバを構築する手順【SG参照 / CloudFormation版との比較付き】</title>
		<link>https://caymezon.com/aws-handson-console-ec2-mysql/</link>
					<comments>https://caymezon.com/aws-handson-console-ec2-mysql/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Sun, 29 Mar 2026 07:32:39 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[AWSコンソール]]></category>
		<category><![CDATA[DBサーバー]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[ec2サーバ構築]]></category>
		<category><![CDATA[IAM]]></category>
		<category><![CDATA[MariaDB]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[SG参照]]></category>
		<category><![CDATA[UserData]]></category>
		<category><![CDATA[セキュリティグループ]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[初心者]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20319</guid>

					<description><![CDATA[<p>目次 はじめにキーワード解説IPアドレス指定 vs SG参照前フェーズとの比較使用するAWSサービス構築するリソース全体の作業順序【重要】⓪ 自分のIPアドレスを確認する方法A: ルーター管理画面で確認（推奨）方法B:  [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-console-ec2-mysql/">EC2サーバ構築ハンズオン：AWSコンソールでEC2 MySQLのDBサーバを構築する手順【SG参照 / CloudFormation版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-4" checked><label class="toc-title" for="toc-checkbox-4">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">キーワード解説</a></li><li><a href="#toc3" tabindex="0">IPアドレス指定 vs SG参照</a></li><li><a href="#toc4" tabindex="0">前フェーズとの比較</a></li><li><a href="#toc5" tabindex="0">使用するAWSサービス</a></li><li><a href="#toc6" tabindex="0">構築するリソース</a></li><li><a href="#toc7" tabindex="0">全体の作業順序</a></li><li><a href="#toc8" tabindex="0">【重要】⓪ 自分のIPアドレスを確認する</a><ol><li><a href="#toc9" tabindex="0">方法A: ルーター管理画面で確認（推奨）</a></li><li><a href="#toc10" tabindex="0">方法B: コマンドで確認</a></li></ol></li><li><a href="#toc11" tabindex="0">① キーペアの作成</a></li><li><a href="#toc12" tabindex="0">② IAMロールの作成</a></li><li><a href="#toc13" tabindex="0">③ クライアントSGの作成</a></li><li><a href="#toc14" tabindex="0">④ DBサーバSGの作成（SG参照の設定）</a></li><li><a href="#toc15" tabindex="0">⑤ DBサーバEC2の起動</a><ol><li><a href="#toc16" tabindex="0">5-1. 基本設定</a></li><li><a href="#toc17" tabindex="0">5-2. セキュリティグループの設定</a></li><li><a href="#toc18" tabindex="0">5-3. IAMロールの設定</a></li><li><a href="#toc19" tabindex="0">5-4. UserDataの設定（MariaDBの自動インストール）</a></li><li><a href="#toc20" tabindex="0">5-5. インスタンスを起動する</a></li></ol></li><li><a href="#toc21" tabindex="0">⑥ クライアントEC2の起動</a><ol><li><a href="#toc22" tabindex="0">6-1. 基本設定</a></li><li><a href="#toc23" tabindex="0">6-2. セキュリティグループの設定</a></li><li><a href="#toc24" tabindex="0">6-3. IAMロールの設定</a></li><li><a href="#toc25" tabindex="0">6-4. UserDataの設定（mysqlクライアントのインストール）</a></li><li><a href="#toc26" tabindex="0">6-5. インスタンスを起動する</a></li></ol></li><li><a href="#toc27" tabindex="0">⑦ 動作確認</a><ol><li><a href="#toc28" tabindex="0">7-1. DBサーバの動作確認</a></li><li><a href="#toc29" tabindex="0">7-2. SG参照の確認：クライアントEC2からMySQL接続</a></li><li><a href="#toc30" tabindex="0">7-3. SG参照の効果を確認する（任意・スキップ可）</a></li></ol></li><li><a href="#toc31" tabindex="0">⑧ リソースの削除</a><ol><li><a href="#toc32" tabindex="0">1. EC2インスタンスを終了する（2台）</a></li><li><a href="#toc33" tabindex="0">2. セキュリティグループを削除する（2つ）</a></li><li><a href="#toc34" tabindex="0">3. IAMロールを削除する</a></li><li><a href="#toc35" tabindex="0">4. キーペアを削除する（任意）</a></li></ol></li><li><a href="#toc36" tabindex="0">CloudFormation版との比較</a></li><li><a href="#toc37" tabindex="0">トラブルシューティング</a></li><li><a href="#toc38" tabindex="0">まとめ</a></li><li><a href="#toc39" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>「EC2サーバでデータベースを動かしたい」「EC2同士の通信をセキュアに制御したい」——そのステップがこのハンズオンです。</p>
<p>この記事では、<strong>AWSコンソール（GUI）のみ</strong>を使って、MySQL互換のDBサーバー（MariaDB）が動作するEC2インスタンスをゼロから手動構築するハンズオンを紹介します。</p>
<pre><code class="language-plaintext">インターネット
  ↓ SSH(22)              ← 自分のIPのみ
  ↓ MySQL(3306)          ← 自分のIPのみ（初期テスト用）
my-ec2-mysql-db-sg（DBサーバSG）
  ↓ MySQL(3306)          ← my-ec2-mysql-client-sg に属するEC2のみ ★SG参照
EC2インスタンス（DBサーバ）       EC2インスタンス（クライアント）
  └── MariaDB 10.5              └── mysqlコマンド（接続テスト用）
        └── sampledb（DB）             ↑
                           my-ec2-mysql-client-sg（クライアントSG）
                             ↓ SSH(22) ← 自分のIPのみ
                           インターネット</code></pre>
<p><strong>このハンズオンで体験できること：</strong></p>
<ul>
<li>セキュリティグループの <strong>SG参照（SG-to-SG）</strong> による EC2間通信制御</li>
<li>EC2サーバへの MariaDB（MySQL互換）インストールと初期設定</li>
<li>2台のEC2（DBサーバ + クライアント）を使った実際のDB接続確認</li>
<li>IPアドレス指定 vs SG参照の違いを体感</li>
</ul>
<p><strong>このハンズオンのポイント：</strong></p>
<p>DBサーバのMySQLポート（3306）を「特定のIPアドレス」ではなく「特定のセキュリティグループに属するEC2」だけに開放します。これが <strong>SG参照（SG-to-SG）</strong> と呼ばれる設定方法で、IPが変わっても自動的に制御できる、本番環境でも使われるセキュアな設計です。</p>
<hr>
<blockquote>
<p><strong>この記事は <a href="https://caymezon.com/aws-handson-cloudformation-ec2-mysql/">CloudFormation版ハンズオン</a> の比較記事です。</strong><br />コンソール操作でSG参照の仕組みを視覚的に学び、CloudFormationとの違いを比較したい方向けです。</p>
</blockquote>
<hr>
<p><!-- ![ハンズオン完成後のMySQL接続確認画面](images/ec2-mysql-top.jpg) --></p>
<p><!-- <a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"> --></p>
<p><!-- <!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWSの基本・仕組み・重要用語が全部わかる教科書 (見るだけ図解)","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51DEDQXj6oL._SL500_.jpg","\/41F589smNwL._SL500_.jpg","\/41R6f9yyCWL._SL500_.jpg","\/41HqWQ9BvmL._SL500_.jpg","\/41p8p0ZU79L._SL500_.jpg","\/41qLC-fndBL._SL500_.jpg","\/41fcLv9VT5L._SL500_.jpg","\/51lRvCsvHqL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815607850","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815607850","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"eaCUB","s":"s"});</script></p>
<div id="msmaflink-eaCUB">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --> --></p>
<h2><span id="toc2">キーワード解説</span></h2>
<table>
<thead>
<tr>
<th>用語</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>EC2（Elastic Compute Cloud）</strong></td>
<td>AWSの仮想サーバーサービス。今回は2台（DBサーバ・クライアント）を起動する</td>
</tr>
<tr>
<td><strong>MariaDB</strong></td>
<td>MySQLから派生したオープンソースのデータベース。コマンド・構文・接続方法がMySQLと完全互換</td>
</tr>
<tr>
<td><strong>セキュリティグループ（SG）</strong></td>
<td>EC2への通信を制御するファイアウォール。今回は2つのSGを作成する</td>
</tr>
<tr>
<td><strong>SG参照（SG-to-SG）</strong></td>
<td>アクセス元としてIPアドレスではなく別のセキュリティグループを指定する設定。そのSGに属するEC2全体を対象にできる</td>
</tr>
<tr>
<td><strong>プライベートIPアドレス</strong></td>
<td>AWSのVPC内でのみ使用できるIPアドレス。EC2間の通信にはプライベートIPを使う</td>
</tr>
<tr>
<td><strong>UserData</strong></td>
<td>EC2の初回起動時のみ自動実行されるシェルスクリプト。今回はMariaDBのインストール・初期設定に使う</td>
</tr>
<tr>
<td><strong>IAMロール</strong></td>
<td>EC2にAWSサービスを利用する権限を付与する仕組み</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc3">IPアドレス指定 vs SG参照</span></h2>
<p>今回のハンズオンで学ぶ「SG参照」がなぜ重要かを確認します。</p>
<table>
<thead>
<tr>
<th>比較項目</th>
<th>IP指定（前回まで）</th>
<th>SG参照（今回）</th>
</tr>
</thead>
<tbody>
<tr>
<td>アクセス元の指定方法</td>
<td><code>123.456.78.901/32</code>（IPアドレス）</td>
<td><code>sg-xxxxx</code>（セキュリティグループID）</td>
</tr>
<tr>
<td>対象</td>
<td>指定したIPのみ</td>
<td>そのSGに属するEC2全体</td>
</tr>
<tr>
<td>IPが変わった場合</td>
<td>設定変更が必要</td>
<td>自動的に制御（変更不要）</td>
</tr>
<tr>
<td>EC2を増やした場合</td>
<td>追加EC2のIPも個別に設定が必要</td>
<td>SGに追加するだけで自動的に許可</td>
</tr>
<tr>
<td>用途</td>
<td>自分のPCからの接続、外部サービスからの接続</td>
<td>APサーバ→DBサーバなどEC2間通信の制御</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc4">前フェーズとの比較</span></h2>
<table>
<thead>
<tr>
<th>比較項目</th>
<th>Phase 1-1 Apache</th>
<th>Phase 1-2 Tomcat</th>
<th>Phase 1-3 MySQL（今回）</th>
</tr>
</thead>
<tbody>
<tr>
<td>役割</td>
<td>Webサーバー</td>
<td>APサーバー</td>
<td>DBサーバー</td>
</tr>
<tr>
<td>ポート</td>
<td>80</td>
<td>8080</td>
<td>3306</td>
</tr>
<tr>
<td>SGのアクセス元</td>
<td>自分のIP</td>
<td>自分のIP</td>
<td><strong>クライアントSG参照</strong></td>
</tr>
<tr>
<td>EC2台数</td>
<td>1台</td>
<td>1台</td>
<td><strong>2台</strong>（DB + クライアント）</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc5">使用するAWSサービス</span></h2>
<table>
<thead>
<tr>
<th>サービス</th>
<th>役割</th>
<th>料金</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>EC2 × 2台</strong></td>
<td>DBサーバ + クライアント（各t2.micro）</td>
<td>月750時間まで無料枠あり（2台で消費が倍）</td>
</tr>
<tr>
<td><strong>セキュリティグループ × 2</strong></td>
<td>DBサーバSG / クライアントSGのアクセス制御</td>
<td>無料</td>
</tr>
<tr>
<td><strong>IAM</strong></td>
<td>EC2へのSession Manager接続権限</td>
<td>無料</td>
</tr>
<tr>
<td><strong>EBS × 2</strong></td>
<td>EC2にアタッチされるストレージ（各8GB）</td>
<td>月30GBまで無料枠あり</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>注意</strong>: EC2を2台同時に稼働させるため、無料枠の消費が2倍になります。ハンズオン後は必ず2台とも削除してください。</p>
</blockquote>
<hr>
<h2><span id="toc6">構築するリソース</span></h2>
<table>
<thead>
<tr>
<th>リソース</th>
<th>役割</th>
</tr>
</thead>
<tbody>
<tr>
<td>キーペア</td>
<td>SSH接続の認証鍵（DBサーバ・クライアント両方で使用）</td>
</tr>
<tr>
<td>IAMロール</td>
<td>EC2にSession Manager接続の権限を付与</td>
</tr>
<tr>
<td>クライアントSG</td>
<td>クライアントEC2（APサーバ役）に適用するSG</td>
</tr>
<tr>
<td>DBサーバSG</td>
<td>DBサーバEC2に適用するSG（クライアントSGを参照）</td>
</tr>
<tr>
<td>DBサーバEC2</td>
<td>MariaDBが動作するDBサーバ本体</td>
</tr>
<tr>
<td>クライアントEC2</td>
<td>mysqlコマンドでDB接続テストを行うEC2（APサーバ役）</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc7">全体の作業順序</span></h2>
<p>依存関係があるため、必ずこの順番で作成します。</p>
<pre><code class="language-plaintext">⓪ 自分のIPアドレスを確認する（重要）
      ↓
① キーペアを作成する
      ↓
② IAMロールを作成する
      ↓
③ クライアントSGを作成する（先に作成する必要がある）
      ↓
④ DBサーバSGを作成する（③のSGを参照する）
      ↓
⑤ DBサーバEC2を起動する
      ↓
⑥ クライアントEC2を起動する
      ↓
⑦ 動作確認（DBサーバ・クライアント）
      ↓
⑧ リソースを削除する</code></pre>
<hr>
<h2><span id="toc8">【重要】⓪ 自分のIPアドレスを確認する</span></h2>
<p>セキュリティグループで自分のIPだけを許可するために、<strong>正確なIPアドレス</strong>を事前に確認します。</p>
<h3><span id="toc9">方法A: ルーター管理画面で確認（推奨）</span></h3>
<ol>
<li>ブラウザで以下のURLにアクセスします（ルーターによって異なります）
<pre><code class="language-plaintext">http://192.168.0.1  または  http://192.168.1.1</code></pre>
</li>
<li>「ネットワークマップ」または「インターネット」項目を開く</li>
<li>**「インターネットIPアドレス」または「WAN IPアドレス」**の値を控えます</li>
</ol>
<h3><span id="toc10">方法B: コマンドで確認</span></h3>
<pre><code class="language-cmd">curl https://checkip.amazonaws.com</code></pre>
<p><strong>控えておく情報</strong>: 自分のIPアドレス（例: <code>203.0.113.1</code>）</p>
<hr>
<h2><span id="toc11">① キーペアの作成</span></h2>
<p>DBサーバとクライアントEC2の両方のSSH接続に使います。1つのキーペアを共用します。</p>
<p><strong>AWSコンソール → EC2 → ネットワーク＆セキュリティ → キーペア → 「キーペアを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-ec2-mysql-key</code></td>
</tr>
<tr>
<td>キーペアのタイプ</td>
<td><strong>RSA</strong></td>
</tr>
<tr>
<td>プライベートキーファイル形式</td>
<td><strong>.pem</strong></td>
</tr>
</tbody>
</table>
<p>「キーペアを作成」をクリックすると <code>my-ec2-mysql-key.pem</code> がダウンロードされます。</p>
<pre><code class="language-plaintext">C:\Users\ユーザー名\.ssh\my-ec2-mysql-key.pem</code></pre>
<blockquote>
<p><strong>注意</strong>: <code>.pem</code> ファイルは<strong>再ダウンロードできません</strong>。紛失した場合は新しいキーペアを作成する必要があります。</p>
</blockquote>
<hr>
<h2><span id="toc12">② IAMロールの作成</span></h2>
<p><strong>AWSコンソール → IAM → ロール → 「ロールを作成」</strong></p>
<table>
<thead>
<tr>
<th>ステップ</th>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>信頼されたエンティティタイプ</td>
<td><strong>AWSのサービス</strong></td>
</tr>
<tr>
<td>1</td>
<td>ユースケース</td>
<td><strong>EC2</strong></td>
</tr>
<tr>
<td>2</td>
<td>許可ポリシー</td>
<td><code>AmazonSSMManagedInstanceCore</code></td>
</tr>
<tr>
<td>3</td>
<td>ロール名</td>
<td><code>my-ec2-mysql-role</code></td>
</tr>
</tbody>
</table>
<p>「ロールを作成」をクリック。</p>
<hr>
<h2><span id="toc13">③ クライアントSGの作成</span></h2>
<blockquote>
<p><strong>なぜ先に作るか</strong>: DBサーバSGの設定でクライアントSGを「参照先」として指定する必要があるため、先に作成しておく必要があります。</p>
</blockquote>
<p><strong>AWSコンソール → EC2 → セキュリティグループ → 「セキュリティグループを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>セキュリティグループ名</td>
<td><code>my-ec2-mysql-client-sg</code></td>
</tr>
<tr>
<td>説明</td>
<td><code>MySQL client SG (AP server role)</code></td>
</tr>
<tr>
<td>VPC</td>
<td>デフォルトVPC（変更不要）</td>
</tr>
</tbody>
</table>
<p><strong>インバウンドルール（「ルールを追加」）:</strong></p>
<table>
<thead>
<tr>
<th>タイプ</th>
<th>プロトコル</th>
<th>ポート</th>
<th>ソース</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td>SSH</td>
<td>TCP</td>
<td>22</td>
<td><code>203.0.113.1/32</code>（自分のIP）</td>
<td>SSH from my IP</td>
</tr>
</tbody>
</table>
<p><strong>アウトバウンドルールを確認します:</strong></p>
<p>SG作成画面の「アウトバウンドルール」欄に以下のルールが<strong>自動設定されていること</strong>を確認します。</p>
<table>
<thead>
<tr>
<th>タイプ</th>
<th>送信先</th>
</tr>
</thead>
<tbody>
<tr>
<td>すべてのトラフィック</td>
<td><code>0.0.0.0/0</code></td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>重要</strong>: このアウトバウンドルールがないとEC2がインターネットに出られず、<code>dnf install</code> でパッケージをダウンロードできなくなります。自動設定されていない場合は「ルールを追加」で追加してください。</p>
</blockquote>
<p>「セキュリティグループを作成」をクリック。</p>
<p><!-- ![クライアントSG作成画面](images/client-sg-create.jpg) --></p>
<hr>
<h2><span id="toc14">④ DBサーバSGの作成（SG参照の設定）</span></h2>
<p><strong>AWSコンソール → EC2 → セキュリティグループ → 「セキュリティグループを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>セキュリティグループ名</td>
<td><code>my-ec2-mysql-db-sg</code></td>
</tr>
<tr>
<td>説明</td>
<td><code>MySQL DB server SG</code></td>
</tr>
<tr>
<td>VPC</td>
<td>デフォルトVPC（変更不要）</td>
</tr>
</tbody>
</table>
<p><strong>インバウンドルール（「ルールを追加」で3ルール追加します）:</strong></p>
<p><strong>ルール1: SSH（管理用）</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>タイプ</td>
<td>SSH</td>
</tr>
<tr>
<td>ソースタイプ</td>
<td>カスタム</td>
</tr>
<tr>
<td>ソース</td>
<td><code>203.0.113.1/32</code>（自分のIP）</td>
</tr>
</tbody>
</table>
<p><strong>ルール2: MySQL（クライアントSGからの接続）← このハンズオンの核心</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>タイプ</td>
<td>MySQL/Aurora</td>
</tr>
<tr>
<td>ソースタイプ</td>
<td><strong>カスタム</strong></td>
</tr>
<tr>
<td>ソース</td>
<td>検索ボックスに <code>my-ec2-mysql-client-sg</code> と入力して選択</td>
</tr>
<tr>
<td>説明</td>
<td><code>MySQL from client SG only</code></td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>ここがSG参照</strong>: ソースとして「IPアドレス」ではなく「セキュリティグループ」を指定しています。<code>my-ec2-mysql-client-sg</code> に属するEC2からのMySQL接続のみを許可し、インターネットからは接続できません。</p>
</blockquote>
<p><strong>ルール3: MySQL（自分のIPからの接続）← 初期テスト・確認用</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>タイプ</td>
<td>MySQL/Aurora</td>
</tr>
<tr>
<td>ソースタイプ</td>
<td>カスタム</td>
</tr>
<tr>
<td>ソース</td>
<td><code>203.0.113.1/32</code>（自分のIP）</td>
</tr>
<tr>
<td>説明</td>
<td><code>MySQL from my IP (for initial testing)</code></td>
</tr>
</tbody>
</table>
<p><strong>アウトバウンドルールを確認します:</strong></p>
<p>「アウトバウンドルール」欄に「すべてのトラフィック / 0.0.0.0/0」が設定されていることを確認します（クライアントSGと同様）。</p>
<p>「セキュリティグループを作成」をクリック。</p>
<p><!-- ![DBサーバSG作成画面 - SG参照の設定](images/db-sg-create.jpg) --></p>
<hr>
<h2><span id="toc15">⑤ DBサーバEC2の起動</span></h2>
<p><strong>AWSコンソール → EC2 → インスタンス → 「インスタンスを起動」</strong></p>
<h3><span id="toc16">5-1. 基本設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-ec2-mysql-db-instance</code></td>
</tr>
<tr>
<td>アプリケーションおよびOSイメージ</td>
<td><strong>Amazon Linux 2023 AMI</strong>（デフォルトで選択済み）</td>
</tr>
<tr>
<td>インスタンスタイプ</td>
<td><strong>t2.micro</strong>（無料枠対象）</td>
</tr>
<tr>
<td>キーペア</td>
<td><code>my-ec2-mysql-key</code></td>
</tr>
</tbody>
</table>
<h3><span id="toc17">5-2. セキュリティグループの設定</span></h3>
<p>「ネットワーク設定」→「<strong>既存のセキュリティグループを選択する</strong>」→ <code>my-ec2-mysql-db-sg</code> を選択します。</p>
<blockquote>
<p><strong>注意</strong>: 「セキュリティグループを作成する」ではなく「<strong>既存のセキュリティグループを選択する</strong>」を選びます。④で作成済みの <code>my-ec2-mysql-db-sg</code> を指定します。</p>
</blockquote>
<h3><span id="toc18">5-3. IAMロールの設定</span></h3>
<p>「高度な詳細」→「IAM インスタンスプロファイル」→ <code>my-ec2-mysql-role</code> を選択します。</p>
<h3><span id="toc19">5-4. UserDataの設定（MariaDBの自動インストール）</span></h3>
<p>「高度な詳細」の一番下「ユーザーデータ」に以下を貼り付けます。</p>
<pre><code class="language-bash">#!/bin/bash
dnf update -y
dnf install -y mariadb105-server mariadb105

systemctl start mariadb
systemctl enable mariadb

sudo mysql -u root &lt;&lt; 'SQLEOF'
SET PASSWORD FOR root@localhost = PASSWORD('Admin1234!');
CREATE USER IF NOT EXISTS 'handson'@'%' IDENTIFIED BY 'Handson1234!';
GRANT ALL PRIVILEGES ON *.* TO 'handson'@'%' WITH GRANT OPTION;
CREATE DATABASE IF NOT EXISTS sampledb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
FLUSH PRIVILEGES;
SQLEOF</code></pre>
<p><strong>各コマンドの説明:</strong></p>
<table>
<thead>
<tr>
<th>コマンド</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>dnf install -y mariadb105-server mariadb105</code></td>
<td>MariaDB サーバーとクライアントをインストール</td>
</tr>
<tr>
<td><code>systemctl start mariadb</code></td>
<td>MariaDBを起動</td>
</tr>
<tr>
<td><code>systemctl enable mariadb</code></td>
<td>OS起動時にMariaDBが自動起動するよう設定</td>
</tr>
<tr>
<td><code>SET PASSWORD FOR root@localhost</code></td>
<td>rootパスワードを設定（<code>Admin1234!</code>）</td>
</tr>
<tr>
<td><code>CREATE USER &#39;handson&#39;@&#39;%&#39;</code></td>
<td>どのホストからでも接続できるユーザーを作成（<code>%</code>は任意のホスト）</td>
</tr>
<tr>
<td><code>GRANT ALL PRIVILEGES ON *.*</code></td>
<td>handsonユーザーに全権限を付与</td>
</tr>
<tr>
<td><code>CREATE DATABASE sampledb</code></td>
<td>動作確認用のデータベースを作成</td>
</tr>
<tr>
<td><code>FLUSH PRIVILEGES</code></td>
<td>権限設定を即時反映</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong><code>sudo mysql -u root</code> について</strong>: MariaDB インストール直後の root は unix_socket 認証（OSのrootユーザーとして接続）が有効になっています。<code>-p</code> でパスワードを指定すると <code>ERROR 1698 Access denied</code> になるため、初回設定は <code>sudo mysql -u root</code>（パスワードなし）で接続します。</p>
</blockquote>
<blockquote>
<p><strong>パスワードについて</strong>: このハンズオンでは学習用として <code>Admin1234!</code> / <code>Handson1234!</code> を使用しています。本番環境では必ず強力なパスワードに変更してください。</p>
</blockquote>
<h3><span id="toc20">5-5. インスタンスを起動する</span></h3>
<p>「インスタンスを起動」をクリック。<strong>起動後2〜3分待ちます</strong>。</p>
<p><strong>控えておく情報:</strong></p>
<ul>
<li>DBサーバのパブリックIPアドレス</li>
<li>DBサーバの<strong>プライベートIPアドレス</strong>（クライアントEC2からの接続に使用）</li>
</ul>
<p>インスタンス詳細 → 「プライベート IPv4 アドレス」を確認してメモします。</p>
<p><!-- ![DBサーバEC2起動後の画面](images/db-ec2-running.jpg) --></p>
<hr>
<h2><span id="toc21">⑥ クライアントEC2の起動</span></h2>
<p><strong>AWSコンソール → EC2 → インスタンス → 「インスタンスを起動」</strong></p>
<h3><span id="toc22">6-1. 基本設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-ec2-mysql-client-instance</code></td>
</tr>
<tr>
<td>アプリケーションおよびOSイメージ</td>
<td><strong>Amazon Linux 2023 AMI</strong></td>
</tr>
<tr>
<td>インスタンスタイプ</td>
<td><strong>t2.micro</strong></td>
</tr>
<tr>
<td>キーペア</td>
<td><code>my-ec2-mysql-key</code></td>
</tr>
</tbody>
</table>
<h3><span id="toc23">6-2. セキュリティグループの設定</span></h3>
<p>「ネットワーク設定」→「<strong>既存のセキュリティグループを選択する</strong>」→ <code>my-ec2-mysql-client-sg</code> を選択します。</p>
<h3><span id="toc24">6-3. IAMロールの設定</span></h3>
<p>「高度な詳細」→「IAM インスタンスプロファイル」→ <code>my-ec2-mysql-role</code> を選択します。</p>
<h3><span id="toc25">6-4. UserDataの設定（mysqlクライアントのインストール）</span></h3>
<pre><code class="language-bash">#!/bin/bash
dnf update -y
dnf install -y mariadb105</code></pre>
<blockquote>
<p>mysqlコマンド（クライアントツール）のみをインストールします。DBサーバ機能（<code>mariadb105-server</code>）はインストールしません。</p>
</blockquote>
<h3><span id="toc26">6-5. インスタンスを起動する</span></h3>
<p>「インスタンスを起動」をクリック。起動完了まで約2〜3分待ちます。</p>
<p><strong>控えておく情報:</strong> クライアントEC2のパブリックIPアドレス</p>
<p><!-- ![クライアントEC2起動後の画面](images/client-ec2-running.jpg) --></p>
<hr>
<h2><span id="toc27">⑦ 動作確認</span></h2>
<h3><span id="toc28">7-1. DBサーバの動作確認</span></h3>
<p>DBサーバにSSH接続します。</p>
<pre><code class="language-cmd">ssh -i C:\Users\ユーザー名\.ssh\my-ec2-mysql-key.pem ec2-user@（DBサーバのパブリックIP）</code></pre>
<p>接続後に以下を実行します。</p>
<pre><code class="language-bash">sudo systemctl status mariadb

# MariaDBのバージョン確認
mysql --version

# rootでログイン（パスワード: Admin1234!）
mysql -u root -pAdmin1234!</code></pre>
<p>MariaDBのプロンプト（<code>MariaDB [(none)]&gt;</code>）が表示されたら以下を実行します。</p>
<pre><code class="language-sql">-- ユーザー一覧を確認
SELECT User, Host FROM mysql.user;

-- データベース一覧を確認（sampledb が存在することを確認）
SHOW DATABASES;

-- sampledbに接続
USE sampledb;

-- テスト用のテーブルを作成
CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(50) NOT NULL,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- データを挿入
INSERT INTO users (name) VALUES ('Alice'), ('Bob'), ('Charlie');

-- データを確認
SELECT * FROM users;

-- MariaDBから切断
EXIT;</code></pre>
<p>DBサーバから切断します。</p>
<pre><code class="language-bash">exit</code></pre>
<h3><span id="toc29">7-2. SG参照の確認：クライアントEC2からMySQL接続</span></h3>
<p>クライアントEC2に接続します。</p>
<pre><code class="language-cmd">ssh -i C:\Users\ユーザー名\.ssh\my-ec2-mysql-key.pem ec2-user@（クライアントのパブリックIP）</code></pre>
<p>クライアントEC2からDBサーバのプライベートIPに向けてMySQL接続します。</p>
<pre><code class="language-bash"># DBサーバのプライベートIPに接続（XXX.XXX.XXX.XXX はDBサーバのプライベートIP）
mysql -h XXX.XXX.XXX.XXX -u handson -pHandson1234! sampledb</code></pre>
<p>接続成功すると <code>MariaDB [sampledb]&gt;</code> が表示されます。</p>
<pre><code class="language-sql">-- DBサーバで作成したデータが見えることを確認
SELECT * FROM users;

EXIT;</code></pre>
<pre><code class="language-bash">exit</code></pre>
<blockquote>
<p><strong>プライベートIPを使う理由</strong>: EC2間の通信は同じVPC内なのでプライベートIPで通信できます。パブリックIPを使うとインターネットを経由してしまい、セキュリティ上も効率上も好ましくありません。</p>
</blockquote>
<p><!-- ![クライアントEC2からのMySQL接続確認](images/client-mysql-connect.jpg) --></p>
<h3><span id="toc30">7-3. SG参照の効果を確認する（任意・スキップ可）</span></h3>
<blockquote>
<p><strong>前提</strong>: ローカルPCに <code>mysql</code> クライアントがインストールされている場合のみ実施します。7-2でクライアントEC2からの接続が成功していれば、このハンズオンの学習目的（SG参照によるEC2間通信制御）は達成済みです。</p>
</blockquote>
<p>ローカルPCに <code>mysql</code> コマンドがある場合、ローカルターミナルで以下を実行します。</p>
<pre><code class="language-cmd">mysql -h （DBサーバのパブリックIP） -u handson -pHandson1234! sampledb</code></pre>
<blockquote>
<p><strong>補足</strong>: 今回のSGにはルール3（自分のIPからのMySQL許可）を追加しているため接続できます。ルール3を削除すると、インターネットからの接続は完全に遮断されます。本番環境では<strong>ルール3を削除</strong>し、クライアントSG参照のみにするのがベストプラクティスです。</p>
</blockquote>
<hr>
<h2><span id="toc31">⑧ リソースの削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ず削除してください。削除する順番が重要です。</strong></p>
<h3><span id="toc32">1. EC2インスタンスを終了する（2台）</span></h3>
<p><strong>EC2 → インスタンス → <code>my-ec2-mysql-db-instance</code> と <code>my-ec2-mysql-client-instance</code> を両方選択 → 「インスタンスの状態」→「インスタンスを終了」</strong></p>
<p>状態が「終了済み」になるまで待ちます（2〜5分）。</p>
<h3><span id="toc33">2. セキュリティグループを削除する（2つ）</span></h3>
<blockquote>
<p><strong>注意</strong>: 先にDBサーバSGを削除します。クライアントSGはDBサーバSGから参照されているため、先にDBサーバSGを削除しないとエラーになります。</p>
</blockquote>
<p><strong>① DBサーバSGを先に削除します:</strong></p>
<p><strong>EC2 → セキュリティグループ → <code>my-ec2-mysql-db-sg</code> を選択 → 「アクション」→「セキュリティグループを削除」</strong></p>
<p><strong>② クライアントSGを削除します:</strong></p>
<p><strong>EC2 → セキュリティグループ → <code>my-ec2-mysql-client-sg</code> を選択 → 「アクション」→「セキュリティグループを削除」</strong></p>
<h3><span id="toc34">3. IAMロールを削除する</span></h3>
<p><strong>IAM → ロール → <code>my-ec2-mysql-role</code> を選択 → 「削除」→ ロール名を入力して確認</strong></p>
<h3><span id="toc35">4. キーペアを削除する（任意）</span></h3>
<p><strong>EC2 → キーペア → <code>my-ec2-mysql-key</code> を選択 → 「アクション」→「削除」</strong></p>
<p>ローカルの <code>.pem</code> ファイルも手動で削除します。</p>
<pre><code class="language-plaintext">C:\Users\ユーザー名\.ssh\my-ec2-mysql-key.pem</code></pre>
<hr>
<h2><span id="toc36">CloudFormation版との比較</span></h2>
<p>コンソール版を体験したら、次は同じ構成をCloudFormation（コード）で再現してみましょう。特にSGの依存関係管理が自動化される点を体験できます。</p>
<table>
<thead>
<tr>
<th>作業</th>
<th>コンソール（手動）</th>
<th>CloudFormation</th>
</tr>
</thead>
<tbody>
<tr>
<td>SG×2台の作成（依存関係あり）</td>
<td>順序を意識して個別に手動作成</td>
<td>template.yaml に定義済み（順序自動管理）</td>
</tr>
<tr>
<td>EC2×2台の起動</td>
<td>2回インスタンス起動操作</td>
<td>コマンド1本（並列作成）</td>
</tr>
<tr>
<td>SG削除（依存関係あり）</td>
<td>DBサーバSG → クライアントSGの順で手動管理</td>
<td><code>delete-stack</code> 1本（自動解決）</td>
</tr>
<tr>
<td>再現性</td>
<td>低い</td>
<td>高い</td>
</tr>
<tr>
<td>バージョン管理</td>
<td>不可</td>
<td>Gitで管理可能</td>
</tr>
</tbody>
</table>
<p><strong>コンソール版で実感できたポイント:</strong></p>
<ul>
<li>SGを削除する際にDBサーバSG → クライアントSGの順番が必要なことを体験できる</li>
<li>SG参照の設定でソースにIPではなくSGを指定する操作の意味が視覚的に理解できる</li>
<li>プライベートIPで通信している様子を直接確認できる</li>
</ul>
<p><strong>CloudFormation版でも試してみる</strong>: <a href="https://caymezon.com/aws-handson-cloudformation-ec2-mysql/">EC2サーバ構築をIaC化：CloudFormationでEC2 MySQLのDBサーバを自動デプロイする手順</a></p>
<hr>
<h2><span id="toc37">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td>クライアントEC2からMySQLに接続できない</td>
<td>DBサーバSGのSG参照ルールが正しく設定されていない</td>
<td>SGのインバウンドルールでMySQL(3306)のソースが <code>my-ec2-mysql-client-sg</code> になっているか確認</td>
</tr>
<tr>
<td>クライアントEC2からMySQLに接続できない</td>
<td>クライアントEC2が <code>my-ec2-mysql-client-sg</code> に属していない</td>
<td>クライアントEC2のセキュリティグループを確認</td>
</tr>
<tr>
<td><code>ERROR 2003: Can&#39;t connect to MySQL server</code></td>
<td>プライベートIPではなくパブリックIPを指定している</td>
<td>DBサーバの<strong>プライベートIPアドレス</strong>を指定する</td>
</tr>
<tr>
<td>MariaDBに接続できない（DBサーバ内）</td>
<td>UserDataのインストールが完了していない</td>
<td><code>sudo cat /var/log/cloud-init-output.log</code> でインストール状況を確認</td>
</tr>
<tr>
<td><code>Access denied for user &#39;handson&#39;</code></td>
<td>パスワードが違うorユーザーが作成されていない</td>
<td>rootでログインして <code>SELECT User,Host FROM mysql.user;</code> で確認</td>
</tr>
<tr>
<td>SGが削除できない（依存関係エラー）</td>
<td>クライアントSGをDBサーバSGより先に削除しようとしている</td>
<td><strong>DBサーバSG（<code>my-ec2-mysql-db-sg</code>）を先に削除</strong>してからクライアントSGを削除する</td>
</tr>
<tr>
<td>EC2インスタンスが「使用中」でSGを削除できない</td>
<td>インスタンスがまだ終了していない</td>
<td>インスタンス「終了済み」になってから再試行</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc38">まとめ</span></h2>
<p>今回のハンズオンで体験できたこと：</p>
<table>
<thead>
<tr>
<th>確認項目</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>SG参照の設定</strong></td>
<td>DBサーバSGのMySQL(3306)ルールのソースにクライアントSGを指定</td>
</tr>
<tr>
<td><strong>MariaDBのセットアップ</strong></td>
<td>UserDataでインストール・起動・ユーザー作成・DB作成を自動化</td>
</tr>
<tr>
<td><strong>EC2間通信の確認</strong></td>
<td>クライアントEC2からプライベートIPを使ってDBサーバに接続</td>
</tr>
<tr>
<td><strong>SG削除の依存関係</strong></td>
<td>DBサーバSG → クライアントSGの順番で削除する必要があることを体験</td>
</tr>
<tr>
<td><strong>2台のリソース管理</strong></td>
<td>EC2とSGをそれぞれ2つ管理する手間を体験（CloudFormationの必要性を実感）</td>
</tr>
</tbody>
</table>
<p>SG参照を手動で設定・確認することで、CloudFormationが裏で何を自動化しているかが理解できます。ぜひ次は <a href="https://caymezon.com/aws-handson-cloudformation-ec2-mysql/">CloudFormation版</a> で同じ構成をコードで再現してみてください。</p>
<hr>
<h2><span id="toc39">関連記事</span></h2>
<p><!-- <a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"> --></p>
<p><!-- <!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWS運用入門 改訂第2版 押さえておきたいAWSの基本と運用ノウハウ [AWS深掘りガイド]","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51AAOubymTL._SL500_.jpg","\/51VMG6YKHdL._SL500_.jpg","\/41EdPB8azAL._SL500_.jpg","\/41v2JFE-9jL._SL500_.jpg","\/41FEEqR-yDL._SL500_.jpg","\/41JfZAdnTPL._SL500_.jpg","\/41vGK0czQrL._SL500_.jpg","\/41-SnYtz2aL._SL500_.jpg","\/41sPrV5fi3L._SL500_.jpg","\/41p7JtvYJ1L._SL500_.jpg","\/4169GVNTs8L._SL500_.jpg","\/41BPI5HP3zL._SL500_.jpg","\/41QOyk60CYL._SL500_.jpg","\/41APjk6FphL._SL500_.jpg","\/41ezKUu7VRL._SL500_.jpg","\/41A1n3K+r5L._SL500_.jpg","\/41aY2T8lEOL._SL500_.jpg","\/419Ca1V6HZL._SL500_.jpg","\/41zQkYyLPzL._SL500_.jpg","\/41YpHcyxiTL._SL500_.jpg","\/41-tKN5mt6L._SL500_.jpg","\/419Mv6m55IL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815631085","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815631085","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"E8MM1","s":"s"});</script></p>
<div id="msmaflink-E8MM1">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --> --></p><p>The post <a href="https://caymezon.com/aws-handson-console-ec2-mysql/">EC2サーバ構築ハンズオン：AWSコンソールでEC2 MySQLのDBサーバを構築する手順【SG参照 / CloudFormation版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-console-ec2-mysql/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>EC2サーバ構築ハンズオン：AWSコンソールでTomcatを構築する手順【EC2 Tomcat / CloudFormation版との比較付き】</title>
		<link>https://caymezon.com/aws-handson-console-ec2-tomcat/</link>
					<comments>https://caymezon.com/aws-handson-console-ec2-tomcat/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Sun, 29 Mar 2026 04:44:53 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[APサーバー]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[AWSコンソール]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[ec2サーバ構築]]></category>
		<category><![CDATA[IAM]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Tomcat]]></category>
		<category><![CDATA[UserData]]></category>
		<category><![CDATA[セキュリティグループ]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[初心者]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20313</guid>

					<description><![CDATA[<p>目次 はじめにキーワード解説Apache（Webサーバー）と Tomcat（APサーバー）の違い使用するAWSサービス構築するリソース全体の作業順序【重要】⓪ 自分のIPアドレスを確認する方法A: ルーター管理画面で確認 [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-console-ec2-tomcat/">EC2サーバ構築ハンズオン：AWSコンソールでTomcatを構築する手順【EC2 Tomcat / CloudFormation版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-6" checked><label class="toc-title" for="toc-checkbox-6">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">キーワード解説</a></li><li><a href="#toc3" tabindex="0">Apache（Webサーバー）と Tomcat（APサーバー）の違い</a></li><li><a href="#toc4" tabindex="0">使用するAWSサービス</a></li><li><a href="#toc5" tabindex="0">構築するリソース</a></li><li><a href="#toc6" tabindex="0">全体の作業順序</a></li><li><a href="#toc7" tabindex="0">【重要】⓪ 自分のIPアドレスを確認する</a><ol><li><a href="#toc8" tabindex="0">方法A: ルーター管理画面で確認（推奨）</a></li><li><a href="#toc9" tabindex="0">方法B: コマンドで確認</a></li></ol></li><li><a href="#toc10" tabindex="0">① キーペアの作成</a><ol><li><a href="#toc11" tabindex="0">ダウンロードしたキーペアを保存する</a></li></ol></li><li><a href="#toc12" tabindex="0">② IAMロールの作成</a><ol><li><a href="#toc13" tabindex="0">ステップ1: エンティティタイプとユースケースの選択</a></li><li><a href="#toc14" tabindex="0">ステップ2: 許可ポリシーのアタッチ</a></li><li><a href="#toc15" tabindex="0">ステップ3: ロール名の設定</a></li></ol></li><li><a href="#toc16" tabindex="0">③ EC2インスタンスの起動</a><ol><li><a href="#toc17" tabindex="0">3-1. 基本設定</a></li><li><a href="#toc18" tabindex="0">3-2. セキュリティグループの設定</a></li><li><a href="#toc19" tabindex="0">3-3. IAMロールの設定</a></li><li><a href="#toc20" tabindex="0">3-4. UserDataの設定（Java + Tomcatの自動インストール）</a></li><li><a href="#toc21" tabindex="0">3-5. インスタンスを起動する</a></li></ol></li><li><a href="#toc22" tabindex="0">④ 動作確認</a><ol><li><a href="#toc23" tabindex="0">ブラウザで確認</a></li><li><a href="#toc24" tabindex="0">SSHで接続して確認</a></li><li><a href="#toc25" tabindex="0">UserDataのインストール状況を確認する方法</a></li><li><a href="#toc26" tabindex="0">【接続できない場合】IPアドレスが異なる可能性</a></li></ol></li><li><a href="#toc27" tabindex="0">⑤ リソースの削除</a><ol><li><a href="#toc28" tabindex="0">1. EC2インスタンスを終了する</a></li><li><a href="#toc29" tabindex="0">2. セキュリティグループを削除する</a></li><li><a href="#toc30" tabindex="0">3. IAMロールを削除する</a></li><li><a href="#toc31" tabindex="0">4. キーペアを削除する（任意）</a></li></ol></li><li><a href="#toc32" tabindex="0">CloudFormation版との比較</a></li><li><a href="#toc33" tabindex="0">トラブルシューティング</a></li><li><a href="#toc34" tabindex="0">まとめ</a></li><li><a href="#toc35" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>「EC2サーバ上でJavaアプリを動かしたい」——ApacheでHTMLを返せるようになったら、次はJavaが実行できるAPサーバー（Tomcat）に挑戦しましょう。</p>
<p>この記事では、<strong>AWSコンソール（GUI）のみ</strong>を使って、Tomcat APサーバーが動作するEC2インスタンスをゼロから手動で構築するハンズオンを紹介します。</p>
<pre><code class="language-plaintext">インターネット
  ↓ TCP 8080（Tomcat HTTP）← ブラウザでアクセス
  ↓ TCP 22（SSH）          ← ターミナルで接続
セキュリティグループ（ファイアウォール）
  ↓ 自分のIPのみ通過させる
EC2インスタンス（t2.micro / Amazon Linux 2023）
  ├── Java 17（Amazon Corretto）← Tomcatの実行基盤
  ├── Tomcat 10.1（APサーバー）← UserDataで自動インストール
  │     └── /opt/tomcat/latest/webapps/ROOT/index.jsp を返す
  └── IAMロール（Session Manager接続用）</code></pre>
<p><strong>このハンズオンで体験できること：</strong></p>
<ul>
<li>EC2サーバーへのJava 17（Amazon Corretto）とTomcat 10のインストール</li>
<li>セキュリティグループによるポートアクセス制御（SSH:22 / Tomcat:8080）</li>
<li>UserDataを使ったJava + Tomcatの初回起動時自動インストール</li>
<li>JSPが実行されていることをブラウザで確認（Apacheの静的HTMLとの違い）</li>
</ul>
<p><strong>このハンズオンの特徴：</strong></p>
<ul>
<li>Apache版（Phase 1-1）の次のステップとして、APサーバーとWebサーバーの違いを体験できる</li>
<li>手動操作を通じて、各リソースの役割と依存関係を視覚的に理解できる</li>
</ul>
<hr>
<blockquote>
<p><strong>この記事は <a href="https://caymezon.com/aws-handson-cloudformation-ec2-tomcat/">CloudFormation版ハンズオン</a> の比較記事です。</strong><br />コンソール操作でEC2 Tomcatサーバー構築の全体像を学び、CloudFormationとの違いを比較したい方向けです。</p>
</blockquote>
<hr>
<p><!-- ![ハンズオン完成後のTomcat動作確認画面](images/ec2-tomcat-top.jpg) --></p>
<p><!-- <a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"> --></p>
<p><!-- <!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWSの基本・仕組み・重要用語が全部わかる教科書 (見るだけ図解)","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51DEDQXj6oL._SL500_.jpg","\/41F589smNwL._SL500_.jpg","\/41R6f9yyCWL._SL500_.jpg","\/41HqWQ9BvmL._SL500_.jpg","\/41p8p0ZU79L._SL500_.jpg","\/41qLC-fndBL._SL500_.jpg","\/41fcLv9VT5L._SL500_.jpg","\/51lRvCsvHqL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815607850","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815607850","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"eaCUB","s":"s"});</script></p>
<div id="msmaflink-eaCUB">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --> --></p>
<h2><span id="toc2">キーワード解説</span></h2>
<table>
<thead>
<tr>
<th>用語</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>EC2（Elastic Compute Cloud）</strong></td>
<td>AWSの仮想サーバーサービス。今回はここにJava + Tomcatをインストールする</td>
</tr>
<tr>
<td><strong>Tomcat</strong></td>
<td>JavaのWebアプリケーション（JSP/Servlet）を実行するAPサーバー。Apacheとは異なりJavaコードを動かすことができる</td>
</tr>
<tr>
<td><strong>Amazon Corretto</strong></td>
<td>AWSが提供するOpenJDKのディストリビューション。無償・本番利用可能なJava実行環境</td>
</tr>
<tr>
<td><strong>JSP（JavaServer Pages）</strong></td>
<td>HTMLにJavaコードを埋め込んで動的なページを生成する技術。Tomcatがサーバー側で実行してHTMLを返す</td>
</tr>
<tr>
<td><strong>セキュリティグループ</strong></td>
<td>EC2への通信を制御するファイアウォール。今回はポート22（SSH）と8080（Tomcat）を開ける</td>
</tr>
<tr>
<td><strong>UserData</strong></td>
<td>EC2の初回起動時のみ自動実行されるシェルスクリプト。今回はJava + Tomcatのインストールに使う</td>
</tr>
<tr>
<td><strong>IAMロール</strong></td>
<td>EC2にAWSサービスを利用する権限を付与する仕組み。今回はSession Manager接続に使う</td>
</tr>
<tr>
<td><strong>キーペア</strong></td>
<td>SSHでEC2に接続するための鍵ペア（公開鍵＋秘密鍵）</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc3">Apache（Webサーバー）と Tomcat（APサーバー）の違い</span></h2>
<table>
<thead>
<tr>
<th>比較項目</th>
<th>Apache（前回）</th>
<th>Tomcat（今回）</th>
</tr>
</thead>
<tbody>
<tr>
<td>種類</td>
<td>Webサーバー</td>
<td>APサーバー（Application Server）</td>
</tr>
<tr>
<td>得意なこと</td>
<td>静的ファイル（HTML/CSS/画像）の配信</td>
<td>Java（JSP/Servlet）の実行</td>
</tr>
<tr>
<td>デフォルトポート</td>
<td>80</td>
<td><strong>8080</strong></td>
</tr>
<tr>
<td>コンテンツの置き場</td>
<td><code>/var/www/html/</code></td>
<td><code>/opt/tomcat/latest/webapps/ROOT/</code></td>
</tr>
<tr>
<td>インストール方法</td>
<td><code>yum install httpd</code>（1コマンド）</td>
<td>Java + Tomcatを手動インストール（複数ステップ）</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc4">使用するAWSサービス</span></h2>
<table>
<thead>
<tr>
<th>サービス</th>
<th>役割</th>
<th>料金</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>EC2</strong></td>
<td>Java + Tomcatが動作するAPサーバー本体（t2.micro）</td>
<td>月750時間まで無料枠あり</td>
</tr>
<tr>
<td><strong>セキュリティグループ</strong></td>
<td>SSH/Tomcatのアクセス制御</td>
<td>無料</td>
</tr>
<tr>
<td><strong>IAM</strong></td>
<td>EC2へのSession Manager接続権限</td>
<td>無料</td>
</tr>
<tr>
<td><strong>EBS</strong></td>
<td>EC2にアタッチされるストレージ（デフォルト8GB）</td>
<td>月30GBまで無料枠あり</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>注意</strong>: 無料枠はAWSアカウント開設から12ヶ月間です。期間終了後はEC2インスタンス稼働時間に課金されます。ハンズオン後は必ずリソースを削除してください。</p>
</blockquote>
<hr>
<h2><span id="toc5">構築するリソース</span></h2>
<table>
<thead>
<tr>
<th>リソース</th>
<th>役割</th>
</tr>
</thead>
<tbody>
<tr>
<td>キーペア</td>
<td>SSHでEC2に接続するための認証鍵</td>
</tr>
<tr>
<td>IAMロール</td>
<td>EC2にSession Manager接続の権限を付与</td>
</tr>
<tr>
<td>セキュリティグループ</td>
<td>SSH(22)・Tomcat(8080)のアクセス制御</td>
</tr>
<tr>
<td>EC2インスタンス</td>
<td>Java + Tomcatが動作するAPサーバー本体</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc6">全体の作業順序</span></h2>
<p>依存関係があるため、必ずこの順番で作成します。</p>
<pre><code class="language-plaintext">⓪ 自分のIPアドレスを確認する（重要）
      ↓
① キーペアを作成する
      ↓
② IAMロールを作成する
      ↓
③ EC2インスタンスを起動する
  （セキュリティグループ・UserDataも同時に設定）
      ↓
④ 動作確認（ブラウザ・SSH）
      ↓
⑤ リソースを削除する</code></pre>
<hr>
<h2><span id="toc7">【重要】⓪ 自分のIPアドレスを確認する</span></h2>
<p>セキュリティグループで自分のIPだけを許可するために、<strong>正確なIPアドレス</strong>を事前に確認します。</p>
<blockquote>
<p><strong>注意</strong>: <code>curl https://checkip.amazonaws.com</code> で表示されるIPと、EC2への実際の接続元IPが<strong>一致しない場合</strong>があります（ISPやプロキシの経路の違いによる）。最も確実な方法はルーター管理画面での確認です。</p>
</blockquote>
<h3><span id="toc8">方法A: ルーター管理画面で確認（推奨）</span></h3>
<ol>
<li>ブラウザで以下のURLにアクセスします（ルーターによって異なります）
<pre><code class="language-plaintext">http://192.168.0.1  または  http://192.168.1.1</code></pre>
</li>
<li>「ネットワークマップ」または「インターネット」項目を開く</li>
<li>**「インターネットIPアドレス」または「WAN IPアドレス」**の値を控えます</li>
</ol>
<h3><span id="toc9">方法B: コマンドで確認</span></h3>
<pre><code class="language-cmd">curl https://checkip.amazonaws.com</code></pre>
<p><strong>控えておく情報</strong>: 自分のIPアドレス（例: <code>203.0.113.1</code>）</p>
<hr>
<h2><span id="toc10">① キーペアの作成</span></h2>
<p>キーペアはSSHでEC2に接続するための鍵です。EC2起動時に指定する必要があるため、最初に作成します。</p>
<p><strong>AWSコンソール → EC2 → ネットワーク＆セキュリティ → キーペア → 「キーペアを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-ec2-tomcat-key</code></td>
</tr>
<tr>
<td>キーペアのタイプ</td>
<td><strong>RSA</strong></td>
</tr>
<tr>
<td>プライベートキーファイル形式</td>
<td><strong>.pem</strong></td>
</tr>
</tbody>
</table>
<p>「キーペアを作成」をクリックすると、自動的に <code>my-ec2-tomcat-key.pem</code> がダウンロードされます。</p>
<h3><span id="toc11">ダウンロードしたキーペアを保存する</span></h3>
<p>ダウンロードされた <code>my-ec2-tomcat-key.pem</code> を以下の場所に移動します。</p>
<pre><code class="language-plaintext">C:\Users\ユーザー名\.ssh\my-ec2-tomcat-key.pem</code></pre>
<blockquote>
<p><strong>注意</strong>: <code>.pem</code> ファイルは<strong>再ダウンロードできません</strong>。紛失した場合は新しいキーペアを作成する必要があります。</p>
</blockquote>
<blockquote>
<p><strong>前回のキーペアの流用について</strong>: EC2 + Apacheハンズオンで作成した <code>my-ec2-apache-key</code> を流用しても動作します。その場合この手順はスキップします。</p>
</blockquote>
<p><!-- ![キーペア作成画面](images/keypair-create.jpg) --></p>
<hr>
<h2><span id="toc12">② IAMロールの作成</span></h2>
<p>Session Manager（ブラウザからEC2に接続できるAWS機能）を使えるようにするためのIAMロールを作成します。</p>
<blockquote>
<p><strong>なぜIAMロールが必要か</strong>: EC2がAWSのサービス（Session Manager）を利用するには、そのEC2自身に「このサービスを使う権限」を付与する必要があります。この権限の設定がIAMロールです。</p>
</blockquote>
<p><strong>AWSコンソール → IAM → ロール → 「ロールを作成」</strong></p>
<h3><span id="toc13">ステップ1: エンティティタイプとユースケースの選択</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>信頼されたエンティティタイプ</td>
<td><strong>AWSのサービス</strong></td>
</tr>
<tr>
<td>ユースケース</td>
<td><strong>EC2</strong></td>
</tr>
</tbody>
</table>
<p>「次へ」をクリック。</p>
<h3><span id="toc14">ステップ2: 許可ポリシーのアタッチ</span></h3>
<p>検索ボックスに <code>AmazonSSMManagedInstanceCore</code> と入力してチェックを入れます。</p>
<p>「次へ」をクリック。</p>
<h3><span id="toc15">ステップ3: ロール名の設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>ロール名</td>
<td><code>my-ec2-tomcat-role</code></td>
</tr>
</tbody>
</table>
<p>「ロールを作成」をクリック。</p>
<p><!-- ![IAMロール作成画面](images/iam-role-create.jpg) --></p>
<hr>
<h2><span id="toc16">③ EC2インスタンスの起動</span></h2>
<p>キーペアとIAMロールを作成したあと、EC2インスタンスを起動します。<br />セキュリティグループとUserData（Java + Tomcat自動インストール）も同時に設定します。</p>
<p><strong>AWSコンソール → EC2 → インスタンス → 「インスタンスを起動」</strong></p>
<h3><span id="toc17">3-1. 基本設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-ec2-tomcat-instance</code></td>
</tr>
<tr>
<td>アプリケーションおよびOSイメージ</td>
<td><strong>Amazon Linux 2023 AMI</strong>（デフォルトで選択済み）</td>
</tr>
<tr>
<td>インスタンスタイプ</td>
<td><strong>t2.micro</strong>（無料枠対象）</td>
</tr>
<tr>
<td>キーペア</td>
<td><code>my-ec2-tomcat-key</code></td>
</tr>
</tbody>
</table>
<p><!-- ![EC2インスタンス起動画面 - 基本設定](images/ec2-launch-basic.jpg) --></p>
<h3><span id="toc18">3-2. セキュリティグループの設定</span></h3>
<p>「ネットワーク設定」→「セキュリティグループを作成する」を選択します。</p>
<p><strong>セキュリティグループ名と説明を設定:</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>セキュリティグループ名</td>
<td><code>my-ec2-tomcat-sg</code></td>
</tr>
<tr>
<td>説明</td>
<td><code>EC2 Tomcat hands-on SG</code></td>
</tr>
</tbody>
</table>
<p><strong>「インバウンドセキュリティグループのルールを追加」ボタンで以下の2ルールを追加します。</strong></p>
<p><strong>ルール1: SSH接続の許可</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>タイプ</td>
<td>SSH</td>
</tr>
<tr>
<td>ソースタイプ</td>
<td>カスタム</td>
</tr>
<tr>
<td>ソース</td>
<td><code>203.0.113.1/32</code>（⓪で確認した自分のIP + /32）</td>
</tr>
</tbody>
</table>
<p><strong>ルール2: Tomcat HTTPアクセスの許可</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>タイプ</td>
<td>カスタム TCP</td>
</tr>
<tr>
<td>ポート範囲</td>
<td><code>8080</code></td>
</tr>
<tr>
<td>ソースタイプ</td>
<td>カスタム</td>
</tr>
<tr>
<td>ソース</td>
<td><code>203.0.113.1/32</code>（⓪で確認した自分のIP + /32）</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>ポート8080について</strong>: TomcatはデフォルトでHTTP <strong>8080番ポート</strong>をListenします。Apacheの80番とは異なるため、セキュリティグループでも8080を明示的に開ける必要があります。</p>
</blockquote>
<blockquote>
<p><strong>/32 とは</strong>: 「このIPアドレス1つだけ」という意味のCIDR表記です。<code>0.0.0.0/0</code> は全世界に開放することになりセキュリティリスクが高いため、必ず自分のIPのみに制限します。</p>
</blockquote>
<p><!-- ![セキュリティグループ設定画面](images/security-group-create.jpg) --></p>
<h3><span id="toc19">3-3. IAMロールの設定</span></h3>
<p>「高度な詳細」を開く → 「IAM インスタンスプロファイル」→ <code>my-ec2-tomcat-role</code> を選択します。</p>
<h3><span id="toc20">3-4. UserDataの設定（Java + Tomcatの自動インストール）</span></h3>
<p>「高度な詳細」の一番下にある「ユーザーデータ」に以下を貼り付けます。</p>
<pre><code class="language-bash">#!/bin/bash
dnf update -y
dnf install -y java-17-amazon-corretto

useradd -m -d /opt/tomcat -U -s /bin/false tomcat

TOMCAT_VERSION="10.1.25"
cd /tmp
wget -q "https://archive.apache.org/dist/tomcat/tomcat-10/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz" \
  -O apache-tomcat.tar.gz
tar xzf apache-tomcat.tar.gz
mv "apache-tomcat-${TOMCAT_VERSION}" /opt/tomcat/latest
chown -R tomcat:tomcat /opt/tomcat
chmod -R u+x /opt/tomcat/latest/bin

cat &gt; /etc/systemd/system/tomcat.service &lt;&lt; 'SVCEOF'
[Unit]
Description=Apache Tomcat Web Application Container
After=network.target

[Service]
Type=forking
User=tomcat
Group=tomcat
Environment="JAVA_HOME=/usr/lib/jvm/java-17-amazon-corretto"
Environment="CATALINA_HOME=/opt/tomcat/latest"
Environment="CATALINA_BASE=/opt/tomcat/latest"
Environment="CATALINA_PID=/opt/tomcat/latest/temp/tomcat.pid"
Environment="JAVA_OPTS=-Xms256m -Xmx512m"
ExecStart=/opt/tomcat/latest/bin/startup.sh
ExecStop=/opt/tomcat/latest/bin/shutdown.sh
Restart=on-failure

[Install]
WantedBy=multi-user.target
SVCEOF

systemctl daemon-reload
systemctl enable tomcat
systemctl start tomcat

cat &gt; /opt/tomcat/latest/webapps/ROOT/index.jsp &lt;&lt; 'JSPEOF'
&lt;%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;&lt;meta charset="UTF-8"&gt;&lt;title&gt;Tomcat on EC2&lt;/title&gt;&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;Hello from Tomcat on Amazon Linux 2023!&lt;/h1&gt;
&lt;p&gt;Java Version: &lt;%= System.getProperty("java.version") %&gt;&lt;/p&gt;
&lt;p&gt;Tomcat Version: &lt;%= application.getServerInfo() %&gt;&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
JSPEOF
chown tomcat:tomcat /opt/tomcat/latest/webapps/ROOT/index.jsp</code></pre>
<p><strong>各コマンドの説明:</strong></p>
<table>
<thead>
<tr>
<th>コマンド</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>dnf update -y</code></td>
<td>OSのパッケージを最新化する（Amazon Linux 2023はdnfを使用）</td>
</tr>
<tr>
<td><code>dnf install -y java-17-amazon-corretto</code></td>
<td>AWSが提供するJava 17ディストリビューションをインストール</td>
</tr>
<tr>
<td><code>useradd -m -d /opt/tomcat -U -s /bin/false tomcat</code></td>
<td>Tomcat専用システムユーザーを作成（ログイン不可・セキュリティ対策）</td>
</tr>
<tr>
<td><code>wget -q ... -O apache-tomcat.tar.gz</code></td>
<td>Apache公式アーカイブからTomcatをダウンロード</td>
</tr>
<tr>
<td><code>tar xzf apache-tomcat.tar.gz</code></td>
<td>ダウンロードしたtar.gzを展開</td>
</tr>
<tr>
<td><code>mv ... /opt/tomcat/latest</code></td>
<td>Tomcatを <code>/opt/tomcat/latest/</code> に配置</td>
</tr>
<tr>
<td><code>chown -R tomcat:tomcat /opt/tomcat</code></td>
<td>Tomcatディレクトリの所有者をtomcatユーザーに変更</td>
</tr>
<tr>
<td><code>chmod -R u+x /opt/tomcat/latest/bin</code></td>
<td>binディレクトリのスクリプトに実行権限を付与</td>
</tr>
<tr>
<td><code>cat &gt; /etc/systemd/system/tomcat.service</code></td>
<td>TomcatをLinuxサービスとして登録するファイルを作成</td>
</tr>
<tr>
<td><code>systemctl daemon-reload</code></td>
<td>systemdにサービス定義ファイルの変更を反映</td>
</tr>
<tr>
<td><code>systemctl enable tomcat</code></td>
<td>OS起動時にTomcatが自動起動するよう設定</td>
</tr>
<tr>
<td><code>systemctl start tomcat</code></td>
<td>Tomcatを起動</td>
</tr>
<tr>
<td><code>cat &gt; .../index.jsp</code></td>
<td>テスト用JSPページを作成（Javaコード入り）</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>Amazon Corretto（コレット）とは</strong>: AWSが提供するOpenJDKのディストリビューション。無償・本番利用可能で、Amazon Linux 2023のパッケージリポジトリから直接インストールできます。</p>
</blockquote>
<blockquote>
<p><strong>JAVA_OPTS=-Xms256m -Xmx512m</strong>: Javaの使用メモリを制限する設定です。t2.microは1GBのメモリしかないため、最小256MB・最大512MBに制限して他のプロセスと共存できるようにしています。</p>
</blockquote>
<blockquote>
<p><strong>UserDataはインスタンスの初回起動時のみ実行されます</strong>。Tomcatのダウンロードを含むため、完了まで<strong>約5〜10分</strong>かかります。</p>
</blockquote>
<h3><span id="toc21">3-5. インスタンスを起動する</span></h3>
<p>「インスタンスを起動」ボタンをクリック。</p>
<p>起動完了まで約2〜3分待ちます。インスタンスの「状態」が「実行中」になったことを確認します。</p>
<p><strong>控えておく情報: インスタンスのパブリックIPアドレス</strong></p>
<p>インスタンス一覧 → 作成したインスタンスをクリック → 「パブリック IPv4 アドレス」を確認してメモします。</p>
<p><!-- ![EC2インスタンス起動後の画面](images/ec2-running.jpg) --></p>
<hr>
<h2><span id="toc22">④ 動作確認</span></h2>
<blockquote>
<p><strong>重要</strong>: UserDataでのJava + Tomcatインストールが完了するまで<strong>約5〜10分</strong>かかります。インスタンスが「実行中」になってもすぐには接続できません。</p>
</blockquote>
<h3><span id="toc23">ブラウザで確認</span></h3>
<p>ブラウザで以下のURLにアクセスします。ポート番号 <strong>8080</strong> を忘れずに入力してください。</p>
<pre><code class="language-plaintext">http://（パブリックIPアドレス）:8080</code></pre>
<p>以下のように表示されれば成功です。</p>
<pre><code class="language-plaintext">Hello from Tomcat on Amazon Linux 2023!
Java Version: 17.x.x
Tomcat Version: Apache Tomcat/10.1.25</code></pre>
<blockquote>
<p><strong>JSPが実行されている証拠</strong>: <code>Java Version</code> や <code>Tomcat Version</code> はJavaコード（<code>&lt;%= ... %&gt;</code>）がサーバー側で実行されて表示されています。ApacheのHTMLと違い、TomcatがJavaを動かして動的にページを生成しています。</p>
</blockquote>
<blockquote>
<p><strong>表示されない場合</strong>: UserDataのインストールが完了していない可能性があります。5〜10分待ってからリロードしてください。それでも表示されない場合はSSHで接続してログを確認します。</p>
</blockquote>
<p><!-- ![ブラウザでのTomcat動作確認](images/tomcat-web-browser.jpg) --></p>
<h3><span id="toc24">SSHで接続して確認</span></h3>
<p>ローカルPCのターミナル（VSCode CMD）で実行します。</p>
<pre><code class="language-cmd">ssh -i C:\Users\ユーザー名\.ssh\my-ec2-tomcat-key.pem ec2-user@（パブリックIPアドレス）</code></pre>
<p>初回接続時に以下の確認が出ます。<code>yes</code> を入力します。</p>
<pre><code class="language-plaintext">Are you sure you want to continue connecting (yes/no)? yes</code></pre>
<p>接続できたら以下を実行します。</p>
<pre><code class="language-bash">java -version

# Tomcatサービスの動作状態を確認（active (running) と表示されれば正常）
sudo systemctl status tomcat

# TomcatのメインログでERRORがないか確認
sudo tail -50 /opt/tomcat/latest/logs/catalina.out

# Tomcatが8080番ポートをListenしているか確認
sudo ss -tlnp | grep :8080

# EC2から切断
exit</code></pre>
<p><strong>Tomcatのディレクトリ構成:</strong></p>
<table>
<thead>
<tr>
<th>パス</th>
<th>役割</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>/opt/tomcat/latest/webapps/ROOT/</code></td>
<td>デフォルトWebアプリのルート（JSP/HTMLを置く場所）</td>
</tr>
<tr>
<td><code>/opt/tomcat/latest/conf/server.xml</code></td>
<td>Tomcatの設定ファイル（ポート番号などを管理）</td>
</tr>
<tr>
<td><code>/opt/tomcat/latest/logs/catalina.out</code></td>
<td>Tomcatのメインログ（エラー確認に使う）</td>
</tr>
<tr>
<td><code>/opt/tomcat/latest/bin/startup.sh</code></td>
<td>Tomcat起動スクリプト</td>
</tr>
<tr>
<td><code>/opt/tomcat/latest/bin/shutdown.sh</code></td>
<td>Tomcat停止スクリプト</td>
</tr>
</tbody>
</table>
<h3><span id="toc25">UserDataのインストール状況を確認する方法</span></h3>
<p>インスタンスにSSHで接続できた場合、UserDataの実行ログで進捗を確認できます。</p>
<pre><code class="language-bash"># UserDataのログを確認（インストールの進捗・エラーを確認できる）
sudo cat /var/log/cloud-init-output.log</code></pre>
<p><!-- ![SSH接続後のTomcat動作確認](images/ssh-tomcat-status.jpg) --></p>
<h3><span id="toc26">【接続できない場合】IPアドレスが異なる可能性</span></h3>
<p><code>curl</code> で確認したIPを設定したが接続できない場合、実際の接続元IPが異なる可能性があります。</p>
<p><strong>一時的に全開放して真のIPを確認する方法:</strong></p>
<p>コンソール → EC2 → セキュリティグループ → <code>my-ec2-tomcat-sg</code> → 「インバウンドルールを編集」</p>
<p>SSHのルールを一時的に <code>0.0.0.0/0</code> に変更してSSH接続し、以下を実行します。</p>
<pre><code class="language-bash">echo $SSH_CLIENT
# 出力例: 203.0.113.1 17508 22
# 先頭の値が真の接続元IP</code></pre>
<p>このIPをメモしてSSH接続を切断し、セキュリティグループのSSHルールを <code>真のIP/32</code> に戻します。</p>
<hr>
<h2><span id="toc27">⑤ リソースの削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ず削除してください。削除する順番が重要です。</strong></p>
<h3><span id="toc28">1. EC2インスタンスを終了する</span></h3>
<p><strong>EC2 → インスタンス → <code>my-ec2-tomcat-instance</code> を選択 → 「インスタンスの状態」→「インスタンスを終了」</strong></p>
<p>確認ダイアログで「終了」をクリック。状態が「終了済み」になるまで待ちます（2〜5分）。</p>
<blockquote>
<p><strong>「停止」と「終了」の違い</strong>: 「停止」は一時停止（EBSストレージ課金は続く）。「終了」は完全削除（課金停止）。学習後は「終了」を選びます。</p>
</blockquote>
<h3><span id="toc29">2. セキュリティグループを削除する</span></h3>
<p><strong>EC2 → セキュリティグループ → <code>my-ec2-tomcat-sg</code> を選択 → 「アクション」→「セキュリティグループを削除」</strong></p>
<blockquote>
<p>インスタンス終了が完了している必要があります。「使用中」エラーが出る場合はインスタンスが「終了済み」状態になるまで待ってください。</p>
</blockquote>
<h3><span id="toc30">3. IAMロールを削除する</span></h3>
<p><strong>IAM → ロール → <code>my-ec2-tomcat-role</code> を選択 → 「削除」→ ロール名を入力して確認</strong></p>
<h3><span id="toc31">4. キーペアを削除する（任意）</span></h3>
<p>他のEC2でも使い回す場合は残してよいです。不要な場合は削除します。</p>
<p><strong>EC2 → キーペア → <code>my-ec2-tomcat-key</code> を選択 → 「アクション」→「削除」→ 確認テキストを入力</strong></p>
<p>ローカルの <code>.pem</code> ファイルも手動で削除します。</p>
<pre><code class="language-plaintext">C:\Users\ユーザー名\.ssh\my-ec2-tomcat-key.pem</code></pre>
<hr>
<h2><span id="toc32">CloudFormation版との比較</span></h2>
<p>コンソール版を体験したら、次は同じ構成をCloudFormation（コード）で再現してみましょう。何が自動化されるのかがよくわかります。</p>
<table>
<thead>
<tr>
<th>作業</th>
<th>コンソール（手動）</th>
<th>CloudFormation</th>
</tr>
</thead>
<tbody>
<tr>
<td>IAMロール作成</td>
<td>画面でポチポチ（5クリック以上）</td>
<td>template.yaml に定義済み</td>
</tr>
<tr>
<td>セキュリティグループ作成</td>
<td>画面でポチポチ</td>
<td>template.yaml に定義済み</td>
</tr>
<tr>
<td>EC2起動（UserData含む）</td>
<td>画面でポチポチ</td>
<td>template.yaml に定義済み</td>
</tr>
<tr>
<td>デプロイ全体</td>
<td>複数画面を行き来（20〜30分）</td>
<td>コマンド1本（5〜10分）</td>
</tr>
<tr>
<td>削除</td>
<td>リソースを個別に依存関係順で手動削除</td>
<td><code>delete-stack</code> 1本</td>
</tr>
<tr>
<td>再現性</td>
<td>低い（手動ミスのリスクがある）</td>
<td>高い（同じ環境を何度でも再現可能）</td>
</tr>
<tr>
<td>バージョン管理</td>
<td>不可</td>
<td>Gitで管理可能</td>
</tr>
</tbody>
</table>
<p><strong>コンソール版で実感できたポイント:</strong></p>
<ul>
<li>Java + Tomcatのインストール手順が長く、手動では設定ミスが起きやすいことを実感できる</li>
<li>ポート8080の開放やTomcatユーザーの作成など、セキュリティ設定の重要性が身につく</li>
<li>UserDataの完了を待つ間に、コンソール版とCloudFormation版の差が体感できる</li>
</ul>
<p><strong>CloudFormation版でも試してみる</strong>: <a href="https://caymezon.com/aws-handson-cloudformation-ec2-tomcat/">EC2サーバ構築をIaC化：CloudFormationでEC2 Tomcatを自動デプロイする手順</a></p>
<hr>
<h2><span id="toc33">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td>ブラウザで何も表示されない（起動後10分以内）</td>
<td>UserDataのインストールが完了していない</td>
<td><code>sudo cat /var/log/cloud-init-output.log</code> でインストール状況を確認</td>
</tr>
<tr>
<td>ブラウザで何も表示されない（10分以上経過）</td>
<td>Tomcatが起動に失敗している</td>
<td><code>sudo systemctl status tomcat</code> と <code>sudo tail -100 /opt/tomcat/latest/logs/catalina.out</code> を確認</td>
</tr>
<tr>
<td>ブラウザでTomcatのデフォルトページが表示される</td>
<td>JSPの配置タイミングがTomcat起動より遅れた</td>
<td><code>sudo systemctl restart tomcat</code> でTomcatを再起動する</td>
</tr>
<tr>
<td>SSH接続タイムアウト</td>
<td>セキュリティグループのIP設定誤り</td>
<td>セキュリティグループのSSH(22)ルールのIPを確認</td>
</tr>
<tr>
<td>ブラウザにアクセスできない（8080）</td>
<td>セキュリティグループのポート8080が開いていない</td>
<td>セキュリティグループのインバウンドルールで8080が追加されているか確認</td>
</tr>
<tr>
<td><code>java: command not found</code></td>
<td>Javaのインストールが失敗している</td>
<td><code>sudo dnf install -y java-17-amazon-corretto</code> を手動実行</td>
</tr>
<tr>
<td>Tomcatは起動しているがJSPが動かない</td>
<td>index.jspの所有者がtomcatユーザーになっていない</td>
<td><code>sudo chown tomcat:tomcat /opt/tomcat/latest/webapps/ROOT/index.jsp</code> を実行</td>
</tr>
<tr>
<td>セキュリティグループが削除できない</td>
<td>EC2インスタンスがまだ使用中</td>
<td>インスタンス「終了済み」状態になってから再試行</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc34">まとめ</span></h2>
<p>今回のハンズオンで体験できたこと：</p>
<table>
<thead>
<tr>
<th>確認項目</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>キーペア作成</strong></td>
<td>SSH接続に必要な鍵ペアをコンソールで作成し、.pemファイルをローカルに保存</td>
</tr>
<tr>
<td><strong>IAMロール作成</strong></td>
<td>AmazonSSMManagedInstanceCoreポリシーをEC2にアタッチして接続権限を付与</td>
</tr>
<tr>
<td><strong>セキュリティグループ</strong></td>
<td>SSH(22)/Tomcat(8080)を自分のIPのみに制限してEC2を保護</td>
</tr>
<tr>
<td><strong>UserDataによる自動化</strong></td>
<td>Java 17 + Tomcat 10のインストールと起動を初回起動時のスクリプトで自動化</td>
</tr>
<tr>
<td><strong>APサーバー確認</strong></td>
<td>ブラウザとSSHの両方でTomcat動作・JSP実行を確認</td>
</tr>
<tr>
<td><strong>リソース削除</strong></td>
<td>依存関係順に4つのリソースを手動で削除</td>
</tr>
</tbody>
</table>
<p>手動操作でひとつひとつ作ると、CloudFormationが裏で何を自動化しているかが理解できます。ぜひ次は <a href="https://caymezon.com/aws-handson-cloudformation-ec2-tomcat/">CloudFormation版</a> で同じ構成をコードで再現してみてください。</p>
<hr>
<h2><span id="toc35">関連記事</span></h2>
<p><!-- <a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"> --></p>
<p><!-- <!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWS運用入門 改訂第2版 押さえておきたいAWSの基本と運用ノウハウ [AWS深掘りガイド]","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51AAOubymTL._SL500_.jpg","\/51VMG6YKHdL._SL500_.jpg","\/41EdPB8azAL._SL500_.jpg","\/41v2JFE-9jL._SL500_.jpg","\/41FEEqR-yDL._SL500_.jpg","\/41JfZAdnTPL._SL500_.jpg","\/41vGK0czQrL._SL500_.jpg","\/41-SnYtz2aL._SL500_.jpg","\/41sPrV5fi3L._SL500_.jpg","\/41p7JtvYJ1L._SL500_.jpg","\/4169GVNTs8L._SL500_.jpg","\/41BPI5HP3zL._SL500_.jpg","\/41QOyk60CYL._SL500_.jpg","\/41APjk6FphL._SL500_.jpg","\/41ezKUu7VRL._SL500_.jpg","\/41A1n3K+r5L._SL500_.jpg","\/41aY2T8lEOL._SL500_.jpg","\/419Ca1V6HZL._SL500_.jpg","\/41zQkYyLPzL._SL500_.jpg","\/41YpHcyxiTL._SL500_.jpg","\/41-tKN5mt6L._SL500_.jpg","\/419Mv6m55IL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815631085","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815631085","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"E8MM1","s":"s"});</script></p>
<div id="msmaflink-E8MM1">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --> --></p><p>The post <a href="https://caymezon.com/aws-handson-console-ec2-tomcat/">EC2サーバ構築ハンズオン：AWSコンソールでTomcatを構築する手順【EC2 Tomcat / CloudFormation版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-console-ec2-tomcat/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>AWSコンソールでEC2 + Apacheウェブサーバーを構築する手順【EC2ハンズオン / CloudFormation版との比較付き】</title>
		<link>https://caymezon.com/aws-handson-console-ec2-apache/</link>
					<comments>https://caymezon.com/aws-handson-console-ec2-apache/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Mon, 23 Mar 2026 08:38:56 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[AWSコンソール]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[IAM]]></category>
		<category><![CDATA[UserData]]></category>
		<category><![CDATA[Webサーバー]]></category>
		<category><![CDATA[セキュリティグループ]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[初心者]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20289</guid>

					<description><![CDATA[<p>目次 はじめにキーワード解説使用するAWSサービス構築するリソース全体の作業順序【重要】⓪ 自分のIPアドレスを確認する方法A: ルーター管理画面で確認（推奨）方法B: コマンドで確認① キーペアの作成ダウンロードしたキ [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-console-ec2-apache/">AWSコンソールでEC2 + Apacheウェブサーバーを構築する手順【EC2ハンズオン / CloudFormation版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-8" checked><label class="toc-title" for="toc-checkbox-8">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">キーワード解説</a></li><li><a href="#toc3" tabindex="0">使用するAWSサービス</a></li><li><a href="#toc4" tabindex="0">構築するリソース</a></li><li><a href="#toc5" tabindex="0">全体の作業順序</a></li><li><a href="#toc6" tabindex="0">【重要】⓪ 自分のIPアドレスを確認する</a><ol><li><a href="#toc7" tabindex="0">方法A: ルーター管理画面で確認（推奨）</a></li><li><a href="#toc8" tabindex="0">方法B: コマンドで確認</a></li></ol></li><li><a href="#toc9" tabindex="0">① キーペアの作成</a><ol><li><a href="#toc10" tabindex="0">ダウンロードしたキーペアを保存する</a></li></ol></li><li><a href="#toc11" tabindex="0">② IAMロールの作成</a><ol><li><a href="#toc12" tabindex="0">ステップ1: エンティティタイプとユースケースの選択</a></li><li><a href="#toc13" tabindex="0">ステップ2: 許可ポリシーのアタッチ</a></li><li><a href="#toc14" tabindex="0">ステップ3: ロール名の設定</a></li></ol></li><li><a href="#toc15" tabindex="0">③ EC2インスタンスの起動</a><ol><li><a href="#toc16" tabindex="0">3-1. 基本設定</a></li><li><a href="#toc17" tabindex="0">3-2. セキュリティグループの設定</a></li><li><a href="#toc18" tabindex="0">3-3. IAMロールの設定</a></li><li><a href="#toc19" tabindex="0">3-4. UserDataの設定（Apacheの自動インストール）</a></li><li><a href="#toc20" tabindex="0">3-5. インスタンスを起動する</a></li></ol></li><li><a href="#toc21" tabindex="0">④ 動作確認</a><ol><li><a href="#toc22" tabindex="0">Webブラウザで確認</a></li><li><a href="#toc23" tabindex="0">SSHで接続して確認</a></li><li><a href="#toc24" tabindex="0">【接続できない場合】IPアドレスが異なる可能性</a></li></ol></li><li><a href="#toc25" tabindex="0">⑤ リソースの削除</a><ol><li><a href="#toc26" tabindex="0">1. EC2インスタンスを終了する</a></li><li><a href="#toc27" tabindex="0">2. セキュリティグループを削除する</a></li><li><a href="#toc28" tabindex="0">3. IAMロールを削除する</a></li><li><a href="#toc29" tabindex="0">4. キーペアを削除する（任意）</a></li></ol></li><li><a href="#toc30" tabindex="0">CloudFormation版との比較</a></li><li><a href="#toc31" tabindex="0">トラブルシューティング</a></li><li><a href="#toc32" tabindex="0">まとめ</a></li><li><a href="#toc33" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>「EC2インスタンスを立ち上げてWebサーバーを動かしたい」——AWSを学ぶうえで避けて通れない基本中の基本です。</p>
<p>この記事では、<strong>AWSコンソール（GUI）のみ</strong>を使って、Apacheウェブサーバーが動作するEC2インスタンスをゼロから手動で構築するハンズオンを紹介します。</p>
<pre><code class="language-plaintext">インターネット
  ↓ HTTP（ポート80）    ← ブラウザでアクセス
  ↓ SSH（ポート22）     ← ターミナルで接続
セキュリティグループ（ファイアウォール）
  ↓ 自分のIPのみ通過させる
EC2インスタンス（t2.micro / Amazon Linux 2023）
  ├── Apache httpd（UserDataで自動インストール）
  │     └── /var/www/html/index.html を返す
  └── IAMロール（Session Manager接続用）</code></pre>
<p><strong>このハンズオンで体験できること：</strong></p>
<ul>
<li>EC2インスタンスの基本操作（起動・設定・終了）</li>
<li>セキュリティグループによるポートアクセス制御（SSH:22 / HTTP:80）</li>
<li>UserData を使った初回起動時の Apache 自動インストール</li>
<li>IAMロールによる EC2 への権限付与の仕組み</li>
</ul>
<p><strong>このハンズオンの特徴：</strong></p>
<ul>
<li>キーペア・IAMロール・セキュリティグループ・EC2インスタンスを画面操作で1つずつ作成する</li>
<li>手動操作を通じて、各リソースの役割と依存関係を視覚的に理解できる</li>
</ul>
<hr>
<blockquote>
<p><strong>この記事は <a href="https://caymezon.com/aws-handson-cloudformation-ec2-apache/">CloudFormation版ハンズオン</a> の比較記事です。</strong><br />コンソール操作でEC2・Apache・セキュリティグループの連携を視覚的に学び、CloudFormationと何が違うのかを比較したい方向けです。</p>
</blockquote>
<hr>
<p><!-- ![ハンズオン完成後のWebページ表示](images/ec2-apache-top.jpg) --></p>
<p><!-- <a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"> --></p>
<p><!-- <!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWSの基本・仕組み・重要用語が全部わかる教科書 (見るだけ図解)","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51DEDQXj6oL._SL500_.jpg","\/41F589smNwL._SL500_.jpg","\/41R6f9yyCWL._SL500_.jpg","\/41HqWQ9BvmL._SL500_.jpg","\/41p8p0ZU79L._SL500_.jpg","\/41qLC-fndBL._SL500_.jpg","\/41fcLv9VT5L._SL500_.jpg","\/51lRvCsvHqL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815607850","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815607850","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"eaCUB","s":"s"});</script></p>
<div id="msmaflink-eaCUB">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --> --></p>
<h2><span id="toc2">キーワード解説</span></h2>
<table>
<thead>
<tr>
<th>用語</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>EC2（Elastic Compute Cloud）</strong></td>
<td>AWSの仮想サーバーサービス。今回はここにApacheをインストールする</td>
</tr>
<tr>
<td><strong>Apache（httpd）</strong></td>
<td>世界で最も広く使われているWebサーバーソフト。ブラウザからのHTTPリクエストを受け取りHTMLを返す</td>
</tr>
<tr>
<td><strong>セキュリティグループ</strong></td>
<td>EC2への通信を制御するファイアウォール。ポートごとにアクセス元IPを制限できる</td>
</tr>
<tr>
<td><strong>UserData</strong></td>
<td>EC2の初回起動時のみ自動実行されるシェルスクリプト。今回はApacheのインストールに使う</td>
</tr>
<tr>
<td><strong>IAMロール</strong></td>
<td>EC2にAWSサービスを利用する権限を付与する仕組み。今回はSession Manager接続に使う</td>
</tr>
<tr>
<td><strong>キーペア</strong></td>
<td>SSHでEC2に接続するための鍵ペア（公開鍵＋秘密鍵）</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc3">使用するAWSサービス</span></h2>
<table>
<thead>
<tr>
<th>サービス</th>
<th>役割</th>
<th>料金</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>EC2</strong></td>
<td>Apacheが動作するWebサーバー本体（t2.micro）</td>
<td>月750時間まで無料枠あり</td>
</tr>
<tr>
<td><strong>セキュリティグループ</strong></td>
<td>SSH/HTTPのアクセス制御</td>
<td>無料</td>
</tr>
<tr>
<td><strong>IAM</strong></td>
<td>EC2へのSession Manager接続権限</td>
<td>無料</td>
</tr>
<tr>
<td><strong>EBS</strong></td>
<td>EC2にアタッチされるストレージ（デフォルト8GB）</td>
<td>月30GBまで無料枠あり</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>注意</strong>: 無料枠はAWSアカウント開設から12ヶ月間です。期間終了後はEC2インスタンス稼働時間に課金されます。ハンズオン後は必ずリソースを削除してください。</p>
</blockquote>
<hr>
<h2><span id="toc4">構築するリソース</span></h2>
<table>
<thead>
<tr>
<th>リソース</th>
<th>役割</th>
</tr>
</thead>
<tbody>
<tr>
<td>キーペア</td>
<td>SSHでEC2に接続するための認証鍵</td>
</tr>
<tr>
<td>IAMロール</td>
<td>EC2にSession Manager接続の権限を付与</td>
</tr>
<tr>
<td>セキュリティグループ</td>
<td>SSH(22)・HTTP(80)のアクセス制御</td>
</tr>
<tr>
<td>EC2インスタンス</td>
<td>Apacheが動作するWebサーバー本体</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc5">全体の作業順序</span></h2>
<p>依存関係があるため、必ずこの順番で作成します。</p>
<pre><code class="language-plaintext">⓪ 自分のIPアドレスを確認する（重要）
      ↓
① キーペアを作成する
      ↓
② IAMロールを作成する
      ↓
③ EC2インスタンスを起動する
  （セキュリティグループ・UserDataも同時に設定）
      ↓
④ 動作確認（Web・SSH）
      ↓
⑤ リソースを削除する</code></pre>
<hr>
<h2><span id="toc6">【重要】⓪ 自分のIPアドレスを確認する</span></h2>
<p>セキュリティグループで自分のIPだけを許可するために、<strong>正確なIPアドレス</strong>を事前に確認します。</p>
<blockquote>
<p><strong>注意</strong>: <code>curl https://checkip.amazonaws.com</code> で表示されるIPと、EC2への実際の接続元IPが<strong>一致しない場合</strong>があります（ISPやプロキシの経路の違いによる）。最も確実な方法はルーター管理画面での確認です。</p>
</blockquote>
<h3><span id="toc7">方法A: ルーター管理画面で確認（推奨）</span></h3>
<ol>
<li>ブラウザで以下のURLにアクセスします（ルーターによって異なります）
<pre><code class="language-plaintext">http://192.168.0.1  または  http://192.168.1.1</code></pre>
</li>
<li>「ネットワークマップ」または「インターネット」項目を開く</li>
<li>**「インターネットIPアドレス」または「WAN IPアドレス」**の値を控えます</li>
</ol>
<h3><span id="toc8">方法B: コマンドで確認</span></h3>
<pre><code class="language-cmd">curl https://checkip.amazonaws.com</code></pre>
<p><strong>控えておく情報</strong>: 自分のIPアドレス（例: <code>203.0.113.1</code>）</p>
<hr>
<h2><span id="toc9">① キーペアの作成</span></h2>
<p>キーペアはSSHでEC2に接続するための鍵です。EC2起動時に指定する必要があるため、最初に作成します。</p>
<p><strong>AWSコンソール → EC2 → ネットワーク＆セキュリティ → キーペア → 「キーペアを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-ec2-apache-key</code></td>
</tr>
<tr>
<td>キーペアのタイプ</td>
<td><strong>RSA</strong></td>
</tr>
<tr>
<td>プライベートキーファイル形式</td>
<td><strong>.pem</strong></td>
</tr>
</tbody>
</table>
<p>「キーペアを作成」をクリックすると、自動的に <code>my-ec2-apache-key.pem</code> がダウンロードされます。</p>
<h3><span id="toc10">ダウンロードしたキーペアを保存する</span></h3>
<p>ダウンロードされた <code>my-ec2-apache-key.pem</code> を以下の場所に移動します。</p>
<pre><code class="language-plaintext">C:\Users\ユーザー名\.ssh\my-ec2-apache-key.pem</code></pre>
<blockquote>
<p><strong>注意</strong>: <code>.pem</code> ファイルは<strong>再ダウンロードできません</strong>。紛失した場合は新しいキーペアを作成する必要があります。</p>
</blockquote>
<p><!-- ![キーペア作成画面](images/keypair-create.jpg) --></p>
<hr>
<h2><span id="toc11">② IAMロールの作成</span></h2>
<p>Session Manager（ブラウザからEC2に接続できるAWS機能）を使えるようにするためのIAMロールを作成します。</p>
<blockquote>
<p><strong>なぜIAMロールが必要か</strong>: EC2がAWSのサービス（Session Manager）を利用するには、そのEC2自身に「このサービスを使う権限」を付与する必要があります。この権限の設定がIAMロールです。</p>
</blockquote>
<p><strong>AWSコンソール → IAM → ロール → 「ロールを作成」</strong></p>
<h3><span id="toc12">ステップ1: エンティティタイプとユースケースの選択</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>信頼されたエンティティタイプ</td>
<td><strong>AWSのサービス</strong></td>
</tr>
<tr>
<td>ユースケース</td>
<td><strong>EC2</strong></td>
</tr>
</tbody>
</table>
<p>「次へ」をクリック。</p>
<h3><span id="toc13">ステップ2: 許可ポリシーのアタッチ</span></h3>
<p>検索ボックスに <code>AmazonSSMManagedInstanceCore</code> と入力してチェックを入れます。</p>
<p>「次へ」をクリック。</p>
<h3><span id="toc14">ステップ3: ロール名の設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>ロール名</td>
<td><code>my-ec2-apache-role</code></td>
</tr>
</tbody>
</table>
<p>「ロールを作成」をクリック。</p>
<p><!-- ![IAMロール作成画面](images/iam-role-create.jpg) --></p>
<hr>
<h2><span id="toc15">③ EC2インスタンスの起動</span></h2>
<p>キーペアとIAMロールを作成したあと、EC2インスタンスを起動します。<br />セキュリティグループとUserData（Apache自動インストール）も同時に設定します。</p>
<p><strong>AWSコンソール → EC2 → インスタンス → 「インスタンスを起動」</strong></p>
<h3><span id="toc16">3-1. 基本設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>名前</td>
<td><code>my-ec2-apache-instance</code></td>
</tr>
<tr>
<td>アプリケーションおよびOSイメージ</td>
<td><strong>Amazon Linux 2023 AMI</strong>（デフォルトで選択済み）</td>
</tr>
<tr>
<td>インスタンスタイプ</td>
<td><strong>t2.micro</strong>（無料枠対象）</td>
</tr>
<tr>
<td>キーペア</td>
<td><code>my-ec2-apache-key</code></td>
</tr>
</tbody>
</table>
<p><!-- ![EC2インスタンス起動画面 - 基本設定](images/ec2-launch-basic.jpg) --></p>
<h3><span id="toc17">3-2. セキュリティグループの設定</span></h3>
<p>「ネットワーク設定」→「セキュリティグループを作成する」を選択します。</p>
<p><strong>セキュリティグループ名と説明を設定:</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>セキュリティグループ名</td>
<td><code>my-ec2-apache-sg</code></td>
</tr>
<tr>
<td>説明</td>
<td><code>EC2 Apache hands-on SG</code></td>
</tr>
</tbody>
</table>
<p><strong>「インバウンドセキュリティグループのルールを追加」ボタンで以下の2ルールを追加します。</strong></p>
<p><strong>ルール1: SSH接続の許可</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>タイプ</td>
<td>SSH</td>
</tr>
<tr>
<td>ソースタイプ</td>
<td>カスタム</td>
</tr>
<tr>
<td>ソース</td>
<td><code>203.0.113.1/32</code>（⓪で確認した自分のIP + /32）</td>
</tr>
</tbody>
</table>
<p><strong>ルール2: HTTPアクセスの許可</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>タイプ</td>
<td>HTTP</td>
</tr>
<tr>
<td>ソースタイプ</td>
<td>カスタム</td>
</tr>
<tr>
<td>ソース</td>
<td><code>203.0.113.1/32</code>（⓪で確認した自分のIP + /32）</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>/32 とは</strong>: 「このIPアドレス1つだけ」という意味のCIDR表記です。<code>0.0.0.0/0</code> は全世界に開放することになりセキュリティリスクが高いため、必ず自分のIPのみに制限します。</p>
</blockquote>
<p><!-- ![セキュリティグループ設定画面](images/security-group-create.jpg) --></p>
<h3><span id="toc18">3-3. IAMロールの設定</span></h3>
<p>「高度な詳細」を開く → 「IAM インスタンスプロファイル」→ <code>my-ec2-apache-role</code> を選択します。</p>
<h3><span id="toc19">3-4. UserDataの設定（Apacheの自動インストール）</span></h3>
<p>「高度な詳細」の一番下にある「ユーザーデータ」に以下を貼り付けます。</p>
<pre><code class="language-bash">#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "&lt;h1&gt;Hello from Amazon Linux 2023!&lt;/h1&gt;" &gt; /var/www/html/index.html
echo "&lt;p&gt;Instance ID: $(ec2-metadata --instance-id | cut -d ' ' -f 2)&lt;/p&gt;" &gt;&gt; /var/www/html/index.html
echo "&lt;p&gt;Availability Zone: $(ec2-metadata --availability-zone | cut -d ' ' -f 2)&lt;/p&gt;" &gt;&gt; /var/www/html/index.html</code></pre>
<p><strong>各コマンドの説明:</strong></p>
<table>
<thead>
<tr>
<th>コマンド</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>yum update -y</code></td>
<td>OSのパッケージを最新化する</td>
</tr>
<tr>
<td><code>yum install -y httpd</code></td>
<td>Apache（httpd）をインストールする</td>
</tr>
<tr>
<td><code>systemctl start httpd</code></td>
<td>Apacheを起動する</td>
</tr>
<tr>
<td><code>systemctl enable httpd</code></td>
<td>OS起動時にApacheが自動起動するよう設定する</td>
</tr>
<tr>
<td><code>echo &quot;...&quot; &gt; /var/www/html/index.html</code></td>
<td>Apacheが返すテスト用HTMLを作成する</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>UserDataとは</strong>: インスタンスの<strong>初回起動時のみ</strong>自動実行されるシェルスクリプトです。この仕組みを使うことで、EC2起動と同時にApacheのインストールまで自動化できます。</p>
</blockquote>
<h3><span id="toc20">3-5. インスタンスを起動する</span></h3>
<p>「インスタンスを起動」ボタンをクリック。</p>
<p>起動完了まで約2〜3分待ちます。インスタンスの「状態」が「実行中」になったことを確認します。</p>
<p><strong>控えておく情報: インスタンスのパブリックIPアドレス</strong></p>
<p>インスタンス一覧 → 作成したインスタンスをクリック → 「パブリック IPv4 アドレス」を確認してメモします。</p>
<p><!-- ![EC2インスタンス起動後の画面](images/ec2-running.jpg) --></p>
<hr>
<h2><span id="toc21">④ 動作確認</span></h2>
<h3><span id="toc22">Webブラウザで確認</span></h3>
<p>ブラウザで以下のURLにアクセスします。</p>
<pre><code class="language-plaintext">http://（パブリックIPアドレス）</code></pre>
<p>以下のように表示されれば成功です。</p>
<pre><code class="language-plaintext">Hello from Amazon Linux 2023!
Instance ID: i-0123456789abcdef0
Availability Zone: ap-northeast-1a</code></pre>
<blockquote>
<p><strong>表示されない場合</strong>: UserDataのApacheインストールが完了するまで2〜3分かかります。少し待ってからリロードしてください。</p>
</blockquote>
<p><!-- ![ブラウザでのWebページ確認](images/apache-web-browser.jpg) --></p>
<h3><span id="toc23">SSHで接続して確認</span></h3>
<p>ローカルPCのターミナル（VSCode CMD）で実行します。</p>
<pre><code class="language-cmd">ssh -i C:\Users\ユーザー名\.ssh\my-ec2-apache-key.pem ec2-user@（パブリックIPアドレス）</code></pre>
<p>初回接続時に以下の確認が出ます。<code>yes</code> を入力します。</p>
<pre><code class="language-plaintext">Are you sure you want to continue connecting (yes/no)? yes</code></pre>
<p>接続成功するとAmazon Linux 2023のプロンプトが表示されます。以下で動作確認をします。</p>
<pre><code class="language-bash">sudo systemctl status httpd

# Apacheが返しているHTMLファイルを確認
cat /var/www/html/index.html

# ApacheのドキュメントルートをApacheの設定ファイルで確認
cat /etc/httpd/conf/httpd.conf | grep DocumentRoot

# EC2から切断
exit</code></pre>
<p><strong>Apacheのディレクトリ構成:</strong></p>
<table>
<thead>
<tr>
<th>パス</th>
<th>役割</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>/var/www/html/</code></td>
<td>Webコンテンツの置き場所（ドキュメントルート）</td>
</tr>
<tr>
<td><code>/etc/httpd/conf/httpd.conf</code></td>
<td>Apacheのメイン設定ファイル</td>
</tr>
<tr>
<td><code>/var/log/httpd/access_log</code></td>
<td>Apacheアクセスログ</td>
</tr>
<tr>
<td><code>/var/log/httpd/error_log</code></td>
<td>Apacheエラーログ</td>
</tr>
</tbody>
</table>
<p><!-- ![SSH接続後のApache動作確認](images/ssh-apache-status.jpg) --></p>
<h3><span id="toc24">【接続できない場合】IPアドレスが異なる可能性</span></h3>
<p><code>curl</code> で確認したIPを設定したが接続できない場合、実際の接続元IPが異なる可能性があります。</p>
<p><strong>一時的に全開放して真のIPを確認する方法:</strong></p>
<p>コンソール → EC2 → セキュリティグループ → <code>my-ec2-apache-sg</code> → 「インバウンドルールを編集」</p>
<p>SSHのルールを一時的に <code>0.0.0.0/0</code> に変更してSSH接続し、以下を実行します。</p>
<pre><code class="language-bash">echo $SSH_CLIENT
# 出力例: 203.0.113.1 17508 22
# 先頭の値が真の接続元IP</code></pre>
<p>このIPをメモしてSSH接続を切断し、セキュリティグループのSSHルールを <code>真のIP/32</code> に戻します。</p>
<hr>
<h2><span id="toc25">⑤ リソースの削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ず削除してください。削除する順番が重要です。</strong></p>
<h3><span id="toc26">1. EC2インスタンスを終了する</span></h3>
<p><strong>EC2 → インスタンス → <code>my-ec2-apache-instance</code> を選択 → 「インスタンスの状態」→「インスタンスを終了」</strong></p>
<p>確認ダイアログで「終了」をクリック。状態が「終了済み」になるまで待ちます（2〜5分）。</p>
<blockquote>
<p><strong>「停止」と「終了」の違い</strong>: 「停止」は一時停止（EBSストレージ課金は続く）。「終了」は完全削除（課金停止）。学習後は「終了」を選びます。</p>
</blockquote>
<h3><span id="toc27">2. セキュリティグループを削除する</span></h3>
<p><strong>EC2 → セキュリティグループ → <code>my-ec2-apache-sg</code> を選択 → 「アクション」→「セキュリティグループを削除」</strong></p>
<blockquote>
<p>インスタンス終了が完了している必要があります。「使用中」エラーが出る場合はインスタンスが「終了済み」状態になるまで待ってください。</p>
</blockquote>
<h3><span id="toc28">3. IAMロールを削除する</span></h3>
<p><strong>IAM → ロール → <code>my-ec2-apache-role</code> を選択 → 「削除」→ ロール名を入力して確認</strong></p>
<h3><span id="toc29">4. キーペアを削除する（任意）</span></h3>
<p>他のEC2でも使い回す場合は残してよいです。不要な場合は削除します。</p>
<p><strong>EC2 → キーペア → <code>my-ec2-apache-key</code> を選択 → 「アクション」→「削除」→ 確認テキストを入力</strong></p>
<p>ローカルの <code>.pem</code> ファイルも手動で削除します。</p>
<pre><code class="language-plaintext">C:\Users\ユーザー名\.ssh\my-ec2-apache-key.pem</code></pre>
<hr>
<h2><span id="toc30">CloudFormation版との比較</span></h2>
<p>コンソール版を体験したら、次は同じ構成を CloudFormation（コード）で再現してみましょう。何が自動化されるのかがよくわかります。</p>
<table>
<thead>
<tr>
<th>作業</th>
<th>コンソール（手動）</th>
<th>CloudFormation</th>
</tr>
</thead>
<tbody>
<tr>
<td>IAMロール作成</td>
<td>画面でポチポチ（5クリック以上）</td>
<td>template.yaml に定義済み</td>
</tr>
<tr>
<td>セキュリティグループ作成</td>
<td>画面でポチポチ</td>
<td>template.yaml に定義済み</td>
</tr>
<tr>
<td>EC2起動（UserData含む）</td>
<td>画面でポチポチ</td>
<td>template.yaml に定義済み</td>
</tr>
<tr>
<td>デプロイ全体</td>
<td>複数画面を行き来（15〜20分）</td>
<td>コマンド1本（5分）</td>
</tr>
<tr>
<td>削除</td>
<td>リソースを個別に依存関係順で手動削除</td>
<td><code>delete-stack</code> 1本</td>
</tr>
<tr>
<td>再現性</td>
<td>低い（手動ミスのリスクがある）</td>
<td>高い（同じ環境を何度でも再現可能）</td>
</tr>
<tr>
<td>バージョン管理</td>
<td>不可</td>
<td>Gitで管理可能</td>
</tr>
</tbody>
</table>
<p><strong>コンソール版で実感できたポイント:</strong></p>
<ul>
<li>キーペア・IAMロール・セキュリティグループ・EC2の依存関係が視覚的に理解できる</li>
<li>セキュリティグループのインバウンドルールを手動設定することで、ポートとCIDRの意味が身につく</li>
<li>UserData の仕組みを実際に設定することで、EC2の初期化フローが理解できる</li>
</ul>
<p><strong>CloudFormation版でも試してみる</strong>: <a href="https://caymezon.com/aws-handson-cloudformation-ec2-apache/">AWS CloudFormationでEC2 + ApacheウェブサーバーをIaC化しよう</a></p>
<hr>
<h2><span id="toc31">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td>Webページが表示されない（起動直後）</td>
<td>UserDataのApacheインストールが未完了</td>
<td>2〜3分待ってからリロード</td>
</tr>
<tr>
<td>SSH接続タイムアウト</td>
<td>セキュリティグループのIP設定誤り</td>
<td>⓪のIP確認方法で真のIPを再確認</td>
</tr>
<tr>
<td>SSHエラー「WARNING: UNPROTECTED PRIVATE KEY FILE!」</td>
<td>.pemファイルの権限が広すぎる（Linux/Mac）</td>
<td><code>chmod 400 ~/.ssh/my-ec2-apache-key.pem</code> を実行</td>
</tr>
<tr>
<td>セキュリティグループが削除できない</td>
<td>EC2インスタンスがまだ使用中</td>
<td>インスタンス「終了済み」状態になってから再試行</td>
</tr>
<tr>
<td>Apacheは起動しているのにページが見えない</td>
<td>セキュリティグループのHTTP(80)設定ミス</td>
<td>SGのインバウンドルールでHTTP:80が追加されているか確認</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc32">まとめ</span></h2>
<p>今回のハンズオンで体験できたこと：</p>
<table>
<thead>
<tr>
<th>確認項目</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>キーペア作成</strong></td>
<td>SSH接続に必要な鍵ペアをコンソールで作成し、.pemファイルをローカルに保存</td>
</tr>
<tr>
<td><strong>IAMロール作成</strong></td>
<td>AmazonSSMManagedInstanceCoreポリシーをEC2にアタッチして接続権限を付与</td>
</tr>
<tr>
<td><strong>セキュリティグループ</strong></td>
<td>SSH(22)/HTTP(80)を自分のIPのみに制限してEC2を保護</td>
</tr>
<tr>
<td><strong>UserDataによる自動化</strong></td>
<td>Apacheのインストールと起動を初回起動時のスクリプトで自動化</td>
</tr>
<tr>
<td><strong>Webサーバー確認</strong></td>
<td>ブラウザとSSHの両方でApache動作を確認</td>
</tr>
<tr>
<td><strong>リソース削除</strong></td>
<td>依存関係順に4つのリソースを手動で削除</td>
</tr>
</tbody>
</table>
<p>手動操作でひとつひとつ作ると、CloudFormationが裏で何を自動化しているかが理解できます。ぜひ次は <a href="https://caymezon.com/aws-handson-cloudformation-ec2-apache/">CloudFormation版</a> で同じ構成をコードで再現してみてください。</p>
<hr>
<h2><span id="toc33">関連記事</span></h2>
<p><!-- <a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"> --></p>
<p><!-- <!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWS運用入門 改訂第2版 押さえておきたいAWSの基本と運用ノウハウ [AWS深掘りガイド]","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51AAOubymTL._SL500_.jpg","\/51VMG6YKHdL._SL500_.jpg","\/41EdPB8azAL._SL500_.jpg","\/41v2JFE-9jL._SL500_.jpg","\/41FEEqR-yDL._SL500_.jpg","\/41JfZAdnTPL._SL500_.jpg","\/41vGK0czQrL._SL500_.jpg","\/41-SnYtz2aL._SL500_.jpg","\/41sPrV5fi3L._SL500_.jpg","\/41p7JtvYJ1L._SL500_.jpg","\/4169GVNTs8L._SL500_.jpg","\/41BPI5HP3zL._SL500_.jpg","\/41QOyk60CYL._SL500_.jpg","\/41APjk6FphL._SL500_.jpg","\/41ezKUu7VRL._SL500_.jpg","\/41A1n3K+r5L._SL500_.jpg","\/41aY2T8lEOL._SL500_.jpg","\/419Ca1V6HZL._SL500_.jpg","\/41zQkYyLPzL._SL500_.jpg","\/41YpHcyxiTL._SL500_.jpg","\/41-tKN5mt6L._SL500_.jpg","\/419Mv6m55IL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815631085","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815631085","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"E8MM1","s":"s"});</script></p>
<div id="msmaflink-E8MM1">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --> --></p><p>The post <a href="https://caymezon.com/aws-handson-console-ec2-apache/">AWSコンソールでEC2 + Apacheウェブサーバーを構築する手順【EC2ハンズオン / CloudFormation版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-console-ec2-apache/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>AWSコンソールでチャットボットログAPIを構築する手順【API Gateway + Lambda + CloudWatch Logs ハンズオン / SAM版との比較付き】</title>
		<link>https://caymezon.com/aws-handson-console-chatbot-log-api/</link>
					<comments>https://caymezon.com/aws-handson-console-chatbot-log-api/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Sun, 08 Mar 2026 05:02:41 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[APIGateway]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[AWSコンソール]]></category>
		<category><![CDATA[CloudWatchLogs]]></category>
		<category><![CDATA[Lambda]]></category>
		<category><![CDATA[MetricFilter]]></category>
		<category><![CDATA[REST API]]></category>
		<category><![CDATA[カスタムメトリクス]]></category>
		<category><![CDATA[サーバーレス]]></category>
		<category><![CDATA[チャットボット]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[初心者]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20257</guid>

					<description><![CDATA[<p>目次 はじめにキーワード解説使用するAWSサービス全体の作業順序① CloudWatch Log Group を作成する② CloudWatch Metric Filter を作成するフィルターパターンの設定メトリクスの [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-console-chatbot-log-api/">AWSコンソールでチャットボットログAPIを構築する手順【API Gateway + Lambda + CloudWatch Logs ハンズオン / SAM版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-10" checked><label class="toc-title" for="toc-checkbox-10">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">キーワード解説</a></li><li><a href="#toc3" tabindex="0">使用するAWSサービス</a></li><li><a href="#toc4" tabindex="0">全体の作業順序</a></li><li><a href="#toc5" tabindex="0">① CloudWatch Log Group を作成する</a></li><li><a href="#toc6" tabindex="0">② CloudWatch Metric Filter を作成する</a><ol><li><a href="#toc7" tabindex="0">フィルターパターンの設定</a></li><li><a href="#toc8" tabindex="0">メトリクスの設定</a></li></ol></li><li><a href="#toc9" tabindex="0">③ Lambda 関数を作成する</a><ol><li><a href="#toc10" tabindex="0">タイムアウトの設定</a></li><li><a href="#toc11" tabindex="0">環境変数の設定</a></li><li><a href="#toc12" tabindex="0">コードの入力</a></li></ol></li><li><a href="#toc13" tabindex="0">④ Lambda の実行ロールに権限を追加する</a><ol><li><a href="#toc14" tabindex="0">CloudWatch Logs と CloudWatch の権限をまとめて追加する</a></li></ol></li><li><a href="#toc15" tabindex="0">⑤ API Gateway REST API を作成する</a><ol><li><a href="#toc16" tabindex="0">5-1. API の作成</a></li><li><a href="#toc17" tabindex="0">5-2. /logs リソースを作成する</a></li><li><a href="#toc18" tabindex="0">5-3. POST メソッドを作成する（ログ書き込み）</a></li><li><a href="#toc19" tabindex="0">5-4. GET メソッドを作成する（ログ取得）</a></li><li><a href="#toc20" tabindex="0">5-5. API をデプロイする</a></li></ol></li><li><a href="#toc21" tabindex="0">⑥ 動作テスト</a><ol><li><a href="#toc22" tabindex="0">事前準備: API URL を変数に設定する</a></li><li><a href="#toc23" tabindex="0">テスト 1: ログを記録する（POST /logs）</a></li><li><a href="#toc24" tabindex="0">テスト 2: エラーログを記録する（Metric Filter のテスト）</a></li><li><a href="#toc25" tabindex="0">テスト 3: ログを取得する（GET /logs）</a></li><li><a href="#toc26" tabindex="0">CloudWatch でログを確認する</a></li><li><a href="#toc27" tabindex="0">CloudWatch Logs Insights でクエリを実行する（任意）</a></li><li><a href="#toc28" tabindex="0">カスタムメトリクスを確認する（任意）</a></li></ol></li><li><a href="#toc29" tabindex="0">⑦ リソースの削除</a><ol><li><a href="#toc30" tabindex="0">1. API Gateway を削除する</a></li><li><a href="#toc31" tabindex="0">2. Lambda 関数を削除する</a></li><li><a href="#toc32" tabindex="0">3. CloudWatch Log Group を削除する</a></li><li><a href="#toc33" tabindex="0">4. IAM ロールを削除する（任意）</a></li><li><a href="#toc34" tabindex="0">5. CloudWatch Lambda ロググループを削除する（任意）</a></li></ol></li><li><a href="#toc35" tabindex="0">SAM との対比</a></li><li><a href="#toc36" tabindex="0">トラブルシューティング</a></li><li><a href="#toc37" tabindex="0">まとめ</a><ol><li><a href="#toc38" tabindex="0">コンソール版で実感できたポイント</a></li></ol></li><li><a href="#toc39" tabindex="0">コンソール版と SAM 版を比較してみる</a></li><li><a href="#toc40" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>「チャットボットの会話ログをAPIで受け取り、AWSに蓄積したい」——そんな要件を実現する構成が <strong>API Gateway + Lambda + CloudWatch Logs</strong> の組み合わせです。</p>
<p>この記事では、<strong>AWSコンソールのみ</strong>を使って、チャットボットの会話ログを記録・取得するREST APIをゼロから構築するハンズオンを紹介します。</p>
<pre><code class="language-plaintext">クライアント
  ↓ POST /logs（会話ログを送信）
API Gateway（REST API）
  ↓ Lambda プロキシ統合
Lambda（ChatLogFunction / Python 3.12）
  ↓ boto3 logs.put_log_events()
CloudWatch Log Group（/chatbot/chatbot-logs）
  ↓ Metric Filter（level = "error" のログを検出）
CloudWatch カスタムメトリクス（ChatErrorCount）</code></pre>
<p><strong>このハンズオンで体験できること：</strong></p>
<ul>
<li>API Gateway REST API のリソース・メソッド作成と Lambda プロキシ統合</li>
<li>CloudWatch Logs カスタムロググループへのログ書き込み（<code>put_log_events</code>）</li>
<li>Metric Filter によるエラーログの自動メトリクス変換</li>
<li>CloudWatch Logs Insights でのログクエリ実行</li>
</ul>
<hr>
<blockquote>
<p><strong>この記事は <a href="#">SAM版ハンズオン</a> の比較記事です。</strong><br />コンソール操作でAPI Gateway・Lambda・CloudWatch Logsの連携を視覚的に学び、SAM と何が違うのかを比較したい方向けです。</p>
</blockquote>
<hr>
<p><a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"></p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWSの基本・仕組み・重要用語が全部わかる教科書 (見るだけ図解)","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51DEDQXj6oL._SL500_.jpg","\/41F589smNwL._SL500_.jpg","\/41R6f9yyCWL._SL500_.jpg","\/41HqWQ9BvmL._SL500_.jpg","\/41p8p0ZU79L._SL500_.jpg","\/41qLC-fndBL._SL500_.jpg","\/41fcLv9VT5L._SL500_.jpg","\/51lRvCsvHqL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815607850","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815607850","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"eaCUB","s":"s"});</script></p>
<div id="msmaflink-eaCUB">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p>
<h2><span id="toc2">キーワード解説</span></h2>
<table>
<thead>
<tr>
<th>用語</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>CloudWatch Log Group</strong></td>
<td>ログの論理的なまとまり。今回はチャットログ専用グループを作成する</td>
</tr>
<tr>
<td><strong>Log Stream</strong></td>
<td>Log Group の中の個別のログストリーム。今回はセッションIDごとに作成する</td>
</tr>
<tr>
<td><strong>put_log_events</strong></td>
<td>boto3 でカスタムロググループにログを書き込む API</td>
</tr>
<tr>
<td><strong>Metric Filter</strong></td>
<td>ロググループに届いたログを JSON フィルターでマッチさせ、カスタムメトリクスを自動生成する仕組み</td>
</tr>
<tr>
<td><strong>カスタムメトリクス</strong></td>
<td>CloudWatch に独自のメトリクスを記録する機能。アラーム設定やダッシュボードに使える</td>
</tr>
<tr>
<td><strong>Lambda プロキシ統合</strong></td>
<td>API Gateway が HTTP リクエスト全体を Lambda に渡す最もシンプルな統合方式</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc3">使用するAWSサービス</span></h2>
<table>
<thead>
<tr>
<th>サービス</th>
<th>役割</th>
<th>料金</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>API Gateway</strong></td>
<td>REST APIのエンドポイント（POST /logs, GET /logs）</td>
<td>月100万リクエストまで無料</td>
</tr>
<tr>
<td><strong>Lambda</strong></td>
<td>ログの書き込み・取得処理（Python 3.12）</td>
<td>月100万リクエスト・400,000 GB-秒まで無料</td>
</tr>
<tr>
<td><strong>CloudWatch Logs</strong></td>
<td>チャットログの保存・クエリ</td>
<td>月5GBまで無料</td>
</tr>
<tr>
<td><strong>CloudWatch メトリクス</strong></td>
<td>エラーログのカスタムメトリクス化</td>
<td>月10件まで無料</td>
</tr>
<tr>
<td><strong>IAM</strong></td>
<td>Lambda の実行権限管理</td>
<td>無料</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc4">全体の作業順序</span></h2>
<pre><code class="language-plaintext">① CloudWatch Log Group を作成する
      ↓
② CloudWatch Metric Filter を作成する（error ログ → メトリクス）
      ↓
③ Lambda 関数を作成する（コード・環境変数・タイムアウト設定）
      ↓
④ Lambda の実行ロールに権限を追加する
  （CloudWatch Logs: 書き込み・読み取り / CloudWatch: PutMetricData）
      ↓
⑤ API Gateway REST API を作成する（POST /logs, GET /logs）
      ↓
⑥ 動作テスト（curl でログ送信 → コンソールで確認）
      ↓
⑦ リソースの削除</code></pre>
<blockquote>
<p><strong>Log Group を先に作る理由：</strong><br />Metric Filter の作成にはロググループが必要なため、最初に作成します。</p>
</blockquote>
<hr>
<h2><span id="toc5">① CloudWatch Log Group を作成する</span></h2>
<p><strong>AWSコンソール → CloudWatch → ロググループ → 「ロググループの作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>ロググループ名</td>
<td><code>/chatbot/chatbot-logs</code></td>
</tr>
<tr>
<td>保持期間</td>
<td><strong>7日間</strong></td>
</tr>
</tbody>
</table>
<p>「作成」をクリック。</p>
<p><strong>控えておく情報:</strong></p>
<ul>
<li><strong>ロググループ名</strong>: <code>/chatbot/chatbot-logs</code></li>
</ul>
<hr>
<h2><span id="toc6">② CloudWatch Metric Filter を作成する</span></h2>
<p>エラーログを自動的にカスタムメトリクスに変換するフィルターを設定します。</p>
<p><strong>CloudWatch → ロググループ → <code>/chatbot/chatbot-logs</code> → 「メトリクスフィルター」タブ → 「メトリクスフィルターを作成」</strong></p>
<h3><span id="toc7">フィルターパターンの設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>フィルターパターン</td>
<td><code>{ $.level = &quot;error&quot; }</code></td>
</tr>
</tbody>
</table>
<p>「パターンのテスト」でテストデータを入力して確認できます（任意）。「次へ」をクリック。</p>
<h3><span id="toc8">メトリクスの設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>フィルター名</td>
<td><code>ChatErrorFilter</code></td>
</tr>
<tr>
<td>メトリクスの名前空間</td>
<td><code>ChatBot/chatbot-logs</code></td>
</tr>
<tr>
<td>メトリクス名</td>
<td><code>ChatErrorCount</code></td>
</tr>
<tr>
<td>メトリクス値</td>
<td><code>1</code></td>
</tr>
<tr>
<td>デフォルト値</td>
<td><code>0</code></td>
</tr>
</tbody>
</table>
<p>「次へ」→「メトリクスフィルターを作成」。</p>
<blockquote>
<p><strong>Metric Filter の仕組み:</strong><br />CloudWatch Logs に届いたログが <code>{ $.level = &quot;error&quot; }</code> にマッチするたびに、<br /><code>ChatBot/chatbot-logs</code> 名前空間の <code>ChatErrorCount</code> に <code>1</code> が加算されます。<br />ログに <code>{&quot;level&quot;: &quot;error&quot;, ...}</code> という JSON が含まれていればマッチします。</p>
</blockquote>
<hr>
<h2><span id="toc9">③ Lambda 関数を作成する</span></h2>
<p><strong>AWSコンソール → Lambda → 「関数の作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>作成方法</td>
<td>一から作成</td>
</tr>
<tr>
<td>関数名</td>
<td><code>ChatLogFunction</code></td>
</tr>
<tr>
<td>ランタイム</td>
<td><strong>Python 3.12</strong></td>
</tr>
<tr>
<td>アーキテクチャ</td>
<td>x86_64</td>
</tr>
<tr>
<td>実行ロール</td>
<td>「基本的な Lambda アクセス権限で新しいロールを作成」（デフォルト）</td>
</tr>
</tbody>
</table>
<p>「関数の作成」をクリック。</p>
<h3><span id="toc10">タイムアウトの設定</span></h3>
<p><strong>「設定」タブ → 「一般設定」→「編集」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>タイムアウト</td>
<td><strong>10</strong> 秒</td>
</tr>
</tbody>
</table>
<p>「保存」をクリック。</p>
<h3><span id="toc11">環境変数の設定</span></h3>
<p><strong>「設定」タブ → 「環境変数」→「編集」→「環境変数を追加」</strong></p>
<table>
<thead>
<tr>
<th>キー</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>LOG_GROUP_NAME</code></td>
<td><code>/chatbot/chatbot-logs</code></td>
</tr>
</tbody>
</table>
<p>「保存」をクリック。</p>
<h3><span id="toc12">コードの入力</span></h3>
<p>「コード」タブ → <code>lambda_function.py</code> を開いて既存の内容を全て置き換えます。</p>
<pre><code class="language-python">import json
import os
import time
import uuid

import boto3
from botocore.exceptions import ClientError

logs_client = boto3.client("logs")
cloudwatch = boto3.client("cloudwatch")

LOG_GROUP_NAME = os.environ["LOG_GROUP_NAME"]
METRIC_NAMESPACE = "ChatBot/" + LOG_GROUP_NAME.split("/")[-1]  # "ChatBot/chatbot-logs"


def lambda_handler(event, context):
    http_method = event.get("httpMethod", "")
    resource = event.get("resource", "/")

    if http_method == "POST" and resource == "/logs":
        return post_log(event)
    elif http_method == "GET" and resource == "/logs":
        return get_logs(event)
    else:
        return _response(404, {"error": "Not Found"})


def post_log(event):
    try:
        body = json.loads(event.get("body") or "{}")
    except json.JSONDecodeError:
        return _response(400, {"error": "Invalid JSON"})

    session_id = body.get("session_id") or str(uuid.uuid4())
    user_id = body.get("user_id", "anonymous")
    message = body.get("message", "")
    response_text = body.get("response", "")
    level = body.get("level", "info")

    log_entry = {
        "session_id": session_id,
        "user_id": user_id,
        "message": message,
        "response": response_text,
        "level": level,
    }

    log_stream_name = f"session/{session_id}"
    _ensure_log_stream(log_stream_name)  # ストリームを作成（既存なら無視）
    logs_client.put_log_events(
        logGroupName=LOG_GROUP_NAME,
        logStreamName=log_stream_name,
        logEvents=[
            {
                "timestamp": int(time.time() * 1000),  # ミリ秒単位の Unix 時間
                "message": json.dumps(log_entry, ensure_ascii=False),
            }
        ],
    )

    cloudwatch.put_metric_data(
        Namespace=METRIC_NAMESPACE,
        MetricData=[
            {
                "MetricName": "MessageCount",
                "Dimensions": [{"Name": "Level", "Value": level}],
                "Value": 1,
                "Unit": "Count",
            }
        ],
    )

    return _response(200, {
        "session_id": session_id,
        "log_stream": log_stream_name,
        "message": "ログを記録した",
    })


def get_logs(event):
    params = event.get("queryStringParameters") or {}
    session_id = params.get("session_id")
    limit = min(int(params.get("limit", "20")), 100)

    if not session_id:
        return _response(400, {"error": "session_id クエリパラメーターは必須"})

    log_stream_name = f"session/{session_id}"

    try:
        resp = logs_client.get_log_events(
            logGroupName=LOG_GROUP_NAME,
            logStreamName=log_stream_name,
            limit=limit,
            startFromHead=False,  # 最新のログから取得
        )
        events = []
        for e in resp["events"]:
            try:
                msg = json.loads(e["message"])
            except json.JSONDecodeError:
                msg = e["message"]
            events.append({"timestamp_ms": e["timestamp"], "log": msg})
    except ClientError as e:
        if e.response["Error"]["Code"] == "ResourceNotFoundException":
            events = []  # ログストリームが存在しない場合は空リストを返す
        else:
            raise

    return _response(200, {
        "session_id": session_id,
        "log_count": len(events),
        "logs": events,
    })


def _ensure_log_stream(log_stream_name: str) -&gt; None:
    try:
        logs_client.create_log_stream(
            logGroupName=LOG_GROUP_NAME,
            logStreamName=log_stream_name,
        )
    except ClientError as e:
        if e.response["Error"]["Code"] != "ResourceAlreadyExistsException":
            raise  # 既存ストリームは無視、それ以外のエラーは再送出


def _response(status_code: int, body: dict) -&gt; dict:
    return {
        "statusCode": status_code,
        "headers": {"Content-Type": "application/json"},
        "body": json.dumps(body, ensure_ascii=False),
    }</code></pre>
<p>「Deploy」ボタンをクリックしてコードを保存します。</p>
<hr>
<h2><span id="toc13">④ Lambda の実行ロールに権限を追加する</span></h2>
<p>デフォルトの実行ロールは CloudWatch Logs への書き込み（Lambdaの実行ログ出力）のみです。<br />今回はカスタムロググループへの書き込み・読み取りと、カスタムメトリクスへの書き込み権限を追加します。</p>
<p><strong>Lambda → <code>ChatLogFunction</code> → 「設定」タブ → 「アクセス権限」→ 実行ロール名のリンクをクリック</strong></p>
<p>（例: <code>ChatLogFunction-role-XXXX</code>）→ IAM コンソールのロール画面が開きます。</p>
<h3><span id="toc14">CloudWatch Logs と CloudWatch の権限をまとめて追加する</span></h3>
<p>「許可を追加」→「インラインポリシーを作成」→「JSON」タブを選択して以下を入力します。</p>
<pre><code class="language-json">{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogStream",
        "logs:PutLogEvents",
        "logs:GetLogEvents",
        "logs:DescribeLogStreams"
      ],
      "Resource": [
        "arn:aws:logs:ap-northeast-1:YOUR_ACCOUNT_ID:log-group:/chatbot/chatbot-logs",
        "arn:aws:logs:ap-northeast-1:YOUR_ACCOUNT_ID:log-group:/chatbot/chatbot-logs:*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "cloudwatch:PutMetricData",
      "Resource": "*"
    }
  ]
}</code></pre>
<blockquote>
<p><code>YOUR_ACCOUNT_ID</code> を自分の AWS アカウント ID（12桁）に置き換えてください。<br />アカウント ID は <code>aws sts get-caller-identity</code> で確認できます。</p>
</blockquote>
<p>「次へ」→ ポリシー名: <code>ChatLogPolicy</code> → 「ポリシーを作成」。</p>
<blockquote>
<p><strong>なぜ 2 種類の権限が必要か:</strong></p>
<ul>
<li><code>logs:PutLogEvents</code> — <code>put_log_events()</code> でカスタムロググループにログを書き込む</li>
<li><code>logs:GetLogEvents</code> — <code>get_log_events()</code> でログを読み取る</li>
<li><code>cloudwatch:PutMetricData</code> — <code>put_metric_data()</code> でカスタムメトリクスを記録する</li>
</ul>
</blockquote>
<hr>
<h2><span id="toc15">⑤ API Gateway REST API を作成する</span></h2>
<h3><span id="toc16">5-1. API の作成</span></h3>
<p><strong>AWSコンソール → API Gateway → 「APIを作成」→ 「REST API」→「構築」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>API タイプ</td>
<td>REST API（WebSocket ではない方）</td>
</tr>
<tr>
<td>API 名</td>
<td><code>ChatLogAPI</code></td>
</tr>
<tr>
<td>エンドポイントタイプ</td>
<td>リージョン</td>
</tr>
</tbody>
</table>
<p>「API を作成」をクリック。</p>
<h3><span id="toc17">5-2. /logs リソースを作成する</span></h3>
<p><strong>「リソース」→「リソースを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>リソース名</td>
<td><code>logs</code></td>
</tr>
<tr>
<td>リソースパス</td>
<td><code>/logs</code></td>
</tr>
</tbody>
</table>
<p>「リソースを作成」をクリック。</p>
<h3><span id="toc18">5-3. POST メソッドを作成する（ログ書き込み）</span></h3>
<p><code>/logs</code> リソースを選択した状態で「メソッドを作成」。</p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>メソッドタイプ</td>
<td><strong>POST</strong></td>
</tr>
<tr>
<td>統合タイプ</td>
<td><strong>Lambda 関数</strong></td>
</tr>
<tr>
<td>Lambda プロキシ統合</td>
<td><strong>有効（チェックを入れる）</strong></td>
</tr>
<tr>
<td>Lambda 関数</td>
<td><code>ChatLogFunction</code></td>
</tr>
</tbody>
</table>
<p>「メソッドを作成」をクリック。</p>
<h3><span id="toc19">5-4. GET メソッドを作成する（ログ取得）</span></h3>
<p>同様に <code>GET</code> メソッドを追加します。設定は POST と同じ（Lambda 関数: <code>ChatLogFunction</code>）。</p>
<h3><span id="toc20">5-5. API をデプロイする</span></h3>
<p><strong>「API をデプロイ」→</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>ステージ</td>
<td>「新しいステージ」</td>
</tr>
<tr>
<td>ステージ名</td>
<td><code>Prod</code></td>
</tr>
</tbody>
</table>
<p>「デプロイ」をクリック。</p>
<p><strong>デプロイ後に表示される URL を控えておきます:</strong></p>
<pre><code class="language-plaintext">https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/Prod</code></pre>
<hr>
<h2><span id="toc21">⑥ 動作テスト</span></h2>
<h3><span id="toc22">事前準備: API URL を変数に設定する</span></h3>
<pre><code class="language-cmd">set API_URL=https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/Prod</code></pre>
<blockquote>
<p><code>XXXXXXXXXX</code> を ⑤ でデプロイ後に表示された URL の値に置き換えてください。</p>
</blockquote>
<hr>
<h3><span id="toc23">テスト 1: ログを記録する（POST /logs）</span></h3>
<pre><code class="language-cmd">curl -X POST "%API_URL%/logs" ^
  -H "Content-Type: application/json" ^
  -d "{\"session_id\": \"session-001\", \"user_id\": \"user001\", \"message\": \"今日の天気は？\", \"response\": \"東京は晴れです\", \"level\": \"info\"}"</code></pre>
<p>期待するレスポンス:</p>
<pre><code class="language-json">{
  "session_id": "session-001",
  "log_stream": "session/session-001",
  "message": "ログを記録した"
}</code></pre>
<p><!-- ![POST /logs のレスポンス確認](images/post-logs-response.jpg) --></p>
<hr>
<h3><span id="toc24">テスト 2: エラーログを記録する（Metric Filter のテスト）</span></h3>
<pre><code class="language-cmd">curl -X POST "%API_URL%/logs" ^
  -H "Content-Type: application/json" ^
  -d "{\"session_id\": \"session-001\", \"user_id\": \"user001\", \"message\": \"注文履歴を見せて\", \"response\": \"エラーが発生しました\", \"level\": \"error\"}"</code></pre>
<blockquote>
<p>このリクエスト後、CloudWatch メトリクス <code>ChatBot/chatbot-logs &gt; ChatErrorCount</code> が +1 されます。<br />反映まで数分かかることがあります。</p>
</blockquote>
<hr>
<h3><span id="toc25">テスト 3: ログを取得する（GET /logs）</span></h3>
<pre><code class="language-cmd">curl "%API_URL%/logs?session_id=session-001"</code></pre>
<p>期待するレスポンス:</p>
<pre><code class="language-json">{
  "session_id": "session-001",
  "log_count": 2,
  "logs": [
    {
      "timestamp_ms": 1700000000000,
      "log": {
        "session_id": "session-001",
        "user_id": "user001",
        "message": "今日の天気は？",
        "response": "東京は晴れです",
        "level": "info"
      }
    }
  ]
}</code></pre>
<p><!-- ![GET /logs のレスポンス確認](images/get-logs-response.jpg) --></p>
<hr>
<h3><span id="toc26">CloudWatch でログを確認する</span></h3>
<p><strong>CloudWatch → ロググループ → <code>/chatbot/chatbot-logs</code> → ログストリーム</strong></p>
<ul>
<li><code>session/session-001</code> ストリームをクリック</li>
<li>送信した会話ログが JSON 形式で記録されていることを確認します</li>
</ul>
<p><!-- ![CloudWatch Logs のセッションストリーム](images/cloudwatch-log-stream.jpg) --></p>
<h3><span id="toc27">CloudWatch Logs Insights でクエリを実行する（任意）</span></h3>
<p><strong>CloudWatch → Logs Insights</strong></p>
<p>ロググループに <code>/chatbot/chatbot-logs</code> を選択し、<strong>時間範囲を「直近1時間」など幅のある範囲に設定</strong>してから以下のクエリを実行します。</p>
<blockquote>
<p><strong>注意</strong>: 開始時刻と終了時刻が同じだとエラー <code>Query&#39;s end date and time is either before the log groups creation time...</code> が出ます。カレンダーアイコンで時間幅を確保してください。</p>
</blockquote>
<pre><code class="language-plaintext">fields @timestamp, session_id, user_id, level, message
| filter level = "error"
| sort @timestamp desc
| limit 20</code></pre>
<p>エラーログだけを抽出して確認できます。</p>
<h3><span id="toc28">カスタムメトリクスを確認する（任意）</span></h3>
<p><strong>CloudWatch → メトリクス → すべてのメトリクス → カスタム名前空間 → <code>ChatBot/chatbot-logs</code></strong></p>
<table>
<thead>
<tr>
<th>メトリクス名</th>
<th>説明</th>
<th>発生元</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>ChatErrorCount</code></td>
<td>error ログが書き込まれるたびに +1</td>
<td>Metric Filter（自動）</td>
</tr>
<tr>
<td><code>MessageCount</code></td>
<td>POST /logs が呼ばれるたびに +1</td>
<td>Lambda の put_metric_data</td>
</tr>
</tbody>
</table>
<p><!-- ![CloudWatch カスタムメトリクスの確認画面](images/cloudwatch-custom-metrics.jpg) --></p>
<hr>
<h2><span id="toc29">⑦ リソースの削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ず削除してください。</strong></p>
<h3><span id="toc30">1. API Gateway を削除する</span></h3>
<p><strong>API Gateway → API → <code>ChatLogAPI</code> → 「削除」→ API 名を入力 → 「削除」</strong></p>
<h3><span id="toc31">2. Lambda 関数を削除する</span></h3>
<p><strong>Lambda → 関数 → <code>ChatLogFunction</code> → 「アクション」→「削除」</strong></p>
<h3><span id="toc32">3. CloudWatch Log Group を削除する</span></h3>
<p><strong>CloudWatch → ロググループ → <code>/chatbot/chatbot-logs</code> → 「アクション」→「ロググループを削除」</strong></p>
<blockquote>
<p>Metric Filter はロググループを削除すると自動的に削除されます。</p>
</blockquote>
<h3><span id="toc33">4. IAM ロールを削除する（任意）</span></h3>
<p><strong>IAM → ロール → <code>ChatLogFunction-role-XXXX</code> を削除</strong></p>
<h3><span id="toc34">5. CloudWatch Lambda ロググループを削除する（任意）</span></h3>
<p><strong>CloudWatch → ロগগループ → <code>/aws/lambda/ChatLogFunction</code> → 削除</strong></p>
<hr>
<h2><span id="toc35">SAM との対比</span></h2>
<table>
<thead>
<tr>
<th>SAMの記述</th>
<th>コンソールでやること</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>AWS::Logs::LogGroup</code></td>
<td>CloudWatch → ロググループを作成</td>
</tr>
<tr>
<td><code>AWS::Logs::MetricFilter</code></td>
<td>ロググループ → メトリクスフィルターを作成</td>
</tr>
<tr>
<td><code>Statement: logs:PutLogEvents</code></td>
<td>IAM → ロールにインラインポリシーを追加</td>
</tr>
<tr>
<td><code>Statement: cloudwatch:PutMetricData</code></td>
<td>同上（同じポリシーに含める）</td>
</tr>
<tr>
<td><code>Events: Type: Api</code>（POST + GET）</td>
<td>API Gateway → リソース・メソッドを作成してデプロイ</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>コンソール版のつまずきポイント:</strong><br />IAM のインラインポリシーに <code>YOUR_ACCOUNT_ID</code> を自分のアカウントIDに書き換えるのを忘れると <code>AccessDeniedException</code> が発生します。<br />SAM版では <code>!GetAtt ChatLogGroup.Arn</code> で自動解決されるため、この手作業が不要です。</p>
</blockquote>
<hr>
<h2><span id="toc36">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>AccessDeniedException: logs:PutLogEvents</code></td>
<td>Lambda ロールに権限がない</td>
<td>④ の手順でインラインポリシーを追加する</td>
</tr>
<tr>
<td><code>ResourceNotFoundException</code> (Log Group)</td>
<td>環境変数のロググループ名が誤っている</td>
<td><code>LOG_GROUP_NAME</code> 環境変数と ① で作成したグループ名を確認する</td>
</tr>
<tr>
<td>POST で 500 エラー</td>
<td>Lambda 実行エラー</td>
<td>Lambda → 「モニタリング」→「CloudWatch Logs を表示」でエラー詳細を確認する</td>
</tr>
<tr>
<td>GET で <code>{&quot;log_count&quot;: 0}</code></td>
<td>ログがない or session_id が異なる</td>
<td>POST で使った session_id と一致しているか確認する</td>
</tr>
<tr>
<td>Metric Filter が反映されない</td>
<td>数分かかる</td>
<td>5〜10 分後に CloudWatch メトリクスを再確認する</td>
</tr>
<tr>
<td><code>InvalidParameterException</code> (put_log_events)</td>
<td>タイムスタンプが古すぎる or 未来すぎる</td>
<td><code>int(time.time() * 1000)</code> でミリ秒タイムスタンプを生成しているか確認する</td>
</tr>
<tr>
<td>API Gateway から 403 が返る</td>
<td>ステージのデプロイ忘れ</td>
<td>API Gateway → 「API をデプロイ」を再実行する</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc37">まとめ</span></h2>
<p>今回のハンズオンで体験できたこと：</p>
<table>
<thead>
<tr>
<th>確認項目</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>API Gateway + Lambda 連携</strong></td>
<td>Lambda プロキシ統合で REST API の POST / GET を1関数で処理</td>
</tr>
<tr>
<td><strong>カスタムロググループへの書き込み</strong></td>
<td><code>put_log_events()</code> でセッション単位のログストリームに記録</td>
</tr>
<tr>
<td><strong>Metric Filter</strong></td>
<td><code>{ $.level = &quot;error&quot; }</code> でエラーログを自動的にメトリクスへ変換</td>
</tr>
<tr>
<td><strong>CloudWatch Logs Insights</strong></td>
<td>クエリでエラーログだけを抽出・確認</td>
</tr>
</tbody>
</table>
<h3><span id="toc38">コンソール版で実感できたポイント</span></h3>
<ul>
<li>API Gateway のリソース・メソッド・デプロイという3段階の設定が視覚的に理解できる</li>
<li>IAM ポリシーのリソース ARN を手動で記述することで、権限スコープの意味が身につく</li>
<li>Metric Filter の仕組みを GUI で設定することで、JSON フィルター構文の動作が理解できる</li>
</ul>
<hr>
<h2><span id="toc39">コンソール版と SAM 版を比較してみる</span></h2>
<p>コンソールで API Gateway + Lambda + CloudWatch Logs の連携を理解したら、SAM で同じ構成をコードで定義することで「SAM が何を自動化しているか」が明確になります。IAM ポリシーの ARN 解決や Log Group の保持期間設定など、コンソールでの手動操作がコードに対応しています。</p>
<p><!-- TODO: SAM版記事へのリンクを追加 --></p>
<hr>
<h2><span id="toc40">関連記事</span></h2>
<p><a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"></p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWS運用入門 改訂第2版 押さえておきたいAWSの基本と運用ノウハウ [AWS深掘りガイド]","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51AAOubymTL._SL500_.jpg","\/51VMG6YKHdL._SL500_.jpg","\/41EdPB8azAL._SL500_.jpg","\/41v2JFE-9jL._SL500_.jpg","\/41FEEqR-yDL._SL500_.jpg","\/41JfZAdnTPL._SL500_.jpg","\/41vGK0czQrL._SL500_.jpg","\/41-SnYtz2aL._SL500_.jpg","\/41sPrV5fi3L._SL500_.jpg","\/41p7JtvYJ1L._SL500_.jpg","\/4169GVNTs8L._SL500_.jpg","\/41BPI5HP3zL._SL500_.jpg","\/41QOyk60CYL._SL500_.jpg","\/41APjk6FphL._SL500_.jpg","\/41ezKUu7VRL._SL500_.jpg","\/41A1n3K+r5L._SL500_.jpg","\/41aY2T8lEOL._SL500_.jpg","\/419Ca1V6HZL._SL500_.jpg","\/41zQkYyLPzL._SL500_.jpg","\/41YpHcyxiTL._SL500_.jpg","\/41-tKN5mt6L._SL500_.jpg","\/419Mv6m55IL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815631085","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815631085","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"E8MM1","s":"s"});</script></p>
<div id="msmaflink-E8MM1">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p><p>The post <a href="https://caymezon.com/aws-handson-console-chatbot-log-api/">AWSコンソールでチャットボットログAPIを構築する手順【API Gateway + Lambda + CloudWatch Logs ハンズオン / SAM版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-console-chatbot-log-api/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>AWSコンソールだけで画像認識パイプラインを構築する手順【S3 + Lambda + Rekognition / SAM版との比較付き】</title>
		<link>https://caymezon.com/aws-handson-console-rekognition-image-pipeline/</link>
					<comments>https://caymezon.com/aws-handson-console-rekognition-image-pipeline/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Sun, 08 Mar 2026 02:58:22 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[AWSコンソール]]></category>
		<category><![CDATA[Lambda]]></category>
		<category><![CDATA[ML]]></category>
		<category><![CDATA[Rekognition]]></category>
		<category><![CDATA[S3]]></category>
		<category><![CDATA[SAM比較]]></category>
		<category><![CDATA[サーバーレス]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[初心者]]></category>
		<category><![CDATA[画像認識]]></category>
		<category><![CDATA[画像認識パイプライン]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20249</guid>

					<description><![CDATA[<p>目次 はじめにキーワード解説使用するAWSサービス全体の作業順序① S3 バケットを作成する② Lambda 関数を作成するタイムアウトの設定コードの入力③ Lambda の実行ロールに権限を追加する3-1. Rekog [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-console-rekognition-image-pipeline/">AWSコンソールだけで画像認識パイプラインを構築する手順【S3 + Lambda + Rekognition / SAM版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-12" checked><label class="toc-title" for="toc-checkbox-12">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">キーワード解説</a></li><li><a href="#toc3" tabindex="0">使用するAWSサービス</a></li><li><a href="#toc4" tabindex="0">全体の作業順序</a></li><li><a href="#toc5" tabindex="0">① S3 バケットを作成する</a></li><li><a href="#toc6" tabindex="0">② Lambda 関数を作成する</a><ol><li><a href="#toc7" tabindex="0">タイムアウトの設定</a></li><li><a href="#toc8" tabindex="0">コードの入力</a></li></ol></li><li><a href="#toc9" tabindex="0">③ Lambda の実行ロールに権限を追加する</a><ol><li><a href="#toc10" tabindex="0">3-1. Rekognition 権限を追加する</a></li><li><a href="#toc11" tabindex="0">3-2. S3 GetObject 権限を追加する</a></li></ol></li><li><a href="#toc12" tabindex="0">④ Lambda に S3 トリガーを追加する</a></li><li><a href="#toc13" tabindex="0">⑤ 動作テスト</a><ol><li><a href="#toc14" tabindex="0">テスト用画像の準備</a></li><li><a href="#toc15" tabindex="0">画像をアップロードする</a></li><li><a href="#toc16" tabindex="0">CloudWatch Logs でラベル検出結果を確認する</a></li><li><a href="#toc17" tabindex="0">複数枚でテストする</a></li></ol></li><li><a href="#toc18" tabindex="0">⑥ リソースの削除</a><ol><li><a href="#toc19" tabindex="0">1. S3 バケットのオブジェクトを全て削除する</a></li><li><a href="#toc20" tabindex="0">2. S3 バケットを削除する</a></li><li><a href="#toc21" tabindex="0">3. Lambda のトリガーを削除する</a></li><li><a href="#toc22" tabindex="0">4. Lambda 関数を削除する</a></li><li><a href="#toc23" tabindex="0">5. IAM ロールを削除する（任意）</a></li><li><a href="#toc24" tabindex="0">6. CloudWatch Logs のロググループを削除する（任意）</a></li></ol></li><li><a href="#toc25" tabindex="0">SAMとの対比</a></li><li><a href="#toc26" tabindex="0">トラブルシューティング</a></li><li><a href="#toc27" tabindex="0">まとめ</a><ol><li><a href="#toc28" tabindex="0">コンソール版で実感できたポイント</a></li></ol></li><li><a href="#toc29" tabindex="0">コンソール版と SAM 版を比較してみる</a></li><li><a href="#toc30" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>「S3に画像をアップロードしたら、自動で中身を分析してほしい」——そんな仕組みを、<strong>AWSコンソールのみ</strong>でゼロから構築するハンズオンです。</p>
<p>Amazon Rekognition の <code>DetectLabels</code> API を使うと、画像に写っている物体・シーン・動物などを自動で検出できます。犬の写真をアップロードすれば「Dog（信頼度98%）」「Animal（97%）」といったラベルが返ってきます。</p>
<pre><code class="language-plaintext">ユーザー
  ↓ JPEG / PNG をアップロード
S3 バケット（UploadBucket）
  ↓ ObjectCreated イベント（自動）
Lambda（DetectFunction）
  ↓ rekognition:DetectLabels（S3Object を指定）
Amazon Rekognition
  ↓ [{"name": "Dog", "confidence": 98.5}, ...] を返す
Lambda
  ↓ print（JSON）
CloudWatch Logs</code></pre>
<p><strong>このハンズオンで体験できること：</strong></p>
<ul>
<li><strong>S3 トリガー</strong> — S3 へのアップロードを契機に Lambda を自動起動する仕組み</li>
<li><strong>Rekognition DetectLabels</strong> — 画像内の物体・シーン・動物を検出してラベルと信頼度を返す API</li>
<li><strong>IAM 権限管理</strong> — Lambda から S3・Rekognition を呼び出すために必要な権限の追加手順</li>
<li><strong>S3Object 参照</strong> — 画像データを Lambda に転送せず S3 の場所を直接 Rekognition に渡す効率的な方法</li>
</ul>
<hr>
<blockquote>
<p><strong>この記事は <a href="#">SAM版ハンズオン</a> の比較記事です。</strong><br />コンソール操作で S3・Lambda・Rekognition の連携を視覚的に学び、SAM と何が違うのかを比較したい方向けです。</p>
</blockquote>
<hr>
<p><a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"></p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWSの基本・仕組み・重要用語が全部わかる教科書 (見るだけ図解)","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51DEDQXj6oL._SL500_.jpg","\/41F589smNwL._SL500_.jpg","\/41R6f9yyCWL._SL500_.jpg","\/41HqWQ9BvmL._SL500_.jpg","\/41p8p0ZU79L._SL500_.jpg","\/41qLC-fndBL._SL500_.jpg","\/41fcLv9VT5L._SL500_.jpg","\/51lRvCsvHqL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815607850","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815607850","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"eaCUB","s":"s"});</script></p>
<div id="msmaflink-eaCUB">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p>
<h2><span id="toc2">キーワード解説</span></h2>
<table>
<thead>
<tr>
<th>用語</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>DetectLabels</strong></td>
<td>Rekognition API。画像内の物体・シーンを検出してラベル名と信頼度を返す</td>
</tr>
<tr>
<td><strong>信頼度（Confidence）</strong></td>
<td>ラベルが正確であるかどうかの確度（0〜100%）。今回は70%以上のみ返す</td>
</tr>
<tr>
<td><strong>S3Object 参照</strong></td>
<td>画像データを Lambda に転送せず、S3 の場所を Rekognition に渡す方式</td>
</tr>
<tr>
<td><strong>S3 イベント通知</strong></td>
<td>S3 バケットへのオブジェクト作成・削除などをトリガーに Lambda を呼び出す仕組み</td>
</tr>
<tr>
<td><strong>実行ロール</strong></td>
<td>Lambda が他の AWS サービスを操作するために使う IAM ロール</td>
</tr>
<tr>
<td><strong>無料枠</strong></td>
<td>最初の12ヶ月 / 月5,000枚まで無料。超過後は $0.001/枚</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc3">使用するAWSサービス</span></h2>
<table>
<thead>
<tr>
<th>サービス</th>
<th>役割</th>
<th>料金</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>S3</strong></td>
<td>画像のアップロード先バケット</td>
<td>月5GBまで無料</td>
</tr>
<tr>
<td><strong>Lambda</strong></td>
<td>S3 イベントを受けて Rekognition を呼び出す</td>
<td>月100万リクエスト・400,000 GB-秒まで無料</td>
</tr>
<tr>
<td><strong>Rekognition</strong></td>
<td>画像ラベル検出（DetectLabels）</td>
<td>最初の12ヶ月 / 月5,000枚まで無料</td>
</tr>
<tr>
<td><strong>IAM</strong></td>
<td>Lambda の実行権限管理</td>
<td>無料</td>
</tr>
<tr>
<td><strong>CloudWatch Logs</strong></td>
<td>Lambda の実行ログ（ラベル検出結果）</td>
<td>月5GBまで無料</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc4">全体の作業順序</span></h2>
<pre><code class="language-plaintext">① S3 バケットを作成する
      ↓
② Lambda 関数を作成する（コード入力・タイムアウト設定）
      ↓
③ Lambda の実行ロールに権限を追加する
  （S3: GetObject / Rekognition: DetectLabels）
      ↓
④ Lambda に S3 トリガーを追加する
      ↓
⑤ 動作テスト（画像をアップロード → ログを確認）
      ↓
⑥ リソースの削除</code></pre>
<hr>
<h2><span id="toc5">① S3 バケットを作成する</span></h2>
<p><strong>AWSコンソール → S3 → 「バケットを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>バケット名</td>
<td><code>my-rekognition-upload</code>（グローバルユニークな名前）</td>
</tr>
<tr>
<td>リージョン</td>
<td><strong>アジアパシフィック（東京）ap-northeast-1</strong></td>
</tr>
<tr>
<td>その他</td>
<td>デフォルトのまま</td>
</tr>
</tbody>
</table>
<p>「バケットを作成」をクリック。</p>
<p><strong>控えておく情報:</strong></p>
<ul>
<li><strong>バケット名</strong>（削除時・IAMポリシー設定時に使用）</li>
</ul>
<blockquote>
<p><strong>バケット名のグローバルユニークについて：</strong><br />S3 のバケット名は全 AWS アカウントで一意である必要があります。<code>my-rekognition-upload-</code> に自分のアカウントIDや日付を追加すると重複を避けられます。</p>
</blockquote>
<hr>
<h2><span id="toc6">② Lambda 関数を作成する</span></h2>
<p><strong>AWSコンソール → Lambda → 「関数の作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>作成方法</td>
<td>一から作成</td>
</tr>
<tr>
<td>関数名</td>
<td><code>DetectFunction</code></td>
</tr>
<tr>
<td>ランタイム</td>
<td><strong>Python 3.12</strong></td>
</tr>
<tr>
<td>アーキテクチャ</td>
<td>x86_64</td>
</tr>
<tr>
<td>実行ロール</td>
<td>「基本的な Lambda アクセス権限で新しいロールを作成」（デフォルト）</td>
</tr>
</tbody>
</table>
<p>「関数の作成」をクリック。</p>
<h3><span id="toc7">タイムアウトの設定</span></h3>
<p><strong>「設定」タブ → 「一般設定」→「編集」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>タイムアウト</td>
<td><strong>30</strong> 秒</td>
</tr>
</tbody>
</table>
<p>「保存」をクリック。</p>
<blockquote>
<p><strong>タイムアウトを 30 秒にする理由：</strong><br />Rekognition API の呼び出しには数秒かかることがあります。デフォルト（3秒）では Rekognition のレスポンスを待ちきれずタイムアウトするため、余裕を持って 30 秒に設定します。</p>
</blockquote>
<h3><span id="toc8">コードの入力</span></h3>
<p>「コード」タブ → <code>lambda_function.py</code> を開いて既存の内容を全て置き換える。</p>
<pre><code class="language-python">import json
import urllib.parse
import boto3

rekognition = boto3.client("rekognition")


def lambda_handler(event, context):
    for record in event["Records"]:
        bucket = record["s3"]["bucket"]["name"]
        key = urllib.parse.unquote_plus(record["s3"]["object"]["key"])

        print(json.dumps({"status": "start", "bucket": bucket, "key": key}))

        response = rekognition.detect_labels(
            Image={
                "S3Object": {
                    "Bucket": bucket,
                    "Name": key,
                }
            },
            MaxLabels=10,
            MinConfidence=70,
        )

        labels = [
            {
                "name": label["Name"],
                "confidence": round(label["Confidence"], 1),
            }
            for label in response["Labels"]
        ]

        result = {
            "bucket": bucket,
            "key": key,
            "label_count": len(labels),
            "labels": labels,
        }
        print(json.dumps(result, ensure_ascii=False))

    return {"processedCount": len(event["Records"])}</code></pre>
<p>「Deploy」ボタンをクリックしてコードを保存する。</p>
<p><strong>コードのポイント:</strong></p>
<table>
<thead>
<tr>
<th>ポイント</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>rekognition = boto3.client(&quot;rekognition&quot;)</code> をグローバルに置く</td>
<td>Lambda のコールドスタート時に1回だけ初期化。ウォームスタート時は再利用されパフォーマンスが向上する</td>
</tr>
<tr>
<td><code>urllib.parse.unquote_plus(key)</code></td>
<td>日本語や空白を含むファイル名は S3 イベントで URL エンコードされるため、デコードが必要</td>
</tr>
<tr>
<td><code>S3Object</code> 参照</td>
<td>画像データを Lambda のメモリに転送せず S3 の場所を Rekognition に渡す。メモリ効率が良い</td>
</tr>
<tr>
<td><code>MinConfidence=70</code></td>
<td>信頼度 70% 未満のラベルは結果から除外。全件見たい場合は <code>0</code> に変更して Deploy する</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc9">③ Lambda の実行ロールに権限を追加する</span></h2>
<p>デフォルトの実行ロールは CloudWatch Logs への書き込みのみ。<br />S3 からの読み取りと Rekognition の呼び出し権限を追加する。</p>
<p><strong>Lambda → <code>DetectFunction</code> → 「設定」タブ → 「アクセス権限」→ 実行ロール名のリンクをクリック</strong></p>
<p>（例: <code>DetectFunction-role-XXXX</code>）→ IAM コンソールのロール画面が開く。</p>
<h3><span id="toc10">3-1. Rekognition 権限を追加する</span></h3>
<p>「許可を追加」→「ポリシーをアタッチ」</p>
<p>検索ボックスに <code>Rekognition</code> と入力 → <strong><code>AmazonRekognitionReadOnlyAccess</code></strong> にチェック → 「許可を追加」。</p>
<blockquote>
<p><strong>AmazonRekognitionReadOnlyAccess に含まれる主な権限:</strong></p>
<ul>
<li><code>rekognition:DetectLabels</code> — ラベル検出（今回使用）</li>
<li><code>rekognition:DetectFaces</code> — 顔検出</li>
<li><code>rekognition:DetectText</code> — テキスト検出</li>
</ul>
</blockquote>
<h3><span id="toc11">3-2. S3 GetObject 権限を追加する</span></h3>
<p>「許可を追加」→「インラインポリシーを作成」</p>
<p>「JSON」タブを選択して以下を入力する（<code>my-rekognition-upload</code> を ① のバケット名に変更）:</p>
<pre><code class="language-json">{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-rekognition-upload/*"
    }
  ]
}</code></pre>
<p>「次へ」→ ポリシー名: <code>S3ReadForRekognition</code> → 「ポリシーを作成」。</p>
<blockquote>
<p><strong>なぜ S3 の権限が必要か:</strong><br />Rekognition に <code>S3Object</code> を指定した場合、Rekognition が Lambda の IAM ロールを借りて<br />S3 からオブジェクトを取得します。Lambda ロールに <code>s3:GetObject</code> がないと 403 エラーになります。</p>
<p>SAM版では <code>S3ReadPolicy</code>（SAM 組み込みポリシー）が特定バケットのみに <code>s3:GetObject</code> を自動付与します。<br />コンソール版では手動でインラインポリシーを作成する必要があります。</p>
</blockquote>
<hr>
<h2><span id="toc12">④ Lambda に S3 トリガーを追加する</span></h2>
<p><strong>Lambda → <code>DetectFunction</code> → 「設定」タブ → 「トリガー」→「トリガーを追加」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>ソース</td>
<td><strong>S3</strong></td>
</tr>
<tr>
<td>バケット</td>
<td><code>my-rekognition-upload</code>（① で作成したバケット）</td>
</tr>
<tr>
<td>イベントタイプ</td>
<td><strong>すべてのオブジェクト作成イベント（s3:ObjectCreated:*）</strong></td>
</tr>
<tr>
<td>プレフィックス</td>
<td>空欄（全ファイルを対象）</td>
</tr>
<tr>
<td>サフィックス</td>
<td>空欄（全形式を対象）</td>
</tr>
</tbody>
</table>
<p>「再帰呼び出し」の確認チェックボックスにチェック → 「追加」をクリック。</p>
<blockquote>
<p><strong>再帰呼び出しについて：</strong><br />Lambda の実行結果を同じバケットに書き込む構成にすると、S3 イベントが再発火して無限ループになります。<br />今回は S3 への書き込みを行わないため問題ありません。</p>
</blockquote>
<p><!-- ![S3トリガー追加画面：バケットとイベントタイプの設定](images/s3-trigger-setting.jpg) --></p>
<hr>
<h2><span id="toc13">⑤ 動作テスト</span></h2>
<h3><span id="toc14">テスト用画像の準備</span></h3>
<p>任意の JPEG または PNG 画像を用意する（例: 犬・猫・風景など）。<br />ファイルサイズは <strong>15MB 以下</strong> であることを確認する。</p>
<h3><span id="toc15">画像をアップロードする</span></h3>
<p><strong>方法 A: S3 コンソール</strong></p>
<p>S3 → <code>my-rekognition-upload</code> → 「アップロード」→ ファイルをドラッグ＆ドロップ → 「アップロード」</p>
<p><strong>方法 B: AWS CLI</strong></p>
<pre><code class="language-cmd">aws s3 cp "C:\Users\yourname\Pictures\dog.jpg" s3://my-rekognition-upload/ --region ap-northeast-1</code></pre>
<h3><span id="toc16">CloudWatch Logs でラベル検出結果を確認する</span></h3>
<p><strong>Lambda → <code>DetectFunction</code> → 「モニタリング」タブ → 「CloudWatch Logs を表示」</strong></p>
<p>最新のロットストリームを開いて以下のような出力を確認する。</p>
<pre><code class="language-json">{"status": "start", "bucket": "my-rekognition-upload", "key": "dog.jpg"}
{
  "bucket": "my-rekognition-upload",
  "key": "dog.jpg",
  "label_count": 8,
  "labels": [
    {"name": "Dog", "confidence": 98.5},
    {"name": "Pet", "confidence": 98.5},
    {"name": "Animal", "confidence": 98.5},
    {"name": "Canine", "confidence": 98.5},
    {"name": "Mammal", "confidence": 97.2},
    {"name": "Golden Retriever", "confidence": 85.3},
    {"name": "Grass", "confidence": 76.1},
    {"name": "Outdoors", "confidence": 71.4}
  ]
}
{"processedCount": 1}</code></pre>
<p><!-- ![CloudWatch Logsのラベル検出結果：犬の写真から8つのラベルが検出された様子](images/cloudwatch-detect-result.jpg) --></p>
<blockquote>
<p><strong><code>MinConfidence: 70</code> の効果：</strong><br />信頼度 70% 未満のラベルは結果に含まれません。<br />全ラベルを確認したい場合は <code>MinConfidence=0</code> に変更して「Deploy」する。</p>
</blockquote>
<h3><span id="toc17">複数枚でテストする</span></h3>
<pre><code class="language-cmd">aws s3 cp "C:\Users\yourname\Pictures\cat.jpg"  s3://my-rekognition-upload/ --region ap-northeast-1
aws s3 cp "C:\Users\yourname\Pictures\city.jpg" s3://my-rekognition-upload/ --region ap-northeast-1</code></pre>
<p>各ファイルのアップロードごとに Lambda が起動し、それぞれのラベル検出結果がログに記録される。</p>
<blockquote>
<p><strong>無料枠の管理：</strong><br />AWS コンソール → Billing → 無料利用枠 → 「Amazon Rekognition」で当月の使用枚数を確認できます。<br />月5,000枚まで無料のため、学習目的のハンズオンでは通常課金されません。</p>
</blockquote>
<hr>
<h2><span id="toc18">⑥ リソースの削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ず削除してください。</strong></p>
<h3><span id="toc19">1. S3 バケットのオブジェクトを全て削除する</span></h3>
<pre><code class="language-cmd">aws s3 rm s3://my-rekognition-upload --recursive --region ap-northeast-1</code></pre>
<h3><span id="toc20">2. S3 バケットを削除する</span></h3>
<p><strong>S3 → <code>my-rekognition-upload</code> → 「削除」→ バケット名を入力 → 「削除」</strong></p>
<h3><span id="toc21">3. Lambda のトリガーを削除する</span></h3>
<p><strong>Lambda → <code>DetectFunction</code> → 「設定」→「トリガー」→ S3 トリガーを選択 → 「削除」</strong></p>
<h3><span id="toc22">4. Lambda 関数を削除する</span></h3>
<p><strong>Lambda → 関数 → <code>DetectFunction</code> → 「アクション」→「削除」</strong></p>
<h3><span id="toc23">5. IAM ロールを削除する（任意）</span></h3>
<p><strong>IAM → ロール → <code>DetectFunction-role-XXXX</code> を削除</strong></p>
<h3><span id="toc24">6. CloudWatch Logs のロググループを削除する（任意）</span></h3>
<p><strong>CloudWatch → ロググループ → <code>/aws/lambda/DetectFunction</code> → 削除</strong></p>
<blockquote>
<p><strong>SAM版との大きな違い（SAMのメリット）：</strong><br />SAM版では <code>sam delete</code> 1コマンドで上記すべてのリソースを一括削除できます。</p>
</blockquote>
<hr>
<h2><span id="toc25">SAMとの対比</span></h2>
<table>
<thead>
<tr>
<th>SAMの記述</th>
<th>コンソールでやること</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>AWS::S3::Bucket</code></td>
<td>S3 → バケットを作成</td>
</tr>
<tr>
<td><code>S3ReadPolicy</code>（SAM組み込み）</td>
<td>IAM → ロールにインラインポリシーで <code>s3:GetObject</code> を追加</td>
</tr>
<tr>
<td><code>RekognitionDetectOnlyPolicy</code>（SAM組み込み）</td>
<td>IAM → ロールに <code>AmazonRekognitionReadOnlyAccess</code> をアタッチ</td>
</tr>
<tr>
<td><code>Events: Type: S3</code>（ObjectCreated）</td>
<td>Lambda → トリガーを追加（S3・全オブジェクト作成イベント）</td>
</tr>
<tr>
<td><code>sam delete</code></td>
<td>S3を空にしてから削除 + Lambda + IAM + CloudWatch Logs を個別に削除</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>コンソール版のつまずきポイント：</strong><br /><code>AccessDeniedException</code> が出た場合、S3 の GetObject 権限（インラインポリシー）と Rekognition の DetectLabels 権限（AmazonRekognitionReadOnlyAccess）の両方が揃っているか確認しましょう。どちらか一方が欠けていてもエラーになります。</p>
</blockquote>
<hr>
<h2><span id="toc26">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td>Lambda が動作しない（ログが出ない）</td>
<td>S3 トリガーが設定されていない</td>
<td>④ の手順で S3 トリガーを追加する</td>
</tr>
<tr>
<td><code>AccessDeniedException</code> for Rekognition</td>
<td>Lambda ロールに Rekognition 権限がない</td>
<td>③-1 の手順で <code>AmazonRekognitionReadOnlyAccess</code> をアタッチ</td>
</tr>
<tr>
<td><code>AccessDenied</code> for S3</td>
<td>Lambda ロールに S3 GetObject 権限がない</td>
<td>③-2 の手順でインラインポリシーを追加</td>
</tr>
<tr>
<td><code>InvalidImageFormatException</code></td>
<td>JPEG/PNG 以外のファイルをアップロードした</td>
<td>JPEG または PNG ファイルを使用する</td>
</tr>
<tr>
<td><code>ImageTooLargeException</code></td>
<td>15MB を超える画像をアップロードした</td>
<td>15MB 以下の画像を使用する</td>
</tr>
<tr>
<td>ラベルが 0 件</td>
<td><code>MinConfidence</code> が高すぎる</td>
<td>コードの <code>MinConfidence=70</code> を下げて「Deploy」する</td>
</tr>
<tr>
<td>日本語ファイル名でエラー</td>
<td>URL エンコードが解除されていない</td>
<td>コードに <code>urllib.parse.unquote_plus(key)</code> が含まれているか確認</td>
</tr>
<tr>
<td>Lambda がタイムアウトする</td>
<td>タイムアウトが短い（デフォルト3秒）</td>
<td>② の手順でタイムアウトを 30 秒に変更する</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc27">まとめ</span></h2>
<p>今回のハンズオンで体験できたこと：</p>
<table>
<thead>
<tr>
<th>確認項目</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>S3 トリガー</strong></td>
<td>画像アップロードと同時に Lambda が自動起動する仕組みを体験</td>
</tr>
<tr>
<td><strong>Rekognition DetectLabels</strong></td>
<td>画像に写った物体・動物・シーンが自動でラベル付けされる様子を確認</td>
</tr>
<tr>
<td><strong>S3Object 参照</strong></td>
<td>画像をLambdaに転送せずS3の場所だけを渡す効率的な連携方法</td>
</tr>
<tr>
<td><strong>IAM 権限の設定</strong></td>
<td>S3・Rekognition それぞれに必要な権限を個別に追加する手順</td>
</tr>
</tbody>
</table>
<h3><span id="toc28">コンソール版で実感できたポイント</span></h3>
<ul>
<li>S3 → Lambda → Rekognition という3つのサービスの<strong>データの流れ</strong>が視覚的に理解できる</li>
<li>実行ロールに必要な権限を1つずつ追加することで、IAM の仕組みが身につく</li>
<li>リソースを個別に作成・削除することで、各サービスの独立性と依存関係が明確になる</li>
</ul>
<hr>
<h2><span id="toc29">コンソール版と SAM 版を比較してみる</span></h2>
<p>コンソールで S3・Lambda・Rekognition の連携を理解したら、SAM で同じ構成をコードで定義することで「SAM が何を自動化しているか」が明確になります。<code>S3ReadPolicy</code> や <code>RekognitionDetectOnlyPolicy</code> による1行での権限付与など、コンソールでの手動操作がコードに対応しています。</p>
<p><!-- TODO: SAM版記事へのリンクを追加 --></p>
<hr>
<h2><span id="toc30">関連記事</span></h2>
<p><a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"></p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWS運用入門 改訂第2版 押さえておきたいAWSの基本と運用ノウハウ [AWS深掘りガイド]","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51AAOubymTL._SL500_.jpg","\/51VMG6YKHdL._SL500_.jpg","\/41EdPB8azAL._SL500_.jpg","\/41v2JFE-9jL._SL500_.jpg","\/41FEEqR-yDL._SL500_.jpg","\/41JfZAdnTPL._SL500_.jpg","\/41vGK0czQrL._SL500_.jpg","\/41-SnYtz2aL._SL500_.jpg","\/41sPrV5fi3L._SL500_.jpg","\/41p7JtvYJ1L._SL500_.jpg","\/4169GVNTs8L._SL500_.jpg","\/41BPI5HP3zL._SL500_.jpg","\/41QOyk60CYL._SL500_.jpg","\/41APjk6FphL._SL500_.jpg","\/41ezKUu7VRL._SL500_.jpg","\/41A1n3K+r5L._SL500_.jpg","\/41aY2T8lEOL._SL500_.jpg","\/419Ca1V6HZL._SL500_.jpg","\/41zQkYyLPzL._SL500_.jpg","\/41YpHcyxiTL._SL500_.jpg","\/41-tKN5mt6L._SL500_.jpg","\/419Mv6m55IL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815631085","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815631085","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"E8MM1","s":"s"});</script></p>
<div id="msmaflink-E8MM1">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p><p>The post <a href="https://caymezon.com/aws-handson-console-rekognition-image-pipeline/">AWSコンソールだけで画像認識パイプラインを構築する手順【S3 + Lambda + Rekognition / SAM版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-console-rekognition-image-pipeline/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>AWSコンソールだけでSNS + SQS + Lambda 通知システムを構築する手順【Pub/Sub・ファンアウト・DLQ / SAM版との比較付き】</title>
		<link>https://caymezon.com/aws-handson-console-sns-sqs-lambda/</link>
					<comments>https://caymezon.com/aws-handson-console-sns-sqs-lambda/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Sun, 08 Mar 2026 00:44:37 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[AWSコンソール]]></category>
		<category><![CDATA[DLQ]]></category>
		<category><![CDATA[Lambda]]></category>
		<category><![CDATA[Pub/Sub]]></category>
		<category><![CDATA[SAM比較]]></category>
		<category><![CDATA[SNS]]></category>
		<category><![CDATA[SQS]]></category>
		<category><![CDATA[サーバーレス]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[ファンアウト]]></category>
		<category><![CDATA[初心者]]></category>
		<category><![CDATA[通知システム]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20243</guid>

					<description><![CDATA[<p>目次 はじめにキーワード解説使用するAWSサービス全体の作業順序① SNS Topic を作成する② SQS キューを3つ作成する2-1. AlertDLQ（デッドレターキュー）を先に作成する2-2. LogQueue  [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-console-sns-sqs-lambda/">AWSコンソールだけでSNS + SQS + Lambda 通知システムを構築する手順【Pub/Sub・ファンアウト・DLQ / SAM版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-14" checked><label class="toc-title" for="toc-checkbox-14">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">キーワード解説</a></li><li><a href="#toc3" tabindex="0">使用するAWSサービス</a></li><li><a href="#toc4" tabindex="0">全体の作業順序</a></li><li><a href="#toc5" tabindex="0">① SNS Topic を作成する</a></li><li><a href="#toc6" tabindex="0">② SQS キューを3つ作成する</a><ol><li><a href="#toc7" tabindex="0">2-1. AlertDLQ（デッドレターキュー）を先に作成する</a></li><li><a href="#toc8" tabindex="0">2-2. LogQueue を作成する（フィルターなし・全メッセージ用）</a></li><li><a href="#toc9" tabindex="0">2-3. AlertQueue を作成する（フィルターあり・アラート用）</a></li></ol></li><li><a href="#toc10" tabindex="0">③ SNS → SQS サブスクリプションを2つ作成する</a><ol><li><a href="#toc11" tabindex="0">3-1. LogQueue サブスクリプション（フィルターなし）</a></li><li><a href="#toc12" tabindex="0">3-2. AlertQueue サブスクリプション（フィルターあり）</a></li></ol></li><li><a href="#toc13" tabindex="0">④ Lambda 関数を2つ作成する</a><ol><li><a href="#toc14" tabindex="0">4-1. LogFunction（全ログ処理）</a></li><li><a href="#toc15" tabindex="0">4-2. AlertFunction（アラート処理・DLQ テスト機能付き）</a></li></ol></li><li><a href="#toc16" tabindex="0">⑤ SQS トリガーを各 Lambda に追加する</a><ol><li><a href="#toc17" tabindex="0">5-1. LogFunction に LogQueue トリガーを追加する</a></li><li><a href="#toc18" tabindex="0">5-2. AlertFunction に AlertQueue トリガーを追加する</a></li></ol></li><li><a href="#toc19" tabindex="0">⑥ 動作テスト</a><ol><li><a href="#toc20" tabindex="0">テスト1: level=info（LogFunction のみ受信）</a></li><li><a href="#toc21" tabindex="0">テスト2: level=warning（両 Lambda が受信 ＝ ファンアウト）</a></li><li><a href="#toc22" tabindex="0">テスト3: level=warning + body=error（AlertFunction 失敗 → DLQ）</a></li></ol></li><li><a href="#toc23" tabindex="0">⑦ リソースの削除</a><ol><li><a href="#toc24" tabindex="0">1. Lambda のトリガーを削除する</a></li><li><a href="#toc25" tabindex="0">2. Lambda 関数を削除する</a></li><li><a href="#toc26" tabindex="0">3. SNS サブスクリプションを削除する</a></li><li><a href="#toc27" tabindex="0">4. SNS Topic を削除する</a></li><li><a href="#toc28" tabindex="0">5. SQS キューを3つ削除する</a></li><li><a href="#toc29" tabindex="0">6. IAM ロールを削除する（任意）</a></li><li><a href="#toc30" tabindex="0">7. CloudWatch Logs のロググループを削除する（任意）</a></li></ol></li><li><a href="#toc31" tabindex="0">SAMとの対比</a></li><li><a href="#toc32" tabindex="0">トラブルシューティング</a></li><li><a href="#toc33" tabindex="0">まとめ</a><ol><li><a href="#toc34" tabindex="0">コンソール版で実感できたポイント</a></li></ol></li><li><a href="#toc35" tabindex="0">コンソール版と SAM 版を比較してみる</a></li><li><a href="#toc36" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>「1回メッセージを送るだけで、複数のシステムに同時に通知したい」——そんな要件を実現する設計パターンが <strong>Pub/Sub（パブリッシュ・サブスクライブ）</strong> と <strong>ファンアウト</strong> です。</p>
<p>この記事では、<strong>AWSコンソールのみ</strong>を使って、SNS + SQS + Lambda による通知システムをゼロから構築するハンズオンを紹介します。</p>
<pre><code class="language-plaintext">Publisher（aws sns publish）
  ↓ メッセージを1回発行するだけ
SNS Topic（NotificationTopic）
  │
  ├─ サブスクリプション（フィルターなし）
  │    → LogQueue → LogFunction → CloudWatch Logs（全メッセージを記録）
  │
  └─ サブスクリプション（level=warning/critical のみ）
       → AlertQueue → AlertFunction → CloudWatch Logs（アラート処理）
                          ↓ 処理失敗（3回）
                        AlertDLQ</code></pre>
<p><strong>このハンズオンで体験できること：</strong></p>
<ul>
<li><strong>Pub/Sub パターン</strong> — Publisher と Subscriber が疎結合で通信する仕組み</li>
<li><strong>ファンアウト</strong> — 1回の publish で複数の Lambda が並行して動作する体験</li>
<li><strong>SNS フィルターポリシー</strong> — メッセージ属性で配信先を絞り込む設定</li>
<li><strong>DLQ（デッドレターキュー）</strong> — 処理失敗メッセージの退避先を実際に確認</li>
</ul>
<hr>
<blockquote>
<p><strong>この記事は <a href="#">SAM版ハンズオン</a> の比較記事です。</strong><br />コンソール操作で SNS・SQS・Lambda の連携を視覚的に学び、SAM と何が違うのかを比較したい方向けです。</p>
</blockquote>
<hr>
<p><a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"></p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWSの基本・仕組み・重要用語が全部わかる教科書 (見るだけ図解)","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51DEDQXj6oL._SL500_.jpg","\/41F589smNwL._SL500_.jpg","\/41R6f9yyCWL._SL500_.jpg","\/41HqWQ9BvmL._SL500_.jpg","\/41p8p0ZU79L._SL500_.jpg","\/41qLC-fndBL._SL500_.jpg","\/41fcLv9VT5L._SL500_.jpg","\/51lRvCsvHqL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815607850","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815607850","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"eaCUB","s":"s"});</script></p>
<div id="msmaflink-eaCUB">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p>
<h2><span id="toc2">キーワード解説</span></h2>
<table>
<thead>
<tr>
<th>用語</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>SNS Topic</strong></td>
<td>メッセージの送信先。複数のサブスクライバーに同時配信できる</td>
</tr>
<tr>
<td><strong>サブスクリプション</strong></td>
<td>Topic からメッセージを受け取るエンドポイントの設定</td>
</tr>
<tr>
<td><strong>Pub/Sub</strong></td>
<td>Publisher（発行者）と Subscriber（購読者）が疎結合で通信するパターン</td>
</tr>
<tr>
<td><strong>ファンアウト</strong></td>
<td>1つのメッセージを複数の宛先に同時配信するパターン</td>
</tr>
<tr>
<td><strong>フィルターポリシー</strong></td>
<td>メッセージ属性に基づき、配信するかどうかを制御するルール</td>
</tr>
<tr>
<td><strong>DLQ（デッドレターキュー）</strong></td>
<td>処理に失敗したメッセージを退避させるキュー</td>
</tr>
<tr>
<td><strong>SNS エンベロープ</strong></td>
<td>SNS が SQS に配信する際にメッセージを包む JSON 構造</td>
</tr>
<tr>
<td><strong>可視性タイムアウト</strong></td>
<td>SQS がメッセージを処理中に他のコンシューマーから見えなくする時間</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc3">使用するAWSサービス</span></h2>
<table>
<thead>
<tr>
<th>サービス</th>
<th>役割</th>
<th>料金</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>SNS</strong></td>
<td>メッセージの発行・ファンアウト配信</td>
<td>月100万リクエストまで無料</td>
</tr>
<tr>
<td><strong>SQS</strong></td>
<td>メッセージキューイング（LogQueue / AlertQueue / AlertDLQ）</td>
<td>月100万リクエストまで無料</td>
</tr>
<tr>
<td><strong>Lambda</strong></td>
<td>キューからメッセージを受信して処理（LogFunction / AlertFunction）</td>
<td>月100万リクエスト・400,000 GB-秒まで無料</td>
</tr>
<tr>
<td><strong>IAM</strong></td>
<td>Lambda の実行権限管理</td>
<td>無料</td>
</tr>
<tr>
<td><strong>CloudWatch Logs</strong></td>
<td>Lambda の実行ログ</td>
<td>月5GBまで無料</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc4">全体の作業順序</span></h2>
<pre><code class="language-plaintext">① SNS Topic を作成する
      ↓
② SQS キューを3つ作成する（AlertDLQ / LogQueue / AlertQueue）
      ↓
③ SNS → SQS サブスクリプションを2つ作成する
  （LogQueue: フィルターなし / AlertQueue: フィルターあり）
      ↓
④ Lambda 関数を2つ作成する
      ↓
⑤ SQS トリガーを各 Lambda に追加する
      ↓
⑥ 動作テスト（3パターン）
      ↓
⑦ リソースの削除</code></pre>
<blockquote>
<p><strong>AlertDLQ を先に作成する理由：</strong><br />AlertQueue の作成時に DLQ として AlertDLQ の ARN を指定するため、AlertDLQ を先に作る必要があります。</p>
</blockquote>
<hr>
<h2><span id="toc5">① SNS Topic を作成する</span></h2>
<p><strong>AWSコンソール → SNS → 「トピック」→「トピックを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>タイプ</td>
<td><strong>スタンダード</strong></td>
</tr>
<tr>
<td>名前</td>
<td><code>NotificationTopic</code></td>
</tr>
</tbody>
</table>
<p>その他の設定はデフォルトのまま。「トピックを作成」をクリック。</p>
<p><strong>控えておく情報:</strong></p>
<ul>
<li><strong>トピック ARN</strong>（例: <code>arn:aws:sns:ap-northeast-1:123456789012:NotificationTopic</code>）</li>
</ul>
<blockquote>
<p><strong>スタンダードとFIFOの違い：</strong><br />スタンダードは順序保証なし・高スループット。FIFO は順序保証あり・1回限りの配信が必要な場合に使用します。今回のログ/アラート通知にはスタンダードが適しています。</p>
</blockquote>
<hr>
<h2><span id="toc6">② SQS キューを3つ作成する</span></h2>
<p><strong>AWSコンソール → SQS → 「キューを作成」</strong></p>
<h3><span id="toc7">2-1. AlertDLQ（デッドレターキュー）を先に作成する</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>タイプ</td>
<td>スタンダード</td>
</tr>
<tr>
<td>名前</td>
<td><code>AlertDLQ</code></td>
</tr>
<tr>
<td>メッセージ保持期間</td>
<td>1 日（学習用なので短く設定）</td>
</tr>
</tbody>
</table>
<p>「キューを作成」をクリック。</p>
<p><strong>控えておく情報:</strong></p>
<ul>
<li><strong>AlertDLQ の ARN</strong>（例: <code>arn:aws:sqs:ap-northeast-1:123456789012:AlertDLQ</code>）</li>
</ul>
<hr>
<h3><span id="toc8">2-2. LogQueue を作成する（フィルターなし・全メッセージ用）</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>タイプ</td>
<td>スタンダード</td>
</tr>
<tr>
<td>名前</td>
<td><code>LogQueue</code></td>
</tr>
<tr>
<td>可視性タイムアウト</td>
<td><strong>180</strong> 秒</td>
</tr>
</tbody>
</table>
<p>「キューを作成」をクリック。</p>
<blockquote>
<p><strong>可視性タイムアウトを 180 秒にする理由：</strong><br />Lambda のデフォルトタイムアウト（3秒）より長く設定することで、処理中に他のコンシューマーがメッセージを二重取得するのを防ぎます。DLQ テストでは 180秒 × 3回 ≒ 9分待つことになります。</p>
</blockquote>
<hr>
<h3><span id="toc9">2-3. AlertQueue を作成する（フィルターあり・アラート用）</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>タイプ</td>
<td>スタンダード</td>
</tr>
<tr>
<td>名前</td>
<td><code>AlertQueue</code></td>
</tr>
<tr>
<td>可視性タイムアウト</td>
<td><strong>180</strong> 秒</td>
</tr>
</tbody>
</table>
<p>「デッドレターキュー」セクション:</p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>デッドレターキューを有効にする</td>
<td><strong>オン</strong></td>
</tr>
<tr>
<td>デッドレターキューの ARN</td>
<td><code>AlertDLQ</code> の ARN を貼り付ける</td>
</tr>
<tr>
<td>最大受信数</td>
<td><strong>3</strong></td>
</tr>
</tbody>
</table>
<p>「キューを作成」をクリック。</p>
<p><strong>控えておく情報:</strong></p>
<ul>
<li><strong>LogQueue の ARN</strong></li>
<li><strong>AlertQueue の ARN</strong></li>
</ul>
<hr>
<h2><span id="toc10">③ SNS → SQS サブスクリプションを2つ作成する</span></h2>
<blockquote>
<p><strong>SQS キューポリシーの自動追加について：</strong><br />コンソールで SNS → SQS サブスクリプションを作成すると、<br />SNS が SQS キューのアクセスポリシーに <code>sns.amazonaws.com</code> からの <code>sqs:SendMessage</code> 権限を自動追加します。<br />手動でのポリシー設定は不要です（SAM版では <code>AWS::SQS::QueuePolicy</code> を明示的に定義する必要があります）。</p>
</blockquote>
<h3><span id="toc11">3-1. LogQueue サブスクリプション（フィルターなし）</span></h3>
<p><strong>SNS → <code>NotificationTopic</code> → 「サブスクリプション」タブ → 「サブスクリプションを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>プロトコル</td>
<td><strong>Amazon SQS</strong></td>
</tr>
<tr>
<td>エンドポイント</td>
<td><code>LogQueue</code> の ARN</td>
</tr>
<tr>
<td>サブスクリプションフィルターポリシー</td>
<td><strong>設定しない</strong>（空欄のまま）</td>
</tr>
</tbody>
</table>
<p>「サブスクリプションを作成」をクリック。</p>
<hr>
<h3><span id="toc12">3-2. AlertQueue サブスクリプション（フィルターあり）</span></h3>
<p><strong>SNS → <code>NotificationTopic</code> → 「サブスクリプション」タブ → 「サブスクリプションを作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>プロトコル</td>
<td><strong>Amazon SQS</strong></td>
</tr>
<tr>
<td>エンドポイント</td>
<td><code>AlertQueue</code> の ARN</td>
</tr>
</tbody>
</table>
<p>「サブスクリプションフィルターポリシー」セクション:</p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>サブスクリプションフィルターポリシー</td>
<td><strong>有効にする</strong></td>
</tr>
<tr>
<td>フィルターポリシーのスコープ</td>
<td><strong>メッセージ属性</strong>（デフォルト）</td>
</tr>
<tr>
<td>JSON エディタ</td>
<td>以下を入力</td>
</tr>
</tbody>
</table>
<pre><code class="language-json">{
  "level": ["warning", "critical"]
}</code></pre>
<blockquote>
<p><strong>フィルターポリシーの意味：</strong><br /><code>level</code> メッセージ属性の値が <code>&quot;warning&quot;</code> または <code>&quot;critical&quot;</code> のメッセージのみ AlertQueue に配信します。<br /><code>level=info</code> のメッセージは AlertQueue に届かない（LogQueue には届く）。</p>
</blockquote>
<blockquote>
<p><strong>よくある間違い（フィルターが動作しない場合）：</strong></p>
<ul>
<li>スコープが「<strong>メッセージ本文</strong>」になっている → **「メッセージ属性」**に変更する</li>
<li>JSON のスペルミス（<code>&quot;warning&quot;</code> のクォートが抜けている等）</li>
</ul>
</blockquote>
<p>「サブスクリプションを作成」をクリック。</p>
<hr>
<h2><span id="toc13">④ Lambda 関数を2つ作成する</span></h2>
<p><strong>AWSコンソール → Lambda → 「関数の作成」</strong>（共通設定）</p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>作成方法</td>
<td>一から作成</td>
</tr>
<tr>
<td>ランタイム</td>
<td><strong>Python 3.12</strong></td>
</tr>
<tr>
<td>アーキテクチャ</td>
<td>x86_64</td>
</tr>
<tr>
<td>実行ロール</td>
<td>「基本的な Lambda アクセス権限で新しいロールを作成」（デフォルトのまま）</td>
</tr>
</tbody>
</table>
<p>コードを貼り付けたあと、必ず <strong>「Deploy」</strong> ボタンを押してコードを保存します。</p>
<hr>
<h3><span id="toc14">4-1. LogFunction（全ログ処理）</span></h3>
<p><strong>関数名</strong>: <code>LogFunction</code></p>
<p>コードエディタで <code>lambda_function.py</code> を開き、以下を貼り付けて「Deploy」をクリック。</p>
<pre><code class="language-python">import json


def lambda_handler(event, context):
    results = []

    for record in event["Records"]:
        sns_envelope = json.loads(record["body"])
        message = sns_envelope["Message"]  # 実際のメッセージ本文
        attributes = sns_envelope.get("MessageAttributes", {})
        level = attributes.get("level", {}).get("Value", "info")

        result = {
            "queue": "log",
            "level": level,
            "message": message,
        }
        print(json.dumps(result, ensure_ascii=False))
        results.append(result)

    print(json.dumps({"processedCount": len(results)}, ensure_ascii=False))
    return {"processedCount": len(results)}</code></pre>
<blockquote>
<p><strong><code>json.loads(record[&quot;body&quot;])</code> が必要な理由：</strong><br />SNS → SQS 配信では、SQS のメッセージボディに <strong>SNS エンベロープ</strong>（JSON文字列）が格納されます。<br />そのため <code>record[&quot;body&quot;]</code> はそのまま使えず、<code>json.loads</code> でパースする必要があります。</p>
<pre><code class="language-json">{
  "Type": "Notification",
  "TopicArn": "arn:aws:sns:...:NotificationTopic",
  "Message": "警告メッセージ",
  "MessageAttributes": {
    "level": {"Type": "String", "Value": "warning"}
  }
}</code></pre>
</blockquote>
<hr>
<h3><span id="toc15">4-2. AlertFunction（アラート処理・DLQ テスト機能付き）</span></h3>
<p><strong>関数名</strong>: <code>AlertFunction</code></p>
<pre><code class="language-python">import json


def lambda_handler(event, context):
    results = []

    for record in event["Records"]:
        sns_envelope = json.loads(record["body"])
        message = sns_envelope["Message"]
        attributes = sns_envelope.get("MessageAttributes", {})
        level = attributes.get("level", {}).get("Value", "unknown")

        # DLQテスト用: "error" というメッセージを受信したら意図的に例外発生
        if message.strip().lower() == "error":
            raise ValueError(
                f"アラート処理に失敗: level={level}, message={message}"
            )

        result = {
            "queue": "alert",
            "level": level,
            "message": message,
            "alert_triggered": True,
        }
        print(json.dumps(result, ensure_ascii=False))
        results.append(result)

    print(json.dumps({"processedCount": len(results)}, ensure_ascii=False))
    return {"processedCount": len(results)}</code></pre>
<blockquote>
<p><strong>DLQ テストのしくみ：</strong><br /><code>message == &quot;error&quot;</code> のとき意図的に <code>ValueError</code> を発生させています。<br />SQS は処理失敗を検知してメッセージをキューに戻し、可視性タイムアウト（180秒）後に再試行します。<br />これを3回繰り返すと <code>AlertDLQ</code> に移動します。</p>
</blockquote>
<hr>
<h2><span id="toc16">⑤ SQS トリガーを各 Lambda に追加する</span></h2>
<h3><span id="toc17">5-1. LogFunction に LogQueue トリガーを追加する</span></h3>
<p><strong>Lambda → <code>LogFunction</code> → 「設定」タブ → 「トリガー」→「トリガーを追加」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>ソース</td>
<td><strong>SQS</strong></td>
</tr>
<tr>
<td>SQS キュー</td>
<td><code>LogQueue</code></td>
</tr>
<tr>
<td>バッチサイズ</td>
<td><strong>5</strong></td>
</tr>
<tr>
<td>トリガーの有効化</td>
<td>オン</td>
</tr>
</tbody>
</table>
<p>「追加」をクリック。</p>
<p><strong>権限の追加:</strong></p>
<p>Lambda → <code>LogFunction</code> → 「設定」タブ → 「アクセス権限」→ 実行ロール名をクリック（IAM コンソールへ）<br />→「許可を追加」→「ポリシーをアタッチ」→ <code>AWSLambdaSQSQueueExecutionRole</code> をアタッチ。</p>
<blockquote>
<p><strong><code>AWSLambdaSQSQueueExecutionRole</code> が必要な理由：</strong><br />Lambda が SQS からメッセージを受信（<code>sqs:ReceiveMessage</code>）・削除（<code>sqs:DeleteMessage</code>）するために必要な権限がまとまったポリシーです。これがないと Lambda がメッセージを取得できません。</p>
</blockquote>
<hr>
<h3><span id="toc18">5-2. AlertFunction に AlertQueue トリガーを追加する</span></h3>
<p><strong>Lambda → <code>AlertFunction</code> → 「設定」タブ → 「トリガー」→「トリガーを追加」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>ソース</td>
<td><strong>SQS</strong></td>
</tr>
<tr>
<td>SQS キュー</td>
<td><code>AlertQueue</code></td>
</tr>
<tr>
<td>バッチサイズ</td>
<td><strong>1</strong></td>
</tr>
<tr>
<td>トリガーの有効化</td>
<td>オン</td>
</tr>
</tbody>
</table>
<p>「追加」をクリック。権限の追加（<code>AWSLambdaSQSQueueExecutionRole</code>）も同様に実施する。</p>
<blockquote>
<p><strong>AlertFunction のバッチサイズを 1 にする理由：</strong><br />1件ずつ処理することで、1件が失敗しても他のメッセージに影響が出ません。<br />DLQ へ移動するメッセージを1件に限定できるため、テストが分かりやすくなります。</p>
</blockquote>
<hr>
<h2><span id="toc19">⑥ 動作テスト</span></h2>
<p>3つのシナリオで SNS フィルター・ファンアウト・DLQ の動作を確認します。</p>
<table>
<thead>
<tr>
<th>テスト</th>
<th>メッセージ属性</th>
<th>LogFunction</th>
<th>AlertFunction</th>
<th>確認ポイント</th>
</tr>
</thead>
<tbody>
<tr>
<td>テスト1</td>
<td><code>level=info</code></td>
<td>処理 ✓</td>
<td>処理しない</td>
<td><strong>フィルター</strong>動作</td>
</tr>
<tr>
<td>テスト2</td>
<td><code>level=warning</code></td>
<td>処理 ✓</td>
<td>処理 ✓</td>
<td><strong>ファンアウト</strong>（1発行→2Lambda）</td>
</tr>
<tr>
<td>テスト3</td>
<td><code>level=warning</code> + body=<code>error</code></td>
<td>処理 ✓</td>
<td>失敗→DLQ</td>
<td><strong>DLQ</strong> 動作</td>
</tr>
</tbody>
</table>
<hr>
<h3><span id="toc20">テスト1: level=info（LogFunction のみ受信）</span></h3>
<pre><code class="language-cmd">aws sns publish ^
  --topic-arn arn:aws:sns:ap-northeast-1:123456789012:NotificationTopic ^
  --message "情報メッセージ" ^
  --message-attributes "{\"level\":{\"DataType\":\"String\",\"StringValue\":\"info\"}}" ^
  --region ap-northeast-1</code></pre>
<blockquote>
<p><code>123456789012</code> を自分のアカウントIDに置き換えてください。</p>
</blockquote>
<p><strong>期待する動作:</strong></p>
<ul>
<li><code>LogFunction</code> が処理 → CloudWatch Logs にログが記録される</li>
<li><code>AlertFunction</code> は動作しない（フィルターで除外）</li>
</ul>
<p><strong>CloudWatch Logs で確認:</strong></p>
<p>Lambda → <code>LogFunction</code> → 「モニタリング」タブ → 「CloudWatch Logs を表示」</p>
<pre><code class="language-json">{"queue": "log", "level": "info", "message": "情報メッセージ"}
{"processedCount": 1}</code></pre>
<hr>
<h3><span id="toc21">テスト2: level=warning（両 Lambda が受信 ＝ ファンアウト）</span></h3>
<pre><code class="language-cmd">aws sns publish ^
  --topic-arn arn:aws:sns:ap-northeast-1:123456789012:NotificationTopic ^
  --message "警告メッセージ" ^
  --message-attributes "{\"level\":{\"DataType\":\"String\",\"StringValue\":\"warning\"}}" ^
  --region ap-northeast-1</code></pre>
<p><strong>期待する動作:</strong></p>
<ul>
<li><code>LogFunction</code> が処理（<code>level=warning</code> を受信）</li>
<li><code>AlertFunction</code> も処理（フィルターを通過）</li>
<li><strong>1回の publish で 2つの Lambda が並行して動作する</strong> ← ファンアウトのポイント</li>
</ul>
<p><strong>LogFunction のログ:</strong></p>
<pre><code class="language-json">{"queue": "log", "level": "warning", "message": "警告メッセージ"}</code></pre>
<p><strong>AlertFunction のログ:</strong></p>
<pre><code class="language-json">{"queue": "alert", "level": "warning", "message": "警告メッセージ", "alert_triggered": true}</code></pre>
<p><!-- ![ファンアウト動作確認：LogFunction と AlertFunction が同時に実行](images/fanout-both-lambda.jpg) --></p>
<hr>
<h3><span id="toc22">テスト3: level=warning + body=error（AlertFunction 失敗 → DLQ）</span></h3>
<pre><code class="language-cmd">aws sns publish ^
  --topic-arn arn:aws:sns:ap-northeast-1:123456789012:NotificationTopic ^
  --message "error" ^
  --message-attributes "{\"level\":{\"DataType\":\"String\",\"StringValue\":\"warning\"}}" ^
  --region ap-northeast-1</code></pre>
<p><strong>期待する動作:</strong></p>
<ul>
<li><code>LogFunction</code> → 正常処理（<code>message=error</code> でも例外なし）</li>
<li><code>AlertFunction</code> → <code>ValueError</code> 発生</li>
<li>AlertQueue の可視性タイムアウト（180秒）後に再試行 × 3回 → <code>AlertDLQ</code> に移動</li>
</ul>
<blockquote>
<p><strong>DLQ に移動するまでの待機時間:</strong> 最大 180秒 × 3回 ≒ 9分かかります。<br />CloudWatch Logs で <code>AlertFunction</code> に <code>[ERROR] ValueError</code> が 3回記録されたことを確認してから DLQ をポーリングするとよいです。</p>
</blockquote>
<p><strong>DLQ にメッセージが届いたか確認:</strong></p>
<p>SQS → <code>AlertDLQ</code> → 「メッセージを送受信」→「メッセージをポーリング」</p>
<p><code>&quot;error&quot;</code> のメッセージ（SNS エンベロープ形式）が表示されれば DLQ 動作確認完了。</p>
<p><!-- ![AlertDLQ にメッセージが届いた様子](images/dlq-message-arrived.jpg) --></p>
<hr>
<h2><span id="toc23">⑦ リソースの削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ず削除してください。</strong></p>
<h3><span id="toc24">1. Lambda のトリガーを削除する</span></h3>
<ul>
<li><strong>Lambda → <code>LogFunction</code> → 「設定」→「トリガー」→ SQS トリガーを削除</strong></li>
<li><strong>Lambda → <code>AlertFunction</code> → 同様に削除</strong></li>
</ul>
<h3><span id="toc25">2. Lambda 関数を削除する</span></h3>
<ul>
<li><code>LogFunction</code> / <code>AlertFunction</code> を削除</li>
</ul>
<h3><span id="toc26">3. SNS サブスクリプションを削除する</span></h3>
<p><strong>SNS → <code>NotificationTopic</code> → 「サブスクリプション」タブ → 2つのサブスクリプションを削除</strong></p>
<h3><span id="toc27">4. SNS Topic を削除する</span></h3>
<p><strong>SNS → トピック → <code>NotificationTopic</code> → 「削除」</strong></p>
<h3><span id="toc28">5. SQS キューを3つ削除する</span></h3>
<p><strong>SQS → <code>LogQueue</code> / <code>AlertQueue</code> / <code>AlertDLQ</code> を各々削除</strong></p>
<h3><span id="toc29">6. IAM ロールを削除する（任意）</span></h3>
<p><strong>IAM → ロール → <code>LogFunction-role-XXXX</code> / <code>AlertFunction-role-XXXX</code> を削除</strong></p>
<h3><span id="toc30">7. CloudWatch Logs のロググループを削除する（任意）</span></h3>
<p><strong>CloudWatch → ロググループ → <code>/aws/lambda/LogFunction</code> / <code>/aws/lambda/AlertFunction</code> を削除</strong></p>
<blockquote>
<p><strong>SAM版との大きな違い（SAMのメリット）：</strong><br />SAM版では <code>sam delete</code> 1コマンドで上記すべてのリソースを一括削除できます。</p>
</blockquote>
<hr>
<h2><span id="toc31">SAMとの対比</span></h2>
<table>
<thead>
<tr>
<th>SAMの記述</th>
<th>コンソールでやること</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>AWS::SNS::Topic</code></td>
<td>SNS → トピックを作成</td>
</tr>
<tr>
<td><code>AWS::SQS::QueuePolicy</code></td>
<td>SNS サブスクリプション作成時に<strong>自動追加</strong>される</td>
</tr>
<tr>
<td><code>AWS::SNS::Subscription</code></td>
<td>SNS → サブスクリプションを作成（フィルターポリシー含む）</td>
</tr>
<tr>
<td><code>FilterPolicy: &#39;{&quot;level&quot;: ...}&#39;</code></td>
<td>サブスクリプション作成時の「フィルターポリシー」に JSON を入力</td>
</tr>
<tr>
<td><code>SQSPollerPolicy</code> × 2</td>
<td>Lambda の IAM ロールに <code>AWSLambdaSQSQueueExecutionRole</code> をアタッチ</td>
</tr>
<tr>
<td><code>sam delete</code></td>
<td>SNS / SQS × 3 / Lambda × 2 / IAM / ロググループを個別に削除</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>コンソール版の最大のつまずきポイント：</strong><br />SNS の「サブスクリプション」を作り忘れると、SNS publish しても SQS キューにメッセージが届きません。<br />「キューにメッセージが来ない」と感じたら、まずサブスクリプションが正しく作成されているか確認しましょう。</p>
</blockquote>
<hr>
<h2><span id="toc32">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td>SNS publish してもキューにメッセージが来ない</td>
<td><strong>SNS サブスクリプションが未作成</strong></td>
<td>SNS → <code>NotificationTopic</code> → 「サブスクリプション」タブで2つ作成されているか確認</td>
</tr>
<tr>
<td>SNS publish してもキューにメッセージが来ない（その2）</td>
<td>SQS キューポリシーが設定されていない</td>
<td>SQS → キュー → 「アクセスポリシー」タブで <code>sns.amazonaws.com</code> からの <code>sqs:SendMessage</code> があるか確認</td>
</tr>
<tr>
<td><code>level=warning</code> でも AlertQueue に届かない</td>
<td>フィルターポリシーのスコープが「メッセージ本文」になっている</td>
<td>SNS → サブスクリプション → フィルターポリシーのスコープを**「メッセージ属性」**に変更</td>
</tr>
<tr>
<td>Lambda が実行されない</td>
<td>SQS トリガーが設定されていない</td>
<td>⑤ の手順でトリガーを追加する</td>
</tr>
<tr>
<td>Lambda が実行されない（SQS権限エラー）</td>
<td><code>AWSLambdaSQSQueueExecutionRole</code> がアタッチされていない</td>
<td>⑤ の権限追加手順を実施する</td>
</tr>
<tr>
<td>DLQ にメッセージが届かない</td>
<td>可視性タイムアウト（180秒）× 3回 の待機中</td>
<td>最大 9分待つ。CloudWatch Logs で 3回の ERROR ログを確認してからポーリング</td>
</tr>
<tr>
<td>SNS エンベロープの構造が分からない</td>
<td>Lambda のコードで <code>print(record[&quot;body&quot;])</code> して CloudWatch Logs で確認する</td>
<td></td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc33">まとめ</span></h2>
<p>今回のハンズオンで体験できたこと：</p>
<table>
<thead>
<tr>
<th>確認項目</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Pub/Sub パターン</strong></td>
<td>Publisher は誰が受け取るか知らずに SNS Topic に発行するだけ。Subscriber（SQS）が購読して処理</td>
</tr>
<tr>
<td><strong>ファンアウト</strong></td>
<td><code>level=warning</code> の1回の publish で LogFunction と AlertFunction の両方が並行して動作</td>
</tr>
<tr>
<td><strong>SNS フィルターポリシー</strong></td>
<td><code>level=info</code> は LogQueue のみ配信、<code>level=warning/critical</code> は両キューに配信</td>
</tr>
<tr>
<td><strong>DLQ</strong></td>
<td>AlertFunction が 3回失敗したメッセージが AlertDLQ に退避</td>
</tr>
</tbody>
</table>
<h3><span id="toc34">コンソール版で実感できたポイント</span></h3>
<ul>
<li>SNS Topic / SQS キュー / Lambda という3つのリソースの<strong>組み合わせ方</strong>が視覚的に理解できる</li>
<li>SNS サブスクリプションのフィルターポリシーJSON を直接入力することで、ルールの書き方が身につく</li>
<li>リソースを1つずつ作成することで、各サービスの役割と依存関係が明確になる</li>
</ul>
<hr>
<h2><span id="toc35">コンソール版と SAM 版を比較してみる</span></h2>
<p>コンソールで SNS + SQS + Lambda の連携を理解したら、SAM で同じ構成をコードで定義することで「SAM が何を自動化しているか」が明確になります。<code>AWS::SQS::QueuePolicy</code> の明示的な記述や <code>SQSPollerPolicy</code> によるワンライン権限付与など、コンソールでの手動操作がコードに対応しています。</p>
<p><!-- TODO: SAM版記事へのリンクを追加 --></p>
<hr>
<h2><span id="toc36">関連記事</span></h2>
<p><a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"></p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWS運用入門 改訂第2版 押さえておきたいAWSの基本と運用ノウハウ [AWS深掘りガイド]","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51AAOubymTL._SL500_.jpg","\/51VMG6YKHdL._SL500_.jpg","\/41EdPB8azAL._SL500_.jpg","\/41v2JFE-9jL._SL500_.jpg","\/41FEEqR-yDL._SL500_.jpg","\/41JfZAdnTPL._SL500_.jpg","\/41vGK0czQrL._SL500_.jpg","\/41-SnYtz2aL._SL500_.jpg","\/41sPrV5fi3L._SL500_.jpg","\/41p7JtvYJ1L._SL500_.jpg","\/4169GVNTs8L._SL500_.jpg","\/41BPI5HP3zL._SL500_.jpg","\/41QOyk60CYL._SL500_.jpg","\/41APjk6FphL._SL500_.jpg","\/41ezKUu7VRL._SL500_.jpg","\/41A1n3K+r5L._SL500_.jpg","\/41aY2T8lEOL._SL500_.jpg","\/419Ca1V6HZL._SL500_.jpg","\/41zQkYyLPzL._SL500_.jpg","\/41YpHcyxiTL._SL500_.jpg","\/41-tKN5mt6L._SL500_.jpg","\/419Mv6m55IL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815631085","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815631085","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"E8MM1","s":"s"});</script></p>
<div id="msmaflink-E8MM1">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p><p>The post <a href="https://caymezon.com/aws-handson-console-sns-sqs-lambda/">AWSコンソールだけでSNS + SQS + Lambda 通知システムを構築する手順【Pub/Sub・ファンアウト・DLQ / SAM版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-console-sns-sqs-lambda/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>AWSコンソールだけでStep Functions + Lambdaワークフローを構築する手順【SAM版との比較付き / 新UI対応】</title>
		<link>https://caymezon.com/aws-handson-console-step-functions-lambda/</link>
					<comments>https://caymezon.com/aws-handson-console-step-functions-lambda/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Sun, 01 Mar 2026 05:25:15 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[AWSコンソール]]></category>
		<category><![CDATA[Lambda]]></category>
		<category><![CDATA[SAM比較]]></category>
		<category><![CDATA[StepFunctions]]></category>
		<category><![CDATA[エラー処理]]></category>
		<category><![CDATA[ステートマシン]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[ワークフロー]]></category>
		<category><![CDATA[並列処理]]></category>
		<category><![CDATA[初心者]]></category>
		<category><![CDATA[新UI]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20229</guid>

					<description><![CDATA[<p>目次 はじめにStep Functions 新UIで戸惑いやすいポイント（先読み）キーワード解説前提条件使用するAWSサービス全体の作業順序① Lambda 関数を5つ作成する共通手順1-1. ValidateFunct [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-console-step-functions-lambda/">AWSコンソールだけでStep Functions + Lambdaワークフローを構築する手順【SAM版との比較付き / 新UI対応】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-16" checked><label class="toc-title" for="toc-checkbox-16">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">Step Functions 新UIで戸惑いやすいポイント（先読み）</a></li><li><a href="#toc3" tabindex="0">キーワード解説</a></li><li><a href="#toc4" tabindex="0">前提条件</a></li><li><a href="#toc5" tabindex="0">使用するAWSサービス</a></li><li><a href="#toc6" tabindex="0">全体の作業順序</a></li><li><a href="#toc7" tabindex="0">① Lambda 関数を5つ作成する</a><ol><li><a href="#toc8" tabindex="0">共通手順</a></li><li><a href="#toc9" tabindex="0">1-1. ValidateFunction（注文検証）</a></li><li><a href="#toc10" tabindex="0">1-2. InventoryFunction（在庫確認）</a></li><li><a href="#toc11" tabindex="0">1-3. PaymentFunction（支払い処理）</a></li><li><a href="#toc12" tabindex="0">1-4. ConfirmFunction（注文確定）</a></li><li><a href="#toc13" tabindex="0">1-5. ErrorHandlerFunction（エラー処理）</a></li></ol></li><li><a href="#toc14" tabindex="0">② Step Functions ステートマシンを作成する</a><ol><li><a href="#toc15" tabindex="0">2-1. 作成方法の選択（新UI：3択モーダル）</a></li><li><a href="#toc16" tabindex="0">2-2. 名前とタイプの設定（モーダル）</a></li><li><a href="#toc17" tabindex="0">2-3. ASL の入力（「{ } コード」タブ）</a></li><li><a href="#toc18" tabindex="0">2-4. 実行ロールの確認と作成（「設定」タブ）</a></li></ol></li><li><a href="#toc19" tabindex="0">③ 動作テスト</a><ol><li><a href="#toc20" tabindex="0">テスト1: 正常処理</a></li><li><a href="#toc21" tabindex="0">テスト2: 在庫切れエラー（Parallel Catch の確認）</a></li><li><a href="#toc22" tabindex="0">テスト3: 支払い失敗エラー（Parallel Catch の確認）</a></li><li><a href="#toc23" tabindex="0">テスト4: 検証エラー（ValidateOrder Retry + Catch の確認）</a></li></ol></li><li><a href="#toc24" tabindex="0">④ リソースの削除</a><ol><li><a href="#toc25" tabindex="0">1. ステートマシンを削除する</a></li><li><a href="#toc26" tabindex="0">2. Lambda 関数を5つ削除する</a></li><li><a href="#toc27" tabindex="0">3. IAM ロールを削除する（任意）</a></li><li><a href="#toc28" tabindex="0">4. CloudWatch Logs のロググループを削除する（任意）</a></li></ol></li><li><a href="#toc29" tabindex="0">SAMとの対比</a></li><li><a href="#toc30" tabindex="0">トラブルシューティング</a></li><li><a href="#toc31" tabindex="0">まとめ</a></li><li><a href="#toc32" tabindex="0">コンソール版とSAM版を比較してみる</a></li><li><a href="#toc33" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>「複数のLambda関数を順番に呼び出したい」「エラーが起きたとき自動でリトライして、それでも失敗したら別の処理に切り替えたい」という要件を、<strong>AWS Step Functions</strong> は視覚的なフロー定義で実現します。</p>
<p>この記事では、<strong>AWSコンソールのみ</strong>を使って、受注処理ワークフロー（注文検証 → 在庫確認・支払い並列処理 → 注文確定）をゼロから構築するハンズオンを紹介します。</p>
<pre><code class="language-plaintext">入力: 注文データ（order_id / item_id / quantity）
  ↓
[ValidateOrder] 注文検証 ... Task + Retry + Catch
  ↓ 成功
[ProcessInParallel] 並列処理 ... Parallel + Catch
  ├─ [CheckInventory] 在庫確認
  └─ [ProcessPayment] 支払い処理
  ↓ 成功
[ConfirmOrder] 注文確定
  ↓
終了（成功）

[HandleError] エラー処理（Catch 先）
  ↓
終了（エラー通知済み）</code></pre>
<p><strong>このハンズオンで体験できること：</strong></p>
<ul>
<li>Step Functions の <strong>Task / Parallel / Retry / Catch</strong> という基本パターン</li>
<li>並列ブランチの結果をリストとして次のステートに渡す仕組み</li>
<li><strong>Workflow Studio（新UI）</strong> の操作方法 — ビジュアルエディタと ASL コードエディタの関係</li>
<li><code>ResultPath: &quot;$.error&quot;</code> でエラー情報を元の入力にマージして後続ステートに渡すテクニック</li>
</ul>
<hr>
<blockquote>
<p><strong>この記事は <a href="#">SAM版ハンズオン</a> の比較記事です。</strong><br />コンソール操作でStep Functionsの概念を視覚的に学び、SAMと何が違うのかを比較したい方向けです。</p>
</blockquote>
<hr>
<p><a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"></p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWSの基本・仕組み・重要用語が全部わかる教科書 (見るだけ図解)","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51DEDQXj6oL._SL500_.jpg","\/41F589smNwL._SL500_.jpg","\/41R6f9yyCWL._SL500_.jpg","\/41HqWQ9BvmL._SL500_.jpg","\/41p8p0ZU79L._SL500_.jpg","\/41qLC-fndBL._SL500_.jpg","\/41fcLv9VT5L._SL500_.jpg","\/51lRvCsvHqL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815607850","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815607850","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"eaCUB","s":"s"});</script></p>
<div id="msmaflink-eaCUB">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p>
<h2><span id="toc2">Step Functions 新UIで戸惑いやすいポイント（先読み）</span></h2>
<p>操作を始める前に、<strong>2026年時点の新UI</strong>と旧UIの違いを把握しておきましょう。</p>
<table>
<thead>
<tr>
<th>変更点</th>
<th>旧UI</th>
<th>新UI（現在）</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>作成モーダル</strong></td>
<td>「空白のステートマシン」テンプレートを選択</td>
<td><strong>3択モーダル</strong> が表示される</td>
</tr>
<tr>
<td><strong>作成選択肢</strong></td>
<td>テンプレートギャラリーのみ</td>
<td><strong>「自分で作成する」</strong>「Hello World を実行」「テンプレートを選択」の3択</td>
</tr>
<tr>
<td><strong>ASL入力の場所</strong></td>
<td>作成フォームに「コード」タブ</td>
<td><strong>Workflow Studio 内の「{ } コード」タブ</strong></td>
</tr>
<tr>
<td><strong>ロール設定タイミング</strong></td>
<td>ASL入力と同じ画面</td>
<td><strong>「設定」タブ</strong>で別途確認</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>最大のハマりポイント：</strong><br />「テンプレートを選択」を押してしまうと36個のテンプレートギャラリーが開きます。今回の目的には <strong>「自分で作成する」</strong> を選ぶ必要があります。これを知らずに迷う人が多いポイントです。</p>
</blockquote>
<hr>
<h2><span id="toc3">キーワード解説</span></h2>
<table>
<thead>
<tr>
<th>用語</th>
<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>ステートマシン</strong></td>
<td>ワークフローの全体定義。状態（State）の集合と遷移ルールをもつ</td>
</tr>
<tr>
<td><strong>Task ステート</strong></td>
<td>Lambda などの外部リソースを呼び出す状態</td>
</tr>
<tr>
<td><strong>Parallel ステート</strong></td>
<td>複数のブランチを<strong>同時に実行</strong>する状態。両ブランチの結果がリストで次のステートに渡る</td>
</tr>
<tr>
<td><strong>Retry</strong></td>
<td>エラー発生時に同じステートを自動で<strong>再実行</strong>するルール</td>
</tr>
<tr>
<td><strong>Catch</strong></td>
<td>リトライ後もエラーが続く場合に<strong>別のステートへ遷移</strong>するルール</td>
</tr>
<tr>
<td><strong>ResultPath</strong></td>
<td>Catch 時にエラー情報をどのフィールドに格納するかの指定（<code>&quot;$.error&quot;</code> → 元の入力の <code>error</code> キーにマージ）</td>
</tr>
<tr>
<td><strong>ASL</strong></td>
<td>Amazon States Language。ステートマシン定義の JSON 形式</td>
</tr>
<tr>
<td><strong>Workflow Studio</strong></td>
<td>Step Functions のビジュアルエディタ。フロー図と ASL コードを双方向に編集できる</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc4">前提条件</span></h2>
<table>
<thead>
<tr>
<th>ツール</th>
<th>確認コマンド</th>
<th>備考</th>
</tr>
</thead>
<tbody>
<tr>
<td>AWSアカウント</td>
<td>—</td>
<td>IAMユーザーまたはルートユーザー</td>
</tr>
<tr>
<td>AWS CLI v2（任意）</td>
<td><code>aws --version</code></td>
<td>テスト実行を CLI で行う場合のみ必要</td>
</tr>
</tbody>
</table>
<p>今回はほぼコンソール操作のみで完結します。</p>
<hr>
<h2><span id="toc5">使用するAWSサービス</span></h2>
<table>
<thead>
<tr>
<th>サービス</th>
<th>役割</th>
<th>料金</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Step Functions</strong></td>
<td>ワークフロー（ステートマシン）の管理・実行</td>
<td>月4,000回の状態遷移まで無料（標準タイプ）</td>
</tr>
<tr>
<td><strong>Lambda</strong></td>
<td>各ステートで実行されるビジネスロジック</td>
<td>月100万リクエスト・400,000 GB-秒まで無料</td>
</tr>
<tr>
<td><strong>IAM</strong></td>
<td>Lambda・Step Functionsの実行権限管理</td>
<td>無料</td>
</tr>
<tr>
<td><strong>CloudWatch Logs</strong></td>
<td>Lambdaの実行ログ</td>
<td>月5GBまで無料</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc6">全体の作業順序</span></h2>
<pre><code class="language-plaintext">① Lambda 関数を5つ作成する
      ↓（各関数の ARN が必要）
② Step Functions ステートマシンを作成する（新UI対応）
      ↓
③ 動作テスト（正常処理 / エラー処理）
      ↓
④ リソースの削除</code></pre>
<hr>
<h2><span id="toc7">① Lambda 関数を5つ作成する</span></h2>
<h3><span id="toc8">共通手順</span></h3>
<p><strong>AWSコンソール → Lambda → 「関数の作成」</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>作成方法</td>
<td>一から作成</td>
</tr>
<tr>
<td>ランタイム</td>
<td><strong>Python 3.12</strong></td>
</tr>
<tr>
<td>アーキテクチャ</td>
<td>x86_64</td>
</tr>
<tr>
<td>実行ロール</td>
<td>「基本的な Lambda アクセス権限で新しいロールを作成」（デフォルトのまま）</td>
</tr>
</tbody>
</table>
<p>各関数でコードを貼り付けたあと、必ず <strong>「Deploy」</strong> ボタンを押してコードを保存します。</p>
<hr>
<h3><span id="toc9">1-1. ValidateFunction（注文検証）</span></h3>
<p><strong>関数名</strong>: <code>ValidateFunction</code></p>
<p>コードエディタで <code>lambda_function.py</code> を開き、既存の内容を全て置き換えて以下を貼り付ける。</p>
<pre><code class="language-python">import json


def lambda_handler(event, context):
    order_id = event.get("order_id")
    item_id = event.get("item_id")
    quantity = event.get("quantity", 0)

    if not order_id:
        raise ValueError("order_id が指定されていません")
    if not item_id:
        raise ValueError("item_id が指定されていません")
    if not isinstance(quantity, int) or quantity &lt;= 0:
        raise ValueError(f"quantity は正の整数である必要があります: {quantity}")

    result = {
        **event,          # 元の入力フィールドをすべて引き継ぐ（テスト用フラグを後続ステートに渡すため）
        "validated": True,
    }
    print(json.dumps({"step": "validate", **result}, ensure_ascii=False))
    return result</code></pre>
<p><strong>ARN を控えておく</strong>: 関数ページ右上の「関数の ARN」をコピー（例: <code>arn:aws:lambda:ap-northeast-1:123456789012:function:ValidateFunction</code>）</p>
<hr>
<h3><span id="toc10">1-2. InventoryFunction（在庫確認）</span></h3>
<p><strong>関数名</strong>: <code>InventoryFunction</code></p>
<pre><code class="language-python">import json


def lambda_handler(event, context):
    order_id = event.get("order_id")
    item_id = event.get("item_id")
    quantity = event.get("quantity", 1)

    if item_id == "item-999":
        raise ValueError(f"在庫不足: item_id={item_id}")

    result = {
        "order_id": order_id,
        "item_id": item_id,
        "quantity": quantity,
        "stock_available": True,
    }
    print(json.dumps({"step": "inventory", **result}, ensure_ascii=False))
    return result</code></pre>
<p><strong>ARN を控えておく</strong></p>
<hr>
<h3><span id="toc11">1-3. PaymentFunction（支払い処理）</span></h3>
<p><strong>関数名</strong>: <code>PaymentFunction</code></p>
<pre><code class="language-python">import json


def lambda_handler(event, context):
    order_id = event.get("order_id")
    quantity = event.get("quantity", 1)

    # エラーテスト用: fail_payment=True の場合は例外発生
    if event.get("fail_payment"):
        raise RuntimeError(f"支払い処理に失敗: order_id={order_id}")

    amount = quantity * 1000  # 1個 1,000円

    result = {
        "order_id": order_id,
        "amount": amount,
        "payment_status": "completed",
    }
    print(json.dumps({"step": "payment", **result}, ensure_ascii=False))
    return result</code></pre>
<p><strong>ARN を控えておく</strong></p>
<hr>
<h3><span id="toc12">1-4. ConfirmFunction（注文確定）</span></h3>
<p><strong>関数名</strong>: <code>ConfirmFunction</code></p>
<pre><code class="language-python">import json
import datetime


def lambda_handler(event, context):
    # Parallel ステートの後に呼ばれるため、event はリスト形式
    #   event[0]: CheckInventory（在庫確認）の結果
    #   event[1]: ProcessPayment（支払い処理）の結果
    inventory_result = event[0]
    payment_result = event[1]

    order_id = inventory_result.get("order_id")
    now = datetime.datetime.now(datetime.timezone.utc)

    result = {
        "order_id": order_id,
        "item_id": inventory_result.get("item_id"),
        "quantity": inventory_result.get("quantity"),
        "amount": payment_result.get("amount"),
        "confirmed_at": now.isoformat(),
        "status": "confirmed",
    }
    print(json.dumps({"step": "confirm", **result}, ensure_ascii=False))
    return result</code></pre>
<p><strong>ARN を控えておく</strong></p>
<blockquote>
<p><strong>Parallel ステート後の <code>event</code> がリストになる理由：</strong><br /><code>ProcessInParallel</code> の各ブランチの出力が配列でまとめられて次のステートに渡されます。<code>event[0]</code> が在庫確認の結果、<code>event[1]</code> が支払い処理の結果です。この仕様を知らないと <code>list indices must be integers</code> エラーで詰まります。</p>
</blockquote>
<hr>
<h3><span id="toc13">1-5. ErrorHandlerFunction（エラー処理）</span></h3>
<p><strong>関数名</strong>: <code>ErrorHandlerFunction</code></p>
<pre><code class="language-python">import json


def lambda_handler(event, context):
    # ResultPath: "$.error" により、エラー情報が元の入力に付加されて渡される
    error_info = event.get("error", {})
    original_input = {k: v for k, v in event.items() if k != "error"}

    result = {
        "status": "error",
        "error_type": error_info.get("Error", "Unknown"),
        "error_cause": error_info.get("Cause", ""),
        "original_input": original_input,
    }
    print(json.dumps({"step": "error_handler", **result}, ensure_ascii=False))
    return result</code></pre>
<p><strong>ARN を控えておく</strong></p>
<hr>
<h2><span id="toc14">② Step Functions ステートマシンを作成する</span></h2>
<p><strong>AWSコンソール → Step Functions → 「ステートマシンを作成」</strong></p>
<h3><span id="toc15">2-1. 作成方法の選択（新UI：3択モーダル）</span></h3>
<p>「ステートマシンを作成」ボタンを押すと <strong>3択のモーダル</strong> が表示されます。</p>
<p><img decoding="async" src="https://caymezon.com/wp-content/uploads/2026/03/aws-handson-console-step-functions-lambda-stepfunctions-creat-modal-f49940.jpg" alt="Step Functions 作成モーダル（新UI）"></p>
<table>
<thead>
<tr>
<th>選択肢</th>
<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
<td>Hello World を実行</td>
<td>ガイド付きチュートリアル（今回は使わない）</td>
</tr>
<tr>
<td>テンプレートを選択</td>
<td>36個のテンプレートギャラリーが開く（今回は使わない）</td>
</tr>
<tr>
<td><strong>自分で作成する</strong></td>
<td>ゼロからワークフローを作成する ← <strong>これを選ぶ</strong></td>
</tr>
</tbody>
</table>
<p><strong>「自分で作成する」</strong> をクリックします。</p>
<blockquote>
<p><strong>「テンプレートを選択」を押してしまった場合：</strong><br />テンプレートギャラリーが開きます。左上の「✕」で閉じて、改めてモーダルから「自分で作成する」を選んでください。</p>
</blockquote>
<hr>
<h3><span id="toc16">2-2. 名前とタイプの設定（モーダル）</span></h3>
<p>「自分で作成する」をクリックすると Workflow Studio が開き、同時に設定モーダルが表示されます。</p>
<p><!-- ![Step Functions 名前・タイプ設定モーダル](images/stepfunctions-name-type-modal.jpg) --></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>ステートマシン名</td>
<td><code>OrderWorkflow</code></td>
</tr>
<tr>
<td>ステートマシンのタイプ</td>
<td><strong>標準</strong></td>
</tr>
</tbody>
</table>
<p>「続行」をクリックするとモーダルが閉じ、Workflow Studio の編集画面に切り替わります。</p>
<blockquote>
<p><strong>標準（Standard）と Express の違い：</strong><br />標準タイプは「正確に1回実行」「最大1年の実行時間」「実行履歴をコンソールで確認可能」が特徴です。受注処理のような確実な実行が必要なユースケースに適しています。</p>
</blockquote>
<hr>
<h3><span id="toc17">2-3. ASL の入力（「{ } コード」タブ）</span></h3>
<p>Workflow Studio の画面上部にある <strong>「{ } コード」</strong> タブをクリックしてコードエディタを表示します。</p>
<p><!-- ![Workflow Studio コードタブ](images/stepfunctions-workflow-studio-code.jpg) --></p>
<p>既存の内容を<strong>全て削除</strong>し、以下の JSON を貼り付けます。</p>
<blockquote>
<p><strong>【重要】</strong> <code>REPLACE_WITH_ARN_ValidateFunction</code> などのプレースホルダーを、① で控えた実際の Lambda ARN に置き換えること。</p>
</blockquote>
<pre><code class="language-json">{
  "Comment": "受注処理ワークフロー（検証 → 並列処理 → 確定）",
  "StartAt": "ValidateOrder",
  "States": {
    "ValidateOrder": {
      "Type": "Task",
      "Resource": "REPLACE_WITH_ARN_ValidateFunction",
      "Next": "ProcessInParallel",
      "Retry": [
        {
          "ErrorEquals": ["States.ALL"],
          "IntervalSeconds": 2,
          "MaxAttempts": 1,
          "BackoffRate": 2.0
        }
      ],
      "Catch": [
        {
          "ErrorEquals": ["States.ALL"],
          "Next": "HandleError",
          "ResultPath": "$.error"
        }
      ]
    },
    "ProcessInParallel": {
      "Type": "Parallel",
      "Branches": [
        {
          "StartAt": "CheckInventory",
          "States": {
            "CheckInventory": {
              "Type": "Task",
              "Resource": "REPLACE_WITH_ARN_InventoryFunction",
              "End": true
            }
          }
        },
        {
          "StartAt": "ProcessPayment",
          "States": {
            "ProcessPayment": {
              "Type": "Task",
              "Resource": "REPLACE_WITH_ARN_PaymentFunction",
              "End": true
            }
          }
        }
      ],
      "Next": "ConfirmOrder",
      "Catch": [
        {
          "ErrorEquals": ["States.ALL"],
          "Next": "HandleError",
          "ResultPath": "$.error"
        }
      ]
    },
    "ConfirmOrder": {
      "Type": "Task",
      "Resource": "REPLACE_WITH_ARN_ConfirmFunction",
      "End": true
    },
    "HandleError": {
      "Type": "Task",
      "Resource": "REPLACE_WITH_ARN_ErrorHandlerFunction",
      "End": true
    }
  }
}</code></pre>
<p>貼り付けると <strong>「フロー」タブ</strong> に切り替えると、フロー図が自動生成されます。ASL を正しく記述できているかを視覚的に確認できます。</p>
<p><!-- ![Workflow Studio フロー図プレビュー](images/stepfunctions-workflow-preview.jpg) --></p>
<hr>
<h3><span id="toc18">2-4. 実行ロールの確認と作成（「設定」タブ）</span></h3>
<p>画面上部の <strong>「設定」</strong> タブをクリックして実行ロールを確認します。</p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>実行ロール</td>
<td><strong>「新しいロールを作成」</strong>（デフォルトのまま）</td>
</tr>
<tr>
<td>ログ記録</td>
<td>OFF（デフォルトのまま）</td>
</tr>
</tbody>
</table>
<p>「新しいロールを作成」を選ぶと、以下のような青いボックスが表示されます。</p>
<blockquote>
<p>実行ロールは、完全な許可で作成されます。<code>StepFunctions-OrderWorkflow-role-XXXX</code> という名前の新しい実行ロールが作成されます。ステートマシンで指定されたアクションに必要なすべての許可が自動生成されます。</p>
</blockquote>
<p>「自動生成された許可を確認」を展開すると <code>lambda:Invoke</code> が含まれていることを確認できます。</p>
<p>右上の <strong>「作成」</strong> ボタンをクリックします。</p>
<blockquote>
<p><strong>IAMロールの自動作成について：</strong><br />ASL 定義に記述した Lambda ARN に対して <code>lambda:Invoke</code> 権限を持つロールが自動的に作成されます。SAM版では <code>LambdaInvokePolicy</code> ポリシーでこれを明示的に定義しています。</p>
</blockquote>
<hr>
<h2><span id="toc19">③ 動作テスト</span></h2>
<p><strong>Step Functions → <code>OrderWorkflow</code> → 「実行を開始」</strong></p>
<h3><span id="toc20">テスト1: 正常処理</span></h3>
<p><strong>入力データ:</strong></p>
<pre><code class="language-json">{
  "order_id": "ORD-001",
  "item_id": "item-001",
  "quantity": 2
}</code></pre>
<p>「実行を開始」をクリックします。</p>
<p><strong>実行グラフで確認:</strong></p>
<ul>
<li>全ステートが<strong>緑色</strong>になることを確認する</li>
<li><code>ProcessInParallel</code> の2つのブランチが<strong>同時に緑</strong>になることを確認する（並列処理の視覚化）</li>
</ul>
<p><!-- ![正常処理の実行グラフ](images/stepfunctions-success-graph.jpg) --></p>
<p><strong>出力を確認:</strong></p>
<p>実行完了後、「出力」タブで以下のような JSON が表示されます。</p>
<pre><code class="language-json">{
  "order_id": "ORD-001",
  "item_id": "item-001",
  "quantity": 2,
  "amount": 2000,
  "confirmed_at": "2026-03-01T10:00:00.000000+00:00",
  "status": "confirmed"
}</code></pre>
<hr>
<h3><span id="toc21">テスト2: 在庫切れエラー（Parallel Catch の確認）</span></h3>
<p><strong>入力データ:</strong></p>
<pre><code class="language-json">{
  "order_id": "ORD-002",
  "item_id": "item-999",
  "quantity": 1
}</code></pre>
<p><strong>期待する動作:</strong></p>
<ol>
<li><code>ValidateOrder</code> → 成功</li>
<li><code>ProcessInParallel</code> → <code>CheckInventory</code> が <code>ValueError</code> を発生させる</li>
<li><code>ProcessInParallel</code> の Catch が動作 → <code>HandleError</code> へ遷移</li>
<li><code>HandleError</code> → 成功（エラー情報をログに記録して終了）</li>
</ol>
<p><strong>実行グラフで確認:</strong></p>
<ul>
<li><code>CheckInventory</code> が<strong>赤く</strong>なる</li>
<li><code>ProcessInParallel</code> から <code>HandleError</code> へ遷移するパスが強調される</li>
</ul>
<p><!-- ![在庫切れエラーの実行グラフ](images/stepfunctions-inventory-error.jpg) --></p>
<p><strong>出力を確認:</strong></p>
<pre><code class="language-json">{
  "status": "error",
  "error_type": "ValueError",
  "error_cause": "在庫不足: item_id=item-999",
  "original_input": {
    "order_id": "ORD-002",
    "item_id": "item-999",
    "quantity": 1,
    "validated": true
  }
}</code></pre>
<hr>
<h3><span id="toc22">テスト3: 支払い失敗エラー（Parallel Catch の確認）</span></h3>
<p><strong>入力データ:</strong></p>
<pre><code class="language-json">{
  "order_id": "ORD-003",
  "item_id": "item-001",
  "quantity": 2,
  "fail_payment": true
}</code></pre>
<p><strong>期待する動作:</strong></p>
<ol>
<li><code>ValidateOrder</code> → 成功</li>
<li><code>ProcessInParallel</code> → <code>ProcessPayment</code> が <code>RuntimeError</code> を発生させる</li>
<li><code>ProcessInParallel</code> の Catch が動作 → <code>HandleError</code> へ遷移</li>
</ol>
<hr>
<h3><span id="toc23">テスト4: 検証エラー（ValidateOrder Retry + Catch の確認）</span></h3>
<p><strong>入力データ（<code>order_id</code> を省略）:</strong></p>
<pre><code class="language-json">{
  "item_id": "item-001",
  "quantity": 2
}</code></pre>
<p><strong>期待する動作:</strong></p>
<ol>
<li><code>ValidateOrder</code> → <code>ValueError</code> 発生</li>
<li>Retry: <code>IntervalSeconds: 2</code> で2秒後に自動リトライ（合計2回試行）</li>
<li>2回とも失敗 → Catch が動作 → <code>HandleError</code> へ遷移</li>
</ol>
<p><strong>Retry の確認方法:</strong></p>
<p>実行グラフで <code>ValidateOrder</code> を選択 → <strong>「イベント」タブ</strong> で以下の順序を確認します：</p>
<pre><code class="language-plaintext">TaskStateEntered → TaskScheduled → TaskStarted → TaskFailed
  → TaskScheduled（リトライ1回目）→ TaskStarted → TaskFailed
  → TaskStateExited（Catch 発動）→ HandleError へ</code></pre>
<p><code>ValidateFunction</code> が合計2回呼ばれていることが分かります。</p>
<hr>
<h2><span id="toc24">④ リソースの削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ずリソースを削除してください。</strong></p>
<h3><span id="toc25">1. ステートマシンを削除する</span></h3>
<p><strong>Step Functions → <code>OrderWorkflow</code> → 「削除」→ 確認テキストを入力 → 「削除」</strong></p>
<p>削除後、ステータスが「<strong>削除中</strong>」に変わります。以下のようなメッセージが表示されます：</p>
<blockquote>
<p>ステートマシンに削除のマークが付けられました。すべての実行が停止されると削除されます。</p>
</blockquote>
<p>これは正常な動作です。実行中のワークフローがすべて終了するまで完全削除を待つ仕様のため、実行中のものがなければ数秒〜数十秒でリストから消えます。ページをリロードして確認します。</p>
<hr>
<h3><span id="toc26">2. Lambda 関数を5つ削除する</span></h3>
<p><strong>Lambda → 関数一覧 → 各関数を選択 → 「アクション」→「削除」</strong></p>
<p>削除対象:</p>
<ul>
<li><code>ValidateFunction</code></li>
<li><code>InventoryFunction</code></li>
<li><code>PaymentFunction</code></li>
<li><code>ConfirmFunction</code></li>
<li><code>ErrorHandlerFunction</code></li>
</ul>
<hr>
<h3><span id="toc27">3. IAM ロールを削除する（任意）</span></h3>
<p>Step Functions の実行ロール（<code>StepFunctions-OrderWorkflow-role-XXXX</code>）と、Lambda 関数のロール（<code>ValidateFunction-role-XXXX</code> など5つ）を削除します。</p>
<p><strong>IAM → ロール → 各ロールを検索して削除</strong></p>
<hr>
<h3><span id="toc28">4. CloudWatch Logs のロググループを削除する（任意）</span></h3>
<p><strong>CloudWatch → ロググループ → 各 Lambda の <code>/aws/lambda/関数名</code> を削除</strong></p>
<hr>
<h2><span id="toc29">SAMとの対比</span></h2>
<table>
<thead>
<tr>
<th>SAMの記述</th>
<th>コンソールでやること</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>AWS::Serverless::StateMachine</code></td>
<td>Step Functions → ステートマシンを作成</td>
</tr>
<tr>
<td><code>Type: STANDARD</code></td>
<td>タイプ = 「標準」</td>
</tr>
<tr>
<td><code>Definition: {...}</code></td>
<td>「{ } コード」タブに ASL JSON を貼り付け</td>
</tr>
<tr>
<td><code>DefinitionSubstitutions</code></td>
<td>JSON 内の ARN プレースホルダーを手動で置換</td>
</tr>
<tr>
<td><code>LambdaInvokePolicy</code> × 5</td>
<td>「設定」タブ → 「新しいロールを作成」で自動生成</td>
</tr>
<tr>
<td><code>sam delete</code></td>
<td>Lambda × 5 / ステートマシン / IAM ロール / ロググループを個別に削除</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc30">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td>実行が即座に <code>ExecutionFailed</code> になる</td>
<td>ASL 内の Lambda ARN が間違っている</td>
<td>① で控えた ARN と再照合する</td>
</tr>
<tr>
<td>「テンプレートを選択」を押してギャラリーが開いた</td>
<td>新UI操作ミス</td>
<td>✕で閉じ、モーダルから「自分で作成する」を選ぶ</td>
</tr>
<tr>
<td>「{ } コード」タブが見つからない</td>
<td>モーダルが前面に出ている</td>
<td>「続行」でモーダルを閉じてから Workflow Studio を操作する</td>
</tr>
<tr>
<td><code>HandleError</code> に渡る <code>error_cause</code> が空</td>
<td>Python 例外が Lambda レベルでハンドルされている</td>
<td>コードの <code>raise</code> が正しく記述されているか確認</td>
</tr>
<tr>
<td><code>ProcessInParallel</code> が一方しか実行されない</td>
<td>Parallel ブランチの定義ミス</td>
<td>ASL JSON の <code>Branches</code> 配列に2つの要素があるか確認</td>
</tr>
<tr>
<td><code>ConfirmFunction</code> でエラー: <code>list indices must be integers</code></td>
<td><code>event[0]</code> / <code>event[1]</code> で取り出しているが、入力が配列でない</td>
<td><code>ProcessInParallel</code> の直後にのみ呼ばれる関数かを確認する</td>
</tr>
<tr>
<td>ステートマシン削除後「削除中」のまま消えない</td>
<td>実行中のワークフローが残っている</td>
<td>実行一覧から実行中のものを停止してから再確認</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc31">まとめ</span></h2>
<p>今回のハンズオンで体験できたこと：</p>
<table>
<thead>
<tr>
<th>確認項目</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Task + Retry + Catch</strong></td>
<td>ValidateOrder で注文検証 → リトライ → それでも失敗したらエラーハンドラへ</td>
</tr>
<tr>
<td><strong>Parallel ステート</strong></td>
<td>在庫確認と支払い処理を同時実行し、両結果をリストで次へ渡す</td>
</tr>
<tr>
<td><strong>ResultPath</strong></td>
<td><code>&quot;$.error&quot;</code> でエラー情報を元の入力にマージ → エラーハンドラで参照</td>
</tr>
<tr>
<td><strong>Workflow Studio</strong></td>
<td>ASL コードと視覚フロー図を双方向で確認できる新UI</td>
</tr>
<tr>
<td><strong>新UI操作</strong></td>
<td>3択モーダル → 「自分で作成する」→「{ } コード」タブ → 「設定」タブ の流れ</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc32">コンソール版とSAM版を比較してみる</span></h2>
<p>コンソールでStep Functionsの概念を理解したら、SAMで同じ構成をコードで定義することで「SAMが何を自動化しているか」が明確になります。<code>DefinitionSubstitutions</code> による ARN の自動差し込みや、<code>LambdaInvokePolicy</code> によるワンライン権限付与など、コンソールでの手動操作がコードに対応しています。</p>
<p><!-- TODO: SAM版記事へのリンクを追加 --></p>
<hr>
<h2><span id="toc33">関連記事</span></h2>
<p><a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"></p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWS運用入門 改訂第2版 押さえておきたいAWSの基本と運用ノウハウ [AWS深掘りガイド]","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51AAOubymTL._SL500_.jpg","\/51VMG6YKHdL._SL500_.jpg","\/41EdPB8azAL._SL500_.jpg","\/41v2JFE-9jL._SL500_.jpg","\/41FEEqR-yDL._SL500_.jpg","\/41JfZAdnTPL._SL500_.jpg","\/41vGK0czQrL._SL500_.jpg","\/41-SnYtz2aL._SL500_.jpg","\/41sPrV5fi3L._SL500_.jpg","\/41p7JtvYJ1L._SL500_.jpg","\/4169GVNTs8L._SL500_.jpg","\/41BPI5HP3zL._SL500_.jpg","\/41QOyk60CYL._SL500_.jpg","\/41APjk6FphL._SL500_.jpg","\/41ezKUu7VRL._SL500_.jpg","\/41A1n3K+r5L._SL500_.jpg","\/41aY2T8lEOL._SL500_.jpg","\/419Ca1V6HZL._SL500_.jpg","\/41zQkYyLPzL._SL500_.jpg","\/41YpHcyxiTL._SL500_.jpg","\/41-tKN5mt6L._SL500_.jpg","\/419Mv6m55IL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815631085","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815631085","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"E8MM1","s":"s"});</script></p>
<div id="msmaflink-E8MM1">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p><p>The post <a href="https://caymezon.com/aws-handson-console-step-functions-lambda/">AWSコンソールだけでStep Functions + Lambdaワークフローを構築する手順【SAM版との比較付き / 新UI対応】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-console-step-functions-lambda/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>AWSコンソールだけでS3 + CloudFront静的サイトホスティングを構築する手順【SAM版との比較付き / 新UI対応】</title>
		<link>https://caymezon.com/aws-handson-console-s3-cloudfront-hosting/</link>
					<comments>https://caymezon.com/aws-handson-console-s3-cloudfront-hosting/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Mon, 23 Feb 2026 07:34:52 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[AWSコンソール]]></category>
		<category><![CDATA[CDN]]></category>
		<category><![CDATA[CloudFront]]></category>
		<category><![CDATA[OAC]]></category>
		<category><![CDATA[S3]]></category>
		<category><![CDATA[SAM比較]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[初心者]]></category>
		<category><![CDATA[新UI]]></category>
		<category><![CDATA[静的サイトホスティング]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20210</guid>

					<description><![CDATA[<p>目次 はじめにCloudFront 新UI で戸惑いやすいポイント（先読み）SAM vs コンソール：どれだけ違うか構築するもの全体の作業順序① S3 バケット作成② CloudFront ディストリビューション作成（新 [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-console-s3-cloudfront-hosting/">AWSコンソールだけでS3 + CloudFront静的サイトホスティングを構築する手順【SAM版との比較付き / 新UI対応】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-18" checked><label class="toc-title" for="toc-checkbox-18">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">CloudFront 新UI で戸惑いやすいポイント（先読み）</a></li><li><a href="#toc3" tabindex="0">SAM vs コンソール：どれだけ違うか</a></li><li><a href="#toc4" tabindex="0">構築するもの</a></li><li><a href="#toc5" tabindex="0">全体の作業順序</a></li><li><a href="#toc6" tabindex="0">① S3 バケット作成</a></li><li><a href="#toc7" tabindex="0">② CloudFront ディストリビューション作成（新UI・6ステップウィザード）</a><ol><li><a href="#toc8" tabindex="0">ステップ1: Choose a plan（プランを選択）</a></li><li><a href="#toc9" tabindex="0">ステップ2: Get started（基本設定）</a></li><li><a href="#toc10" tabindex="0">ステップ3: Specify origin（オリジンの指定）</a></li><li><a href="#toc11" tabindex="0">ステップ4: Enable security（セキュリティ設定）</a></li><li><a href="#toc12" tabindex="0">ステップ5: Review and create（確認と作成）</a></li></ol></li><li><a href="#toc13" tabindex="0">③ S3 バケットポリシーの確認</a></li><li><a href="#toc14" tabindex="0">④ HTML ファイルをアップロード</a><ol><li><a href="#toc15" tabindex="0">index.html（トップページ）</a></li><li><a href="#toc16" tabindex="0">error.html（カスタム404ページ）</a></li><li><a href="#toc17" tabindex="0">方法A: S3 コンソールからアップロード</a></li><li><a href="#toc18" tabindex="0">方法B: AWS CLI でアップロード</a></li></ol></li><li><a href="#toc19" tabindex="0">⑤ CloudFront URL でアクセス確認</a></li><li><a href="#toc20" tabindex="0">⑥ キャッシュの動作確認（任意）</a><ol><li><a href="#toc21" tabindex="0">6-1. index.html を更新してアップロード</a></li><li><a href="#toc22" tabindex="0">6-2. キャッシュを削除する（新UI: 「キャッシュ削除」タブ）</a></li></ol></li><li><a href="#toc23" tabindex="0">⑦ リソースの削除</a><ol><li><a href="#toc24" tabindex="0">1. CloudFront ディストリビューションを無効化する</a></li><li><a href="#toc25" tabindex="0">2. Pricing plan（プライシングプラン）をキャンセルする</a></li><li><a href="#toc26" tabindex="0">3. 月末を待ってから削除する</a></li><li><a href="#toc27" tabindex="0">4. S3 バケット内のファイルをすべて削除する</a></li><li><a href="#toc28" tabindex="0">5. S3 バケットを削除する</a></li><li><a href="#toc29" tabindex="0">6. CloudFront OAC を削除する（任意）</a></li></ol></li><li><a href="#toc30" tabindex="0">SAMとの対比まとめ</a></li><li><a href="#toc31" tabindex="0">トラブルシューティング</a></li><li><a href="#toc32" tabindex="0">まとめ</a><ol><li><a href="#toc33" tabindex="0">コンソール操作で確認できたこと</a></li><li><a href="#toc34" tabindex="0">どちらを使うべきか</a></li></ol></li><li><a href="#toc35" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>この記事は、<a href="https://caymezon.com/aws-handson-s3-cloudfront-hosting/">SAM版ハンズオン記事</a>の比較版です。</p>
<p>SAM版ではコマンド数本でS3・OAC・CloudFront・バケットポリシーが一括デプロイできましたが、<strong>実際にコンソールで操作してみると思わぬハマりポイント</strong>がいくつかあります。</p>
<p>特に <strong>CloudFront コンソールは 2026年に大きくUIが刷新</strong> され、6ステップのウィザード形式に変わりました。ネット上の古い手順書と画面が全く違って戸惑う人が多いはずです。この記事では <strong>2026年の新UI</strong> に対応した手順を詳しく解説します。</p>
<p><strong>この記事を読むとわかること：</strong></p>
<ul>
<li>CloudFront 新UI（6ステップウィザード）の各ステップで何を設定するか</li>
<li>「Allow private S3 bucket access to CloudFront」チェックボックスで何が自動化されるのか</li>
<li><strong>削除時に新登場した「Pricing plan キャンセル」手順</strong>（これを知らないと削除できない）</li>
<li>キャッシュ削除（旧: 「無効化」）の操作と注意点</li>
</ul>
<hr>
<h2><span id="toc2">CloudFront 新UI で戸惑いやすいポイント（先読み）</span></h2>
<p>操作を始める前に、旧UIとの違いを把握しておきましょう。</p>
<table>
<thead>
<tr>
<th>変更点</th>
<th>旧UI</th>
<th>新UI（2026年〜）</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>ウィザード形式</strong></td>
<td>長い1画面に全設定を入力</td>
<td><strong>6ステップのウィザード</strong>に分割</td>
</tr>
<tr>
<td><strong>プランの選択</strong></td>
<td>なし</td>
<td><strong>ステップ1でプランを選択</strong>（無料 / 有料）</td>
</tr>
<tr>
<td><strong>OAC の設定</strong></td>
<td>手動でOACを作成 → ARNをコピー → 貼り付け</td>
<td><strong>「Allow private S3 bucket access」チェック1つ</strong>で自動設定</td>
</tr>
<tr>
<td><strong>「無効化」タブ</strong></td>
<td>Invalidation（無効化）</td>
<td>**「キャッシュ削除」**に名称変更</td>
</tr>
<tr>
<td><strong>削除手順</strong></td>
<td>無効化 → 削除</td>
<td>無効化 → <strong>Pricing plan キャンセル</strong> → 月末待機 → 削除</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>「Pricing plan キャンセル」が最大のハマりポイント：</strong><br />新UIで作成したディストリビューションは「Pricing plan（プライシングプラン）」に加入しています。<br />削除する前にプランをキャンセルする操作が必要で、しかもキャンセルは<strong>月末（翌月1日）に有効</strong>になるため、<strong>すぐに削除できません</strong>。<br />知らないと「subscribed to a pricing plan」エラーで詰まります（後述）。</p>
</blockquote>
<hr>
<p><a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"></p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWSの基本・仕組み・重要用語が全部わかる教科書 (見るだけ図解)","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51DEDQXj6oL._SL500_.jpg","\/41F589smNwL._SL500_.jpg","\/41R6f9yyCWL._SL500_.jpg","\/41HqWQ9BvmL._SL500_.jpg","\/41p8p0ZU79L._SL500_.jpg","\/41qLC-fndBL._SL500_.jpg","\/41fcLv9VT5L._SL500_.jpg","\/51lRvCsvHqL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815607850","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815607850","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"eaCUB","s":"s"});</script></p>
<div id="msmaflink-eaCUB">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p>
<h2><span id="toc3">SAM vs コンソール：どれだけ違うか</span></h2>
<table>
<thead>
<tr>
<th>比較項目</th>
<th>SAM（コード）</th>
<th>コンソール（手動・新UI）</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>OACの設定</strong></td>
<td><code>Type: AWS::CloudFront::OriginAccessControl</code> + 自動ポリシー</td>
<td>ステップ3のチェックボックス1つ</td>
</tr>
<tr>
<td><strong>バケットポリシー更新</strong></td>
<td><code>WebsiteBucketPolicy</code> で自動生成</td>
<td>チェックボックスで自動（ただし確認が必要）</td>
</tr>
<tr>
<td><strong>削除</strong></td>
<td><code>sam delete</code> 1コマンド（即時）</td>
<td><strong>無効化 → プランキャンセル → 月末待機 → 削除</strong></td>
</tr>
<tr>
<td><strong>コスト管理</strong></td>
<td>Pricing planなし</td>
<td><strong>Pricing planのキャンセルが必要</strong></td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc4">構築するもの</span></h2>
<p>SAM版と全く同じ構成・機能の静的サイトホスティング環境を構築します。</p>
<pre><code class="language-plaintext">ブラウザ
  ↓ HTTPS（HTTPは自動リダイレクト）
CloudFront（CDN・エッジキャッシュ）
  ↓ OAC（署名付きリクエスト）
S3 バケット（非公開・パブリックアクセスブロック）
  └── index.html / error.html</code></pre>
<hr>
<h2><span id="toc5">全体の作業順序</span></h2>
<pre><code class="language-plaintext">① S3 バケット作成（非公開）
      ↓
② CloudFront ディストリビューション作成（6ステップウィザード）
      ↓（自動でOAC設定・バケットポリシー更新）
③ S3 バケットポリシーの確認（自動設定を確認）
      ↓
④ HTML ファイルをアップロード
      ↓
⑤ CloudFront URL でアクセス確認
      ↓
⑥ キャッシュの動作確認（任意）
⑦ リソースの削除（要注意: 月末まで待機が必要）</code></pre>
<blockquote>
<p><strong>順序の理由：</strong><br />② でCloudFrontディストリビューションを作成する際に「どのS3バケットをオリジンにするか」を指定するため、① でバケットを先に作成しておく必要があります。</p>
</blockquote>
<hr>
<h2><span id="toc6">① S3 バケット作成</span></h2>
<p><strong>AWSコンソール → S3 → 「バケットを作成」</strong></p>
<p><!-- ![S3 バケット作成画面](images/s3-create-bucket.jpg) --></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>バケット名</td>
<td><code>my-cloudfront-website</code>（任意・グローバルで一意な名前）</td>
</tr>
<tr>
<td>AWSリージョン</td>
<td><strong>アジアパシフィック（東京）ap-northeast-1</strong></td>
</tr>
<tr>
<td>オブジェクト所有者</td>
<td>ACL 無効（デフォルトのまま）</td>
</tr>
<tr>
<td>パブリックアクセスのブロック</td>
<td><strong>すべてブロック</strong>（変更しない）</td>
</tr>
<tr>
<td>バージョニング</td>
<td>無効（デフォルトのまま）</td>
</tr>
</tbody>
</table>
<p>「バケットを作成」をクリックします。</p>
<blockquote>
<p><strong>パブリックアクセスをブロックしたまま使う理由：</strong><br />従来の静的サイトホスティングではS3バケットを公開する方法もありましたが、現在の推奨は <strong>S3を非公開にしてCloudFront OAC経由でのみアクセスさせる</strong>構成です。直接S3 URLからのアクセスを防ぎ、CloudFrontのHTTPS・キャッシュ・WAFの恩恵を受けられます。</p>
</blockquote>
<blockquote>
<p><strong>バケット名のルール：</strong></p>
<ul>
<li>グローバルで一意（AWS全体で重複不可・削除後しばらく再利用不可）</li>
<li><code>my-cloudfront-website-自分のAWSアカウントID</code> のように末尾にアカウントIDを付けると一意にしやすい</li>
<li>SAMでは <code>!Sub &quot;${AWS::StackName}-website-${AWS::AccountId}&quot;</code> で自動的に一意化しています</li>
</ul>
</blockquote>
<p><strong>控えておく情報：</strong></p>
<ul>
<li>バケット名（例: <code>my-cloudfront-website</code>）</li>
</ul>
<hr>
<h2><span id="toc7">② CloudFront ディストリビューション作成（新UI・6ステップウィザード）</span></h2>
<p><strong>AWSコンソール → CloudFront → 「ディストリビューションを作成」</strong></p>
<blockquote>
<p><strong>CloudFrontはグローバルサービスのため、コンソール右上のリージョン表示は「グローバル」になります。</strong><br />S3バケットのリージョンは東京（ap-northeast-1）のままで問題ありません。</p>
</blockquote>
<hr>
<h3><span id="toc8">ステップ1: Choose a plan（プランを選択）</span></h3>
<p><!-- ![CloudFront プラン選択画面（新UI）](images/cloudfront-plan-select.jpg) --></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>プラン</td>
<td><strong>無料（$0/month）</strong></td>
</tr>
</tbody>
</table>
<p>「Next」をクリックします。</p>
<blockquote>
<p><strong>無料プランの内容（1ヶ月あたり）：</strong></p>
<ul>
<li>リクエスト数: 100万（1M）</li>
<li>データ転送: 100GB</li>
<li>DDoS保護・グローバルCDN・デフォルトキャッシュルールが含まれる</li>
</ul>
<p>ハンズオン目的では無料枠で十分です。有料プランは本番サービスで大量トラフィックが想定される場合に選択します。</p>
<p><strong>SAMとの差分：</strong> SAM（CloudFormation）で作成したディストリビューションにはPricing planの概念がありません。「月額$0」のプランでも加入状態になるため、削除時にキャンセル手続きが必要になります（後述）。</p>
</blockquote>
<hr>
<h3><span id="toc9">ステップ2: Get started（基本設定）</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>Distribution name</td>
<td><code>my-cloudfront-site</code>（任意）</td>
</tr>
<tr>
<td>Distribution type</td>
<td><strong>Single website or app</strong></td>
</tr>
<tr>
<td>Route 53 managed domain</td>
<td>空欄（カスタムドメインなし）</td>
</tr>
</tbody>
</table>
<p>「Next」をクリックします。</p>
<hr>
<h3><span id="toc10">ステップ3: Specify origin（オリジンの指定）</span></h3>
<p>このステップが最も重要です。S3バケットをオリジンとして設定し、OACを自動構成します。</p>
<p><!-- ![CloudFront オリジン設定画面（新UI）](images/cloudfront-origin-setting.jpg) --></p>
<p><strong>Origin type セクション：</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>Origin type</td>
<td><strong>Amazon S3</strong> を選択</td>
</tr>
</tbody>
</table>
<p><strong>Origin セクション：</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>S3 origin</td>
<td>① で作成したバケット名を入力または「Browse S3」で選択</td>
</tr>
<tr>
<td>Origin path</td>
<td>空欄（変更不要）</td>
</tr>
</tbody>
</table>
<p><strong>Settings セクション：</strong></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>Allow private S3 bucket access to CloudFront</td>
<td><strong>チェックを入れる（Recommended）</strong></td>
</tr>
<tr>
<td>オリジン設定</td>
<td>Use recommended origin settings（デフォルトのまま）</td>
</tr>
<tr>
<td>Cache settings</td>
<td>Use recommended cache settings tailored to serving S3 content（デフォルトのまま）</td>
</tr>
</tbody>
</table>
<p>「Next」をクリックします。</p>
<blockquote>
<p><strong>「Allow private S3 bucket access to CloudFront」チェックボックスの重要性：</strong></p>
<p>これが新UIの最大の改善点です。チェックを入れると：</p>
<ol>
<li>CloudFrontが S3 に安全にアクセスするための <strong>OAC（Origin Access Control）を自動作成</strong></li>
<li>ディストリビューション作成後に <strong>S3バケットポリシーを自動で更新</strong></li>
</ol>
<p><strong>旧UIでの手順（参考）：</strong></p>
<ol>
<li>CloudFront → OAC を手動で作成</li>
<li>ディストリビューション作成時にOACを選択・ARNをコピー</li>
<li>S3 → バケットポリシーを手動で編集・貼り付け</li>
</ol>
<p>新UIではこのすべてがチェック1つで完結します。</p>
<p><strong>SAMとの差分：</strong> SAMでは <code>Type: AWS::CloudFront::OriginAccessControl</code> リソースと <code>WebsiteBucketPolicy</code> リソースで同じことを明示的に定義しています。</p>
</blockquote>
<hr>
<h3><span id="toc11">ステップ4: Enable security（セキュリティ設定）</span></h3>
<p>「Security protections from WAF are included in your plan at no additional charge.」と表示されます。無料プランにWAF保護が含まれており、追加料金は発生しません。</p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>Use monitor mode</td>
<td><strong>チェックしない</strong>（デフォルトのまま）</td>
</tr>
</tbody>
</table>
<p>「Next」をクリックします。</p>
<blockquote>
<p><strong>「Use monitor mode」について：</strong><br />チェックを入れると「何がブロックされるかを記録するだけ」のモードになります（実際にはブロックしない）。ハンズオンでは不要なのでチェックせずに進みます。</p>
</blockquote>
<hr>
<h3><span id="toc12">ステップ5: Review and create（確認と作成）</span></h3>
<p>設定内容を確認して「ディストリビューションを作成」をクリックします。</p>
<p><strong>控えておく情報：</strong></p>
<ul>
<li>CloudFront ドメイン名（例: <code>xxxxxxxxxxxx.cloudfront.net</code>）</li>
<li>ディストリビューション ID（例: <code>EXXXXXXXXXXXXXXXXX</code>）</li>
</ul>
<blockquote>
<p><strong>CloudFrontのデプロイには 5〜15分かかります。</strong><br />ステータスが「有効」になるまで待ってから次のステップに進んでください。</p>
</blockquote>
<hr>
<h2><span id="toc13">③ S3 バケットポリシーの確認</span></h2>
<p>新UIでは、ステップ3で「Allow private S3 bucket access to CloudFront」にチェックを入れると、ディストリビューション作成時に <strong>S3バケットポリシーが自動で更新されます</strong>。</p>
<p>自動設定されたポリシーを確認します。</p>
<p><strong>S3 → <code>my-cloudfront-website</code> → 「アクセス許可」タブ → 「バケットポリシー」</strong></p>
<p><!-- ![S3 バケットポリシー確認画面](images/s3-bucket-policy.jpg) --></p>
<p>以下のようなポリシーが自動で設定されていることを確認します。</p>
<pre><code class="language-json">{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::my-cloudfront-website/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/EXXXXXXXXXXXXXXXXX"
                }
            }
        }
    ]
}</code></pre>
<p><strong>このポリシーのポイント：</strong></p>
<ul>
<li><code>Principal.Service: cloudfront.amazonaws.com</code> — CloudFrontサービスからのアクセスのみ許可</li>
<li><code>Condition.AWS:SourceArn</code> — <strong>特定のディストリビューション</strong>からのアクセスのみ許可（他のCloudFrontからはアクセスできない）</li>
<li><code>Action: s3:GetObject</code> のみ — 読み取り専用。書き込み・削除は不可</li>
</ul>
<blockquote>
<p><strong>SAMとの差分：</strong> SAMでは <code>WebsiteBucketPolicy</code> リソースに上記と同じポリシーを明示的に記述しています。コンソールでは自動設定されますが、SAMを読むとその中身が可視化されます。</p>
</blockquote>
<hr>
<h2><span id="toc14">④ HTML ファイルをアップロード</span></h2>
<p>アップロードするHTMLファイルの内容を確認しておきます。自分で用意したHTMLがあればそちらを使っても構いません。</p>
<h3><span id="toc15">index.html（トップページ）</span></h3>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="ja"&gt;
&lt;head&gt;
  &lt;meta charset="UTF-8"&gt;
  &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
  &lt;title&gt;S3 + CloudFront ハンズオン&lt;/title&gt;
  &lt;style&gt;
    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      max-width: 640px;
      margin: 60px auto;
      padding: 20px;
      color: #333;
    }
    h1 { color: #232f3e; }
    .badge {
      background: #ff9900;
      color: white;
      padding: 3px 10px;
      border-radius: 4px;
      font-size: 0.85em;
      font-weight: bold;
    }
    .info {
      background: #f4f6f8;
      border-left: 4px solid #ff9900;
      padding: 12px 16px;
      margin: 20px 0;
      border-radius: 0 4px 4px 0;
    }
  &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;デプロイ成功！&lt;/h1&gt;
  &lt;p&gt;
    &lt;span class="badge"&gt;CloudFront CDN&lt;/span&gt; 経由でこのページが配信されています。
  &lt;/p&gt;
  &lt;div class="info"&gt;
    &lt;strong&gt;このページの配信構成:&lt;/strong&gt;&lt;br&gt;
    S3 バケット（オリジン） → CloudFront（CDN）→ あなたのブラウザ
  &lt;/div&gt;
  &lt;p&gt;S3 + CloudFront による静的サイトホスティングのハンズオンです。&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<h3><span id="toc16">error.html（カスタム404ページ）</span></h3>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="ja"&gt;
&lt;head&gt;
  &lt;meta charset="UTF-8"&gt;
  &lt;title&gt;404 - ページが見つかりません&lt;/title&gt;
  &lt;style&gt;
    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      max-width: 640px;
      margin: 60px auto;
      padding: 20px;
      color: #333;
      text-align: center;
    }
    h1 { color: #cc0000; }
    a { color: #ff9900; }
  &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;404 - ページが見つかりません&lt;/h1&gt;
  &lt;p&gt;お探しのページは存在しないか、移動・削除された可能性があります。&lt;/p&gt;
  &lt;p&gt;&lt;a href="/"&gt;トップページへ戻る&lt;/a&gt;&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>上記2ファイルをS3にアップロードします。</p>
<h3><span id="toc17">方法A: S3 コンソールからアップロード</span></h3>
<p><strong>S3 → <code>my-cloudfront-website</code> → 「アップロード」</strong></p>
<p><code>index.html</code> と <code>error.html</code> を選択してアップロードします。</p>
<h3><span id="toc18">方法B: AWS CLI でアップロード</span></h3>
<pre><code class="language-cmd">aws s3 sync C:\my-aws\aws-learning-projects\s3-cloudfront-hosting\website\ ^
  s3://my-cloudfront-website/ ^
  --region ap-northeast-1</code></pre>
<hr>
<h2><span id="toc19">⑤ CloudFront URL でアクセス確認</span></h2>
<p>CloudFrontのステータスが「有効」になったらブラウザでアクセスします。</p>
<pre><code class="language-plaintext">https://xxxxxxxxxxxx.cloudfront.net</code></pre>
<p><strong>期待する表示:</strong> <code>index.html</code> の内容が表示される。</p>
<p><strong>HTTP → HTTPS リダイレクトの確認：</strong></p>
<pre><code class="language-plaintext">http://xxxxxxxxxxxx.cloudfront.net</code></pre>
<p>HTTPでアクセスすると自動的にHTTPSにリダイレクトされることを確認します。</p>
<p><strong>カスタム404ページの確認：</strong></p>
<pre><code class="language-plaintext">https://xxxxxxxxxxxx.cloudfront.net/notfound</code></pre>
<p>存在しないページにアクセスすると <code>error.html</code> の内容が表示されることを確認します。</p>
<p><!-- ![CloudFront経由でindex.htmlが表示](images/cloudfront-index.jpg) --></p>
<hr>
<h2><span id="toc20">⑥ キャッシュの動作確認（任意）</span></h2>
<p>CloudFront CDNの重要な概念「キャッシュ」と「キャッシュ削除（旧: 無効化）」を体験します。</p>
<h3><span id="toc21">6-1. index.html を更新してアップロード</span></h3>
<p><code>index.html</code> のテキストを変更して再度アップロードします。</p>
<pre><code class="language-cmd">aws s3 cp C:\my-aws\aws-learning-projects\s3-cloudfront-hosting\website\index.html ^
  s3://my-cloudfront-website/index.html ^
  --region ap-northeast-1</code></pre>
<p>ブラウザでCloudFront URLにアクセスしても<strong>古いキャッシュが表示される場合があります</strong>（TTLが切れるまで）。</p>
<h3><span id="toc22">6-2. キャッシュを削除する（新UI: 「キャッシュ削除」タブ）</span></h3>
<p><strong>CloudFront → ディストリビューション → 「キャッシュ削除」タブ → 「キャッシュ削除を作成」</strong></p>
<p><!-- ![CloudFront キャッシュ削除画面（新UI）](images/cloudfront-cache-invalidation.jpg) --></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>オブジェクトパス</td>
<td><code>/*</code>（全キャッシュを削除）または <code>/index.html</code>（特定ファイルのみ）</td>
</tr>
</tbody>
</table>
<p>「キャッシュ削除を作成」をクリックします。ステータスが「完了」になったら（1〜3分）ブラウザを強制リロード（<code>Ctrl+Shift+R</code>）して確認します。</p>
<blockquote>
<p><strong>旧UIとの名称変更：</strong><br />旧UIでは「無効化（Invalidation）」タブでしたが、新UIでは「キャッシュ削除」に名称変更されました。機能は同じです。</p>
</blockquote>
<blockquote>
<p><strong>無効化の料金：</strong><br />毎月最初の1,000パスは無料。それ以降は $0.005/パス。<br /><code>/*</code> は1パスとしてカウントされるため、ハンズオン程度なら無料枠内です。</p>
</blockquote>
<hr>
<h2><span id="toc23">⑦ リソースの削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ずリソースを削除してください。</strong></p>
<blockquote>
<p><strong>重要: 新UIで作成したディストリビューションの削除手順（旧UIとは異なります）</strong></p>
<p>旧UIでは「無効化 → 削除」の2ステップでしたが、新UIでは以下の手順が必要です：<br /><strong>無効化 → Pricing plan キャンセル → 月末（翌月1日）まで待機 → 削除</strong></p>
<p>月末まで削除できないのは想定外でハマる人が多いポイントです。</p>
</blockquote>
<hr>
<h3><span id="toc24">1. CloudFront ディストリビューションを無効化する</span></h3>
<p><strong>CloudFront → ディストリビューション → 対象を選択 → 「無効化」ボタン → 確認 → 「無効化」</strong></p>
<p>ステータスが「有効」→「無効」に変わるまで待ちます（5〜15分）。</p>
<blockquote>
<p><strong>無効化が完了しないとディストリビューションを削除できません。</strong>（削除ボタンがグレーアウトしたまま）</p>
</blockquote>
<hr>
<h3><span id="toc25">2. Pricing plan（プライシングプラン）をキャンセルする</span></h3>
<p>ステータスが「無効」になったら、プランをキャンセルします。</p>
<p><strong>無効化したディストリビューションをクリック → 「Billing」セクション → 「Manage plan」→「Cancel plan」（プランをキャンセル）→「Cancel plan」ボタン</strong></p>
<p><!-- ![CloudFront Pricing plan キャンセル画面](images/cloudfront-cancel-plan.jpg) --></p>
<p>キャンセルが受け付けられると「無料プランのキャンセルがスケジュールされています。このプランは [月末日] に終了します。」と表示されます。</p>
<blockquote>
<p><strong>「この日を過ぎると、すべての使用は従量制料金で課金されます」という警告について：</strong><br />これは「もし使い続けた場合」の説明です。ディストリビューションは「無効」状態のためリクエストを受け付けず、使用量ゼロ = 課金ゼロです。無効化済みであれば課金されません。</p>
</blockquote>
<hr>
<h3><span id="toc26">3. 月末を待ってから削除する</span></h3>
<p>プランキャンセルは<strong>月末（翌月1日）に有効</strong>になります。それまでディストリビューションは削除できません。</p>
<p>月末以降：</p>
<p><strong>ディストリビューションを選択 → 「削除」→ 確認 → 「削除」</strong></p>
<blockquote>
<p><strong>キャンセル前に削除しようとすると：</strong><br /><code>You can&#39;t delete this distribution while it&#39;s subscribed to a pricing plan.</code><br />というエラーが表示されます。その場合は手順2のプランキャンセルを行ってください。</p>
</blockquote>
<hr>
<h3><span id="toc27">4. S3 バケット内のファイルをすべて削除する</span></h3>
<p><strong>方法A: AWS CLI で一括削除（推奨）</strong></p>
<pre><code class="language-cmd">aws s3 rm s3://my-cloudfront-website --recursive --region ap-northeast-1</code></pre>
<p><strong>方法B: S3 コンソールから</strong></p>
<p>S3 → <code>my-cloudfront-website</code> → ファイルをすべて選択 → 「削除」→ 確認テキストを入力 → 「オブジェクトを削除」</p>
<hr>
<h3><span id="toc28">5. S3 バケットを削除する</span></h3>
<p><strong>S3 → <code>my-cloudfront-website</code> を選択 → 「削除」→ バケット名を入力 → 「バケットを削除」</strong></p>
<hr>
<h3><span id="toc29">6. CloudFront OAC を削除する（任意）</span></h3>
<p>ステップ3で自動作成された OAC は、ディストリビューション削除後も残ります。不要なら手動で削除します。</p>
<p><strong>CloudFront → 左サイドバー「オリジンアクセスコントロール」→ 作成した OAC を選択 → 「削除」</strong></p>
<blockquote>
<p><strong>注意：</strong> ディストリビューションの「オリジン」タブではなく、左サイドバーの「オリジンアクセスコントロール」から削除します。ディストリビューションが削除済みでないと削除できません。</p>
</blockquote>
<hr>
<h2><span id="toc30">SAMとの対比まとめ</span></h2>
<table>
<thead>
<tr>
<th>SAMの記述</th>
<th>コンソールでやること</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Type: AWS::S3::Bucket</code>（パブリックアクセスブロック自動）</td>
<td>① S3バケット作成（すべてブロックのまま）</td>
</tr>
<tr>
<td><code>Type: AWS::CloudFront::OriginAccessControl</code></td>
<td>ステップ3 「Allow private S3 bucket access」チェックで自動作成</td>
</tr>
<tr>
<td><code>Type: AWS::CloudFront::Distribution</code></td>
<td>② CloudFront 新UIウィザード（6ステップ）</td>
</tr>
<tr>
<td><code>WebsiteBucketPolicy</code>（ポリシー自動生成）</td>
<td>ステップ3のチェックでディストリビューション作成時に自動更新</td>
</tr>
<tr>
<td><code>sam delete</code>（即時削除可能）</td>
<td><strong>無効化 → Pricing planキャンセル → 月末待機 → 削除</strong></td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>削除の大きな違い：</strong><br />コンソール新UIで作成したディストリビューションはPricing planに加入するため、プランキャンセル後に月末まで削除できない制約があります。<br /><strong>SAMで作成したディストリビューションにはPricing planの概念がないため、<code>sam delete</code> で即座に削除手続きが完了します。</strong><br />これがSAM版の大きなメリットのひとつです。</p>
</blockquote>
<hr>
<h2><span id="toc31">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td>CloudFront URL で 403 が返る</td>
<td>バケットポリシーが未設定</td>
<td>③ の手順でバケットポリシーを確認する</td>
</tr>
<tr>
<td>CloudFront URL で 403 が返る</td>
<td>CloudFrontのデプロイがまだ完了していない</td>
<td>ステータスが「有効」になるまで5〜15分待つ</td>
</tr>
<tr>
<td>S3の直接URLにアクセスすると 403</td>
<td>正常（パブリックアクセスをブロックしているため）</td>
<td>CloudFront URL でアクセスする</td>
</tr>
<tr>
<td>index.htmlを更新したのに古い内容が表示される</td>
<td>CloudFrontキャッシュが残っている</td>
<td>⑥ の手順でキャッシュを削除する</td>
</tr>
<tr>
<td>ディストリビューションを削除できない（削除ボタンがグレー）</td>
<td>ステータスが「有効」のまま</td>
<td>「無効化」してステータスが「無効」になるまで待つ</td>
</tr>
<tr>
<td>「subscribed to a pricing plan」エラーが出て削除できない</td>
<td>Pricing planのキャンセル操作が必要</td>
<td>手順2でプランをキャンセルし、月末以降に削除する</td>
</tr>
<tr>
<td>プランキャンセル後も削除できない</td>
<td>キャンセルは月末（翌月1日）まで有効にならない</td>
<td>月末以降に削除する。無効化済みなら課金されない</td>
</tr>
<tr>
<td>OAC 削除時エラー</td>
<td>ディストリビューションの「オリジン」タブを操作しようとしている</td>
<td>左サイドバー「オリジンアクセスコントロール」から削除する</td>
</tr>
<tr>
<td>バケット削除がエラーになる</td>
<td>バケット内にオブジェクトが残っている</td>
<td><code>aws s3 rm s3://バケット名 --recursive</code> で先に空にする</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc32">まとめ</span></h2>
<h3><span id="toc33">コンソール操作で確認できたこと</span></h3>
<p>今回のコンソール操作で、SAMが自動化していることと、新UI特有のハマりポイントが明確になりました：</p>
<table>
<thead>
<tr>
<th>項目</th>
<th>コンソール操作で学べたこと</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>OAC の正体</strong></td>
<td>「CloudFrontからS3へのAWS署名付きリクエストを有効にする」という設定。新UIでチェック1つで完結</td>
</tr>
<tr>
<td><strong>バケットポリシーの役割</strong></td>
<td>OAC設定後に自動生成されるポリシーで「このCloudFrontだけが読める」を実現している</td>
</tr>
<tr>
<td><strong>Pricing plan の存在</strong></td>
<td>新UIならではの概念。月末まで削除できないのは意図的な仕様</td>
</tr>
<tr>
<td><strong>キャッシュ削除（Invalidation）</strong></td>
<td>ファイル更新後にエッジキャッシュを手動でリフレッシュする必要がある</td>
</tr>
</tbody>
</table>
<h3><span id="toc34">どちらを使うべきか</span></h3>
<table>
<thead>
<tr>
<th>シーン</th>
<th>推奨</th>
</tr>
</thead>
<tbody>
<tr>
<td>本番環境・チーム開発</td>
<td><strong>SAM</strong>（再現性・Git管理・削除の容易さ）</td>
</tr>
<tr>
<td>AWSを初めて学ぶ</td>
<td><strong>コンソール</strong>（OAC・バケットポリシーの意味を視覚的に理解する）</td>
</tr>
<tr>
<td>構築済みリソースの確認・デバッグ</td>
<td><strong>コンソール</strong>（キャッシュ削除・バケットポリシー確認）</td>
</tr>
<tr>
<td>すぐにリソースを削除したい</td>
<td><strong>SAM</strong>（Pricing planなし・<code>sam delete</code> 即時）</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc35">関連記事</span></h2>
<ul>
<li>SAM版ハンズオン — コマンド数本でS3 + CloudFront環境を構築</li>
</ul>

<a rel="noopener" href="https://caymezon.com/aws-handson-s3-cloudfront-hosting/" title="AWSハンズオン - S3 + CloudFrontで静的サイトをCDN配信しよう【SAM版 / Windows対応】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/02/aws-handson-s3-cloudfront-hosting-featured-5ba466-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/02/aws-handson-s3-cloudfront-hosting-featured-5ba466-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/02/aws-handson-s3-cloudfront-hosting-featured-5ba466-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/02/aws-handson-s3-cloudfront-hosting-featured-5ba466-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/02/aws-handson-s3-cloudfront-hosting-featured-5ba466-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">AWSハンズオン - S3 + CloudFrontで静的サイトをCDN配信しよう【SAM版 / Windows対応】</div><div class="blogcard-snippet internal-blogcard-snippet">はじめに「ウェブサイトを公開したいけど、サーバーは持ちたくない」「静的なHTMLサイトを世界中から速く見せたい」という要件に、S3 + CloudFront の組み合わせはベストな選択肢のひとつです。この記事では、AWS SAM（Serve...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.02.23</div></div></div></div></a>
<p><a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"></p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWS運用入門 改訂第2版 押さえておきたいAWSの基本と運用ノウハウ [AWS深掘りガイド]","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51AAOubymTL._SL500_.jpg","\/51VMG6YKHdL._SL500_.jpg","\/41EdPB8azAL._SL500_.jpg","\/41v2JFE-9jL._SL500_.jpg","\/41FEEqR-yDL._SL500_.jpg","\/41JfZAdnTPL._SL500_.jpg","\/41vGK0czQrL._SL500_.jpg","\/41-SnYtz2aL._SL500_.jpg","\/41sPrV5fi3L._SL500_.jpg","\/41p7JtvYJ1L._SL500_.jpg","\/4169GVNTs8L._SL500_.jpg","\/41BPI5HP3zL._SL500_.jpg","\/41QOyk60CYL._SL500_.jpg","\/41APjk6FphL._SL500_.jpg","\/41ezKUu7VRL._SL500_.jpg","\/41A1n3K+r5L._SL500_.jpg","\/41aY2T8lEOL._SL500_.jpg","\/419Ca1V6HZL._SL500_.jpg","\/41zQkYyLPzL._SL500_.jpg","\/41YpHcyxiTL._SL500_.jpg","\/41-tKN5mt6L._SL500_.jpg","\/419Mv6m55IL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815631085","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815631085","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"E8MM1","s":"s"});</script></p>
<div id="msmaflink-E8MM1">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p><p>The post <a href="https://caymezon.com/aws-handson-console-s3-cloudfront-hosting/">AWSコンソールだけでS3 + CloudFront静的サイトホスティングを構築する手順【SAM版との比較付き / 新UI対応】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-console-s3-cloudfront-hosting/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>AWSコンソールだけでS3 + Lambdaファイルアップロードトリガーを構築する手順【SAM版との比較付き】</title>
		<link>https://caymezon.com/aws-handson-console-s3-event-lambda/</link>
					<comments>https://caymezon.com/aws-handson-console-s3-event-lambda/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Mon, 23 Feb 2026 04:16:15 +0000</pubDate>
				<category><![CDATA[AWS Basic]]></category>
		<category><![CDATA[Cloud & Infra]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[AWSコンソール]]></category>
		<category><![CDATA[Lambda]]></category>
		<category><![CDATA[S3]]></category>
		<category><![CDATA[S3イベント]]></category>
		<category><![CDATA[SAM比較]]></category>
		<category><![CDATA[ハンズオン]]></category>
		<category><![CDATA[ファイルアップロード]]></category>
		<category><![CDATA[初心者]]></category>
		<category><![CDATA[非同期処理]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20204</guid>

					<description><![CDATA[<p>目次 はじめにSAM vs コンソール：どれだけ違うか構築するもの全体の作業順序① S3 バケット作成1-1. バケットの設定② Lambda 関数作成2-1. 基本設定2-2. コードの入力③ S3 トリガーを Lam [&#8230;]</p>
<p>The post <a href="https://caymezon.com/aws-handson-console-s3-event-lambda/">AWSコンソールだけでS3 + Lambdaファイルアップロードトリガーを構築する手順【SAM版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-20" checked><label class="toc-title" for="toc-checkbox-20">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">SAM vs コンソール：どれだけ違うか</a></li><li><a href="#toc3" tabindex="0">構築するもの</a></li><li><a href="#toc4" tabindex="0">全体の作業順序</a></li><li><a href="#toc5" tabindex="0">① S3 バケット作成</a><ol><li><a href="#toc6" tabindex="0">1-1. バケットの設定</a></li></ol></li><li><a href="#toc7" tabindex="0">② Lambda 関数作成</a><ol><li><a href="#toc8" tabindex="0">2-1. 基本設定</a></li><li><a href="#toc9" tabindex="0">2-2. コードの入力</a></li></ol></li><li><a href="#toc10" tabindex="0">③ S3 トリガーを Lambda に追加</a></li><li><a href="#toc11" tabindex="0">④ 動作テスト</a><ol><li><a href="#toc12" tabindex="0">4-1. テスト用ファイルの準備</a></li><li><a href="#toc13" tabindex="0">4-2. ファイルのアップロード</a></li><li><a href="#toc14" tabindex="0">4-3. CloudWatch Logs でログを確認</a></li><li><a href="#toc15" tabindex="0">4-4. 日本語ファイル名のテスト（任意）</a></li></ol></li><li><a href="#toc16" tabindex="0">⑤ リソースの削除</a><ol><li><a href="#toc17" tabindex="0">1. S3 バケット内のオブジェクトをすべて削除する</a></li><li><a href="#toc18" tabindex="0">2. S3 バケットを削除する</a></li><li><a href="#toc19" tabindex="0">3. Lambda 関数を削除する</a></li><li><a href="#toc20" tabindex="0">4. IAM ロールを削除する（任意）</a></li><li><a href="#toc21" tabindex="0">5. CloudWatch Logs のロググループを削除する（任意）</a></li></ol></li><li><a href="#toc22" tabindex="0">SAMとの対比まとめ</a></li><li><a href="#toc23" tabindex="0">トラブルシューティング</a></li><li><a href="#toc24" tabindex="0">まとめ</a><ol><li><a href="#toc25" tabindex="0">コンソール操作で確認できたこと</a></li><li><a href="#toc26" tabindex="0">どちらを使うべきか</a></li></ol></li><li><a href="#toc27" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>この記事は、<a href="https://caymezon.com/aws-handson-s3-event-lambda/">SAM版ハンズオン記事</a>の比較版です。</p>
<p>SAM版ではコマンド数本でS3バケット・Lambda・イベント通知設定が完了しましたが、<strong>「SAMが裏で何をやっているのか？」「バケット名のグローバルユニーク問題はどう解決する？」「再帰呼び出しの警告って何？」</strong> といった疑問を実際のコンソール操作を通じて体験できるのがこの記事です。</p>
<p><strong>この記事を読むとわかること：</strong></p>
<ul>
<li>S3・Lambda を個別に設定する順序と依存関係</li>
<li>SAMの <code>!Sub &quot;${AWS::StackName}-upload-${AWS::AccountId}&quot;</code> が解決していること（バケット名のグローバルユニーク問題）</li>
<li>「再帰呼び出し」警告の意味と、今回は無視してよい理由</li>
<li>S3バケット削除時に「先に空にする」が必要な理由</li>
</ul>
<hr>
<h2><span id="toc2">SAM vs コンソール：どれだけ違うか</span></h2>
<table>
<thead>
<tr>
<th>比較項目</th>
<th>SAM（コード）</th>
<th>コンソール（手動）</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>バケット名の一意性確保</strong></td>
<td><code>!Sub &quot;...-${AWS::AccountId}&quot;</code> で自動</td>
<td><strong>手動でグローバルユニークな名前を考える</strong></td>
</tr>
<tr>
<td><strong>S3イベント通知設定</strong></td>
<td><code>Type: S3</code> の1行</td>
<td><strong>Lambda → トリガーを追加（画面操作）</strong></td>
</tr>
<tr>
<td><strong>リソースベースポリシー</strong></td>
<td>自動追加</td>
<td><strong>トリガー追加時に自動追加（画面の警告を確認する必要あり）</strong></td>
</tr>
<tr>
<td><strong>削除</strong></td>
<td>バケットを空にしてから <code>sam delete</code></td>
<td><strong>S3オブジェクト削除 → バケット削除 → Lambda削除 × 個別操作</strong></td>
</tr>
</tbody>
</table>
<hr>
<p><a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"></p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWSの基本・仕組み・重要用語が全部わかる教科書 (見るだけ図解)","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51DEDQXj6oL._SL500_.jpg","\/41F589smNwL._SL500_.jpg","\/41R6f9yyCWL._SL500_.jpg","\/41HqWQ9BvmL._SL500_.jpg","\/41p8p0ZU79L._SL500_.jpg","\/41qLC-fndBL._SL500_.jpg","\/41fcLv9VT5L._SL500_.jpg","\/51lRvCsvHqL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815607850","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815607850","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%83%BB%E4%BB%95%E7%B5%84%E3%81%BF%E3%83%BB%E9%87%8D%E8%A6%81%E7%94%A8%E8%AA%9E%E3%81%8C%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E6%95%99%E7%A7%91%E6%9B%B8%20(%E8%A6%8B%E3%82%8B%E3%81%A0%E3%81%91%E5%9B%B3%E8%A7%A3)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"eaCUB","s":"s"});</script></p>
<div id="msmaflink-eaCUB">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p>
<h2><span id="toc3">構築するもの</span></h2>
<p>SAM版と全く同じ構成・機能のファイルアップロードトリガー環境を構築します。</p>
<pre><code class="language-plaintext">ファイルアップロード（コンソール / AWS CLI）
  ↓ S3 ObjectCreated イベント発火
S3 バケット（my-s3-event-upload）
  ↓ Lambda を呼び出し
Lambda（S3EventFunction / Python 3.12）
  ↓ ファイル情報（バケット名・ファイル名・サイズ）をログ出力
CloudWatch Logs</code></pre>
<hr>
<h2><span id="toc4">全体の作業順序</span></h2>
<pre><code class="language-plaintext">① S3 バケット作成
      ↓
② Lambda 関数作成（コード入力）
      ↓
③ S3 トリガーを Lambda に追加（リソースベースポリシーも自動設定）
      ↓
④ ファイルアップロードして動作テスト
⑤ リソースの削除（S3を先に空にする）</code></pre>
<blockquote>
<p><strong>順序の理由：</strong><br />③でS3トリガーを追加する際に「どのバケットを対象にするか」を選択するため、①でバケットを先に作成しておく必要があります。SQSハンズオンのようにARNのコピーが必要な場面はありませんが、バケットが存在しないとトリガー設定画面で選択できません。</p>
</blockquote>
<hr>
<h2><span id="toc5">① S3 バケット作成</span></h2>
<p><strong>AWSコンソール → S3 → 「バケットを作成」</strong></p>
<p><!-- ![S3 バケット作成画面](images/s3-create-bucket.jpg) --></p>
<h3><span id="toc6">1-1. バケットの設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>バケット名</td>
<td><code>my-s3-event-upload</code>（任意。グローバルで一意な名前）</td>
</tr>
<tr>
<td>AWSリージョン</td>
<td><strong>アジアパシフィック（東京）ap-northeast-1</strong></td>
</tr>
<tr>
<td>オブジェクト所有者</td>
<td>ACL 無効（デフォルトのまま）</td>
</tr>
<tr>
<td>パブリックアクセスのブロック</td>
<td>すべてブロック（デフォルトのまま）</td>
</tr>
<tr>
<td>バージョニング</td>
<td>無効（デフォルトのまま）</td>
</tr>
<tr>
<td>暗号化</td>
<td>Amazon S3 マネージドキー（デフォルトのまま）</td>
</tr>
</tbody>
</table>
<p>「バケットを作成」をクリックします。</p>
<blockquote>
<p><strong>バケット名のルール（SAMとの違いが出るポイント）：</strong></p>
<p>S3のバケット名はAWS全体（全リージョン・全アカウント）でグローバルユニークである必要があります。</p>
<ul>
<li>小文字・数字・ハイフンのみ使用可（大文字・アンダースコアは使えない）</li>
<li><code>my-s3-event-upload</code> だと他のユーザーがすでに使っている可能性がある</li>
</ul>
<p><strong>一意にする推奨の方法：</strong></p>
<ul>
<li><code>my-s3-event-upload-自分のAWSアカウントID</code>（最も確実）</li>
<li><code>my-s3-event-upload-20260222</code>（日付を付ける）</li>
</ul>
<p>SAMでは <code>!Sub &quot;${AWS::StackName}-upload-${AWS::AccountId}&quot;</code> で自動的にアカウントIDを付加しています。コンソールではこのルールを頭の中で考えて手動入力する必要があります。</p>
</blockquote>
<p><strong>控えておく情報：</strong></p>
<ul>
<li>バケット名（例: <code>my-s3-event-upload</code>）</li>
</ul>
<hr>
<h2><span id="toc7">② Lambda 関数作成</span></h2>
<p><strong>AWSコンソール → Lambda → 「関数の作成」</strong></p>
<h3><span id="toc8">2-1. 基本設定</span></h3>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>作成方法</td>
<td>一から作成</td>
</tr>
<tr>
<td>関数名</td>
<td><code>S3EventFunction</code></td>
</tr>
<tr>
<td>ランタイム</td>
<td><strong>Python 3.12</strong></td>
</tr>
<tr>
<td>アーキテクチャ</td>
<td>x86_64</td>
</tr>
<tr>
<td>実行ロール</td>
<td>「基本的な Lambda アクセス権限で新しいロールを作成」（デフォルトのまま）</td>
</tr>
</tbody>
</table>
<p>「関数の作成」をクリックします。</p>
<blockquote>
<p><strong>実行ロールについて：</strong><br />今回の Lambda はS3イベントのメタデータ（バケット名・ファイル名・サイズ）を受け取るだけで、S3からファイルの<strong>中身を読み取る処理は行いません</strong>。<br />そのため、基本実行ロール（CloudWatch Logs への書き込み権限のみ）で動作します。<br />ファイルの中身を読み取りたい場合は、実行ロールに <code>s3:GetObject</code> 権限を追加する必要があります。</p>
</blockquote>
<h3><span id="toc9">2-2. コードの入力</span></h3>
<p>関数ページ → 「コード」タブ → コードエディタで <code>lambda_function.py</code> を開きます。</p>
<p>既存の内容を<strong>全て</strong>置き換えて以下を貼り付けます。</p>
<pre><code class="language-python">import json
import urllib.parse


def lambda_handler(event, context):
    results = []

    for record in event["Records"]:          # 複数ファイル同時アップロードに対応
        bucket = record["s3"]["bucket"]["name"]
        # キー名は URL エンコードされているためデコードが必要（日本語・スペース対応）
        key = urllib.parse.unquote_plus(record["s3"]["object"]["key"])
        size = record["s3"]["object"]["size"]
        event_name = record["eventName"]     # 例: "ObjectCreated:Put"
        event_time = record["eventTime"]     # 例: "2026-02-22T10:00:00.000Z"

        info = {
            "eventName": event_name,
            "bucket": bucket,
            "key": key,
            "sizeBytes": size,
            "eventTime": event_time,
        }

        print(json.dumps(info, ensure_ascii=False))
        results.append(info)

    print(json.dumps({"processedCount": len(results)}, ensure_ascii=False))
    return {"processedCount": len(results)}</code></pre>
<p>「Deploy」ボタンをクリックしてコードを保存します。</p>
<hr>
<h2><span id="toc10">③ S3 トリガーを Lambda に追加</span></h2>
<p>Lambdaコンソールからトリガーを追加する方法と、S3コンソールからイベント通知を設定する方法の2つがありますが、ここではLambdaコンソールから行います。</p>
<p><strong>Lambda → <code>S3EventFunction</code> → 「設定」タブ → 「トリガー」→「トリガーを追加」</strong></p>
<p><!-- ![Lambda S3トリガー追加画面](images/lambda-s3-trigger-add.jpg) --></p>
<table>
<thead>
<tr>
<th>設定項目</th>
<th>値</th>
</tr>
</thead>
<tbody>
<tr>
<td>ソース</td>
<td><strong>S3</strong></td>
</tr>
<tr>
<td>バケット</td>
<td>① で作成したバケット（例: <code>my-s3-event-upload</code>）</td>
</tr>
<tr>
<td>イベントタイプ</td>
<td><strong>すべてのオブジェクト作成イベント</strong></td>
</tr>
<tr>
<td>プレフィックス</td>
<td>空欄（全フォルダが対象）</td>
</tr>
<tr>
<td>サフィックス</td>
<td>空欄（全ファイルタイプが対象）</td>
</tr>
<tr>
<td>再帰呼び出し</td>
<td>「このトリガーを確認しました」にチェック</td>
</tr>
</tbody>
</table>
<p>「追加」をクリックします。</p>
<blockquote>
<p><strong>「再帰呼び出し」の警告とは：</strong></p>
<p>S3バケットへのアップロードをトリガーに<strong>同じバケットへ書き込む Lambda</strong> を設定すると、無限ループが発生します。例えば「画像をアップロード → Lambdaがリサイズして同じバケットに保存 → それがまたトリガーになる → …」というパターンです。</p>
<p>今回の Lambda はS3への書き込みを行わず、ログを出力するだけなので問題ありません。「このトリガーを確認しました」にチェックして続行してください。</p>
<p><strong>SAMとの差分：</strong> SAMの <code>Type: S3</code> イベントでも同じ構成になっています。SAMは警告なしに設定されますが、同じリスクが存在します。</p>
</blockquote>
<blockquote>
<p><strong>自動設定されること：</strong><br />Lambdaのリソースベースポリシーに「S3からの呼び出しを許可するポリシー」が自動追加されます。<br />S3がLambdaを呼び出すためのIAM設定を手動で行う必要はありません。</p>
</blockquote>
<hr>
<h2><span id="toc11">④ 動作テスト</span></h2>
<h3><span id="toc12">4-1. テスト用ファイルの準備</span></h3>
<pre><code class="language-cmd">echo テストファイルです &gt; C:\test.txt</code></pre>
<h3><span id="toc13">4-2. ファイルのアップロード</span></h3>
<p><strong>方法A: S3 コンソールからアップロード</strong></p>
<p>S3 → <code>my-s3-event-upload</code> → 「アップロード」→「ファイルを追加」→ <code>test.txt</code> を選択 → 「アップロード」</p>
<p><strong>方法B: AWS CLI でアップロード</strong></p>
<pre><code class="language-cmd">aws s3 cp C:\test.txt s3://my-s3-event-upload/test.txt --region ap-northeast-1</code></pre>
<h3><span id="toc14">4-3. CloudWatch Logs でログを確認</span></h3>
<p>Lambda → <code>S3EventFunction</code> → 「モニタリング」タブ → 「CloudWatch Logs を表示」→ 最新のログストリームを開きます。</p>
<p><!-- ![CloudWatch Logsのログ確認](images/cloudwatch-logs-output.jpg) --></p>
<p><strong>期待するログ出力：</strong></p>
<pre><code class="language-json">{"eventName": "ObjectCreated:Put", "bucket": "my-s3-event-upload", "key": "test.txt", "sizeBytes": 28, "eventTime": "2026-02-22T10:00:00.000Z"}
{"processedCount": 1}</code></pre>
<p><strong>確認ポイント：</strong></p>
<ul>
<li><code>&quot;eventName&quot;: &quot;ObjectCreated:Put&quot;</code> — S3の Put（アップロード）が検知されている</li>
<li><code>&quot;key&quot;: &quot;test.txt&quot;</code> — アップロードしたファイル名が正しく取得されている</li>
<li><code>&quot;sizeBytes&quot;</code> — ファイルサイズが記録されている</li>
</ul>
<h3><span id="toc15">4-4. 日本語ファイル名のテスト（任意）</span></h3>
<pre><code class="language-cmd">echo 日本語テスト &gt; "C:\テスト.txt"
aws s3 cp "C:\テスト.txt" "s3://my-s3-event-upload/テスト.txt" --region ap-northeast-1</code></pre>
<p>ログで <code>&quot;key&quot;: &quot;テスト.txt&quot;</code> と正しくデコードされていることを確認します。</p>
<hr>
<h2><span id="toc16">⑤ リソースの削除</span></h2>
<p><strong>課金を止めるために、ハンズオン完了後は必ずリソースを削除してください。</strong></p>
<blockquote>
<p><strong>S3バケット削除の重要な注意点：</strong><br /><strong>オブジェクトが残っているバケットは削除できません。</strong><br />先にバケット内のファイルをすべて削除してからバケットを削除してください。</p>
<p>SAMの <code>sam delete</code> でも同じ理由から「先にバケットを空にする」手順が必要です。この仕様はSAMを使っても変わりません。</p>
</blockquote>
<h3><span id="toc17">1. S3 バケット内のオブジェクトをすべて削除する</span></h3>
<p><strong>方法A: S3 コンソールから</strong></p>
<p>S3 → <code>my-s3-event-upload</code> → ファイルをすべて選択 → 「削除」→ 確認テキストを入力 → 「オブジェクトを削除」</p>
<p><strong>方法B: AWS CLI で一括削除（推奨）</strong></p>
<pre><code class="language-cmd">aws s3 rm s3://my-s3-event-upload --recursive --region ap-northeast-1</code></pre>
<h3><span id="toc18">2. S3 バケットを削除する</span></h3>
<p><strong>S3 → <code>my-s3-event-upload</code> を選択 → 「削除」→ バケット名を入力 → 「バケットを削除」</strong></p>
<h3><span id="toc19">3. Lambda 関数を削除する</span></h3>
<p><strong>Lambda → 関数 → <code>S3EventFunction</code> を選択 → 「アクション」→「削除」→ 確認テキストを入力 → 「削除」</strong></p>
<h3><span id="toc20">4. IAM ロールを削除する（任意）</span></h3>
<p><strong>IAM → ロール → <code>S3EventFunction-role-XXXX</code> を選択 → 「削除」→ ロール名を入力 → 「削除」</strong></p>
<p>Lambda を削除してもIAMロールはそのまま残ります。不要なら手動で削除します。</p>
<h3><span id="toc21">5. CloudWatch Logs のロググループを削除する（任意）</span></h3>
<p><strong>CloudWatch → ロググループ → <code>/aws/lambda/S3EventFunction</code> → 「アクション」→「ロググループの削除」</strong></p>
<hr>
<h2><span id="toc22">SAMとの対比まとめ</span></h2>
<table>
<thead>
<tr>
<th>SAMの記述</th>
<th>コンソールでやること</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Type: AWS::S3::Bucket</code></td>
<td>S3 → バケットを作成</td>
</tr>
<tr>
<td><code>!Sub &quot;${AWS::StackName}-upload-${AWS::AccountId}&quot;</code></td>
<td>手動でグローバルユニークなバケット名を考えて入力</td>
</tr>
<tr>
<td><code>Type: S3</code> イベント / <code>Events: s3:ObjectCreated:*</code></td>
<td>Lambda → トリガーを追加（S3・全オブジェクト作成イベント）</td>
</tr>
<tr>
<td>リソースベースポリシー（自動）</td>
<td>トリガー追加時に自動設定（「再帰呼び出し」警告にチェック）</td>
</tr>
<tr>
<td><code>DeletionPolicy: Delete</code></td>
<td>手動でバケットを空にしてからバケット削除</td>
</tr>
<tr>
<td><code>sam delete</code></td>
<td>S3バケット・Lambda・IAMロール・ロググループを個別に削除</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc23">トラブルシューティング</span></h2>
<table>
<thead>
<tr>
<th>症状</th>
<th>原因</th>
<th>対処</th>
</tr>
</thead>
<tbody>
<tr>
<td>ファイルをアップロードしてもLambdaが起動しない</td>
<td>S3トリガーが設定されていない</td>
<td>③ の手順でトリガーを追加する</td>
</tr>
<tr>
<td>ログに <code>&quot;key&quot;</code> が <code>%XX%XX...</code> と表示される</td>
<td>URLデコードされていない</td>
<td><code>urllib.parse.unquote_plus(key)</code> でデコードしているか確認</td>
</tr>
<tr>
<td>バケット削除がエラーになる</td>
<td>バケット内にオブジェクトが残っている</td>
<td><code>aws s3 rm s3://バケット名 --recursive</code> で先に空にする</td>
</tr>
<tr>
<td>Lambda が 500 エラー</td>
<td>コードの構文エラーなど</td>
<td>CloudWatch Logs でエラー内容を確認</td>
</tr>
<tr>
<td>トリガー追加時に「再帰呼び出し」の警告が出る</td>
<td>同バケットへの書き込みトリガーへの注意</td>
<td>今回のLambdaはS3に書き込まないためチェックを入れて続行</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc24">まとめ</span></h2>
<h3><span id="toc25">コンソール操作で確認できたこと</span></h3>
<table>
<thead>
<tr>
<th>SAMの記述</th>
<th>コンソール操作で理解できたこと</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>!Sub &quot;...-${AWS::AccountId}&quot;</code></td>
<td>バケット名のグローバルユニーク問題を手動で解決する必要がある</td>
</tr>
<tr>
<td><code>Type: S3</code> イベント（自動）</td>
<td>トリガー追加画面で「再帰呼び出し警告」の意味を確認できる</td>
</tr>
<tr>
<td><code>DeletionPolicy: Delete</code></td>
<td>S3は「先に空にしてから削除」が必須ルール（SAMでも同じ）</td>
</tr>
</tbody>
</table>
<h3><span id="toc26">どちらを使うべきか</span></h3>
<table>
<thead>
<tr>
<th>シーン</th>
<th>推奨</th>
</tr>
</thead>
<tbody>
<tr>
<td>本番環境・チーム開発</td>
<td><strong>SAM</strong>（バケット名の管理・再現性・速度）</td>
</tr>
<tr>
<td>AWSを初めて学ぶ</td>
<td><strong>コンソール</strong>（各設定の意味を理解する）</td>
</tr>
<tr>
<td>構築済みリソースの確認・デバッグ</td>
<td><strong>コンソール</strong>（S3のオブジェクト確認・イベント通知設定の目視）</td>
</tr>
<tr>
<td>同じ構成を繰り返しデプロイ</td>
<td><strong>SAM</strong>（ミスゼロ・自動化）</td>
</tr>
</tbody>
</table>
<hr>
<h2><span id="toc27">関連記事</span></h2>
<ul>
<li>SAM版ハンズオン — コマンド数本でS3 + Lambdaトリガー環境を構築</li>
</ul>

<a rel="noopener" href="https://caymezon.com/aws-handson-s3-event-lambda/" title="AWSハンズオン - S3へのファイルアップロードをトリガーにLambdaを自動起動しよう【SAM版 / Windows対応】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/02/aws-handson-s3-event-lambda-featured-a9f1dc-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/02/aws-handson-s3-event-lambda-featured-a9f1dc-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/02/aws-handson-s3-event-lambda-featured-a9f1dc-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/02/aws-handson-s3-event-lambda-featured-a9f1dc-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/02/aws-handson-s3-event-lambda-featured-a9f1dc-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">AWSハンズオン - S3へのファイルアップロードをトリガーにLambdaを自動起動しよう【SAM版 / Windows対応】</div><div class="blogcard-snippet internal-blogcard-snippet">はじめに「S3にファイルが上がったら自動で処理したい」というのは、AWSを使う現場でよく出てくる要件です。画像のリサイズ、CSVの集計、ログファイルの解析など、ファイルアップロードを起点にした自動処理はサーバーレス構成の代表的なユースケース...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.02.23</div></div></div></div></a>
<p><a rel="nofollow" href="//af.moshimo.com/af/c/click?a_id=1384942&p_id=170&pc_id=185&pl_id=4062&url=https%3A%2F%2Fwww.amazon.co.jp%2Fs%3Fk%3D%25E6%259C%25AC%2BAWS%2B%25E9%2596%258B%25E7%2599%25BA%26__mk_ja_JP%3D%25E3%2582%25AB%25E3%2582%25BF%25E3%2582%25AB%25E3%2583%258A%26crid%3D1DE63UBHFOR4K%26sprefix%3D%25E6%259C%25AC%2Baws%2B%25E9%2596%258B%25E7%2599%25BA%252Caps%252C167%26ref%3Dnb_sb_noss" referrerpolicy="no-referrer-when-downgrade" attributionsrc>Amazon検索[本 AWS 開発]</a><img decoding="async" src="//i.moshimo.com/af/i/impression?a_id=1384942&p_id=170&pc_id=185&pl_id=4062" width="1" height="1" style="border:none;" alt="" loading="lazy"></p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"AWS運用入門 改訂第2版 押さえておきたいAWSの基本と運用ノウハウ [AWS深掘りガイド]","b":"SBクリエイティブ","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/51AAOubymTL._SL500_.jpg","\/51VMG6YKHdL._SL500_.jpg","\/41EdPB8azAL._SL500_.jpg","\/41v2JFE-9jL._SL500_.jpg","\/41FEEqR-yDL._SL500_.jpg","\/41JfZAdnTPL._SL500_.jpg","\/41vGK0czQrL._SL500_.jpg","\/41-SnYtz2aL._SL500_.jpg","\/41sPrV5fi3L._SL500_.jpg","\/41p7JtvYJ1L._SL500_.jpg","\/4169GVNTs8L._SL500_.jpg","\/41BPI5HP3zL._SL500_.jpg","\/41QOyk60CYL._SL500_.jpg","\/41APjk6FphL._SL500_.jpg","\/41ezKUu7VRL._SL500_.jpg","\/41A1n3K+r5L._SL500_.jpg","\/41aY2T8lEOL._SL500_.jpg","\/419Ca1V6HZL._SL500_.jpg","\/41zQkYyLPzL._SL500_.jpg","\/41YpHcyxiTL._SL500_.jpg","\/41-tKN5mt6L._SL500_.jpg","\/419Mv6m55IL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4815631085","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4815631085","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=AWS%E9%81%8B%E7%94%A8%E5%85%A5%E9%96%80%20%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88%20%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84AWS%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%A8%E9%81%8B%E7%94%A8%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6%20%5BAWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89%5D","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"E8MM1","s":"s"});</script></p>
<div id="msmaflink-E8MM1">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p><p>The post <a href="https://caymezon.com/aws-handson-console-s3-event-lambda/">AWSコンソールだけでS3 + Lambdaファイルアップロードトリガーを構築する手順【SAM版との比較付き】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/aws-handson-console-s3-event-lambda/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
