toshiki-notebook/development/aws/handson-serverless.html

262 lines
150 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en-US" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Hands-on #5: サーバーレス入門 | Toshiki's Note</title>
<meta name="description" content="Toshiki's web notebook served via Vitepress!">
<link rel="preload stylesheet" href="/assets/style.5b8dc1f0.css" as="style">
<script type="module" src="/assets/app.11c168a7.js"></script>
<link rel="preload" href="/assets/inter-roman-latin.2ed14f66.woff2" as="font" type="font/woff2" crossorigin="">
<link rel="modulepreload" href="/assets/chunks/framework.b7580407.js">
<link rel="modulepreload" href="/assets/chunks/theme.c3ca1c74.js">
<link rel="modulepreload" href="/assets/chunks/commonjsHelpers.725317a4.js">
<link rel="modulepreload" href="/assets/chunks/PageInfo.vue_vue_type_script_setup_true_lang.250b3e56.js">
<link rel="modulepreload" href="/assets/chunks/s3_bucket_filelist.89f3f384.js">
<link rel="modulepreload" href="/assets/development_aws_handson-serverless.md.38fdac97.lean.js">
<link rel="stylesheet" href="https://cdnjs.toshiki.dev/ajax/libs/KaTeX/0.16.0/katex.min.css">
<link rel="stylesheet" href="https://cdnjs.toshiki.dev/ajax/libs/font-awesome/6.3.0/css/all.min.css">
<link rel="icon" href="https://r2.toshiki.dev/cdn/toshiki-notebook-favicon/favicon.ico">
<meta name="author" content="Anda Toshiki">
<meta name="keywords" content="Toshiki, Anda Toshiki, andatoshiki, GitHub, GitHub action, Vitepress, Vite, Notebook, Knowledge base, Programming, Programming Notes, Academic, Personal, Notebook, Productivity, Journal, Note-taking, Markdown, Notepad, Organization, Tutorial">
<meta name="google-site-verification" content="lm7PNJiYSPEx1dMast1Xptc0Vk0cU06o-daZSsIgr2I">
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="theme-color" content="#3c8772">
<meta property="og:type" content="website">
<meta property="og:locale" content="en-US">
<meta property="og:title" content="Toshiki&#39;s Note">
<meta property="og:description" content="Toshiki&#39;s web notebook served via Vitepress!">
<meta property="og:site" content="https://note.toshiki.dev">
<meta property="og:site_name" content="Toshiki&#39;s Note">
<meta property="og:image" content="https://note.toshiki.dev/og-cover.png">
<script>function siteruntime(){window.setTimeout("siteruntime()",1e3),X=new Date("8/24/2021 10:28:00"),Y=new Date,T=Y.getTime()-X.getTime(),M=24*60*60*1e3,a=T/M,A=Math.floor(a),b=(a-A)*24,B=Math.floor(b),c=(b-B)*60,C=Math.floor((b-B)*60),D=Math.floor((c-C)*60),siteruntime_span.innerHTML="This site has been running for: "+A+" day(s) "+B+" hour(s) "+C+" minute(s) "+D+" second(s)"}siteruntime();</script>
<script async defer data-website-id="" src=""></script>
<script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
<script id="check-mac-os">document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform));</script>
</head>
<body>
<div id="app"><div class="Layout" data-v-f6284a77><!--[--><!--]--><!--[--><span tabindex="-1" data-v-315fcc9b></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-315fcc9b> Skip to content </a><!--]--><!----><header class="VPNav" data-v-f6284a77 data-v-ff202323><div class="VPNavBar has-sidebar" data-v-ff202323 data-v-57f83237><div class="container" data-v-57f83237><div class="title" data-v-57f83237><div class="VPNavBarTitle has-sidebar" data-v-57f83237 data-v-87c32abd><a class="title" href="/" data-v-87c32abd><!--[--><!--]--><!--[--><img class="VPImage logo" src="/logos/logo.png" alt data-v-6ebf9bdf><!--]--><!--[-->Toshiki&#39;s Note<!--]--><!--[--><!--]--></a></div></div><div class="content" data-v-57f83237><div class="curtain" data-v-57f83237></div><div class="content-body" data-v-57f83237><!--[--><!--]--><div class="VPNavBarSearch search" data-v-57f83237><!--[--><!----><div id="docsearch"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><svg class="DocSearch-Search-Icon" width="20" height="20" viewBox="0 0 20 20" aria-label="search icon"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-57f83237 data-v-183ec936><span id="main-nav-aria-label" class="visually-hidden" data-v-183ec936>Main Navigation</span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/development/file-naming-convention" tabindex="0" data-v-183ec936 data-v-416f44b0><!--[--><span data-v-416f44b0>Development</span><!--]--></a><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup active" data-v-183ec936 data-v-62bba1f9><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-62bba1f9><span class="text" data-v-62bba1f9><!----><span data-v-62bba1f9>Academic</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-62bba1f9><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-62bba1f9><div class="VPMenu" data-v-62bba1f9 data-v-17c3596a><div class="items" data-v-17c3596a><!--[--><!--[--><div class="VPMenuGroup" data-v-17c3596a data-v-b9d0e57b><p class="title" data-v-b9d0e57b>K-12</p><!--[--><!--[--><div class="VPMenuLink" data-v-b9d0e57b data-v-ec5470f2><a class="VPLink link" href="/academic/chemistry/index" data-v-ec5470f2><!--[-->Chemistry<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-b9d0e57b data-v-ec5470f2><a class="VPLink link" href="/discrete-math/index" data-v-ec5470f2><!--[-->Discrete Math.<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-b9d0e57b data-v-ec5470f2><a class="VPLink link" href="/academic/literature/index" data-v-ec5470f2><!--[-->Literature<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-b9d0e57b data-v-ec5470f2><a class="VPLink link" href="/academic/cis105/index" data-v-ec5470f2><!--[-->CIS105<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-17c3596a data-v-b9d0e57b><p class="title" data-v-b9d0e57b>Tools</p><!--[--><!--[--><div class="VPMenuLink" data-v-b9d0e57b data-v-ec5470f2><a class="VPLink link" href="/academic/physics/ipho-formulas-jpn/1" data-v-ec5470f2><!--[-->Formulas for IPhO JPN.<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuLink" data-v-17c3596a data-v-ec5470f2><span class="VPLink" data-v-ec5470f2><!--[--><!--]--></span></div><!--]--><!--[--><div class="VPMenuLink" data-v-17c3596a data-v-ec5470f2><span class="VPLink" data-v-ec5470f2><!--[--><!--]--></span></div><!--]--><!--[--><div class="VPMenuLink" data-v-17c3596a data-v-ec5470f2><span class="VPLink" data-v-ec5470f2><!--[--><!--]--></span></div><!--]--><!--[--><div class="VPMenuLink" data-v-17c3596a data-v-ec5470f2><span class="VPLink" data-v-ec5470f2><!--[--><!--]--></span></div><!--]--><!--[--><div class="VPMenuLink" data-v-17c3596a data-v-ec5470f2><span class="VPLink" data-v-ec5470f2><!--[--><!--]--></span></div><!--]--><!--[--><div class="VPMenuLink" data-v-17c3596a data-v-ec5470f2><span class="VPLink" data-v-ec5470f2><!--[--><!--]--></span></div><!--]--><!--[--><div class="VPMenuLink" data-v-17c3596a data-v-ec5470f2><span class="VPLink" data-v-ec5470f2><!--[--><!--]--></span></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-183ec936 data-v-62bba1f9><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-62bba1f9><span class="text" data-v-62bba1f9><!----><span data-v-62bba1f9>Application</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-62bba1f9><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-62bba1f9><div class="VPMenu" data-v-62bba1f9 data-v-17c3596a><div class="items" data-v-17c3596a><!--[--><!--[--><div class="VPMenuGroup" data-v-17c3596a data-v-b9d0e57b><p class="title" data-v-b9d0e57b>Personal projects</p><!--[--><!--[--><div class="VPMenuLink" data-v-b9d0e57b data-v-ec5470f2><a class="VPLink link" href="/application/markdown-it-katex/how-to-use" data-v-ec5470f2><!--[-->markdown-it-katex<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-b9d0e57b data-v-ec5470f2><a class="VPLink link" href="/application/vitepress-plugin-shiki-twoslash/index" data-v-ec5470f2><!--[-->vitepress-plugin-shiki-twoslash<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-183ec936 data-v-62bba1f9><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-62bba1f9><span class="text" data-v-62bba1f9><!----><span data-v-62bba1f9>Save</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-62bba1f9><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-62bba1f9><div class="VPMenu" data-v-62bba1f9 data-v-17c3596a><div class="items" data-v-17c3596a><!--[--><!--[--><div class="VPMenuLink" data-v-17c3596a data-v-ec5470f2><a class="VPLink link" href="/save/reading/index" data-v-ec5470f2><!--[-->Reading<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-17c3596a data-v-ec5470f2><a class="VPLink link" href="/academic/vocabulary/index" data-v-ec5470f2><!--[-->Vocabulary<!--]--></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-57f83237 data-v-dc7cad42><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-dc7cad42 data-v-65b67168 data-v-56eb52d1><span class="check" data-v-56eb52d1><span class="icon" data-v-56eb52d1><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-65b67168><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-65b67168><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-57f83237 data-v-aaebde08 data-v-8a65be56><!--[--><a class="VPSocialLink no-icon" href="https://github.com/andatoshiki" aria-label="github" target="_blank" rel="noopener" data-v-8a65be56 data-v-1b61e2c7><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="https://twitter.com/andatoshiki" aria-label="twitter" target="_blank" rel="noopener" data-v-8a65be56 data-v-1b61e2c7><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Twitter</title><path d="M21.543 7.104c.015.211.015.423.015.636 0 6.507-4.954 14.01-14.01 14.01v-.003A13.94 13.94 0 0 1 0 19.539a9.88 9.88 0 0 0 7.287-2.041 4.93 4.93 0 0 1-4.6-3.42 4.916 4.916 0 0 0 2.223-.084A4.926 4.926 0 0 1 .96 9.167v-.062a4.887 4.887 0 0 0 2.235.616A4.928 4.928 0 0 1 1.67 3.148 13.98 13.98 0 0 0 11.82 8.292a4.929 4.929 0 0 1 8.39-4.49 9.868 9.868 0 0 0 3.128-1.196 4.941 4.941 0 0 1-2.165 2.724A9.828 9.828 0 0 0 24 4.555a10.019 10.019 0 0 1-2.457 2.549z"/></svg></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-57f83237 data-v-e5c8c6ca data-v-62bba1f9><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-62bba1f9><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="icon" data-v-62bba1f9><circle cx="12" cy="12" r="2"></circle><circle cx="19" cy="12" r="2"></circle><circle cx="5" cy="12" r="2"></circle></svg></button><div class="menu" data-v-62bba1f9><div class="VPMenu" data-v-62bba1f9 data-v-17c3596a><!----><!--[--><!--[--><!----><div class="group" data-v-e5c8c6ca><div class="item appearance" data-v-e5c8c6ca><p class="label" data-v-e5c8c6ca>Appearance</p><div class="appearance-action" data-v-e5c8c6ca><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-e5c8c6ca data-v-65b67168 data-v-56eb52d1><span class="check" data-v-56eb52d1><span class="icon" data-v-56eb52d1><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-65b67168><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-65b67168><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div></div></div><div class="group" data-v-e5c8c6ca><div class="item social-links" data-v-e5c8c6ca><div class="VPSocialLinks social-links-list" data-v-e5c8c6ca data-v-8a65be56><!--[--><a class="VPSocialLink no-icon" href="https://github.com/andatoshiki" aria-label="github" target="_blank" rel="noopener" data-v-8a65be56 data-v-1b61e2c7><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="https://twitter.com/andatoshiki" aria-label="twitter" target="_blank" rel="noopener" data-v-8a65be56 data-v-1b61e2c7><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Twitter</title><path d="M21.543 7.104c.015.211.015.423.015.636 0 6.507-4.954 14.01-14.01 14.01v-.003A13.94 13.94 0 0 1 0 19.539a9.88 9.88 0 0 0 7.287-2.041 4.93 4.93 0 0 1-4.6-3.42 4.916 4.916 0 0 0 2.223-.084A4.926 4.926 0 0 1 .96 9.167v-.062a4.887 4.887 0 0 0 2.235.616A4.928 4.928 0 0 1 1.67 3.148 13.98 13.98 0 0 0 11.82 8.292a4.929 4.929 0 0 1 8.39-4.49 9.868 9.868 0 0 0 3.128-1.196 4.941 4.941 0 0 1-2.165 2.724A9.828 9.828 0 0 0 24 4.555a10.019 10.019 0 0 1-2.457 2.549z"/></svg></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-57f83237 data-v-f865e4ad><span class="container" data-v-f865e4ad><span class="top" data-v-f865e4ad></span><span class="middle" data-v-f865e4ad></span><span class="bottom" data-v-f865e4ad></span></span></button></div></div></div></div><!----></header><div class="VPLocalNav reached-top" data-v-f6284a77 data-v-a41c4a1c><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-a41c4a1c><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="menu-icon" data-v-a41c4a1c><path d="M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z"></path><path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z"></path><path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z"></path><path d="M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z"></path></svg><span class="menu-text" data-v-a41c4a1c>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-a41c4a1c data-v-44ae7a43><button data-v-44ae7a43>Return to top</button><!----></div></div><aside class="VPSidebar" data-v-f6284a77 data-v-7ab77f34><div class="curtain" data-v-7ab77f34></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-7ab77f34><span class="visually-hidden" id="sidebar-aria-label" data-v-7ab77f34> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="group" data-v-7ab77f34><section class="VPSidebarItem level-0 collapsible" data-v-7ab77f34 data-v-1b9f5c6f><div class="item" role="button" tabindex="0" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><h2 class="text" data-v-1b9f5c6f>Notes & Issues</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-1b9f5c6f><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-1b9f5c6f><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-1b9f5c6f><!--[--><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/file-naming-convention" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>File Naming Convention</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/rclone-for-r2" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>RClone for R2</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/proxy4shell-terminal" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>Proxies Configuration for Shells & Terminal</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/git-push-authentication-failed" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>Git push results in "Authentication Failed"</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/installing-npm-package-behind-proxy" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>Installing NPM Packages Behind Proxy</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-7ab77f34><section class="VPSidebarItem level-0 collapsible has-active" data-v-7ab77f34 data-v-1b9f5c6f><div class="item" role="button" tabindex="0" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><h2 class="text" data-v-1b9f5c6f>コードで学ぶAWS入門</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-1b9f5c6f><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-1b9f5c6f><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-1b9f5c6f><!--[--><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/index" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>背景</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/main" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>はじめに!</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/cloud" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>クラウド概論</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/aws-get-started" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>AWS 入門</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/handson-ec2" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>Hands-on 1: 初めての EC2 インスタンスを起動する</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/scientific-computing" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>クラウドで行う科学計算・機械学習</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/handson-ec2" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>Hands-on 2: AWS でディープラーニングを実践</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/docker-system" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>Docker 入門</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/handson-qabot" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>Hands-on 3: AWS で自動質問回答ボットを走らせる</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/aws-batch" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>Hands-on 4: AWS Batch を使って機械学習のハイパーパラメータサーチを並列化する</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/webserver" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>Web サービスの作り方</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/serverless" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>Serverless architecture</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/handson-serverless" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>Hands-on 5: サーバーレス入門</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/handson-bashoutter" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>Hands-on 6: Bashoutter</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/closing" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>まとめ</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/appendix" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>ppendix: 環境構築</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1b9f5c6f data-v-1b9f5c6f><div class="item" data-v-1b9f5c6f><div class="indicator" data-v-1b9f5c6f></div><a class="VPLink link link" href="/development/aws/acknowledgement" data-v-1b9f5c6f><!--[--><p class="text" data-v-1b9f5c6f>謝辞</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-f6284a77 data-v-f3ed2c70><div class="VPDoc has-sidebar has-aside" data-v-f3ed2c70 data-v-39e6c32d><!--[--><!--]--><div class="container" data-v-39e6c32d><div class="aside" data-v-39e6c32d><div class="aside-curtain" data-v-39e6c32d></div><div class="aside-container" data-v-39e6c32d><div class="aside-content" data-v-39e6c32d><div class="VPDocAside" data-v-39e6c32d data-v-f5b3965e><!--[--><!--]--><!--[--><!--]--><div class="VPDocAsideOutline" role="navigation" data-v-f5b3965e data-v-99fa007f><div class="content" data-v-99fa007f><div class="outline-marker" data-v-99fa007f></div><div class="outline-title" role="heading" aria-level="2" data-v-99fa007f>TOC</div><nav aria-labelledby="doc-outline-aria-label" data-v-99fa007f><span class="visually-hidden" id="doc-outline-aria-label" data-v-99fa007f> Table of Contents for current page </span><ul class="root" data-v-99fa007f data-v-29e3fa2f><!--[--><!--]--></ul></nav></div></div><!--[--><!--]--><div class="spacer" data-v-f5b3965e></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--[--><!--[--><!--[--><div class="VPDocAsideSponsors"><div class="VPSponsors vp-sponsor aside"><!--[--><section class="vp-sponsor-section"><!----><div class="VPSponsorsGrid vp-sponsor-grid medium"><!--[--><div class="vp-sponsor-grid-item"><a class="vp-sponsor-grid-link" target="_blank" rel="sponsored noopener"><article class="vp-sponsor-grid-box"><h4 class="visually-hidden"></h4><img class="vp-sponsor-grid-image" src="https://jsd.toshiki.dev/gh/andatoshiki/toshiki-notebook@master/assets/logo/sponsor/telegram.png"></article></a></div><!--]--></div></section><!--]--></div></div><!--]--><!--]--><!--]--><!--]--></div></div></div></div><div class="content" data-v-39e6c32d><div class="content-container" data-v-39e6c32d><!--[--><!--]--><!----><main class="main" data-v-39e6c32d><div style="position:relative;" class="vp-doc _development_aws_handson-serverless" data-v-39e6c32d><div><h1 id="hands-on-5-サーバーレス入門" tabindex="-1">Hands-on #5: サーバーレス入門 <a class="header-anchor" href="#hands-on-5-サーバーレス入門" aria-label="Permalink to &quot;Hands-on \#5: サーバーレス入門&quot;"></a></h1><div><section class="border-b-1 border-[var(--vp-c-divider)] w-full border-b-solid mt-[24px] pb-[12px] flex gap-[12px] mb-[12px] flex-wrap max-w-[85%]"><div class="flex gap-[4px] items-center"><svg style="display:inline-block;" viewBox="0 0 16 16" width="1.2em" height="1.2em"><path fill="currentColor" d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16Zm.847-8.145a2.502 2.502 0 1 0-1.694 0C5.471 8.261 4 9.775 4 11c0 .395.145.995 1 .995h6c.855 0 1-.6 1-.995c0-1.224-1.47-2.74-3.153-3.145Z"></path></svg> Author:<span>Anda Toshiki</span></div><!----><div class="flex gap-[4px] items-center"><svg style="display:inline-block;" viewBox="0 0 15 15" width="1.2em" height="1.2em"><path fill="currentColor" fill-rule="evenodd" d="M1.903 7.297c0 3.044 2.207 5.118 4.686 5.547a.521.521 0 1 1-.178 1.027C3.5 13.367.861 10.913.861 7.297c0-1.537.699-2.745 1.515-3.663c.585-.658 1.254-1.193 1.792-1.602H2.532a.5.5 0 0 1 0-1h3a.5.5 0 0 1 .5.5v3a.5.5 0 0 1-1 0V2.686l-.001.002c-.572.43-1.27.957-1.875 1.638c-.715.804-1.253 1.776-1.253 2.97Zm11.108.406c0-3.012-2.16-5.073-4.607-5.533a.521.521 0 1 1 .192-1.024c2.874.54 5.457 2.98 5.457 6.557c0 1.537-.699 2.744-1.515 3.663c-.585.658-1.254 1.193-1.792 1.602h1.636a.5.5 0 1 1 0 1h-3a.5.5 0 0 1-.5-.5v-3a.5.5 0 1 1 1 0v1.845h.002c.571-.432 1.27-.958 1.874-1.64c.715-.803 1.253-1.775 1.253-2.97Z" clip-rule="evenodd"></path></svg> Updated:<span>5 minutes ago</span></div><div class="flex gap-[4px] items-center"><svg style="display:inline-block;" viewBox="0 0 16 16" width="1.2em" height="1.2em"><path fill="currentColor" d="M9.293 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4.707A1 1 0 0 0 13.707 4L10 .293A1 1 0 0 0 9.293 0zM9.5 3.5v-2l3 3h-2a1 1 0 0 1-1-1zM5.485 6.879l1.036 4.144l.997-3.655a.5.5 0 0 1 .964 0l.997 3.655l1.036-4.144a.5.5 0 0 1 .97.242l-1.5 6a.5.5 0 0 1-.967.01L8 9.402l-1.018 3.73a.5.5 0 0 1-.967-.01l-1.5-6a.5.5 0 1 1 .97-.242z"></path></svg> Words:<span>2.4k</span></div><div class="flex gap-[4px] items-center"><svg style="display:inline-block;" viewBox="0 0 20 20" width="1.2em" height="1.2em"><path fill="currentColor" d="M10 0a10 10 0 1 0 10 10A10 10 0 0 0 10 0zm2.5 14.5L9 11V4h2v6l3 3z"></path></svg> Reading:<span>10 min</span></div></section></div><p>前章ではサーバーレスアーキテクチャの概要の説明を行った. 本章では,ハンズオン形式でサーバーレスクラウドを実際に動かしながら,具体的な使用方法を学んでいこう. 今回のハンズオンでは Lambda, S3, DynamoDB の三つのサーバーレスクラウドの構成要素に触れていく. それぞれについて,短いチュートリアルを用意してある.</p><h2 id="lambda-ハンズオン" tabindex="-1">Lambda ハンズオン <a class="header-anchor" href="#lambda-ハンズオン" aria-label="Permalink to &quot;Lambda ハンズオン&quot;"></a></h2><p>まずは, Lambda を実際に動かしてみよう. ハンズオンのソースコードは GitHub の <a href="https://github.com/andatoshiki/toshiki-notebooktree/main/handson/serverless/lambda" target="_blank" rel="noreferrer">handson/serverless/lambda</a> に置いてある.</p><p>このハンズオンで使用するアプリケーションのスケッチを <a href="#fig:lambda_deploy">figure_title</a> に示す. STEP 1 ではAWS CDK を使用して Python で書かれたコードを Lambda に登録する. 続いて STEP 2 では, Invoke API を使用して,同時にいくつもの Lambda を起動し,並列な計算を行う. Lambda のワークフローを体験する目的で最小限の設定である.</p><p><img src="/assets/lambda_deploy.a63df8e9.png" alt="Lambda チュートリアルの概要"></p><p>このハンズオンは,基本的に <a href="https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRank&amp;all-free-tier.sort-order=asc" target="_blank" rel="noreferrer">AWS Lambda の無料枠</a> の範囲内で実行することができる.</p><p><a href="https://github.com/andatoshiki/toshiki-notebookblob/main/handson/serverless/lambda/app.py" target="_blank" rel="noreferrer">app.py</a> にデプロイするプログラムが書かれている. 中身を見てみよう.</p><div class="language-python vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#768390;">#</span></span>
<span class="line"><span style="color:#6CB6FF;">FUNC</span><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">&quot;&quot;&quot;</span></span>
<span class="line"><span style="color:#96D0FF;">import time</span></span>
<span class="line"><span style="color:#96D0FF;">from random import choice, randint</span></span>
<span class="line"><span style="color:#96D0FF;">def handler(event, context):</span></span>
<span class="line"><span style="color:#96D0FF;"> time.sleep(randint(2,5))</span></span>
<span class="line"><span style="color:#96D0FF;"> sushi = [&quot;salmon&quot;, &quot;tuna&quot;, &quot;squid&quot;]</span></span>
<span class="line"><span style="color:#96D0FF;"> message = &quot;Welcome to Cloud Sushi. Your order is &quot; + choice(sushi)</span></span>
<span class="line"><span style="color:#96D0FF;"> print(message)</span></span>
<span class="line"><span style="color:#96D0FF;"> return message</span></span>
<span class="line"><span style="color:#96D0FF;">&quot;&quot;&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F47067;">class</span><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">SimpleLambda</span><span style="color:#ADBAC7;">(</span><span style="color:#6CB6FF;">core</span><span style="color:#ADBAC7;">.</span><span style="color:#6CB6FF;">Stack</span><span style="color:#ADBAC7;">):</span></span>
<span class="line"></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">def</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">__init__</span><span style="color:#ADBAC7;">(self, scope: core.App, name: </span><span style="color:#6CB6FF;">str</span><span style="color:#ADBAC7;">, </span><span style="color:#F47067;">**</span><span style="color:#ADBAC7;">kwargs) -&gt; </span><span style="color:#6CB6FF;">None</span><span style="color:#ADBAC7;">:</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">super</span><span style="color:#ADBAC7;">().</span><span style="color:#6CB6FF;">__init__</span><span style="color:#ADBAC7;">(scope, name, </span><span style="color:#F47067;">**</span><span style="color:#ADBAC7;">kwargs)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">#</span></span>
<span class="line"><span style="color:#ADBAC7;"> handler </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> _lambda.Function(</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">self</span><span style="color:#ADBAC7;">, </span><span style="color:#96D0FF;">&#39;LambdaHandler&#39;</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">runtime</span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;">_lambda.Runtime.</span><span style="color:#6CB6FF;">PYTHON_3_7</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">code</span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;">_lambda.Code.from_inline(</span><span style="color:#6CB6FF;">FUNC</span><span style="color:#ADBAC7;">),</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">handler</span><span style="color:#F47067;">=</span><span style="color:#96D0FF;">&quot;index.handler&quot;</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">memory_size</span><span style="color:#F47067;">=</span><span style="color:#6CB6FF;">128</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">timeout</span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;">core.Duration.seconds(</span><span style="color:#6CB6FF;">10</span><span style="color:#ADBAC7;">),</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">dead_letter_queue_enabled</span><span style="color:#F47067;">=</span><span style="color:#6CB6FF;">True</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> )</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">#</span></span>
<span class="line"><span style="color:#005CC5;">FUNC</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&quot;&quot;&quot;</span></span>
<span class="line"><span style="color:#032F62;">import time</span></span>
<span class="line"><span style="color:#032F62;">from random import choice, randint</span></span>
<span class="line"><span style="color:#032F62;">def handler(event, context):</span></span>
<span class="line"><span style="color:#032F62;"> time.sleep(randint(2,5))</span></span>
<span class="line"><span style="color:#032F62;"> sushi = [&quot;salmon&quot;, &quot;tuna&quot;, &quot;squid&quot;]</span></span>
<span class="line"><span style="color:#032F62;"> message = &quot;Welcome to Cloud Sushi. Your order is &quot; + choice(sushi)</span></span>
<span class="line"><span style="color:#032F62;"> print(message)</span></span>
<span class="line"><span style="color:#032F62;"> return message</span></span>
<span class="line"><span style="color:#032F62;">&quot;&quot;&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">SimpleLambda</span><span style="color:#24292E;">(</span><span style="color:#6F42C1;">core</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">Stack</span><span style="color:#24292E;">):</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">def</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">__init__</span><span style="color:#24292E;">(self, scope: core.App, name: </span><span style="color:#005CC5;">str</span><span style="color:#24292E;">, </span><span style="color:#D73A49;">**</span><span style="color:#24292E;">kwargs) -&gt; </span><span style="color:#005CC5;">None</span><span style="color:#24292E;">:</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">super</span><span style="color:#24292E;">().</span><span style="color:#005CC5;">__init__</span><span style="color:#24292E;">(scope, name, </span><span style="color:#D73A49;">**</span><span style="color:#24292E;">kwargs)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6A737D;">#</span></span>
<span class="line"><span style="color:#24292E;"> handler </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> _lambda.Function(</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">self</span><span style="color:#24292E;">, </span><span style="color:#032F62;">&#39;LambdaHandler&#39;</span><span style="color:#24292E;">,</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#E36209;">runtime</span><span style="color:#D73A49;">=</span><span style="color:#24292E;">_lambda.Runtime.</span><span style="color:#005CC5;">PYTHON_3_7</span><span style="color:#24292E;">,</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#E36209;">code</span><span style="color:#D73A49;">=</span><span style="color:#24292E;">_lambda.Code.from_inline(</span><span style="color:#005CC5;">FUNC</span><span style="color:#24292E;">),</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#E36209;">handler</span><span style="color:#D73A49;">=</span><span style="color:#032F62;">&quot;index.handler&quot;</span><span style="color:#24292E;">,</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#E36209;">memory_size</span><span style="color:#D73A49;">=</span><span style="color:#005CC5;">128</span><span style="color:#24292E;">,</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#E36209;">timeout</span><span style="color:#D73A49;">=</span><span style="color:#24292E;">core.Duration.seconds(</span><span style="color:#005CC5;">10</span><span style="color:#24292E;">),</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#E36209;">dead_letter_queue_enabled</span><span style="color:#D73A49;">=</span><span style="color:#005CC5;">True</span><span style="color:#24292E;">,</span></span>
<span class="line"><span style="color:#24292E;"> )</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br></div></div><ul><li><p>ここで, Lambda で実行されるべき関数を定義している. これは非常に単純な関数で2-5 秒のランダムな時間スリープした後,[&quot;salmon&quot;, &quot;tuna&quot;, &quot;squid&quot;] のいずれかの文字列をランダムに選択し, &quot;Welcome to Cloud Sushi. Your order is XXXX&quot; (XXXX は選ばれた寿司のネタ) というメッセージをリターンする.</p></li><li><p>次に, Lambda に &lt;1&gt; で書いた関数を配置している. パラメータの意味は,文字どおりの意味なので難しくはないが,以下に解説する.</p><ul><li><p><code>runtime=_lambda.Runtime.PYTHON_3_7</code>: ここでは, Python3.7 を使って上記で定義された関数を実行せよ,と指定している. Python3.7 のほかに, Node.js, Java, Ruby, Go などの言語を指定することが可能である.</p></li><li><p><code>code=_lambda.Code.from_inline(FUNC)</code>: 実行されるべき関数が書かれたコードを指定する. ここでは, <code>FUNC=...</code> で定義した文字列を渡しているが,文字列以外にもファイルのパスを渡すことも可能である.</p></li><li><p><code>handler=&quot;index.handler&quot;</code>: これは,コードの中にいくつかのサブ関数が含まれているときに,メインとサブを区別するためのパラメータである. <code>handler</code> という名前の関数をメイン関数として実行せよ,という意味である.</p></li><li><p><code>memory_size=128</code>: メモリーは 128MB を最大で使用することを指定している.</p></li><li><p><code>timeout=core.Duration.seconds(10)</code> タイムアウト時間を 10 秒に設定している. 10 秒以内に関数の実行が終了しなかった場合,エラーが返される.</p></li><li><p><code>dead_letter_queue_enabled=True</code>: アドバンストな設定なので説明は省略する.</p></li></ul></li></ul><p>上記のプログラムを実行することで, Lambda 関数がクラウド上に作成される. 早速デプロイしてみよう.</p><h3 id="デプロイ" tabindex="-1">デプロイ <a class="header-anchor" href="#デプロイ" aria-label="Permalink to &quot;デプロイ&quot;"></a></h3><p>デプロイの手順は,これまでのハンズオンとほとんど共通である. ここでは,コマンドのみ列挙する (<code>#</code> で始まる行はコメントである) それぞれの意味を忘れてしまった場合は,ハンズオン 1, 2 に戻って復習していただきたい. シークレットキーの設定も忘れずに ( (#aws_cli_install))</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#768390;"># プロジェクトのディレクトリに移動</span></span>
<span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">cd</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">handson/serverless/lambda</span></span>
<span class="line"></span>
<span class="line"><span style="color:#768390;"># venv を作成し,依存ライブラリのインストールを行う</span></span>
<span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">python3</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">-m</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">venv</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">.env</span></span>
<span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">source</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">.env/bin/activate</span></span>
<span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">pip</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">install</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">-r</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">requirements.txt</span></span>
<span class="line"></span>
<span class="line"><span style="color:#768390;"># デプロイを実行</span></span>
<span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">cdk</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">deploy</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;"># プロジェクトのディレクトリに移動</span></span>
<span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">cd</span><span style="color:#24292E;"> </span><span style="color:#032F62;">handson/serverless/lambda</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;"># venv を作成し,依存ライブラリのインストールを行う</span></span>
<span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">python3</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">-m</span><span style="color:#24292E;"> </span><span style="color:#032F62;">venv</span><span style="color:#24292E;"> </span><span style="color:#032F62;">.env</span></span>
<span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">source</span><span style="color:#24292E;"> </span><span style="color:#032F62;">.env/bin/activate</span></span>
<span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">pip</span><span style="color:#24292E;"> </span><span style="color:#032F62;">install</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">-r</span><span style="color:#24292E;"> </span><span style="color:#032F62;">requirements.txt</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;"># デプロイを実行</span></span>
<span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">cdk</span><span style="color:#24292E;"> </span><span style="color:#032F62;">deploy</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>デプロイのコマンドが無事に実行されれば, <a href="#handson_04_lambda_cdk_output">figure_title</a> のような出力が得られるはずである. ここで表示されている <code>SimpleLambda.FunctionName = XXXX</code> の XXXX の文字列は後で使うのでメモしておこう.</p><p><img src="/assets/handson_04_lambda_cdk_output.ec6ce64a.png" alt="CDKデプロイ実行後の出力"></p><p>AWS コンソールにログインして,デプロイされたスタックを確認してみよう. コンソールからLambda のページに行くと <a href="#handson_04_lambda_console_func_list">figure_title</a> のような画面から Lambda の関数の一覧が確認できる.</p><p><img src="/assets/lambda_console_func_list.dfadf8c1.png" alt="Lambda コンソール - 関数の一覧"></p><p>今回のアプリケーションで作成したのが <code>SimpleLambda</code> で始まるランダムな名前のついた関数だ. 関数の名前をクリックして,詳細を見てみる. すると <a href="#handson_04_lambda_console_func_detail">figure_title</a> のような画面が表示されるはずだ. 先ほどプログラムの中で定義した Python の関数がエディターから確認できる. さらに下の方にスクロールすると,関数の各種設定も確認できる.</p><p><img src="/assets/lambda_console_func_detail.aaf392fb.png" alt="Lambda コンソール - 関数の詳細"></p><p>Lambda で実行されるコードは, Lambda のコンソール画面 (<a href="#handson_04_lambda_console_func_detail">figure_title</a>) のエディターで編集することもできる. デバッグをするときなどは,こちらを直接いじる方が早い場合もある. その場合は, CDK のコードに行った編集を反映させなおすことを忘れずに.</p><h3 id="lambda-関数の実行" tabindex="-1">Lambda 関数の実行 <a class="header-anchor" href="#lambda-関数の実行" aria-label="Permalink to &quot;Lambda 関数の実行&quot;"></a></h3><p>それでは,作成した Lambda 関数を実行 (invoke) してみよう. AWS の API を使うことで,関数の実行をスタートすることができる. 今回は, <a href="https://github.com/andatoshiki/toshiki-notebookblob/main/handson/serverless/lambda/invoke_one.py" target="_blank" rel="noreferrer">handson/serverless/lambda/invoke_one.py</a> に関数を実行するための簡単なプログラムを提供している. 興味のある読者はコードを読んでもらいたい.</p><p>以下のコマンドでLambda の関数を実行する. コマンドの <code>XXXX</code> の部分は,先ほどデプロイしたときに <code>SimpleLambda.FunctionName = XXXX</code> で得られた XXXX の文字列で置換する.</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">python</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">invoke_one.py</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">XXXX</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">python</span><span style="color:#24292E;"> </span><span style="color:#032F62;">invoke_one.py</span><span style="color:#24292E;"> </span><span style="color:#032F62;">XXXX</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><p>すると, <code>&quot;Welcome to Cloud Sushi. Your order is salmon&quot;</code> という出力が得られるはずだ. とてもシンプルではあるが,クラウド上で先ほどの関数が走り,乱数が生成されたうえで,ランダムな寿司ネタが選択されて出力が返されている. このコマンドを何度か打ってみて,実行ごとに異なる寿司ネタが返されることを確認しよう.</p><p>さて,このコマンドは,一度につき一回の関数を実行したわけであるが, Lambda の本領は一度に大量のタスクを同時に実行できる点である. そこで,今度は一度に 100 個のタスクを同時に送信してみよう. <a href="https://github.com/andatoshiki/toshiki-notebookblob/main/handson/serverless/lambda/invoke_many.py" target="_blank" rel="noreferrer">handson/serverless/lambda/invoke_many.py</a> のスクリプトを使用する.</p><p>次のコマンドを実行しよう. XXXX の部分は前述と同様に置き換える. 第二引数の <code>100</code> は 100 個のタスクを投入せよ,という意味である.</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">python</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">invoke_many.py</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">XXXX</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">100</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">python</span><span style="color:#24292E;"> </span><span style="color:#032F62;">invoke_many.py</span><span style="color:#24292E;"> </span><span style="color:#032F62;">XXXX</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">100</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><p>すると次のような出力が得られるはずだ.</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#6CB6FF;">....................................................................................................</span></span>
<span class="line"><span style="color:#F69D50;">Submitted</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">100</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">tasks</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">to</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">Lambda!</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">....................................................................................................</span></span>
<span class="line"><span style="color:#6F42C1;">Submitted</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">100</span><span style="color:#24292E;"> </span><span style="color:#032F62;">tasks</span><span style="color:#24292E;"> </span><span style="color:#032F62;">to</span><span style="color:#24292E;"> </span><span style="color:#032F62;">Lambda!</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>実際に100 個のタスクが同時に実行されていることを確認しよう. <a href="#handson_04_lambda_console_func_detail">figure_title</a> の画面に戻り, &quot;Monitoring&quot; というタブがあるので,それをクリックする. すると, <a href="#handson_04_lambda_console_monitoring">figure_title</a> のようなグラフが表示されるだろう.</p><p><img src="/assets/lambda_console_monitoring.ff13afd9.png" alt="Lambda コンソール - 関数の実行のモニタリング"></p><p><a href="#handson_04_lambda_console_monitoring">figure_title</a> のグラフの更新には数分かかることがあるので,なにも表示されない場合は少し待つ.</p><p><a href="#handson_04_lambda_console_monitoring">figure_title</a>&quot;Invocations&quot; が関数が何度実行されたかを意味している. たしかに 100 回実行されていることがわかる. さらに, &quot;Concurrent executions&quot; は何個のタスクが同時に行われたかを示している. ここでは 96 となっていることから96 個のタスクが並列的に実行されたことを意味している (これが 100 とならないのは,タスクの開始のコマンドが送られたのが完全には同タイミングではないことに起因する)</p><p>このように,非常にシンプルではあるが, Lambda を使うことで,同時並列的に処理を実行することのできるクラウドシステムを簡単に作ることができた.</p><p>もしこのようなことを従来的な serverful なクラウドで行おうとした場合,クラスターのスケーリングなど多くのコードを書くことに加えて,いろいろなパラメータを調節する必要がある.</p><p>興味がある人は,一気に 1000 個などのジョブを投入してみるとよい. Lambda はそのような大量のリクエストにも対応できることが確認できるだろう. が,あまりやりすぎると Lambda の無料利用枠を超えて料金が発生してしまうので注意.</p><h3 id="スタックの削除" tabindex="-1">スタックの削除 <a class="header-anchor" href="#スタックの削除" aria-label="Permalink to &quot;スタックの削除&quot;"></a></h3><p>最後にスタックを削除しよう. スタックを削除するには,次のコマンドを実行すればよい.</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">cdk</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">destroy</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">cdk</span><span style="color:#24292E;"> </span><span style="color:#032F62;">destroy</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><h2 id="dynamodb-ハンズオン" tabindex="-1">DynamoDB ハンズオン <a class="header-anchor" href="#dynamodb-ハンズオン" aria-label="Permalink to &quot;DynamoDB ハンズオン&quot;"></a></h2><p>続いて, DynamoDB の簡単なチュートリアルをやってみよう. ハンズオンのソースコードは GitHub の <a href="https://github.com/andatoshiki/toshiki-notebooktree/main/handson/serverless/dynamodb" target="_blank" rel="noreferrer">/handson/serverless/dynamodb</a> に置いてある.</p><p>このハンズオンで使用するアプリケーションのスケッチを <a href="#fig:dynamodb_deploy">figure_title</a> に示す. STEP 1 ではAWS CDK を使用して DynamoDB のテーブルを初期化し,デプロイする. 続いて STEP 2 では, API を使用してデータベースのデータの書き込み・読み出し・削除などの操作を練習する.</p><p><img src="/assets/dynamodb_deploy.adddeb55.png" alt="DynamoDB チュートリアルの概要"></p><p>このハンズオンは,基本的に <a href="https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRank&amp;all-free-tier.sort-order=asc" target="_blank" rel="noreferrer">AWS DynamoDB の無料枠</a> の範囲内で実行できる.</p><p><a href="https://github.com/andatoshiki/toshiki-notebookblob/main/handson/serverless/dynamodb/app.py" target="_blank" rel="noreferrer">handson/serverless/dynamodb/app.py</a> にデプロイするプログラムが書かれている. 中身を見てみよう.</p><div class="language-python vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F47067;">class</span><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">SimpleDynamoDb</span><span style="color:#ADBAC7;">(</span><span style="color:#6CB6FF;">core</span><span style="color:#ADBAC7;">.</span><span style="color:#6CB6FF;">Stack</span><span style="color:#ADBAC7;">):</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">def</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">__init__</span><span style="color:#ADBAC7;">(self, scope: core.App, name: </span><span style="color:#6CB6FF;">str</span><span style="color:#ADBAC7;">, </span><span style="color:#F47067;">**</span><span style="color:#ADBAC7;">kwargs) -&gt; </span><span style="color:#6CB6FF;">None</span><span style="color:#ADBAC7;">:</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">super</span><span style="color:#ADBAC7;">().</span><span style="color:#6CB6FF;">__init__</span><span style="color:#ADBAC7;">(scope, name, </span><span style="color:#F47067;">**</span><span style="color:#ADBAC7;">kwargs)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#ADBAC7;"> table </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> ddb.Table(</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">self</span><span style="color:#ADBAC7;">, </span><span style="color:#96D0FF;">&quot;SimpleTable&quot;</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">#</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">partition_key</span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;">ddb.Attribute(</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">name</span><span style="color:#F47067;">=</span><span style="color:#96D0FF;">&quot;item_id&quot;</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">type</span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;">ddb.AttributeType.</span><span style="color:#6CB6FF;">STRING</span></span>
<span class="line"><span style="color:#ADBAC7;"> ),</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">#</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">billing_mode</span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;">ddb.BillingMode.</span><span style="color:#6CB6FF;">PAY_PER_REQUEST</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;">#</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">removal_policy</span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;">core.RemovalPolicy.</span><span style="color:#6CB6FF;">DESTROY</span></span>
<span class="line"><span style="color:#ADBAC7;"> )</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">SimpleDynamoDb</span><span style="color:#24292E;">(</span><span style="color:#6F42C1;">core</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">Stack</span><span style="color:#24292E;">):</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">def</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">__init__</span><span style="color:#24292E;">(self, scope: core.App, name: </span><span style="color:#005CC5;">str</span><span style="color:#24292E;">, </span><span style="color:#D73A49;">**</span><span style="color:#24292E;">kwargs) -&gt; </span><span style="color:#005CC5;">None</span><span style="color:#24292E;">:</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">super</span><span style="color:#24292E;">().</span><span style="color:#005CC5;">__init__</span><span style="color:#24292E;">(scope, name, </span><span style="color:#D73A49;">**</span><span style="color:#24292E;">kwargs)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;"> table </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> ddb.Table(</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">self</span><span style="color:#24292E;">, </span><span style="color:#032F62;">&quot;SimpleTable&quot;</span><span style="color:#24292E;">,</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6A737D;">#</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#E36209;">partition_key</span><span style="color:#D73A49;">=</span><span style="color:#24292E;">ddb.Attribute(</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#E36209;">name</span><span style="color:#D73A49;">=</span><span style="color:#032F62;">&quot;item_id&quot;</span><span style="color:#24292E;">,</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#E36209;">type</span><span style="color:#D73A49;">=</span><span style="color:#24292E;">ddb.AttributeType.</span><span style="color:#005CC5;">STRING</span></span>
<span class="line"><span style="color:#24292E;"> ),</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6A737D;">#</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#E36209;">billing_mode</span><span style="color:#D73A49;">=</span><span style="color:#24292E;">ddb.BillingMode.</span><span style="color:#005CC5;">PAY_PER_REQUEST</span><span style="color:#24292E;">,</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6A737D;">#</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#E36209;">removal_policy</span><span style="color:#D73A49;">=</span><span style="color:#24292E;">core.RemovalPolicy.</span><span style="color:#005CC5;">DESTROY</span></span>
<span class="line"><span style="color:#24292E;"> )</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br></div></div><p>このコードで,最低限の設定がなされた空の DynamoDB テーブルが作成される. それぞれのパラメータの意味を簡単に解説しよう.</p><ul><li><p><code>partition_key</code>: すべての DynamoDB テーブルには Partition key が定義されていなければならない. Partition key とは,テーブル内の要素 (レコード) ごとに存在する固有の ID のことである. 同一の Partition key をもった要素がテーブルの中に二つ以上存在することはできない (注: Sort Key を使用している場合は除く.詳しくは <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html" target="_blank" rel="noreferrer">公式ドキュメンテーション &quot;Core Components of Amazon DynamoDB&quot;</a> 参照) また, Partition key が定義されていない要素はテーブルの中に存在することはできない. ここでは, Partition key に <code>item_id</code> という名前をつけている.</p></li><li><p><code>billing_mode</code>: <code>ddb.BillingMode.PAY_PER_REQUEST</code> を指定することで, <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html#HowItWorks.OnDemand" target="_blank" rel="noreferrer">On-demand Capacity Mode</a> の DynamoDB が作成される. ほかに <code>PROVISIONED</code> というモードがあるが,これはかなり高度なケースを除いて使用しないだろう.</p></li><li><p><code>removal_policy</code>: CloudFormation のスタックが消去されたときに, DynamoDB も一緒に消去されるかどうかを指定する. このコードでは <code>DESTROY</code> を選んでいるので,すべて消去される. ほかのオプションを選択すると,スタックを消去しても DynamoDB のバックアップを残す,などの動作を定義することができる.</p></li></ul><h3 id="デプロイ-1" tabindex="-1">デプロイ <a class="header-anchor" href="#デプロイ-1" aria-label="Permalink to &quot;デプロイ&quot;"></a></h3><p>デプロイの手順は,これまでのハンズオンとほとんど共通である. ここでは,コマンドのみ列挙する (<code>#</code> で始まる行はコメントである) シークレットキーの設定も忘れずに ( (#aws_cli_install))</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#768390;"># プロジェクトのディレクトリに移動</span></span>
<span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">cd</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">handson/serverless/dynamodb</span></span>
<span class="line"></span>
<span class="line"><span style="color:#768390;"># venv を作成し,依存ライブラリのインストールを行う</span></span>
<span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">python3</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">-m</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">venv</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">.env</span></span>
<span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">source</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">.env/bin/activate</span></span>
<span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">pip</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">install</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">-r</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">requirements.txt</span></span>
<span class="line"></span>
<span class="line"><span style="color:#768390;"># デプロイを実行</span></span>
<span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">cdk</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">deploy</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;"># プロジェクトのディレクトリに移動</span></span>
<span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">cd</span><span style="color:#24292E;"> </span><span style="color:#032F62;">handson/serverless/dynamodb</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;"># venv を作成し,依存ライブラリのインストールを行う</span></span>
<span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">python3</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">-m</span><span style="color:#24292E;"> </span><span style="color:#032F62;">venv</span><span style="color:#24292E;"> </span><span style="color:#032F62;">.env</span></span>
<span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">source</span><span style="color:#24292E;"> </span><span style="color:#032F62;">.env/bin/activate</span></span>
<span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">pip</span><span style="color:#24292E;"> </span><span style="color:#032F62;">install</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">-r</span><span style="color:#24292E;"> </span><span style="color:#032F62;">requirements.txt</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;"># デプロイを実行</span></span>
<span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">cdk</span><span style="color:#24292E;"> </span><span style="color:#032F62;">deploy</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>デプロイのコマンドが無事に実行されれば, <a href="#handson_04_dynamodb_cdk_output">figure_title</a> のような出力が得られるはずである. ここで表示されている <code>SimpleDynamoDb.TableName = XXXX</code> の XXXX の文字列は後で使うのでメモしておこう.</p><p><img src="/assets/handson_04_dynamodb_cdk_output.c99cf287.png" alt="CDKデプロイ実行後の出力"></p><p>AWS コンソールにログインして,デプロイされたスタックを確認してみよう. コンソールから, DynamoDB のページに行き,左のメニューバーから &quot;Tables&quot; を選択する. すると, <a href="#handson_04_dynamodb_table_list">figure_title</a> のような画面からテーブルの一覧が確認できる.</p><p><img src="/assets/dynamodb_table_list.16ed11c0.png" alt="DynamoDB のコンソール (テーブルの一覧)"></p><p>今回のアプリケーションで作成したのが <code>SimpleDynamoDb</code> で始まるランダムな名前のついたテーブルだ. テーブルの名前をクリックして,詳細を見てみる. すると <a href="#handson_04_dynamodb_table_detail">figure_title</a> のような画面が表示されるはずだ. &quot;Items&quot; のタブをクリックすると,テーブルの中のレコードを確認できる. 現時点ではなにもデータを書き込んでいないので,空である.</p><p><img src="/assets/dynamodb_table_detail.5b5e346d.png" alt="DynamoDB のコンソール (テーブルの詳細画面)"></p><h3 id="データの読み書き" tabindex="-1">データの読み書き <a class="header-anchor" href="#データの読み書き" aria-label="Permalink to &quot;データの読み書き&quot;"></a></h3><p>それでは, <a href="#sec:serverless_dynamodb_deploy">デプロイ</a> で作ったテーブルを使ってデータの読み書きを実践してみよう. ここでは Python と <a href="https://boto3.amazonaws.com/v1/documentation/api/latest/index.html" target="_blank" rel="noreferrer">boto3</a> ライブラリを用いた方法を紹介する.</p><p>まずは,テーブルに新しい要素を追加してみよう. ハンズオンのディレクトリにある <a href="https://github.com/andatoshiki/toshiki-notebookblob/main/handson/serverless/dynamodb/simple_write.py" target="_blank" rel="noreferrer">simple_write.py</a> を開いてみよう. 中には次のような関数が書かれている.</p><div class="language-python vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F47067;">import</span><span style="color:#ADBAC7;"> boto3</span></span>
<span class="line"><span style="color:#F47067;">from</span><span style="color:#ADBAC7;"> uuid </span><span style="color:#F47067;">import</span><span style="color:#ADBAC7;"> uuid4</span></span>
<span class="line"><span style="color:#ADBAC7;">ddb </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> boto3.resource(</span><span style="color:#96D0FF;">&#39;dynamodb&#39;</span><span style="color:#ADBAC7;">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F47067;">def</span><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">write_item</span><span style="color:#ADBAC7;">(table_name):</span></span>
<span class="line"><span style="color:#ADBAC7;"> table </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> ddb.Table(table_name)</span></span>
<span class="line"><span style="color:#ADBAC7;"> table.put_item(</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">Item</span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;">{</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">&#39;item_id&#39;</span><span style="color:#ADBAC7;">: </span><span style="color:#6CB6FF;">str</span><span style="color:#ADBAC7;">(uuid4()),</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">&#39;first_name&#39;</span><span style="color:#ADBAC7;">: </span><span style="color:#96D0FF;">&#39;John&#39;</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">&#39;last_name&#39;</span><span style="color:#ADBAC7;">: </span><span style="color:#96D0FF;">&#39;Doe&#39;</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">&#39;age&#39;</span><span style="color:#ADBAC7;">: </span><span style="color:#6CB6FF;">25</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> }</span></span>
<span class="line"><span style="color:#ADBAC7;"> )</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">import</span><span style="color:#24292E;"> boto3</span></span>
<span class="line"><span style="color:#D73A49;">from</span><span style="color:#24292E;"> uuid </span><span style="color:#D73A49;">import</span><span style="color:#24292E;"> uuid4</span></span>
<span class="line"><span style="color:#24292E;">ddb </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> boto3.resource(</span><span style="color:#032F62;">&#39;dynamodb&#39;</span><span style="color:#24292E;">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;">def</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">write_item</span><span style="color:#24292E;">(table_name):</span></span>
<span class="line"><span style="color:#24292E;"> table </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> ddb.Table(table_name)</span></span>
<span class="line"><span style="color:#24292E;"> table.put_item(</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#E36209;">Item</span><span style="color:#D73A49;">=</span><span style="color:#24292E;">{</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#032F62;">&#39;item_id&#39;</span><span style="color:#24292E;">: </span><span style="color:#005CC5;">str</span><span style="color:#24292E;">(uuid4()),</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#032F62;">&#39;first_name&#39;</span><span style="color:#24292E;">: </span><span style="color:#032F62;">&#39;John&#39;</span><span style="color:#24292E;">,</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#032F62;">&#39;last_name&#39;</span><span style="color:#24292E;">: </span><span style="color:#032F62;">&#39;Doe&#39;</span><span style="color:#24292E;">,</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#032F62;">&#39;age&#39;</span><span style="color:#24292E;">: </span><span style="color:#005CC5;">25</span><span style="color:#24292E;">,</span></span>
<span class="line"><span style="color:#24292E;"> }</span></span>
<span class="line"><span style="color:#24292E;"> )</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><p>コードを上から読んでいくと,まず最初に boto3 ライブラリをインポートし, <code>dynamodb</code> のリソースを呼び出している. <code>write_item()</code> 関数は, DynamoDB のテーブルの名前 (上で見た SimpleDynamoDb-XXXX) を引数として受け取る. そして, <code>put_item()</code> メソッドを呼ぶことで,新しいアイテムを DB に書き込んでいる. アイテムには <code>item_id</code>, <code>first_name</code>, <code>last_name</code>, <code>age</code> の 4 つの属性が定義されている. ここで, <code>item_id</code> は先ほど説明した Partition key に相当しており, <a href="https://en.wikipedia.org/wiki/Universally_unique_identifier" target="_blank" rel="noreferrer">UUID4</a> を用いたランダムな文字列を割り当てている.</p><p>では, <code>simple_write.py</code> を実行してみよう. &quot;XXXX&quot; の部分を自分がデプロイしたテーブルの名前 (<code>SimpleDynamoDb</code> で始まる文字列) に置き換えたうえで,次のコマンドを実行する.</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">python</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">simple_write.py</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">XXXX</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">python</span><span style="color:#24292E;"> </span><span style="color:#032F62;">simple_write.py</span><span style="color:#24292E;"> </span><span style="color:#032F62;">XXXX</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><p>新しい要素が正しく書き込めたか, AWS コンソールから確認してみよう. <a href="#handson_04_dynamodb_table_detail">figure_title</a> と同じ手順で,テーブルの中身の要素の一覧を表示する. すると <a href="#fig:dynamodb_table_new_item">figure_title</a> のように,期待通り新しい要素が見つかるだろう.</p><p><img src="/assets/dynamodb_table_new_item.a41b221f.png" alt="DynamoDB に新しい要素が追加されたことを確認"></p><p>boto3 を使ってテーブルから要素を読みだすことも可能である. ハンズオンのディレクトリにある <a href="https://github.com/andatoshiki/toshiki-notebookblob/main/handson/serverless/dynamodb/simple_read.py" target="_blank" rel="noreferrer">simple_read.py</a> を見てみよう.</p><div class="language-python vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F47067;">import</span><span style="color:#ADBAC7;"> boto3</span></span>
<span class="line"><span style="color:#ADBAC7;">ddb </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> boto3.resource(</span><span style="color:#96D0FF;">&#39;dynamodb&#39;</span><span style="color:#ADBAC7;">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F47067;">def</span><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">scan_table</span><span style="color:#ADBAC7;">(table_name):</span></span>
<span class="line"><span style="color:#ADBAC7;"> table </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> ddb.Table(table_name)</span></span>
<span class="line"><span style="color:#ADBAC7;"> items </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> table.scan().get(</span><span style="color:#96D0FF;">&quot;Items&quot;</span><span style="color:#ADBAC7;">)</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">print</span><span style="color:#ADBAC7;">(items)</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">import</span><span style="color:#24292E;"> boto3</span></span>
<span class="line"><span style="color:#24292E;">ddb </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> boto3.resource(</span><span style="color:#032F62;">&#39;dynamodb&#39;</span><span style="color:#24292E;">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;">def</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">scan_table</span><span style="color:#24292E;">(table_name):</span></span>
<span class="line"><span style="color:#24292E;"> table </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> ddb.Table(table_name)</span></span>
<span class="line"><span style="color:#24292E;"> items </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> table.scan().get(</span><span style="color:#032F62;">&quot;Items&quot;</span><span style="color:#24292E;">)</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">print</span><span style="color:#24292E;">(items)</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p><code>table.scan().get(&quot;Items&quot;)</code> によって,テーブルの中にあるすべての要素を読みだしている.</p><p>次のコマンドで,このスクリプトを実行してみよう (&quot;XXXX&quot; の部分を正しく置き換えることを忘れずに).</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">python</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">simple_read.py</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">XXXX</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">python</span><span style="color:#24292E;"> </span><span style="color:#032F62;">simple_read.py</span><span style="color:#24292E;"> </span><span style="color:#032F62;">XXXX</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><p>先ほど書き込んだ要素が出力されることを確認しよう.</p><h3 id="大量のデータの読み書き" tabindex="-1">大量のデータの読み書き <a class="header-anchor" href="#大量のデータの読み書き" aria-label="Permalink to &quot;大量のデータの読み書き&quot;"></a></h3><p>DynamoDB の利点は,最初に述べたとおり,負荷に応じて自在にその処理能力を拡大できる点である.</p><p>そこで,ここでは一度に大量のデータを書き込む場合をシミュレートしてみよう. <a href="https://github.com/andatoshiki/toshiki-notebookblob/main/handson/serverless/dynamodb/batch_rw.py" target="_blank" rel="noreferrer">batch_rw.py</a> に,一度に大量の書き込みを実行するためのプログラムが書いてある.</p><p>次のコマンドを実行してみよう (XXXX は自分のテーブルの名前に置き換える)</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">python</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">batch_rw.py</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">XXXX</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">write</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">1000</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">python</span><span style="color:#24292E;"> </span><span style="color:#032F62;">batch_rw.py</span><span style="color:#24292E;"> </span><span style="color:#032F62;">XXXX</span><span style="color:#24292E;"> </span><span style="color:#032F62;">write</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">1000</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><p>このコマンドを実行することで,ランダムなデータが 1000 個データベースに書き込まれる.</p><p>さらに,データベースの検索をかけてみよう. 今回書き込んだデータには <code>age</code> という属性に 1 から 50 のランダムな整数が割り当てられている. <code>age</code> が 2 以下であるような要素だけを検索し拾ってくるには,次のコマンドを実行すればよい.</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">python</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">batch_rw.py</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">XXXX</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">search_under_age</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">2</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">python</span><span style="color:#24292E;"> </span><span style="color:#032F62;">batch_rw.py</span><span style="color:#24292E;"> </span><span style="color:#032F62;">XXXX</span><span style="color:#24292E;"> </span><span style="color:#032F62;">search_under_age</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">2</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><p>上の 2 つのコマンドを何回か繰り返し実行してみて,データベースに負荷をかけてみよう. とくに大きな遅延なく結果が返ってくることが確認できるだろう.</p><h3 id="スタックの削除-1" tabindex="-1">スタックの削除 <a class="header-anchor" href="#スタックの削除-1" aria-label="Permalink to &quot;スタックの削除&quot;"></a></h3><p>DynamoDB で十分に遊ぶことができたら,忘れずにスタックを削除しよう.</p><p>これまでのハンズオンと同様,スタックを削除するには,次のコマンドを実行すればよい.</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">cdk</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">destroy</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">cdk</span><span style="color:#24292E;"> </span><span style="color:#032F62;">destroy</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><h2 id="s3-ハンズオン" tabindex="-1">S3 ハンズオン <a class="header-anchor" href="#s3-ハンズオン" aria-label="Permalink to &quot;S3 ハンズオン&quot;"></a></h2><p>最後に, S3 の簡単なチュートリアルを紹介する. ハンズオンのソースコードは GitHub の <a href="https://github.com/andatoshiki/toshiki-notebooktree/main/handson/serverless/s3" target="_blank" rel="noreferrer">handson/serverless/s3</a> に置いてある.</p><p><a href="#fig:s3_deploy">figure_title</a> が今回提供する S3 チュートリアルの概要である. STEP 1 として, AWS CDK を用いて S3 に新しい空のバケット (Bucket) を作成する. 続いて STEP 2 では,データのアップロード・ダウンロードの方法を解説する.</p><p><img src="/assets/s3_deploy.1631db9e.png" alt="S3 チュートリアルの概要"></p><p>このハンズオンは,基本的に <a href="https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRank&amp;all-free-tier.sort-order=asc" target="_blank" rel="noreferrer">S3 の無料枠</a> の範囲内で実行することができる.</p><p><a href="https://github.com/andatoshiki/toshiki-notebookblob/main/handson/serverless/s3/app.py" target="_blank" rel="noreferrer">app.py</a> にデプロイするプログラムが書かれている. 中身を見てみよう.</p><div class="language-python vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F47067;">class</span><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">SimpleS3</span><span style="color:#ADBAC7;">(</span><span style="color:#6CB6FF;">core</span><span style="color:#ADBAC7;">.</span><span style="color:#6CB6FF;">Stack</span><span style="color:#ADBAC7;">):</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">def</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">__init__</span><span style="color:#ADBAC7;">(self, scope: core.App, name: </span><span style="color:#6CB6FF;">str</span><span style="color:#ADBAC7;">, </span><span style="color:#F47067;">**</span><span style="color:#ADBAC7;">kwargs) -&gt; </span><span style="color:#6CB6FF;">None</span><span style="color:#ADBAC7;">:</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">super</span><span style="color:#ADBAC7;">().</span><span style="color:#6CB6FF;">__init__</span><span style="color:#ADBAC7;">(scope, name, </span><span style="color:#F47067;">**</span><span style="color:#ADBAC7;">kwargs)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#768390;"># S3 bucket to store data</span></span>
<span class="line"><span style="color:#ADBAC7;"> bucket </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> s3.Bucket(</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">self</span><span style="color:#ADBAC7;">, </span><span style="color:#96D0FF;">&quot;bucket&quot;</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">removal_policy</span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;">core.RemovalPolicy.</span><span style="color:#6CB6FF;">DESTROY</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F69D50;">auto_delete_objects</span><span style="color:#F47067;">=</span><span style="color:#6CB6FF;">True</span><span style="color:#ADBAC7;">,</span></span>
<span class="line"><span style="color:#ADBAC7;"> )</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">SimpleS3</span><span style="color:#24292E;">(</span><span style="color:#6F42C1;">core</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">Stack</span><span style="color:#24292E;">):</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">def</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">__init__</span><span style="color:#24292E;">(self, scope: core.App, name: </span><span style="color:#005CC5;">str</span><span style="color:#24292E;">, </span><span style="color:#D73A49;">**</span><span style="color:#24292E;">kwargs) -&gt; </span><span style="color:#005CC5;">None</span><span style="color:#24292E;">:</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">super</span><span style="color:#24292E;">().</span><span style="color:#005CC5;">__init__</span><span style="color:#24292E;">(scope, name, </span><span style="color:#D73A49;">**</span><span style="color:#24292E;">kwargs)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6A737D;"># S3 bucket to store data</span></span>
<span class="line"><span style="color:#24292E;"> bucket </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> s3.Bucket(</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">self</span><span style="color:#24292E;">, </span><span style="color:#032F62;">&quot;bucket&quot;</span><span style="color:#24292E;">,</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#E36209;">removal_policy</span><span style="color:#D73A49;">=</span><span style="color:#24292E;">core.RemovalPolicy.</span><span style="color:#005CC5;">DESTROY</span><span style="color:#24292E;">,</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#E36209;">auto_delete_objects</span><span style="color:#D73A49;">=</span><span style="color:#005CC5;">True</span><span style="color:#24292E;">,</span></span>
<span class="line"><span style="color:#24292E;"> )</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p><code>s3.Bucket()</code> を呼ぶことによって空のバケットが新規に作成される. 上記のコードだと,バケットの名前は自動生成される. もし,自分の指定した名前を与えたい場合は, <code>bucket_name</code> というパラメータを指定すればよい. その際, バケットの名前はユニークでなければならない (i.e. AWS のデプロイが行われるリージョン内で名前の重複がない) 点に注意しよう. もし,同じ名前のバケットが既に存在する場合はエラーが返ってくる.</p><p>デフォルトでは, CloudFormation スタックが削除されたとき, S3 バケットとその中に保存されたファイルは削除されない. これは,大切なデータを誤って消してしまうことを防止するための安全策である. <code>cdk destroy</code> を実行したときにバケットも含めてすべて削除されるようにするには, <code>removal_policy=core.RemovalPolicy.DESTROY, auto_delete_objects=True</code> とパラメータを設定する. 結果もよく理解したうえで,自分の用途にあった適切なパラメータを設定しよう.</p><h3 id="デプロイ-2" tabindex="-1">デプロイ <a class="header-anchor" href="#デプロイ-2" aria-label="Permalink to &quot;デプロイ&quot;"></a></h3><p>デプロイの手順は,これまでのハンズオンとほとんど共通である. ここでは,コマンドのみ列挙する (<code>#</code> で始まる行はコメントである) シークレットキーの設定も忘れずに ( (#aws_cli_install))</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#768390;"># プロジェクトのディレクトリに移動</span></span>
<span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">cd</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">handson/serverless/s3</span></span>
<span class="line"></span>
<span class="line"><span style="color:#768390;"># venv を作成し,依存ライブラリのインストールを行う</span></span>
<span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">python3</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">-m</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">venv</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">.env</span></span>
<span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">source</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">.env/bin/activate</span></span>
<span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">pip</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">install</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">-r</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">requirements.txt</span></span>
<span class="line"></span>
<span class="line"><span style="color:#768390;"># デプロイを実行</span></span>
<span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">cdk</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">deploy</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;"># プロジェクトのディレクトリに移動</span></span>
<span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">cd</span><span style="color:#24292E;"> </span><span style="color:#032F62;">handson/serverless/s3</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;"># venv を作成し,依存ライブラリのインストールを行う</span></span>
<span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">python3</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">-m</span><span style="color:#24292E;"> </span><span style="color:#032F62;">venv</span><span style="color:#24292E;"> </span><span style="color:#032F62;">.env</span></span>
<span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">source</span><span style="color:#24292E;"> </span><span style="color:#032F62;">.env/bin/activate</span></span>
<span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">pip</span><span style="color:#24292E;"> </span><span style="color:#032F62;">install</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">-r</span><span style="color:#24292E;"> </span><span style="color:#032F62;">requirements.txt</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;"># デプロイを実行</span></span>
<span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">cdk</span><span style="color:#24292E;"> </span><span style="color:#032F62;">deploy</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>デプロイを実行すると, <a href="#fig:s3_deploy_output">figure_title</a> のような出力が得られるはずである. ここで表示されている <code>SimpleS3.BucketName = XXXX</code> が,新しく作られたバケットの名前である (今回提供しているコードを使うとランダムな名前がバケットに割り当てられる). これはあとで使うのでメモしておこう.</p><p><img src="/assets/s3_deploy_output.e2727aaa.png" alt="デプロイ実行後の出力"></p><h3 id="データの読み書き-1" tabindex="-1">データの読み書き <a class="header-anchor" href="#データの読み書き-1" aria-label="Permalink to &quot;データの読み書き&quot;"></a></h3><p>スタックのデプロイが完了したら,早速バケットにデータをアップロードしてみよう.</p><p>まずは,以下のコマンドを実行して, <code>tmp.txt</code> という仮のファイルを生成する.</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">echo</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">&quot;Hello world!&quot;</span><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">&gt;&gt;</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">tmp.txt</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">echo</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&quot;Hello world!&quot;</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">&gt;&gt;</span><span style="color:#24292E;"> </span><span style="color:#032F62;">tmp.txt</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><p>ハンズオンのディレクトリにある <a href="https://github.com/andatoshiki/toshiki-notebookblob/main/handson/serverless/s3/simple_s3.py" target="_blank" rel="noreferrer">simple_s3.py</a><a href="https://boto3.amazonaws.com/v1/documentation/api/latest/index.html" target="_blank" rel="noreferrer">boto3</a> ライブラリを使用した S3 のファイルのアップロード・ダウンロードのスクリプトが書いてある. <code>simple_s3.py</code> を使って,上で作成した <code>tmp.txt</code> を以下のコマンドによりバケットにアップロードする. <code>XXXX</code> のところは,自分自身のバケットの名前で置き換えること.</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">python</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">simple_s3.py</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">XXXX</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">upload</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">tmp.txt</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">python</span><span style="color:#24292E;"> </span><span style="color:#032F62;">simple_s3.py</span><span style="color:#24292E;"> </span><span style="color:#032F62;">XXXX</span><span style="color:#24292E;"> </span><span style="color:#032F62;">upload</span><span style="color:#24292E;"> </span><span style="color:#032F62;">tmp.txt</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><p><code>simple_s3.py</code> のアップロードを担当している部分を以下に抜粋する.</p><div class="language-python vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F47067;">def</span><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">upload_file</span><span style="color:#ADBAC7;">(bucket_name, filename, key</span><span style="color:#F47067;">=</span><span style="color:#6CB6FF;">None</span><span style="color:#ADBAC7;">):</span></span>
<span class="line"><span style="color:#ADBAC7;"> bucket </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> s3.Bucket(bucket_name)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">if</span><span style="color:#ADBAC7;"> key </span><span style="color:#F47067;">is</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">None</span><span style="color:#ADBAC7;">:</span></span>
<span class="line"><span style="color:#ADBAC7;"> key </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> os.path.basename(filename)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#ADBAC7;"> bucket.upload_file(filename, key)</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">def</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">upload_file</span><span style="color:#24292E;">(bucket_name, filename, key</span><span style="color:#D73A49;">=</span><span style="color:#005CC5;">None</span><span style="color:#24292E;">):</span></span>
<span class="line"><span style="color:#24292E;"> bucket </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> s3.Bucket(bucket_name)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">if</span><span style="color:#24292E;"> key </span><span style="color:#D73A49;">is</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">None</span><span style="color:#24292E;">:</span></span>
<span class="line"><span style="color:#24292E;"> key </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> os.path.basename(filename)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;"> bucket.upload_file(filename, key)</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p><code>bucket = s3.Bucket(bucket_name)</code> の行で <code>Bucket()</code> オブジェクトを呼び出している. そして, <code>upload_file()</code> メソッドを呼ぶことでファイルのアップロードを実行している.</p><p>S3 においてファイルの識別子として使われるのが <strong>Key</strong> である. これは,従来的なファイルシステムにおけるパス (Path) と相同な概念で,それぞれのファイルに固有な Key が割り当てられる必要がある. Key という呼び方は, S3 が <a href="https://en.wikipedia.org/wiki/Object_storage" target="_blank" rel="noreferrer">Object storage</a> と呼ばれるシステムに立脚していることに由来する. <code>--key</code> のオプションを追加して <code>simple_s3.py</code> を実行することで, Key を指定してアップロードを実行することができる.</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">python</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">simple_s3.py</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">XXXX</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">upload</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">tmp.txt</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">--key</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">a/b/tmp.txt</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">python</span><span style="color:#24292E;"> </span><span style="color:#032F62;">simple_s3.py</span><span style="color:#24292E;"> </span><span style="color:#032F62;">XXXX</span><span style="color:#24292E;"> </span><span style="color:#032F62;">upload</span><span style="color:#24292E;"> </span><span style="color:#032F62;">tmp.txt</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">--key</span><span style="color:#24292E;"> </span><span style="color:#032F62;">a/b/tmp.txt</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><p>ここではアップロードされたファイルに <code>a/b/tmp.txt</code> という Key を割り当てている.</p><p>ここまでコマンドを実行し終えたところで,一度 AWS コンソールに行き S3 の中身を確認してみよう. S3 のコンソールに行くと,バケットの一覧が見つかるはずである. その中から, <code>simples3-bucket</code> から始まるランダムな名前のついたバケットを探し,クリックする. するとバケットの中に含まれるファイルの一覧が表示される (<a href="#fig:s3_bucket_filelist">figure_title</a>)</p><p><img src="/assets/s3_bucket_filelist.f55c0ee0.png" alt="S3 バケットの中のファイル一覧"></p><p>ここで実行した 2 つのコマンドによって, <code>tmp.txt</code> というファイルと, <code>a/b/tmp.txt</code> というファイルが見つかることに注目しよう. 従来的なファイルシステムと似た体験を提供するため, S3 では Key が <strong>&quot;/&quot; (スラッシュ)</strong> によって区切られていた場合,<strong>ツリー状の階層構造</strong>によってファイルを管理することができる.</p><p>オブジェクトストレージには本来ディレクトリという概念はない. 上で紹介した &quot;/&quot; による階層づけはあくまでユーザー体験向上の目的のお化粧的な機能である.</p><p>次に,バケットからファイルのダウンロードを実行してみよう. <code>simple_s3.py</code> を使って,以下のコマンドを実行すればよい. <code>XXXX</code> のところは,自分自身のバケットの名前で置き換えること.</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">python</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">simple_s3.py</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">XXXX</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">download</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">tmp.txt</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">python</span><span style="color:#24292E;"> </span><span style="color:#032F62;">simple_s3.py</span><span style="color:#24292E;"> </span><span style="color:#032F62;">XXXX</span><span style="color:#24292E;"> </span><span style="color:#032F62;">download</span><span style="color:#24292E;"> </span><span style="color:#032F62;">tmp.txt</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><p><code>simple_s3.py</code> のダウンロードを担当している部分を以下に抜粋する.</p><div class="language-python vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F47067;">def</span><span style="color:#ADBAC7;"> </span><span style="color:#DCBDFB;">download_file</span><span style="color:#ADBAC7;">(bucket_name, key, filename</span><span style="color:#F47067;">=</span><span style="color:#6CB6FF;">None</span><span style="color:#ADBAC7;">):</span></span>
<span class="line"><span style="color:#ADBAC7;"> bucket </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> s3.Bucket(bucket_name)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#ADBAC7;"> </span><span style="color:#F47067;">if</span><span style="color:#ADBAC7;"> filename </span><span style="color:#F47067;">is</span><span style="color:#ADBAC7;"> </span><span style="color:#6CB6FF;">None</span><span style="color:#ADBAC7;">:</span></span>
<span class="line"><span style="color:#ADBAC7;"> filename </span><span style="color:#F47067;">=</span><span style="color:#ADBAC7;"> os.path.basename(key)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#ADBAC7;"> bucket.download_file(key, filename)</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">def</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">download_file</span><span style="color:#24292E;">(bucket_name, key, filename</span><span style="color:#D73A49;">=</span><span style="color:#005CC5;">None</span><span style="color:#24292E;">):</span></span>
<span class="line"><span style="color:#24292E;"> bucket </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> s3.Bucket(bucket_name)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">if</span><span style="color:#24292E;"> filename </span><span style="color:#D73A49;">is</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">None</span><span style="color:#24292E;">:</span></span>
<span class="line"><span style="color:#24292E;"> filename </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> os.path.basename(key)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;"> bucket.download_file(key, filename)</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>S3 からのダウンロードはシンプルで, <code>download_file()</code> メソッドを使って,ダウンロードしたい対象の Key を指定すればよい. ローカルのコンピュータでの保存先のパスを 2 個目の引数として渡している.</p><h3 id="スタックの削除-2" tabindex="-1">スタックの削除 <a class="header-anchor" href="#スタックの削除-2" aria-label="Permalink to &quot;スタックの削除&quot;"></a></h3><p>以上のハンズオンで, S3 の一番基本的な使い方を紹介した. ここまでのハンズオンが理解できたら,忘れずにスタックを削除しよう. これまでのハンズオンと同様,スタックを削除するには,次のコマンドを実行すればよい.</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark-dimmed vp-code-dark"><code><span class="line"><span style="color:#F69D50;">$</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">cdk</span><span style="color:#ADBAC7;"> </span><span style="color:#96D0FF;">destroy</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">$</span><span style="color:#24292E;"> </span><span style="color:#032F62;">cdk</span><span style="color:#24292E;"> </span><span style="color:#032F62;">destroy</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div></div></div></main><footer class="VPDocFooter" data-v-39e6c32d data-v-bae355c8><!--[--><!--[--><!--[--><!--[--><!----><!--]--><!--]--><!--]--><!--]--><div class="edit-info" data-v-bae355c8><div class="edit-link" data-v-bae355c8><a class="VPLink link vp-external-link-icon no-icon edit-link-button" href="https://github.com/andatoshiki/toshiki-notebook/edit/master/docs/development/aws/handson-serverless.md" target="_blank" rel="noreferrer" data-v-bae355c8><!--[--><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="edit-link-icon" aria-label="edit icon" data-v-bae355c8><path d="M18,23H4c-1.7,0-3-1.3-3-3V6c0-1.7,1.3-3,3-3h7c0.6,0,1,0.4,1,1s-0.4,1-1,1H4C3.4,5,3,5.4,3,6v14c0,0.6,0.4,1,1,1h14c0.6,0,1-0.4,1-1v-7c0-0.6,0.4-1,1-1s1,0.4,1,1v7C21,21.7,19.7,23,18,23z"></path><path d="M8,17c-0.3,0-0.5-0.1-0.7-0.3C7,16.5,6.9,16.1,7,15.8l1-4c0-0.2,0.1-0.3,0.3-0.5l9.5-9.5c1.2-1.2,3.2-1.2,4.4,0c1.2,1.2,1.2,3.2,0,4.4l-9.5,9.5c-0.1,0.1-0.3,0.2-0.5,0.3l-4,1C8.2,17,8.1,17,8,17zM9.9,12.5l-0.5,2.1l2.1-0.5l9.3-9.3c0.4-0.4,0.4-1.1,0-1.6c-0.4-0.4-1.2-0.4-1.6,0l0,0L9.9,12.5z M18.5,2.5L18.5,2.5L18.5,2.5z"></path></svg> Edit this page on GitHub<!--]--></a></div><div class="last-updated" data-v-bae355c8><p class="VPLastUpdated" data-v-bae355c8 data-v-ec8405ef>Last updated: <time datetime="2024-09-14T10:57:31.000Z" data-v-ec8405ef></time></p></div></div><nav class="prev-next" data-v-bae355c8><div class="pager" data-v-bae355c8><a class="pager-link prev" href="/development/aws/serverless" data-v-bae355c8><span class="desc" data-v-bae355c8>Previous page</span><span class="title" data-v-bae355c8>Serverless architecture</span></a></div><div class="pager" data-v-bae355c8><a class="pager-link next" href="/development/aws/handson-bashoutter" data-v-bae355c8><span class="desc" data-v-bae355c8>Next page</span><span class="title" data-v-bae355c8>Hands-on 6: Bashoutter</span></a></div></nav></footer><!--[--><!--[--><!--[--><div id="comment-container"></div><!--]--><!--]--><!--]--></div></div></div><!--[--><!--]--></div></div><footer class="VPFooter has-sidebar" data-v-f6284a77 data-v-b69a1592><div class="container" data-v-b69a1592><p class="message" data-v-b69a1592>Wrote with <i class="heart fa fa-heart fa-xs fa-beat"></i> and <i class="coffee fa fa-coffee fa-xs" aria-hidden="true"></i> by <a href="https://toshiki.dev">Anda Toshiki</a> at <code>root@andatoshiki:/~</code></p><p class="copyright" data-v-b69a1592>Copyright © 2023-2024 <a href="https://github.com/andatoshiki">Anda Toshiki</a>, <a href="https://github.com/lolilab">LoliLab</a> and <a href="https://github.com/toshikidev">Toshiki Dev</a> present <br /><span id="siteruntime_span"></span></p></div></footer><!--[--><!--]--></div></div>
<script>window.__VP_HASH_MAP__=JSON.parse("{\"academic_cis105_cis105-l11-lecture-note.md\":\"dcae7d7d\",\"academic_chemistry_index.md\":\"ba3ae95f\",\"academic_cis105_cis105-l10-lecture-note.md\":\"1db02e5b\",\"academic_cis105_cis105-l13-lecture-note.md\":\"976b8fa3\",\"academic_cis105_cis105-l12-lecture-note.md\":\"a0ea1384\",\"academic_chemistry_problems_03-02-2.md\":\"7acd1c70\",\"academic_chemistry_problems_03-02-3.md\":\"0ae48661\",\"save_reading_outliers_1.md\":\"71757af9\",\"academic_cis105_cis105-l8-lecture-note.md\":\"9363cce7\",\"academic_vocabulary_2023_02_2023-02-27.md\":\"e4251bb6\",\"academic_vocabulary_index.md\":\"23cd9048\",\"application_markdown-it-katex_how-to-use.md\":\"b7459d30\",\"application_markdown-it-katex_tips.md\":\"035a5adb\",\"academic_chemistry_notes_12-5.md\":\"3c4e276c\",\"academic_cis105_index.md\":\"cafb2281\",\"academic_cis105_cis105-l1-lecture-note.md\":\"23b6f238\",\"academic_cis105_cis105-l5-lecture-note.md\":\"18e16812\",\"development_aws_author.md\":\"9e93d326\",\"application_vitepress-plugin-shiki-twoslash_api_annotations.md\":\"a6f74159\",\"development_aws_handson-jupyter.md\":\"e4b622dd\",\"development_aws_acknowledgement.md\":\"d08f49a6\",\"academic_physics_ipho-formulas-jpn_8.md\":\"e0a1f3c0\",\"development_aws_appendix.md\":\"a869b3c7\",\"development_aws_assignments.md\":\"89c815b1\",\"academic_cis105_cis105-l16-lecture-note.md\":\"af3f1274\",\"development_file-naming-convention.md\":\"3d3270cc\",\"academic_chemistry_problems_02-20.md\":\"a7d8e1be\",\"academic_cis105_cis105-l3-lecture-note.md\":\"b9700860\",\"development_aws_docker-system.md\":\"3942ad51\",\"development_installing-npm-package-behind-proxy.md\":\"9af33e7d\",\"development_aws_handson-bashoutter.md\":\"a78cc683\",\"development_aws_cloud.md\":\"51be64bc\",\"javascript_notes_1_1-1.md\":\"da7ef5af\",\"javascript_notes_1_1-2.md\":\"adf622d4\",\"jp_index.md\":\"63d2ec28\",\"application_vitepress-plugin-shiki-twoslash_api_queries.md\":\"ccae91c5\",\"roadmap.md\":\"5d6c0a73\",\"academic_cis105_cis105-l15-lecture-note.md\":\"0b8d057e\",\"academic_cis105_cis105-l17-lecture-note.md\":\"e1e2d40a\",\"academic_physics_index.md\":\"fb9780e6\",\"development_aws_handson-ec2.md\":\"9fe87b48\",\"academic_literature_writing_methods-of-development.md\":\"90be882b\",\"development_aws_aws-get-started.md\":\"58ce5679\",\"development_aws_webserver.md\":\"109fd1c7\",\"development_aws_closing.md\":\"4058a8ad\",\"application_vitepress-plugin-shiki-twoslash_api_types.md\":\"a1b6fd64\",\"development_aws_serverless.md\":\"d6db190f\",\"application_vitepress-plugin-shiki-twoslash_config_flags.md\":\"13318419\",\"application_vitepress-plugin-shiki-twoslash_config_reference.md\":\"6de83933\",\"academic_cis105_cis105-l4-lecture-note.md\":\"d68c3c89\",\"application_vitepress-plugin-shiki-twoslash_guide_custom-theme.md\":\"7f44f862\",\"application_vitepress-plugin-shiki-twoslash_guide_markdown-extensions.md\":\"b100c15e\",\"development_proxy4shell-terminal.md\":\"dfe13d19\",\"index.md\":\"e5510aac\",\"application_vitepress-plugin-shiki-twoslash_index.md\":\"f38adabf\",\"development_rclone-for-r2.md\":\"10868742\",\"academic_cis105_cis105-l9-lecture-note.md\":\"a43a66ee\",\"application_vitepress-plugin-shiki-twoslash_api_multi-file.md\":\"4a0615c0\",\"application_vitepress-plugin-shiki-twoslash_api_errors.md\":\"51c0047a\",\"development_aws_scientific-computing.md\":\"c1e9992c\",\"application_vitepress-plugin-shiki-twoslash_api_emit.md\":\"fe66ee32\",\"application_vitepress-plugin-shiki-twoslash_api_logging.md\":\"d5f7938c\",\"save_reading_outliers_2.md\":\"ea888244\",\"save_reading_outliers_3.md\":\"e6b01e02\",\"save_reading_outliers_4.md\":\"f881ad44\",\"academic_cis105_cis105-l6-pt2-lecture-note.md\":\"7346f82a\",\"academic_cis105_cis105-l7-lecture-note.md\":\"f5ab720b\",\"academic_physics_ipho-formulas-jpn_2.md\":\"3590a49b\",\"application_vitepress-plugin-shiki-twoslash_api_includes.md\":\"0ec2ad17\",\"academic_chemistry_problems_03-02-1.md\":\"49fab6b8\",\"academic_physics_ipho-formulas-jpn_6.md\":\"105bb130\",\"academic_physics_ipho-formulas-jpn_5.md\":\"beb4cbb2\",\"academic_physics_ipho-formulas-jpn_7.md\":\"f454b8a5\",\"development_aws_handson-qabot.md\":\"58364bc9\",\"development_aws_handson-serverless.md\":\"38fdac97\",\"development_aws_index.md\":\"f11e549e\",\"development_aws_license.md\":\"32e3a6ca\",\"academic_literature_index.md\":\"db84651f\",\"academic_cis105_cis105-l14-lecture-note.md\":\"bf9f01f6\",\"development_git-push-authentication-failed.md\":\"583e69cc\",\"academic_cis105_cis105-l18-lecture-note.md\":\"913e8d11\",\"academic_physics_ipho-formulas-jpn_11.md\":\"397cfe75\",\"academic_cis105_cis105-l2-lecture-note.md\":\"8708106f\",\"save_reading_index.md\":\"7c707485\",\"academic_cis105_cis105-l6-pt1-lecture-note.md\":\"27e33baa\",\"academic_physics_ipho-formulas-jpn_9.md\":\"e9846aba\",\"academic_physics_ipho-formulas-jpn_13.md\":\"c5279afd\",\"development_aws_aws-batch.md\":\"aefedbfa\",\"academic_physics_ipho-formulas-jpn_4.md\":\"09049e77\",\"academic_physics_ipho-formulas-jpn_10.md\":\"1ad4bbaf\",\"academic_physics_ipho-formulas-jpn_12.md\":\"a20477ff\",\"application_vitepress-plugin-shiki-twoslash_api_cutting.md\":\"2325bcd6\",\"development_aws_main.md\":\"4f66446b\",\"academic_physics_ipho-formulas-jpn_3.md\":\"19839164\",\"academic_physics_ipho-formulas-jpn_1.md\":\"cbbb8be5\",\"application_markdown-it-katex_support-function.md\":\"65323d29\",\"application_markdown-it-katex_support-table.md\":\"64126c3a\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Toshiki's Note\",\"description\":\"Toshiki's web notebook served via Vitepress!\",\"base\":\"/\",\"head\":[],\"appearance\":true,\"themeConfig\":{\"nav\":[{\"text\":\"Development\",\"link\":\"/development/file-naming-convention\"},{\"text\":\"Academic\",\"items\":[{\"text\":\"K-12\",\"items\":[{\"text\":\"Chemistry\",\"link\":\"/academic/chemistry/index\",\"activeMatch\":\"/academic/chemistry/\"},{\"text\":\"Discrete Math.\",\"link\":\"/discrete-math/index\",\"activeMatch\":\"/categories/fragments/\"},{\"text\":\"Literature\",\"link\":\"/academic/literature/index\",\"activeMatch\":\"/academic/literature/\"},{\"text\":\"CIS105\",\"link\":\"/academic/cis105/index\",\"activeMatch\":\"/academic/cis105/\"}]},{\"text\":\"Tools\",\"items\":[{\"text\":\"Formulas for IPhO JPN.\",\"link\":\"/academic/physics/ipho-formulas-jpn/1\",\"activeMatch\":\"/academic/physics/ipho-formulas-jpn/\"}]},{\"text\":\"\",\"link\":\"\",\"activeMatch\":\"\"},{\"text\":\"\",\"link\":\"\",\"activeMatch\":\"\"},{\"text\":\"\",\"link\":\"\",\"activeMatch\":\"\"},{\"text\":\"\",\"link\":\"\",\"activeMatch\":\"\"},{\"text\":\"\",\"link\":\"\",\"activeMatch\":\"\"},{\"text\":\"\",\"link\":\"\",\"activeMatch\":\"\"},{\"text\":\"\",\"link\":\"\",\"activeMatch\":\"\"}],\"activeMatch\":\"/academic/\"},{\"text\":\"Application\",\"items\":[{\"text\":\"Personal projects\",\"items\":[{\"text\":\"markdown-it-katex\",\"link\":\"/application/markdown-it-katex/how-to-use\",\"activeMatch\":\"/application/markdown-it-katex/\"},{\"text\":\"vitepress-plugin-shiki-twoslash\",\"link\":\"/application/vitepress-plugin-shiki-twoslash/index\",\"activeMatch\":\"/application/vitepress-plugin-shiki-twoslash/index\"}]}],\"activeMatch\":\"/save/\"},{\"text\":\"Save\",\"items\":[{\"text\":\"Reading\",\"link\":\"/save/reading/index\",\"activeMatch\":\"/save/reading/\"},{\"text\":\"Vocabulary\",\"link\":\"/academic/vocabulary/index\",\"activeMatch\":\"/academic/vocabulary/\"}],\"activeMatch\":\"/save/\"}],\"sidebar\":{\"/development/\":[{\"text\":\"Notes & Issues\",\"collapsed\":false,\"items\":[{\"text\":\"File Naming Convention\",\"link\":\"/development/file-naming-convention\"},{\"text\":\"RClone for R2\",\"link\":\"/development/rclone-for-r2\"},{\"text\":\"Proxies Configuration for Shells & Terminal\",\"link\":\"/development/proxy4shell-terminal\"},{\"text\":\"Git push results in \\\"Authentication Failed\\\"\",\"link\":\"/development/git-push-authentication-failed\"},{\"text\":\"Installing NPM Packages Behind Proxy\",\"link\":\"/development/installing-npm-package-behind-proxy\"}]},{\"text\":\"コードで学ぶAWS入門\",\"collapsed\":false,\"items\":[{\"text\":\"背景\",\"link\":\"/development/aws/index\"},{\"text\":\"はじめに!\",\"link\":\"/development/aws/main\"},{\"text\":\"クラウド概論\",\"link\":\"/development/aws/cloud.md\"},{\"text\":\"AWS 入門\",\"link\":\"/development/aws/aws-get-started\"},{\"text\":\"Hands-on 1: 初めての EC2 インスタンスを起動する\",\"link\":\"/development/aws/handson-ec2.md\"},{\"text\":\"クラウドで行う科学計算・機械学習\",\"link\":\"/development/aws/scientific-computing.md\"},{\"text\":\"Hands-on 2: AWS でディープラーニングを実践\",\"link\":\"/development/aws/handson-ec2.md\"},{\"text\":\"Docker 入門\",\"link\":\"/development/aws/docker-system\"},{\"text\":\"Hands-on 3: AWS で自動質問回答ボットを走らせる\",\"link\":\"/development/aws/handson-qabot\"},{\"text\":\"Hands-on 4: AWS Batch を使って機械学習のハイパーパラメータサーチを並列化する\",\"link\":\"/development/aws/aws-batch\"},{\"text\":\"Web サービスの作り方\",\"link\":\"/development/aws/webserver\"},{\"text\":\"Serverless architecture\",\"link\":\"/development/aws/serverless\"},{\"text\":\"Hands-on 5: サーバーレス入門\",\"link\":\"/development/aws/handson-serverless\"},{\"text\":\"Hands-on 6: Bashoutter\",\"link\":\"/development/aws/handson-bashoutter\"},{\"text\":\"まとめ\",\"link\":\"/development/aws/closing\"},{\"text\":\"ppendix: 環境構築\",\"link\":\"/development/aws/appendix\"},{\"text\":\"謝辞\",\"link\":\"/development/aws/acknowledgement\"}]}],\"/academic/chemistry/\":[{\"text\":\"Textbook\",\"collapsed\":true,\"items\":[{\"text\":\"12-5: Reaction Mechanism\",\"link\":\"/academic/chemistry/notes/12-5\"},{\"text\":\"\",\"link\":\"\"},{\"text\":\"\",\"link\":\"\"},{\"text\":\"\",\"link\":\"\"},{\"text\":\"\",\"link\":\"\"},{\"text\":\"\",\"link\":\"\"},{\"text\":\"\",\"link\":\"\"},{\"text\":\"\",\"link\":\"\"}]},{\"text\":\"Kinetics\",\"collapsed\":false,\"items\":[{\"text\":\"Rate determining steps\",\"link\":\"/academic/chemistry/notes/kinetics/rate-determining-step\"},{\"text\":\"\",\"link\":\"\"},{\"text\":\"\",\"link\":\"\"},{\"text\":\"\",\"link\":\"\"}]},{\"text\":\"Problems & Solutions\",\"collapsed\":true,\"items\":[{\"text\":\"Problem: 02-20\",\"link\":\"/academic/chemistry/problems/02-20\"},{\"text\":\"Problem: 03-02-1\",\"link\":\"/academic/chemistry/problems/03-02-1\"},{\"text\":\"Problem: 03-02-2\",\"link\":\"/academic/chemistry/problems/03-02-2\"},{\"text\":\"Problem: 03-02-3\",\"link\":\"/academic/chemistry/problems/03-02-3\"}]}],\"/academic/physics\":[{\"text\":\"IPhO Formulas: JP Ver.\",\"collapsed\":false,\"items\":[{\"text\":\"1: 数学\",\"link\":\"/academic/physics/ipho-formulas-jpn/1\"},{\"text\":\"2: 一般的な推奨事\",\"link\":\"/academic/physics/ipho-formulas-jpn/2\"},{\"text\":\"3: 運動学\",\"link\":\"/academic/physics/ipho-formulas-jpn/3\"},{\"text\":\"4: 力学\",\"link\":\"/academic/physics/ipho-formulas-jpn/4\"},{\"text\":\"5: 振動と波\",\"link\":\"/academic/physics/ipho-formulas-jpn/5\"},{\"text\":\"6: 幾何光学,測光\",\"link\":\"/academic/physics/ipho-formulas-jpn/6\"},{\"text\":\"7: 波動光学\",\"link\":\"/academic/physics/ipho-formulas-jpn/7\"},{\"text\":\"8: 電気回路\",\"link\":\"/academic/physics/ipho-formulas-jpn/8\"},{\"text\":\"9: 電磁気学\",\"link\":\"/academic/physics/ipho-formulas-jpn/9\"},{\"text\":\"10: 熱力\",\"link\":\"/academic/physics/ipho-formulas-jpn/10\"},{\"text\":\"11: 量子力学\",\"link\":\"/academic/physics/ipho-formulas-jpn/11\"},{\"text\":\"12: Keplerの法則\",\"link\":\"/academic/physics/ipho-formulas-jpn/12\"},{\"text\":\"13: 相対性理論\",\"link\":\"/academic/physics/ipho-formulas-jpn/13\"}]}],\"/academic/cis105/\":[{\"text\":\"CIS 105: Computer Applications and Information Technology\",\"collapsed\":false,\"items\":[{\"text\":\"Course Overview & Schedule\",\"link\":\"/academic/cis105/index\"},{\"text\":\"Lect 1: Everything Changes\",\"link\":\"/academic/cis105/cis105-l1-lecture-note\"},{\"text\":\"Lect 2: Application Software\",\"link\":\"/academic/cis105/cis105-l2-lecture-note\"},{\"text\":\"Lect 3: Computer Hardware\",\"link\":\"/academic/cis105/cis105-l3-lecture-note\"},{\"text\":\"Lect 4: Formulas and Functions\",\"link\":\"/academic/cis105/cis105-l4-lecture-note\"},{\"text\":\"Lect 5: Operating System\",\"link\":\"/academic/cis105/cis105-l5-lecture-note\"},{\"text\":\"Lect 6 Pt 1: System Software\",\"link\":\"/academic/cis105/cis105-l6-pt1-lecture-note\"},{\"text\":\"Lect 6 Pt 2: Logical Functions\",\"link\":\"/academic/cis105/cis105-l6-pt2-lecture-note\"},{\"text\":\"Lect 7: Green Business Computing\",\"link\":\"/academic/cis105/cis105-l7-lecture-note\"},{\"text\":\"Lect 8: Green Computer Networks\",\"link\":\"/academic/cis105/cis105-l8-lecture-note\"},{\"text\":\"Lect 9: Internet\",\"link\":\"/academic/cis105/cis105-l9-lecture-note\"},{\"text\":\"Lect 10: Business Websites\",\"link\":\"/academic/cis105/cis105-l10-lecture-note\"},{\"text\":\"Lect 11: Computer Security\",\"link\":\"/academic/cis105/cis105-l11-lecture-note\"},{\"text\":\"Lect 12: Introduction to SQL\",\"link\":\"/academic/cis105/cis105-l12-lecture-note\"},{\"text\":\"Lect 13: Information Systems in Business\",\"link\":\"/academic/cis105/cis105-l13-lecture-note\"},{\"text\":\"Lect 14: More SQL Statements\",\"link\":\"/academic/cis105/cis105-l14-lecture-note\"},{\"text\":\"Lect 15: Business System Reporting\",\"link\":\"/academic/cis105/cis105-l15-lecture-note\"},{\"text\":\"Lect 16: Information Technology Careers\",\"link\":\"/academic/cis105/cis105-l16-lecture-note\"},{\"text\":\"Lect 17: SQL Clauses: JOIN Query\",\"link\":\"/academic/cis105/cis105-l17-lecture-note\"},{\"text\":\"Lect 18: Databases\",\"link\":\"/academic/cis105/cis105-l18-lecture-note\"}]}],\"/academic/vocabulary/\":[{\"text\":\"Vocabulary\",\"collapsed\":true,\"items\":[{\"text\":\"2023-02-27\",\"link\":\"/academic/vocabulary/2023/02/2023-02-27\"}]}],\"/academic/literature/\":[{\"text\":\"Writing Resources\",\"collapsed\":true,\"items\":[{\"text\":\"Patterns of Organization and Methods of Development\",\"link\":\"/academic/literature/writing/methods-of-development\"}]}],\"/javascript/\":[{\"text\":\"1: Basic JavaScript-Value, Variables, and Control Flow\",\"collapsed\":true,\"items\":[{\"text\":\"1-1: Numbers\",\"link\":\"/javascript/notes/1/1-1\"},{\"text\":\"\",\"link\":\"\"},{\"text\":\"\",\"link\":\"\"},{\"text\":\"\",\"link\":\"\"},{\"text\":\"\",\"link\":\"\"}]}],\"/save/reading/\":[{\"text\":\"Outliers\",\"collapsed\":true,\"items\":[{\"text\":\"Introduction & Chapter 1: The Roseto Mystery\",\"link\":\"/save/reading/outliers/1\"},{\"text\":\"Chapter 2: The 10,000-Hour Rule\",\"link\":\"/save/reading/outliers/2\"},{\"text\":\"Chapter 3: The Trouble with Geniuses, Part 1\",\"link\":\"/save/reading/outliers/3\"},{\"text\":\"Chapter 4: The Trouble with Geniuses, Part 2\",\"link\":\"/save/reading/outliers/4\"}]}],\"/application/markdown-it-katex/\":[{\"text\":\"markdown-it-katex\",\"collapsed\":false,\"items\":[{\"text\":\"1: How to use?\",\"link\":\"/application/markdown-it-katex/how-to-use\"},{\"text\":\"2: KaTeX supported functions\",\"link\":\"/application/markdown-it-katex/support-function\"},{\"text\":\"3: KaTeX support tables\",\"link\":\"/application/markdown-it-katex/support-table\"},{\"text\":\"4: Tips\",\"link\":\"/application/markdown-it-katex/tips\"}]}],\"/application/vitepress-plugin-shiki-twoslash/\":[{\"text\":\"Guide\",\"collapsed\":false,\"items\":[{\"text\":\"Getting Started\",\"link\":\"/application/vitepress-plugin-shiki-twoslash/\"},{\"text\":\"Markdown Extensions\",\"link\":\"/application/vitepress-plugin-shiki-twoslash/guide/markdown-extensions\"},{\"text\":\"Using a Custom Theme\",\"link\":\"/application/vitepress-plugin-shiki-twoslash/guide/custom-theme\"}]},{\"text\":\"Features\",\"collapsed\":false,\"items\":[{\"text\":\"Queries\",\"link\":\"/application/vitepress-plugin-shiki-twoslash/api/queries\"},{\"text\":\"Errors\",\"link\":\"/application/vitepress-plugin-shiki-twoslash/api/errors\"},{\"text\":\"Emit\",\"link\":\"/application/vitepress-plugin-shiki-twoslash/api/emit\"},{\"text\":\"Cutting\",\"link\":\"/application/vitepress-plugin-shiki-twoslash/api/cutting\"},{\"text\":\"Multi-file\",\"link\":\"/application/vitepress-plugin-shiki-twoslash/api/multi-file\"},{\"text\":\"@types\",\"link\":\"/application/vitepress-plugin-shiki-twoslash/api/types\"},{\"text\":\"Meta Annotations\",\"link\":\"/application/vitepress-plugin-shiki-twoslash/api/annotations\"},{\"text\":\"Logging\",\"link\":\"/application/vitepress-plugin-shiki-twoslash/api/logging\"},{\"text\":\"Includes\",\"link\":\"/application/vitepress-plugin-shiki-twoslash/api/includes\"}]},{\"text\":\"Config\",\"collapsed\":false,\"items\":[{\"text\":\"Reference\",\"link\":\"/application/vitepress-plugin-shiki-twoslash/config/reference\"},{\"text\":\"Compiler Flags\",\"link\":\"/application/vitepress-plugin-shiki-twoslash/config/flags\"}]}]},\"footer\":{\"copyright\":\"Copyright © 2023-2024 <a href=\\\"https://github.com/andatoshiki\\\">Anda Toshiki</a>, <a href=\\\"https://github.com/lolilab\\\">LoliLab</a> and <a href=\\\"https://github.com/toshikidev\\\">Toshiki Dev</a> present <br /><span id=\\\"siteruntime_span\\\"></span>\",\"message\":\"Wrote with <i class=\\\"heart fa fa-heart fa-xs fa-beat\\\"></i> and <i class=\\\"coffee fa fa-coffee fa-xs\\\" aria-hidden=\\\"true\\\"></i> by <a href=\\\"https://toshiki.dev\\\">Anda Toshiki</a> at <code>root@andatoshiki:/~</code>\"},\"logo\":\"/logos/logo.png\",\"outline\":\"deep\",\"outlineTitle\":\"TOC\",\"outlineBadges\":false,\"lastUpdatedText\":\"Last updated\",\"algolia\":{\"appId\":\"G9IUR45K98\",\"apiKey\":\"8528cc91281d8112b28f508317a96dd3\",\"indexName\":\"toshiki-notebook\"},\"editLink\":{\"pattern\":\"https://github.com/andatoshiki/toshiki-notebook/edit/master/docs/:path\",\"text\":\"Edit this page on GitHub\"},\"socialLinks\":[{\"icon\":\"github\",\"link\":\"https://github.com/andatoshiki\"},{\"icon\":\"twitter\",\"link\":\"https://twitter.com/andatoshiki\"}]},\"locales\":{\"/\":{\"label\":\"English\",\"lang\":\"en-US\"},\"/jp/\":{\"label\":\"Japanese\",\"title\":\"Vue Test Utils\",\"lang\":\"jp-JP\",\"description\":\"La documentation officielle de Vue Test Utils\"}},\"scrollOffset\":90,\"cleanUrls\":true}");</script>
</body>
</html>